NovaBryan/EVE_Dump
Log | Files | 📦 下载最新源码 (.zip) | Refs | README

service.py (60732B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\script\sys\service.py
      2 from future.utils import raise_
      3 import types
      4 import weakref
      5 import sys
      6 import cPickle
      7 import binascii
      8 import traceback
      9 import blue
     10 import locks
     11 import log
     12 import stackless
     13 import uthread
     14 from carbon.common.script.sys.serviceConst import *
     15 from carbon.common.script.util.logUtil import supersafestr
     16 from carbon.common.script.util.timerstuff import ClockThisWithoutTheStars
     17 from cluster import SERVICE_BEYONCE, SERVICE_STATION, SERVICE_CHARACTER, SERVICE_CHATX, SERVICE_USER, SERVICE_CLUSTERSINGLETON
     18 from eve.common.lib.appConst import CHARNODE_MOD
     19 from eveexceptions import UserError
     20 from stdlogutils import LineWrap
     21 from eveprefs import prefs, boot
     22 callWrapperLocks = {}
     23 callWrapperID = 0
     24 allCallWrappers = weakref.WeakValueDictionary({})
     25 
     26 def GetCallWrappers():
     27     global allCallWrappers
     28     return allCallWrappers
     29 
     30 
     31 class CachedResult():
     32 
     33     def __init__(self, result):
     34         self.result = result
     35 
     36 
     37 class FastCallWrapper(object):
     38 
     39     def __init__(self, session, obj, method, parent):
     40         self.session = session
     41         self.callable = getattr(obj, method)
     42         self.parent = parent
     43 
     44     def __repr__(self):
     45         return '<FastCallWrapper session:%r, callable:%r>' % (self.session, self.callable)
     46 
     47     def __call__(self, *args, **keywords):
     48         with self.session.Masquerade({'base.caller': weakref.ref(self.parent)}):
     49             return self.callable(*args, **keywords)
     50 
     51 
     52 class CallWrapper():
     53     if boot.role == 'client':
     54         __precall__ = ['PreCall_IsExportedCall', 'PreCall_CheckPreArgs', 'PreCall_CachedMethodCall']
     55     else:
     56         __precall__ = ['PreCall_IsExportedCall',
     57          'PreCall_RoleCheck',
     58          'PreCall_CheckPreArgs',
     59          'PreCall_CachedMethodCall',
     60          'PreCall_Lock']
     61     __postcall__ = ['PostCall_CachedMethodCall', 'PostCall_LogCompletedMethodCall', 'PostCall_UnLock']
     62 
     63     def __init__(self, session, object, method, parent, logname = None):
     64         global callWrapperID
     65         if logname is None:
     66             import carbon.common.script.net.machobase as macho
     67             logname = macho.GetLogName(object)
     68         self.__logname__ = logname
     69         self.__session__ = session
     70         self.__method__ = method
     71         if method.endswith('_Ex'):
     72             self.__method_without_Ex__ = method[:-3]
     73         else:
     74             self.__method_without_Ex__ = method
     75         self.__callable__ = object
     76         self.__parent__ = parent
     77         self.__metadata__ = getattr(self.__callable__, '__exportedcalls__', {}).get(self.__method_without_Ex__, [])
     78         self.__thread__ = stackless.getcurrent()
     79         self.requiredRole = ROLE_SERVICE
     80         callWrapperID += 1
     81         allCallWrappers[callWrapperID] = self
     82 
     83     def __call__(self, *args, **keywords):
     84         machoNet = sm.GetServiceIfRunning('machoNet')
     85         if machoNet and machoNet.IsClusterShuttingDown() and session.userid:
     86             log.general.Log('Cluster shutting down, rejecting service call from %s' % session.userid, log.LGNOTICE)
     87             return
     88         from carbon.common.script.net.objectCaching import CacheOK
     89         from carbon.common.script.sys.basesession import CallTimer
     90         with CallTimer(self.__logname__ + '::' + self.__method_without_Ex__):
     91             self.__arguments__ = args
     92             mask = self.__session__.Masquerade({'base.caller': weakref.ref(self.__parent__)})
     93             try:
     94                 cookies = {}
     95                 result = None
     96                 tb = None
     97                 try:
     98                     try:
     99                         for method in self.__precall__:
    100                             if type(self.__metadata__) == types.DictType:
    101                                 extra = self.__metadata__.get('callhandlerargs', {})
    102                             else:
    103                                 extra = {}
    104                             cookieName = method
    105                             if type(method) == types.StringType:
    106                                 method = getattr(self.__callable__, method, getattr(self, method, None))
    107                             cookies[cookieName] = method(self.__method__, args, keywords, **extra)
    108 
    109                     except CacheOK as result:
    110                         tb = sys.exc_info()[2]
    111                         sys.exc_clear()
    112                     except CachedResult as result:
    113                         tb = sys.exc_info()[2]
    114                         sys.exc_clear()
    115                     except Exception as result:
    116                         tb = sys.exc_info()[2]
    117                         sys.exc_clear()
    118                     except:
    119                         log.LogTraceback('Bummer in service.py, all bets are off')
    120                         raise
    121 
    122                     try:
    123                         if result is None:
    124                             args2 = args
    125                             if self.__method_without_Ex__ == self.__method__ or not session.role & ROLE_SERVICE:
    126                                 preargs = []
    127                                 if type(self.__metadata__) == types.DictType:
    128                                     if 'preargs' in self.__metadata__:
    129                                         preargs = self.__metadata__['preargs']
    130                                 elif len(self.__metadata__) > 1:
    131                                     preargs = self.__metadata__[1:]
    132                                 if preargs:
    133                                     args2 = len(preargs) * [None] + list(args)
    134                                     for i in range(len(preargs)):
    135                                         args2[i] = getattr(session, preargs[i])
    136 
    137                             try:
    138                                 if boot.role == 'server' and self.requiredRole in (ROLE_ANY, ROLE_PLAYER) and getattr(session, 'clientID', None) is not None:
    139                                     if prefs.GetValue('enableSecurityMonitor', 0):
    140                                         sm.GetService('securityMonitor').LogCallFromClient(getattr(self.__callable__, '__guid__', 'guid not found'), self.__method_without_Ex__, args2, keywords)
    141                             except Exception as e:
    142                                 log.LogException('Exception invoking the security monitor. Continuing processing the call')
    143                                 sys.exc_clear()
    144 
    145                             if hasattr(self.__callable__, 'PreCallAction'):
    146                                 self.__callable__.PreCallAction(self.__method_without_Ex__)
    147                             result = getattr(self.__callable__, self.__method_without_Ex__)(*args2, **keywords)
    148                     except UserError as result:
    149                         tb = sys.exc_info()[2]
    150                         sys.exc_clear()
    151                     except Exception as result:
    152                         tb = sys.exc_info()[2]
    153                         sys.exc_clear()
    154                     except:
    155                         log.LogTraceback('OMG caught something else during call')
    156                         raise
    157 
    158                     for method in self.__postcall__:
    159                         try:
    160                             if type(self.__metadata__) == types.DictType:
    161                                 extra = self.__metadata__.get('callhandlerargs', {})
    162                             else:
    163                                 extra = {}
    164                             if type(method) == types.StringType:
    165                                 method = getattr(self.__callable__, method, getattr(self, method, None))
    166                             method(cookies, result, self.__method__, args, keywords, **extra)
    167                         except CacheOK as result:
    168                             tb = sys.exc_info()[2]
    169                             sys.exc_clear()
    170                         except CachedResult as result:
    171                             tb = sys.exc_info()[2]
    172                             sys.exc_clear()
    173                         except Exception as result:
    174                             tb = sys.exc_info()[2]
    175                             sys.exc_clear()
    176                         except:
    177                             log.LogTraceback('argh!  caught something else during call')
    178                             raise
    179 
    180                     if result is not None:
    181                         if isinstance(result, Exception):
    182                             raise_(result, None, tb)
    183                         elif isinstance(result, CachedResult):
    184                             return result.result
    185                 finally:
    186                     tb = None
    187 
    188             finally:
    189                 mask.UnMask()
    190                 self.__dict__.clear()
    191 
    192             return result
    193 
    194     def PreCall_StartCallTimer(self, method, args, keywords, **mykeywords):
    195         from carbon.common.script.sys.basesession import CallTimer
    196         return CallTimer(self.__logname__ + '::' + self.__method_without_Ex__)
    197 
    198     def PostCall_StopCallTimer(self, cookies, result, method, args, keywords, **mykeywords):
    199         sct = cookies.get('PreCall_StartCallTimer', None)
    200         if sct is not None:
    201             sct.Done()
    202 
    203     __machomethods__ = ('MachoResolve', 'MachoBindObject', 'MachoResolveObject', 'MachoGetObjectBoundToSession')
    204 
    205     def PreCall_IsExportedCall(self, method, args, keywords, **mykeywords):
    206         if method in ('SetLogInfo', 'SetLogWarning', 'SetLogNotice'):
    207             return
    208         if method not in self.__callable__.__exportedcalls__ and method not in self.__machomethods__:
    209             if not (self.__method__ != self.__method_without_Ex__ and self.__method_without_Ex__ in self.__callable__.__exportedcalls__):
    210                 raise RuntimeError('In %s, method %s is not exported' % (self.__logname__, self.__method_without_Ex__))
    211 
    212     def PreCall_RoleCheck(self, method, args, keywords, **mykeywords):
    213         if not session.role & ROLE_SERVICE:
    214             if type(self.__metadata__) == types.DictType:
    215                 role = self.__metadata__.get('role', ROLE_SERVICE)
    216             elif len(self.__metadata__):
    217                 role = self.__metadata__[0]
    218             elif method in self.__machomethods__:
    219                 role = ROLE_ANY
    220             else:
    221                 role = ROLE_SERVICE
    222             self.requiredRole = role
    223             if not role & session.role:
    224                 session.LogSessionError("Called %s::%s, which requires role 0x%x, which the user doesn't have. User has role 0x%x" % (self.__logname__,
    225                  method,
    226                  role,
    227                  session.role))
    228                 raise RuntimeError('RoleNotAssigned', "%s::%s requires role 0x%x, which the user doesn't have. User has role 0x%x. Calling session: %s" % (self.__logname__,
    229                  method,
    230                  role,
    231                  session.role,
    232                  str(session)))
    233 
    234     def PreCall_CheckPreArgs(self, method, args, keywords, **mykeywords):
    235         if not (session.role & ROLE_SERVICE and method.endswith('_Ex')):
    236             if type(self.__metadata__) == types.DictType:
    237                 preargs = self.__metadata__.get('preargs', [])
    238             elif len(self.__metadata__):
    239                 preargs = self.__metadata__[1:]
    240             else:
    241                 preargs = []
    242             for each in preargs:
    243                 prearg = getattr(session, each)
    244                 if prearg is None:
    245                     session.LogSessionError('A required parameter exception occurred while the user was calling %s::%s.  The missing parameter was %s' % (self.__logname__, self.__method_without_Ex__, each))
    246                     raise RuntimeError('RequiredParameterException', "%s::%s requires parameter %s, which the session doesn't have.  Calling session: %s" % (self.__logname__,
    247                      self.__method_without_Ex__,
    248                      each,
    249                      str(session)))
    250 
    251     def PostCall_LogCompletedMethodCall(self, cookies, result, method, args, keywords, **mykeywords):
    252         logChannel = log.methodcalls
    253         if logChannel.IsOpen(log.LGINFO):
    254             if isinstance(result, Exception):
    255                 eorr = ', EXCEPTION='
    256             else:
    257                 eorr = ', retval='
    258             if keywords:
    259                 logwhat = [self.__logname__,
    260                  '::',
    261                  method,
    262                  ' args=',
    263                  args,
    264                  ', keywords={',
    265                  keywords,
    266                  '}',
    267                  eorr,
    268                  result]
    269             else:
    270                 logwhat = [self.__logname__,
    271                  '::',
    272                  method,
    273                  ' args=',
    274                  args,
    275                  eorr,
    276                  result]
    277             try:
    278                 s = ''.join(map(supersafestr, logwhat))
    279                 if len(s) > 2500:
    280                     s = s[:2500]
    281                 logChannel.Log(s, log.LGINFO, 1)
    282             except TypeError:
    283                 logChannel.Log('[X]'.join(map(supersafestr, logwhat)).replace('\x00', '\\0'), log.LGINFO, 1)
    284                 sys.exc_clear()
    285             except UnicodeEncodeError:
    286                 logChannel.Log('[U]'.join(map(lambda x: x.encode('ascii', 'replace'), map(unicode, logwhat))), log.LGINFO, 1)
    287                 sys.exc_clear()
    288 
    289     def PreCall_Lock(self, method, args, keywords, **mykeywords):
    290         lock = mykeywords.get('lock.lock', 1)
    291         if lock:
    292             scope = mykeywords.get('lock.scope', 'usersession')
    293             if scope == 'usersession' and self.__session__.role & ROLE_SERVICE:
    294                 return
    295             useargs = mykeywords.get('lock.useargs', 0)
    296             try:
    297                 group = mykeywords['lock.group']
    298             except KeyError:
    299                 group = (self.__logname__, method)
    300                 if scope == 'instance':
    301                     group = self.__logname__
    302 
    303             if useargs:
    304                 k = ('PreCall_Lock', group, args)
    305             else:
    306                 k = ('PreCall_Lock', group)
    307             if scope in ('usersession', 'session'):
    308                 k = (k, 'session', self.__session__.sid)
    309             elif scope == 'connection':
    310                 k = (k, 'connection', self.__parent__.__c2ooid__)
    311             elif scope == 'instance':
    312                 k = (k, 'instance', self.__parent__.GetInstanceID())
    313             elif scope == 'service':
    314                 if isinstance(self.__callable__, CoreService):
    315                     k = (k, 'service', self.__parent__.GetInstanceID())
    316                 else:
    317                     srv = sm.StartService(self.__parent__.__serviceName__)
    318                     k = (k, 'service', srv.startedWhen)
    319             elif scope in ('class', 'global'):
    320                 if scope == 'class':
    321                     try:
    322                         k = (k, scope, self.__callable__.__class__.__name__)
    323                     except:
    324                         k = (k,
    325                          scope,
    326                          'logname',
    327                          self.__logname__)
    328 
    329             l = callWrapperLocks.get(k, None)
    330             if not l:
    331                 l = [uthread.Semaphore(k), None]
    332                 callWrapperLocks[k] = l
    333                 cool = True
    334             else:
    335                 cool = l[0].IsCool()
    336             if not cool:
    337                 reaction = mykeywords.get('lock.reaction', 'block')
    338                 if reaction == 'raise':
    339                     othermethod = '<unknown>'
    340                     if l[1] is not None:
    341                         othermethod = l[1][0]
    342                     raise UserError(mykeywords.get('lock.raisemsg', 'CallGroupLocked'), {'thismethod': method,
    343                      'group': group,
    344                      'scope': scope,
    345                      'othermethod': othermethod})
    346                 else:
    347                     if reaction == 'inform':
    348                         keywords['reentrancy'] = l[1]
    349                         return
    350                     if reaction == 'ignore':
    351                         raise CachedResult(None)
    352             sys.exc_clear()
    353             l[0].acquire()
    354             l[1] = (method, args, keywords)
    355             return k
    356 
    357     def PostCall_UnLock(self, cookies, result, method, args, keywords, **mykeywords):
    358         k = cookies.get('PreCall_Lock', None)
    359         if k is not None:
    360             l = callWrapperLocks[k]
    361             l[1] = None
    362             l[0].release()
    363             if l[0].IsCool():
    364                 try:
    365                     if callWrapperLocks[k] is l:
    366                         del callWrapperLocks[k]
    367                 except KeyError:
    368                     pass
    369 
    370     def PreCall_CachedMethodCall(self, method, args, keywords, **mykeywords):
    371         machoVersion = keywords.get('machoVersion', None)
    372         if machoVersion and not mykeywords.get('PreCall_CachedMethodCall.retainMachoVersion', 0):
    373             if len(keywords) == 1:
    374                 keywords.clear()
    375             else:
    376                 del keywords['machoVersion']
    377         cacheInfo = sm.GetService('objectCaching').PerformCachedMethodCall(self.__callable__, self.__logname__, self.__method_without_Ex__, args, machoVersion)
    378         cachable, versionCheck, throwOK, cachedResultRecord, cacheKey, cacheDetails = cacheInfo
    379         if cachable and not versionCheck:
    380             if throwOK:
    381                 from carbon.common.script.net.objectCaching import CacheOK
    382                 raise CacheOK()
    383             elif cachedResultRecord:
    384                 if machoVersion:
    385                     raise CachedResult(cachedResultRecord['rret'])
    386                 else:
    387                     raise CachedResult(cachedResultRecord['lret'])
    388         return (cacheInfo, machoVersion)
    389 
    390     def PostCall_CachedMethodCall(self, cookies, result, method, args, keywords, **mykeywords):
    391         cookie = cookies.get('PreCall_CachedMethodCall', None)
    392         if cookie is not None:
    393             if not isinstance(result, Exception):
    394                 cacheInfo, machoVersion = cookie
    395                 if cacheInfo[0]:
    396                     srv = sm.StartService('objectCaching')
    397                     from carbon.common.script.net.objectCaching import CachedMethodCallResult, CacheOK
    398                     cachable, versionCheck, throwOK, cachedResultRecord, cacheKey, cacheDetails = cacheInfo
    399                     cmcr = CachedMethodCallResult(cacheKey, cacheDetails, result)
    400                     srv.CacheMethodCall(self.__logname__, self.__method_without_Ex__, args, cmcr)
    401                     if machoVersion is not None:
    402                         if machoVersion != 1 and cmcr.GetVersion()[1] == machoVersion[1]:
    403                             srv.LogInfo('ObjectCaching ', self.__logname__, '::', self.__method_without_Ex__, '(', args, ') is the correct version.  raising CacheOK')
    404                             raise CacheOK()
    405                         else:
    406                             srv.LogInfo('ObjectCaching ', self.__logname__, '::', self.__method_without_Ex__, '(', args, ') is not the correct version.  returning a cachable result.  caller=', machoVersion, ', server=', cmcr.GetVersion())
    407                         raise CachedResult(cmcr)
    408                     else:
    409                         errorDesc = "ObjectCaching %s::%s (%s) - the client didn't provide a macho version, not even the default value.  Probably an unbound call to a cached method call, which is NOT supported." % (self.__logname__, self.__method_without_Ex__, args)
    410 
    411 
    412 class ServiceCallWrapper(CallWrapper):
    413     if boot.role == 'client':
    414         __precall__ = ['PreCall_WaitForRunningState',
    415          'PreCall_IsExportedCall',
    416          'PreCall_CheckPreArgs',
    417          'PreCall_CachedMethodCall']
    418     else:
    419         __precall__ = ['PreCall_WaitForRunningState',
    420          'PreCall_IsExportedCall',
    421          'PreCall_RoleCheck',
    422          'PreCall_CheckPreArgs',
    423          'PreCall_CachedMethodCall',
    424          'PreCall_Lock']
    425 
    426     def PreCall_WaitForRunningState(self, method, args, keywords, **mykeywords):
    427         i = 0
    428         while self.__callable__.state != SERVICE_RUNNING:
    429             if self.__callable__.state == SERVICE_STOPPED:
    430                 raise RuntimeError('ServiceStopped', self.__callable__)
    431             blue.pyos.synchro.SleepWallclock(100)
    432             if i % 600 == 0 and i > 0:
    433                 self.__callable__.LogWarn('PreCallHandler:  ', method, args, keywords, ' has been sleeping for a long time waiting for ', self.__logname__, ' to either get to running state, or to stopped state')
    434 
    435 
    436 class UnlockedServiceCallWrapper(ServiceCallWrapper):
    437     if boot.role == 'client':
    438         __precall__ = ['PreCall_WaitForRunningState',
    439          'PreCall_IsExportedCall',
    440          'PreCall_CheckPreArgs',
    441          'PreCall_CachedMethodCall']
    442     else:
    443         __precall__ = ['PreCall_WaitForRunningState',
    444          'PreCall_IsExportedCall',
    445          'PreCall_RoleCheck',
    446          'PreCall_CheckPreArgs',
    447          'PreCall_CachedMethodCall']
    448 
    449 
    450 globalMiniTraceStats = {}
    451 
    452 class MiniTraceCallWrapper():
    453 
    454     def __init__(self, service, func, funcName, depth):
    455         self.service = weakref.proxy(service)
    456         self.func = func
    457         self.funcName = funcName
    458         self.depth = depth
    459 
    460     def __call__(self, *args, **kw):
    461         if self.service.logChannel.IsOpen(1):
    462             stats = globalMiniTraceStats[self.service.__guid__, self.funcName]
    463             l = self.depth
    464             if l == -1:
    465                 l = 2
    466             tb = traceback.extract_stack(limit=l)[:-1]
    467             tb = [ (i[0], i[2], i[1]) for i in tb ]
    468             k0 = tb[-1]
    469             for k in tb:
    470                 stats[k] = stats.get(k, 0) + 1
    471 
    472             self.service.LogInfo(self.funcName, args, kw, ' is being called by ', k0[1], ' in line ', k0[2], ' of ', k0[0])
    473             return self.func(*args, **kw)
    474         else:
    475             return self.func(*args, **kw)
    476 
    477 
    478 MiniTraceStats = globalMiniTraceStats
    479 
    480 class CoreService(object):
    481     __startupdependencies__ = []
    482     __dependencies__ = []
    483     __required__ = ['Sessions']
    484     __name__ = 'service'
    485     __displayname__ = 'Basic Service'
    486     __persistvars__ = []
    487     __nonpersistvars__ = []
    488     __exportedcalls__ = {}
    489     __notifyevents__ = []
    490     __configvalues__ = {}
    491     __counters__ = {}
    492     __machocacheobjects__ = 1
    493     __machoresolve__ = None
    494 
    495     def __init__(self):
    496         super(CoreService, self).__init__()
    497         self.boundObjects = {}
    498         self.serviceLocks = {}
    499         self.startedWhen = blue.os.GetWallclockTimeNow()
    500         self.__servicename__ = getattr(self, '__replaceservice__', self.__guid__.split('.')[1])
    501         self.__logname__ = self.__servicename__
    502         self.logChannel = log.GetChannel(self.__guid__)
    503         self.InitService()
    504         if len(self.__counters__) and 'counter' not in self.__startupdependencies__:
    505             self.__startupdependencies__.append('counter')
    506         self.isLogInfo = bool(prefs.GetValue('logInfo', 1))
    507         self.isLogNotice = bool(prefs.GetValue('logNotice', 1))
    508         self.isLogWarning = bool(prefs.GetValue('logWarning', 1))
    509         self.logContexts = {}
    510         for each in ('Info', 'Warn', 'Error', 'Perf'):
    511             self.logContexts[each] = 'Logging::' + each
    512 
    513     def SetLogInfo(self, b):
    514         if not b and self.isLogInfo:
    515             self.LogInfo('*** LogInfo stopped for ', self.__guid__)
    516         old = self.isLogInfo
    517         self.isLogInfo = b
    518         if b and not old:
    519             self.LogInfo('*** LogInfo started for ', self.__guid__)
    520 
    521     def SetLogNotice(self, b):
    522         if not b and self.isLogNotice:
    523             self.LogNotice('*** LogNotice stopped for ', self.__guid__)
    524         old = self.isLogNotice
    525         self.isLogNotice = b
    526         if b and not old:
    527             self.LogNotice('*** LogNotice started for ', self.__guid__)
    528 
    529     def SetLogWarning(self, b):
    530         if not b and self.isLogWarning:
    531             self.LogWarn('*** LogWarn stopped for ', self.__guid__)
    532         old = self.isLogWarning
    533         self.isLogWarning = b
    534         if b and not old:
    535             self.LogWarn('*** LogWarn started for ', self.__guid__)
    536 
    537     def MachoResolve(self, sess):
    538         if self.__machoresolve__ is not None:
    539             return self._MachoResolveAdditional(sess)
    540 
    541     def _MachoResolveAdditional(self, sess):
    542         if self.__machoresolve__ is None:
    543             return
    544         if sess.role & ROLE_SERVICE:
    545             return
    546         macho = sm.GetService('machoNet')
    547         if self.__machoresolve__ == 'station':
    548             if not sess.stationid:
    549                 return 'You must be located at a station to use this service'
    550             return macho.GetNodeFromAddress(SERVICE_STATION, sess.stationid)
    551         if self.__machoresolve__ == 'solarsystem':
    552             if not sess.solarsystemid:
    553                 return 'You must be located in a solar system to use this service'
    554             return macho.GetNodeFromAddress(SERVICE_BEYONCE, sess.solarsystemid)
    555         if self.__machoresolve__ == 'solarsystem2':
    556             if not sess.solarsystemid2:
    557                 return 'Your location must belong to a known solarsystem'
    558             return macho.GetNodeFromAddress(SERVICE_BEYONCE, sess.solarsystemid2)
    559         if self.__machoresolve__ in ('location', 'locationPreferred'):
    560             if not sess.locationid:
    561                 if self.__machoresolve__ == 'locationPreferred':
    562                     return
    563                 return 'You must be located in a solar system or at station to use this service'
    564             if sess.solarsystemid:
    565                 return macho.GetNodeFromAddress(SERVICE_BEYONCE, sess.solarsystemid)
    566             if sess.stationid:
    567                 return macho.GetNodeFromAddress(SERVICE_STATION, sess.stationid)
    568             raise RuntimeError('machoresolving a location bound service with without a location session')
    569         if self.__machoresolve__ in ('character',):
    570             if sess.charid is None:
    571                 return
    572             else:
    573                 return macho.GetNodeFromAddress(SERVICE_CHARACTER, sess.charid % CHARNODE_MOD)
    574         if self.__machoresolve__ in ('corporation',):
    575             if sess.corpid is None:
    576                 return 'You must have a corpid in your session to use this service'
    577             else:
    578                 return macho.GetNodeFromAddress(SERVICE_CHATX, sess.corpid % 200)
    579         if self.__machoresolve__.startswith('clustersingleton'):
    580             return GetClusterSingletonNodeFromAddress(macho, self.__machoresolve__)
    581         if self.__machoresolve__ == 'user':
    582             if sess.userid is None:
    583                 return 'You must have a userid in your session to use this service'
    584             return macho.GetNodeFromAddress(SERVICE_USER, sess.userid % const.USERNODE_MOD)
    585         raise RuntimeError('__machoresolve__ = %s on service %s is bogus.' % (self.__machoresolve__, self.__logname__))
    586 
    587     def __GetCachedObject(self, key):
    588         return self.boundObjects.get(key, None)
    589 
    590     def __SetCachedObject(self, key, object):
    591         if self.__machocacheobjects__:
    592             self.boundObjects[key] = object
    593 
    594     def __DelCachedObject(self, key):
    595         try:
    596             del self.boundObjects[key]
    597         except KeyError:
    598             pass
    599 
    600     def MachoGetObjectBoundToSession(self, bindParams, callerSession):
    601         with self.LockedService(bindParams):
    602             obj = self.__GetCachedObject(bindParams)
    603             if obj is None:
    604                 obj = self.MachoBindObject(bindParams)
    605                 if not hasattr(obj, 'sessionConnections'):
    606                     obj.objectConnections = {}
    607                     obj.sessionConnections = weakref.WeakValueDictionary({})
    608                     obj.machoInstanceID = blue.os.GetWallclockTimeNow()
    609                     obj.boundBy = bindParams
    610                 self.__SetCachedObject(bindParams, obj)
    611         return ClockThisWithoutTheStars('CoreService::ConnectToObject', callerSession.ConnectToObject, (obj, self.__servicename__, bindParams))
    612 
    613     def RemoveSessionConnectionFromObject(self, connection):
    614         boundObject = connection.__object__
    615         sessionID = connection.__session__.sid
    616         connectionID = connection.__c2ooid__
    617         try:
    618             del boundObject.objectConnections[sessionID][connectionID]
    619         except KeyError:
    620             pass
    621         except Exception:
    622             log.LogException()
    623 
    624         try:
    625             if not boundObject.objectConnections[sessionID]:
    626                 try:
    627                     connection.PseudoMethodCall(boundObject, 'OnSessionDetach')
    628                 except Exception:
    629                     log.LogException()
    630 
    631                 try:
    632                     del boundObject.sessionConnections[sessionID]
    633                 except KeyError:
    634                     self.LogError('Hmmm, session', sessionID, 'missing from', boundObject.sessionConnections.keys(), 'disconnected?', connection.__disconnected__)
    635 
    636         except KeyError:
    637             self.LogError('Woot? Session', sessionID, "isn't in", boundObject.objectConnections.keys())
    638 
    639         try:
    640             del connection.__session__.connectedObjects[connectionID]
    641         except KeyError:
    642             log.LogException()
    643 
    644         with self.LockedService(boundObject.boundBy):
    645             if hasattr(boundObject, 'sessionConnections'):
    646                 if len(boundObject.sessionConnections) == 0:
    647                     delattr(boundObject, 'sessionConnections')
    648                     self.__DelCachedObject(boundObject.boundBy)
    649                     if len(boundObject.objectConnections):
    650                         boundObject.objectConnections.clear()
    651                     connection.PseudoMethodCall(boundObject, 'OnStop')
    652                     if hasattr(boundObject, 'service'):
    653                         delattr(boundObject, 'service')
    654                     if hasattr(boundObject, 'session'):
    655                         delattr(boundObject, 'session')
    656                     for dependency in getattr(boundObject, 'dependencies', []):
    657                         delattr(boundObject, dependency)
    658 
    659     def LockService(self, lockID):
    660         try:
    661             lock = self.serviceLocks[lockID]
    662         except KeyError:
    663             lock = locks.RLock(('service::serviceLock', self.__logname__, lockID))
    664             self.serviceLocks[lockID] = lock
    665 
    666         lock.acquire()
    667         return lock
    668 
    669     def ServiceLockCheck(self, lockID):
    670         if lockID not in self.serviceLocks or self.serviceLocks[lockID].IsCool():
    671             return 0
    672         else:
    673             return max(1, (blue.os.GetWallclockTime() - self.serviceLocks[lockID].lockedWhen) / const.SEC)
    674 
    675     def UnLockService(self, lockID, lock):
    676         lock.release()
    677         if lock.IsCool():
    678             del self.serviceLocks[lockID]
    679 
    680     class LockedServiceCtxt(object):
    681 
    682         def __init__(self, svc, lockKey):
    683             self.svc = svc
    684             self.lockKey = lockKey
    685 
    686         def __enter__(self):
    687             self.lock = self.svc.LockService(self.lockKey)
    688 
    689         def __exit__(self, e, v, tb):
    690             self.svc.UnLockService(self.lockKey, self.lock)
    691 
    692     def LockedService(self, lockKey):
    693         return self.LockedServiceCtxt(self, lockKey)
    694 
    695     def StartMiniTrace(self, funcName, depth = 16):
    696         if funcName not in globalMiniTraceStats:
    697             globalMiniTraceStats[self.__guid__, funcName] = {}
    698             setattr(self, funcName, MiniTraceCallWrapper(self, getattr(self, funcName), funcName, depth))
    699 
    700     def StopMiniTrace(self, funcName, depth = 16):
    701         if funcName not in globalMiniTraceStats:
    702             del globalMiniTraceStats[self.__guid__, funcName]
    703             setattr(self, funcName, getattr(self, funcName).func)
    704 
    705     def GetDependants(self):
    706         dependants = []
    707         myName = self.__servicename__
    708         for i in sm.services:
    709             if myName in sm.services[i].__dependencies__:
    710                 dependants.append(sm.services[i].__servicename__)
    711 
    712         return dependants
    713 
    714     def GetDeepDependants(self, theArr):
    715         newbies = []
    716         for each in self.GetDependants():
    717             if each not in theArr:
    718                 newbies.append(each)
    719                 theArr.append(each)
    720 
    721         for each in newbies:
    722             sm.services[each].GetDeepDependants(theArr)
    723 
    724     def GetDeepDependencies(self, theArr):
    725         newbies = []
    726         for each in self.__dependencies__:
    727             if each not in theArr:
    728                 newbies.append(each)
    729                 theArr.append(each)
    730 
    731         for each in newbies:
    732             sm.services[each].GetDeepDependencies(theArr)
    733 
    734     def InitService(self):
    735         self.state = SERVICE_STOPPED
    736 
    737     def __getattr__(self, key):
    738         if key in self.__configvalues__:
    739             daKey = '%s.%s' % (self.__logname__, key)
    740             return prefs.GetValue(daKey, boot.GetValue(daKey, self.__configvalues__[key]))
    741         if key in self.__counters__:
    742             self.__dict__[key] = self.counter.CreateCounter(key, self.__counters__[key])
    743             return self.__dict__[key]
    744         if hasattr(self.__class__, key):
    745             return getattr(self.__class__, key)
    746         raise_(AttributeError, key)
    747 
    748     def __setattr__(self, key, value):
    749         super(CoreService, self).__setattr__(key, value)
    750         if key in self.__configvalues__:
    751             value = self.OnSetConfigValue(key, value)
    752             prefs.SetValue('%s.%s' % (self.__logname__, key), value)
    753             return
    754         self.__dict__[key] = value
    755 
    756     def ControlMessage(self, control):
    757         if control == SERVICE_CONTROL_STOP:
    758             self.state = SERVICE_STOPPED
    759         elif control == SERVICE_CONTROL_PAUSE:
    760             self.state = SERVICE_PAUSED
    761         elif control == SERVICE_CONTROL_CONTINUE:
    762             self.state = SERVICE_RUNNING
    763         elif control == SERVICE_CONTROL_INTERROGATE:
    764             pass
    765         elif control == SERVICE_CONTROL_SHUTDOWN:
    766             self.state = SERVICE_STOPPED
    767 
    768     def DudLogger(self, *args, **keywords):
    769         pass
    770 
    771     def LogMethodCall(self, *args, **keywords):
    772         logChannel = log.methodcalls
    773         if logChannel.IsOpen(log.LGINFO):
    774             try:
    775                 s = ' '.join(map(supersafestr, args))
    776                 logChannel.Log(s, log.LGINFO, 1)
    777             except TypeError:
    778                 logChannel.Log('[X]'.join(map(supersafestr, args)).replace('\x00', '\\0'), log.LGINFO, 1)
    779                 sys.exc_clear()
    780             except UnicodeEncodeError:
    781                 logChannel.Log('[U]'.join(map(lambda x: x.encode('ascii', 'replace'), map(unicode, args))), log.LGINFO, 1)
    782                 sys.exc_clear()
    783 
    784         else:
    785             self.LogMethodCall = self.DudLogger
    786 
    787     def LogInfo(self, *args, **keywords):
    788         if getattr(self, 'isLogInfo', 0) and self.logChannel.IsLogChannelOpen(1):
    789             try:
    790                 s = ' '.join(map(supersafestr, args))
    791                 self.logChannel.Log(s, 1, 1, force=True)
    792             except TypeError:
    793                 self.logChannel.Log('[X]'.join(map(supersafestr, args)).replace('\x00', '\\0'), 1, 1, force=True)
    794                 sys.exc_clear()
    795             except UnicodeEncodeError:
    796                 self.logChannel.Log('[U]'.join(map(lambda x: x.encode('ascii', 'replace'), map(unicode, args))), 1, 1, force=True)
    797                 sys.exc_clear()
    798 
    799     def LogWarn(self, *args, **keywords):
    800         if self.isLogWarning and self.logChannel.IsLogChannelOpen(2) or charsession and not boot.role == 'client':
    801             try:
    802                 s = ' '.join(map(supersafestr, args))
    803                 if self.logChannel.IsOpen(2):
    804                     self.logChannel.Log(s, 2, 1, force=True)
    805                 for x in LineWrap(s, 10):
    806                     if charsession and not boot.role == 'client':
    807                         charsession.LogSessionHistory(x, None, 1)
    808 
    809             except TypeError:
    810                 sys.exc_clear()
    811                 x = '[X]'.join(map(supersafestr, args)).replace('\x00', '\\0')
    812                 if self.logChannel.IsOpen(2):
    813                     self.logChannel.Log(x, 2, 1, force=True)
    814                 if charsession and not boot.role == 'client':
    815                     charsession.LogSessionHistory(x, None, 1)
    816             except UnicodeEncodeError:
    817                 sys.exc_clear()
    818                 x = '[U]'.join(map(lambda x: x.encode('ascii', 'replace'), map(unicode, args)))
    819                 if self.logChannel.IsOpen(2):
    820                     self.logChannel.Log(x, 2, 1, force=True)
    821                 if charsession and not boot.role == 'client':
    822                     charsession.LogSessionHistory(x, None, 1)
    823 
    824     def LogError(self, *args, **keywords):
    825         if self.logChannel.IsOpen(4) or charsession:
    826             try:
    827                 s = ' '.join(map(supersafestr, args))
    828                 if self.logChannel.IsOpen(4):
    829                     self.logChannel.Log(s, 4, 1)
    830                 for x in LineWrap(s, 40):
    831                     if charsession:
    832                         charsession.LogSessionHistory(x, None, 1)
    833 
    834             except TypeError:
    835                 sys.exc_clear()
    836                 x = '[X]'.join(map(supersafestr, args)).replace('\x00', '\\0')
    837                 if self.logChannel.IsOpen(4):
    838                     self.logChannel.Log(x, 4, 1)
    839                 if charsession:
    840                     charsession.LogSessionHistory(x, None, 1)
    841             except UnicodeEncodeError:
    842                 sys.exc_clear()
    843                 x = '[U]'.join(map(lambda x: x.encode('ascii', 'replace'), map(unicode, args)))
    844                 if self.logChannel.IsOpen(4):
    845                     self.logChannel.Log(x, 4, 1)
    846                 if charsession and not boot.role == 'client':
    847                     charsession.LogSessionHistory(x, None, 1)
    848 
    849     def LogNotice(self, *args, **_unused_keywords):
    850         if getattr(self, 'isLogNotice', 0) and self.logChannel.IsLogChannelOpen(log.LGNOTICE):
    851             try:
    852                 s = ' '.join(map(supersafestr, args))
    853                 self.logChannel.Log(s, log.LGNOTICE, 1, force=True)
    854             except TypeError:
    855                 s = '[X]'.join(map(supersafestr, args)).replace('\x00', '\\0')
    856                 self.logChannel.Log(s, log.LGNOTICE, 1, force=True)
    857                 sys.exc_clear()
    858             except UnicodeEncodeError:
    859                 s = '[U]'.join(map(lambda x: x.encode('ascii', 'replace'), map(unicode, args)))
    860                 self.logChannel.Log(s, log.LGNOTICE, 1, force=True)
    861                 sys.exc_clear()
    862 
    863     def LogException(self, extraText = ''):
    864         log.LogException(extraText, channel=self.__guid__)
    865         sys.exc_clear()
    866 
    867     def LogTraceback(self, extraText = ''):
    868         log.LogTraceback(extraText, show_locals=2, channel=self.__guid__)
    869 
    870     def Run(self, memStream = None):
    871         self.LogInfo('Service: %s starting' % (self.__guid__,))
    872         self.boundObjects = {}
    873 
    874     def Entering(self):
    875         pass
    876 
    877     def Stop(self, memStream = None):
    878         for bo in self.boundObjects.values():
    879             for sess in bo.sessionConnections.values():
    880                 sess.DisconnectObject(bo)
    881 
    882         self.boundObjects = {}
    883 
    884     def IsRunning(self):
    885         return getattr(self, 'state', SERVICE_STOPPED) == SERVICE_RUNNING
    886 
    887     def GetSessionState(self, session_ = None):
    888         if session_ is not None:
    889             session = session_
    890         if session is None:
    891             raise RuntimeError('No session')
    892         return session.GetBag(self.__guid__)
    893 
    894     def GetServiceState(self):
    895         states = {SERVICE_STOPPED: 'Stopped',
    896          SERVICE_START_PENDING: 'Start Pending',
    897          SERVICE_STOP_PENDING: 'Stop Pending',
    898          SERVICE_RUNNING: 'Running',
    899          SERVICE_CONTINUE_PENDING: 'Continue Pending',
    900          SERVICE_PAUSE_PENDING: 'Pause Pending',
    901          SERVICE_PAUSED: 'Paused',
    902          SERVICE_FAILED: 'Failed to start'}
    903         return states.get(self.state, 'unknown')
    904 
    905     def GetHtmlState(self, writer, session = None, request = None):
    906         from carbon.common.script.util import htmlwriter
    907         wr = htmlwriter.HtmlWriter()
    908         if writer is None:
    909             return '(no info available)'
    910         writer.Write(self.HTMLDumpProperties('Basic Service properties', 'wpServiceProperties', self, session, request))
    911         if len(self.__configvalues__):
    912             hd = ['Key',
    913              'Pretty Name',
    914              'Value',
    915              'Default Value',
    916              'Info']
    917             li = []
    918             for each in self.__configvalues__.iterkeys():
    919                 prettyname = each
    920                 info = None
    921                 value = getattr(self, each)
    922                 if hasattr(self, 'GetHtmlStateDetails'):
    923                     r = self.GetHtmlStateDetails(each, value, 0)
    924                     if r:
    925                         prettyname, info = r[0], r[1]
    926                 if value != self.__configvalues__[each]:
    927                     value = '<b>%s</b>' % value
    928                 li.append([each,
    929                  prettyname,
    930                  value,
    931                  self.__configvalues__[each],
    932                  info])
    933 
    934             li.sort(lambda a, b: -(a[0].upper() < b[0].upper()))
    935             edit = '<a href="/admin/services.py?action=EditConfigValues&svcname=%s">Click to edit</a>' % (self.__servicename__,)
    936             writer.Write(htmlwriter.WebPart('Service Config Values - ' + edit, wr.GetTable(hd, li, useFilter=True), 'wpServiceConfigValues'))
    937         if len(self.__counters__):
    938             hd = ['Key',
    939              'Pretty Name',
    940              'Type',
    941              'Current Value',
    942              'Description']
    943             li = []
    944             for each in self.__counters__.iterkeys():
    945                 cname = each
    946                 prettyname = cname
    947                 ctype = self.__counters__[each]
    948                 cvalue = 0
    949                 if hasattr(self, each):
    950                     cvalue = getattr(self, each).Value()
    951                 info = ''
    952                 if hasattr(self, 'GetHtmlStateDetails'):
    953                     r = self.GetHtmlStateDetails(each, cvalue, 0)
    954                     if r:
    955                         prettyname, info = r[0], r[1]
    956                 li.append([cname,
    957                  prettyname,
    958                  ctype,
    959                  cvalue,
    960                  info])
    961 
    962             li.sort(lambda a, b: -(a[0].upper() < b[0].upper()))
    963             reset = '<a href="/admin/services.py?action=ResetCounters&svcname=%s" onClick="return confirm(\'Are you sure?\')">Click to reset</a>' % (self.__servicename__,)
    964             writer.Write(htmlwriter.WebPart('Service Counters - ' + reset, wr.GetTable(hd, li, useFilter=True), 'wpServiceCounters'))
    965         det = '<a href="/admin/services.py?svcname=%s&propertyDetail=yes">Click to view details</a><br>' % self.__servicename__
    966         writer.Write(htmlwriter.WebPart('Service Member Variables - %s' % det, self.HTMLDumpGenericMembers(self, session, request), 'wpServiceMemberVariables'))
    967         if hasattr(self, 'boundObjects'):
    968             if request:
    969                 objectDetail = request.QueryString('objectDetail')
    970                 if objectDetail is not None:
    971                     objectDetail = cPickle.loads(binascii.a2b_hex(objectDetail))
    972             else:
    973                 objectDetail = None
    974             object = self.boundObjects.get(objectDetail, None)
    975             if object:
    976                 writer.WriteH2('Bound Object %s' % unicode(objectDetail))
    977                 if object.__doc__ is not None:
    978                     writer.Write(htmlwriter.Swing(object.__doc__).replace('\n', '<br>'))
    979                 writer.Write(self.HTMLDumpProperties('Properties of Bound Object %s' % unicode(objectDetail), 'wpBoundObjectProperties %s' % unicode(objectDetail), object, session, request))
    980                 writer.Write(self.HTMLDumpGenericMembers(object, session, request))
    981         self.HTMLWriteServiceMethods(writer, session, request)
    982         self.HTMLWriteExtraState(writer, session, request)
    983 
    984     def HTMLWriteExtraState(self, writer, session, request):
    985         pass
    986 
    987     def HTMLWriteServiceMethods(self, writer, session, request):
    988         from carbon.common.script.util import htmlwriter
    989         hd = ['Method', 'Roles']
    990         li = []
    991         for method in self.__exportedcalls__:
    992             details = self.__exportedcalls__[method]
    993             if type(details) == types.DictType:
    994                 role = details.get('role', 0)
    995             elif len(details) > 0:
    996                 role = details[0]
    997             else:
    998                 role = 0
    999             from carbon.common.script.sys import serviceConst
   1000             if role == serviceConst.ROLE_ANY:
   1001                 rolestr = 'ANY'
   1002             else:
   1003                 rolestr = ''
   1004                 for each in dir(serviceConst):
   1005                     if each.startswith('ROLE_') and getattr(serviceConst, each) & role != 0:
   1006                         rolestr += each[5:] + ', '
   1007 
   1008                 rolestr = rolestr[:-2]
   1009             li.append([writer.Link('', method, {'action': 'WebExec',
   1010               'service': self.__guid__.split('.')[1],
   1011               'method': method}), rolestr])
   1012 
   1013         li.sort()
   1014         wr = htmlwriter.HtmlWriter()
   1015         writer.Write(htmlwriter.WebPart('Service Methods', wr.GetTable(hd, li, useFilter=True), 'wpServiceMethods'))
   1016         svcname = self.__servicename__
   1017         txt = '<table>'
   1018         txt += '\n            <tr><td>Info Logging:</td><td> %s</td><td>\n            &nbsp;|&nbsp;&nbsp;<a href="?action=ToggleInfoLog&svcname=%s&which=%s">Toggle</a>\n            &nbsp;&middot;&nbsp;&nbsp;<a href="?action=ToggleInfoLog&svcname=%s&allnodes=1&which=1" OnClick="return confirm(\'Are you sure?\');">Start on All Nodes</a>\n            &nbsp;&middot;&nbsp;&nbsp;<a href="?action=ToggleInfoLog&svcname=%s&allnodes=1&which=0">Stop on All Nodes</a></tr>\n            ' % (['OFF', '<font color=red><b>ON</b></font>'][self.isLogInfo],
   1019          svcname,
   1020          int(not self.isLogInfo),
   1021          svcname,
   1022          svcname)
   1023         txt += '\n            <tr><td>Notice Logging:</td><td> %s</td><td>\n            &nbsp;|&nbsp;&nbsp;<a href="?action=ToggleNoticeLog&svcname=%s&which=%s">Toggle</a>\n            &nbsp;&middot;&nbsp;&nbsp;<a href="?action=ToggleNoticeLog&svcname=%s&allnodes=1&which=1" OnClick="return confirm(\'Are you sure?\');">Start on All Nodes</a>\n            &nbsp;&middot;&nbsp;&nbsp;<a href="?action=ToggleNoticeLog&svcname=%s&allnodes=1&which=0">Stop on All Nodes</a></tr>\n            ' % (['OFF', '<font color=red><b>ON</b></font>'][self.isLogNotice],
   1024          svcname,
   1025          int(not self.isLogNotice),
   1026          svcname,
   1027          svcname)
   1028         txt += '\n            <tr><td>Warning Logging:</td><td> %s</td><td>\n            &nbsp;|&nbsp;&nbsp;<a href="?action=ToggleWarningLog&svcname=%s&which=%s">Toggle</a>\n            &nbsp;&middot;&nbsp;&nbsp;<a href="?action=ToggleWarningLog&svcname=%s&allnodes=1&which=1">Start on All Nodes</a>\n            &nbsp;&middot;&nbsp;&nbsp;<a href="?action=ToggleWarningLog&svcname=%s&allnodes=1&which=0">Stop on All Nodes</a></tr>\n            ' % (['OFF', '<b>ON</b>'][self.isLogWarning],
   1029          svcname,
   1030          int(not self.isLogWarning),
   1031          svcname,
   1032          svcname)
   1033         txt += '</table>'
   1034         writer.Write(htmlwriter.WebPart('Logging', '<div style="padding:5px;">%s</div>' % txt, 'wpServiceLogging'))
   1035 
   1036     def HTMLDumpGenericMembers(self, dumpWho, session, request):
   1037         from carbon.common.script.util import htmlwriter
   1038         wr = htmlwriter.HtmlWriter()
   1039         if request:
   1040             detail = request.QueryString('detail')
   1041         else:
   1042             detail = None
   1043         if request:
   1044             propertyDetails = request.QueryString('propertyDetail') == 'yes'
   1045             from carbon.common.script.util.profiling import CalcMemoryUsage
   1046         else:
   1047             propertyDetails = False
   1048 
   1049         def Str(v):
   1050             from carbon.common.script.util import htmlwriter
   1051             try:
   1052                 return htmlwriter.Swing(unicode(v))
   1053             except:
   1054                 sys.exc_clear()
   1055                 return '(?)'
   1056 
   1057         li = []
   1058         theItems = dumpWho.__dict__.keys()
   1059         theItems.sort(lambda a, b: -(a.upper() < b.upper()))
   1060         something = 0
   1061         for k in theItems:
   1062             v = dumpWho.__dict__[k]
   1063             if hasattr(dumpWho, '__dependencies__') and k in dumpWho.__dependencies__:
   1064                 continue
   1065             if hasattr(dumpWho, '__configvalues__') and k in dumpWho.__configvalues__:
   1066                 continue
   1067             if hasattr(dumpWho, '__exportedcalls__') and k in dumpWho.__exportedcalls__:
   1068                 continue
   1069             if hasattr(dumpWho, '__counters__') and k in dumpWho.__counters__:
   1070                 continue
   1071             if k in ('state', 'startedWhen', 'serviceLocks', 'logChannel', 'session', 'boundObjects', '__servicelock__', 'objectConnections', 'sessionConnections', '__sessionfilter__', '__logname__', 'logContexts'):
   1072                 continue
   1073             if k.startswith('_' + dumpWho.__class__.__name__ + '__'):
   1074                 k = k[len('_' + dumpWho.__class__.__name__):]
   1075             r = None
   1076             ok = k
   1077             if hasattr(dumpWho, 'GetHtmlStateDetails'):
   1078                 r = dumpWho.GetHtmlStateDetails(k, v, k == detail)
   1079             if r:
   1080                 if propertyDetails and type(r[1]) in types.StringTypes:
   1081                     xtra = ' [type: %s]' % type(v).__name__
   1082                     length = None
   1083                     try:
   1084                         length = len(v)
   1085                         xtra += ' [length: %d]' % len(v)
   1086                     except:
   1087                         pass
   1088 
   1089                     try:
   1090                         xtra += ' [memusage: %d]' % CalcMemoryUsage(v)[2]
   1091                     except:
   1092                         pass
   1093 
   1094                     k, v = r[0], r[1]
   1095                 else:
   1096                     k, v = r[0], r[1]
   1097             elif k != detail:
   1098                 if type(v) in (types.ListType,
   1099                  types.TupleType,
   1100                  types.DictType,
   1101                  types.InstanceType) or isinstance(v, dict):
   1102                     xtra = ''
   1103                     if propertyDetails and (type(v) in (types.ListType, types.TupleType, types.DictType) or isinstance(v, dict)):
   1104                         xtra = ' - length: %d' % len(v)
   1105                         try:
   1106                             xtra += ' [memusage: %d kB]' % int(int(CalcMemoryUsage(v)[2]) / 1024)
   1107                         except Exception as e:
   1108                             xtra += ' [memusage: ??] %s' % e
   1109 
   1110                     v = '&lt;click details to view&gt; [type: %s]%s' % (type(v).__name__, xtra)
   1111                 else:
   1112                     v = Str(v)
   1113             else:
   1114                 var = getattr(dumpWho, detail, None)
   1115                 if type(var) in [types.ListType, types.TupleType]:
   1116                     lines = []
   1117                     for i in var:
   1118                         lines.append([Str(i)])
   1119 
   1120                     v = htmlwriter.GetTable([], lines)
   1121                 elif isinstance(v, dict):
   1122                     lines = []
   1123                     for key, val in var.iteritems():
   1124                         lines.append([Str(key), Str(val)])
   1125 
   1126                     v = htmlwriter.GetTable([], lines)
   1127                 else:
   1128                     v = Str(v)
   1129                     v = '<pre>%s</pre>' % v
   1130             k = htmlwriter.Link('', k, [request.query, {'detail': ok}])
   1131             li.append([k, v])
   1132             something = 1
   1133 
   1134         if not something:
   1135             return 'This service does not have any custom member variables'
   1136         return wr.GetTable([], li)
   1137 
   1138     def HTMLDumpProperties(self, title, page, dumpWho, session, request):
   1139         from carbon.common.script.util import htmlwriter
   1140 
   1141         def Str(v):
   1142             from carbon.common.script.util import htmlwriter
   1143             try:
   1144                 return htmlwriter.Swing(unicode(v))
   1145             except:
   1146                 sys.exc_clear()
   1147                 return '(?)'
   1148 
   1149         hd = ['Property', 'Value']
   1150         deepdependencies = []
   1151         if hasattr(dumpWho, 'GetDeepDependencies'):
   1152             dumpWho.GetDeepDependencies(deepdependencies)
   1153         deepdependants = []
   1154         if hasattr(dumpWho, 'GetDeepDependendants'):
   1155             dumpWho.GetDeepDependants(deepdependants)
   1156         dependencies = []
   1157         if hasattr(dumpWho, '__dependencies__'):
   1158             dependencies = dumpWho.__dependencies__
   1159         dependants = []
   1160         if hasattr(dumpWho, 'GetDependants'):
   1161             dependants = dumpWho.GetDependants()
   1162         persistvars = []
   1163         if hasattr(dumpWho, '__persistvars__'):
   1164             persistvars = dumpWho.__persistvars__
   1165         nonpersistvars = []
   1166         if hasattr(dumpWho, '__nonpersistvars__'):
   1167             nonpersistvars = dumpWho.__nonpersistvars__
   1168         notifyevents = []
   1169         if hasattr(dumpWho, '__notifyevents__'):
   1170             notifyevents = list(dumpWho.__notifyevents__)
   1171         exportedcalls = []
   1172         if hasattr(dumpWho, '__exportedcalls__'):
   1173             exportedcalls = dumpWho.__exportedcalls__.keys()
   1174         objectConnections = []
   1175         for connectionByC2OOID in getattr(dumpWho, 'objectConnections', {}).itervalues():
   1176             for connection in connectionByC2OOID.itervalues():
   1177                 objectConnections.append(Str(connection))
   1178 
   1179         sessionConnections = []
   1180         for each in getattr(dumpWho, 'sessionConnections', {}).itervalues():
   1181             sessionConnections.append(Str(each))
   1182 
   1183         boundObjects = []
   1184         if hasattr(dumpWho, 'boundObjects'):
   1185             boundObjects = dumpWho.boundObjects.keys()
   1186         sessionfilter = []
   1187         if hasattr(dumpWho, '__sessionfilter__'):
   1188             sessionfilter = dumpWho.__sessionfilter__
   1189 
   1190         def Alphabetize(arr, objectDetail = False, dependency = False):
   1191             try:
   1192                 li = arr[:]
   1193                 li.sort(lambda a, b: -(Str(a).upper() < Str(b).upper()))
   1194                 if objectDetail:
   1195                     li = [ htmlwriter.Link('', unicode(val), [request.query, {'objectDetail': binascii.b2a_hex(cPickle.dumps(val, 1))}]) for val in li ]
   1196                 elif dependency:
   1197                     li = [ htmlwriter.Link('', unicode(val), [request.query, {'svcname': unicode(val)}]) for val in li ]
   1198                 else:
   1199                     li = [ unicode(val) for val in li ]
   1200                 if len(li) > 100:
   1201                     return '&lt; %d entries &gt;' % len(li)
   1202                 return ', '.join(li)
   1203             except:
   1204                 log.LogException()
   1205                 sys.exc_clear()
   1206                 return ', '.join(arr)
   1207 
   1208         li = [['Objects bound to me', Alphabetize(boundObjects, objectDetail=True)],
   1209          ['Sessions using me', Alphabetize(sessionConnections)],
   1210          ['Objects using me', Alphabetize(objectConnections)],
   1211          ['Session Filter', Alphabetize(sessionfilter)],
   1212          ['I depend on', Alphabetize(dependencies, dependency=True)],
   1213          ['<nobr>I depend on - recursively</nobr>', Alphabetize(deepdependencies, dependency=True)],
   1214          ['Who depends on me', Alphabetize(dependants, dependency=True)],
   1215          ['Who depends on me - recursively', Alphabetize(deepdependants, dependency=True)],
   1216          ['Persistant Variables', Alphabetize(persistvars)],
   1217          ['Non-persistant Variables', Alphabetize(nonpersistvars)],
   1218          ['I listen to these events', Alphabetize(notifyevents)],
   1219          ['I export these calls', Alphabetize(exportedcalls)]]
   1220         if hasattr(dumpWho, 'GetServiceState'):
   1221             li.append(['Service State', dumpWho.GetServiceState()])
   1222         if hasattr(dumpWho, 'session'):
   1223             li.append(['Service Session', htmlwriter.Swing(repr(dumpWho.session))])
   1224         if hasattr(dumpWho, '__servicelock__'):
   1225             li.append(['Service Lock', htmlwriter.Swing(unicode(getattr(dumpWho, '__servicelock__', None)))])
   1226         li.sort(lambda a, b: -(a[0].upper() < b[0].upper()))
   1227         li = [ each for each in li if each[1] ]
   1228         wr = htmlwriter.HtmlWriter()
   1229         return htmlwriter.WebPart(title, wr.GetTable(hd, li, useFilter=True), page)
   1230 
   1231     def OnSetConfigValue(self, key, value):
   1232         return value
   1233 
   1234     def GetSPConfigValues(self):
   1235         r = []
   1236         for a in sorted(self.__configvalues__.keys()):
   1237             v = getattr(self, a)
   1238             t = type(getattr(self, a))
   1239             r.append((a, v, t))
   1240 
   1241         return r
   1242 
   1243     def SetSPConfigValues(self, values):
   1244         for a in self.__configvalues__.keys():
   1245             if a in values:
   1246                 setattr(self, a, values[a])
   1247 
   1248 
   1249 def GetClusterSingletonNodeFromAddress(mn, machoresolve):
   1250     try:
   1251         num = int(machoresolve.split('_')[1])
   1252     except:
   1253         log.general.Log('clustersingleton machoresolve without mod number. Using 0')
   1254         num = 0
   1255 
   1256     numMod = num % const.CLUSTERSINGLETON_MOD
   1257     if num >= const.CLUSTERSINGLETON_MOD:
   1258         log.general.Log('clustersingleton machoresolve with out-of-bounds mod number', num, 'rolling over to', numMod, log.LGWARN)
   1259     return mn.GetNodeFromAddress(SERVICE_CLUSTERSINGLETON, numMod)
   1260 
   1261 
   1262 class AppProxyService(CoreService):
   1263     __solservice__ = None
   1264 
   1265     def __init__(self):
   1266         self.solNodeID = None
   1267         CoreService.__init__(self)
   1268 
   1269     def GetSolNodeService(self):
   1270         if not getattr(self, '__solservice__'):
   1271             self.LogError('Application Proxy Service incorrectly configured. The service requires the __solservice__ attribute which is a tuple of (solServiceName, serviceMask, serviceBucket)')
   1272             return
   1273         solServiceName, serviceMask, bucket = self.__solservice__
   1274         if self.solNodeID is not None:
   1275             if self.solNodeID not in sm.services['machoNet'].transportIDbySolNodeID:
   1276                 self.LogWarn('Sol node', self.solNodeID, ' is no longer available. Finding a new one...')
   1277                 self.solNodeID = None
   1278         if self.solNodeID is None:
   1279             svc = self.session.ConnectToSolServerService('machoNet', None)
   1280             nodeID = svc.GetNodeFromAddress(serviceMask, bucket)
   1281             if nodeID is None or nodeID <= 0:
   1282                 raise RuntimeError('Could not find any sol nodes with mask %s' % serviceMask)
   1283             self.LogInfo('Found a new sol node at', nodeID)
   1284             self.solNodeID = nodeID
   1285         svc = self.session.ConnectToSolServerService(solServiceName, nodeID=self.solNodeID)
   1286         return svc
   1287 
   1288 
   1289 class ClusterSingletonService(CoreService):
   1290     __ready__ = 0
   1291     __startupdependencies__ = ['machoNet']
   1292 
   1293     def __init__(self):
   1294         for dep in ClusterSingletonService.__startupdependencies__:
   1295             if dep not in self.__startupdependencies__:
   1296                 self.__startupdependencies__.append(dep)
   1297 
   1298         CoreService.__init__(self)
   1299 
   1300     def Run(self, *args):
   1301         CoreService.Run(self, *args)
   1302         sm.RegisterForNotifyEvent(self, 'OnClusterStartup')
   1303         sm.RegisterForNotifyEvent(self, 'OnNodeDeath')
   1304         if self.machoNet.IsClusterStarted():
   1305             uthread.new(self.__ConditionallyPrime)
   1306 
   1307     def PrimeService(self):
   1308         raise NotImplementedError('You cannot inherit from ClusterSingletonService without implementing PrimeService()')
   1309 
   1310     def _MachoResolveClusterSingleton(self):
   1311         if getattr(self, '__machoresolve__', None):
   1312             serviceNodeID = GetClusterSingletonNodeFromAddress(self.machoNet, self.__machoresolve__)
   1313         else:
   1314             serviceNodeID = self.MachoResolve(session)
   1315         return serviceNodeID
   1316 
   1317     def _ShouldPrimeService(self):
   1318         if self.__ready__:
   1319             return False
   1320         serviceNodeID = self._MachoResolveClusterSingleton()
   1321         myNodeID = self.machoNet.GetNodeID()
   1322         if serviceNodeID and myNodeID != serviceNodeID:
   1323             return False
   1324         return True
   1325 
   1326     def _PrimeService(self):
   1327         with locks.TempLock((self, 'PrimeService')):
   1328             if not self.__ready__:
   1329                 try:
   1330                     self.LogInfo('Priming clustersingleton service...')
   1331                     startTime = blue.os.GetWallclockTimeNow()
   1332                     self.PrimeService()
   1333                     self.LogNotice('Done priming clustersingleton service %s in %.3f seconds.' % (self.__logname__, (blue.os.GetWallclockTimeNow() - startTime) / float(const.SEC)))
   1334                 except Exception as e:
   1335                     log.LogException('Error priming Cluster Singleton service %s' % self.__logname__)
   1336                 finally:
   1337                     self.__ready__ = 1
   1338 
   1339     def PreCallAction(self, methodName):
   1340         if not self._ShouldPrimeService():
   1341             return
   1342         self._PrimeService()
   1343 
   1344     def OnClusterStartup(self):
   1345         self.__ConditionallyPrime()
   1346 
   1347     def __ConditionallyPrime(self):
   1348         sm.WaitForServiceObjectState(self, (SERVICE_RUNNING,))
   1349         if not self._ShouldPrimeService():
   1350             return
   1351         self.LogNotice('I am the right node for this cluster singleton service at startup. Priming the service...')
   1352         self._PrimeService()
   1353 
   1354     def OnNodeDeath(self, nodeID, confirmed, reason = None):
   1355         if not self._ShouldPrimeService():
   1356             return
   1357         self.LogWarn('Old Cluster Singleton node %s for this service has died. I will now service calls. Starting by priming Service' % nodeID)
   1358         self._PrimeService()
   1359 
   1360 
   1361 Service = CoreService