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

moniker.py (12149B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\script\net\moniker.py
      2 import weakref
      3 import cPickle
      4 import sys
      5 import log
      6 import uthread
      7 from carbon.common.script.net import machoNet
      8 from carbon.common.script.net.machoNetExceptions import UnMachoDestination
      9 from carbon.common.script.sys import basesession
     10 from carbon.common.script.sys.service import ROLE_SERVICE
     11 from eveexceptions import UserError
     12 allMonikers = weakref.WeakSet()
     13 
     14 class Moniker():
     15     __guid__ = 'util.Moniker'
     16     __passbyvalue__ = 1
     17     __persistvar__ = ['__serviceName',
     18      '__nodeID',
     19      '__bindParams',
     20      '__sessionCheck']
     21 
     22     def __init__(self, serviceName = None, bindParams = None, nodeID = None):
     23         global allMonikers
     24         self.__serviceName = serviceName
     25         self.__bindParams = bindParams
     26         self.__nodeID = nodeID
     27         self.__sessionCheck = None
     28         self.boundObject = None
     29         allMonikers.add(self)
     30 
     31     def __del__(self):
     32         self.__ClearBoundObject()
     33 
     34     def __str__(self):
     35         if self.__class__ == Moniker:
     36             name = 'Generic'
     37         else:
     38             name = self.__class__.__name__
     39         args = (name,
     40          self.__serviceName,
     41          self.__nodeID,
     42          self.__bindParams)
     43         return '%s moniker on service %s, node %s, params %s' % args
     44 
     45     def SetSessionCheck(self, sessionCheck):
     46         self.__sessionCheck = sessionCheck
     47 
     48     def __PerformSessionCheck(self):
     49         if self.__sessionCheck:
     50             for attribute, expected in self.__sessionCheck.iteritems():
     51                 if session:
     52                     current = getattr(session, attribute, None)
     53                 else:
     54                     current = None
     55                 if current != expected or not expected and current:
     56                     log.LogTraceback('__PerformSessionCheck:  Monikers session has changed. Traceback=', toAlertSvc=0, severity=log.LGWARN)
     57                     raise RuntimeError('MonikerSessionCheckFailure', {'attribute': attribute,
     58                      'expected': expected,
     59                      'current': current,
     60                      'serviceName': self.__serviceName,
     61                      'bindParams': self.__bindParams})
     62 
     63     def ToURLString(self):
     64         import binascii
     65         return binascii.b2a_hex(cPickle.dumps((self.__serviceName, self.__bindParams), 1))
     66 
     67     def FromURLString(self, s):
     68         import binascii
     69         b = binascii.a2b_hex(s)
     70         self.__serviceName, self.__bindParams = cPickle.loads(b)
     71 
     72     def __getstate__(self):
     73         ret = []
     74         for each in self.__persistvar__:
     75             ret.append(self.__dict__['_Moniker' + each])
     76 
     77         return tuple(ret)
     78 
     79     def __setstate__(self, state):
     80         self.boundObject = None
     81         for i in xrange(len(self.__persistvar__)):
     82             self.__dict__['_Moniker' + self.__persistvar__[i]] = state[i]
     83 
     84         if self.__nodeID is not None:
     85             if machoNet.mode == 'client' or basesession.IsInClientContext():
     86                 sm.services['machoNet'].SetNodeOfAddress(self.__serviceName, self.__bindParams, self.__nodeID)
     87         allMonikers.add(self)
     88 
     89     __remobsuppmeth__ = ('RegisterObjectChangeHandler', 'UnRegisterObjectChangeHandler')
     90 
     91     def __getattr__(self, key):
     92         if key in self.__remobsuppmeth__:
     93             self.Bind()
     94             return getattr(self.boundObject, key)
     95         elif not key[0].isupper():
     96             if key.startswith('__'):
     97                 raise AttributeError(key)
     98             self.Bind()
     99             return getattr(self.boundObject, key)
    100         else:
    101             return MonikerCallWrap(self, key)
    102 
    103     def __ClearBoundObject(self, disconnectDelay = 30):
    104         if self.boundObject is not None and isinstance(self.boundObject, basesession.ObjectConnection):
    105             try:
    106                 self.boundObject.DisconnectObject(disconnectDelay)
    107             except AttributeError:
    108                 pass
    109 
    110         self.boundObject = None
    111 
    112     def Bind(self, sess = None, call = None):
    113         localKeywords = ('machoTimeout', 'noCallThrottling')
    114         done = set()
    115         while 1:
    116             try:
    117                 if self.__bindParams is None:
    118                     raise RuntimeError("Thou shall not use None as a Moniker's __bindParams")
    119                 if '__semaphoreB__' not in self.__dict__:
    120                     self.__semaphoreB__ = uthread.Semaphore(('moniker::Bind', self.__serviceName, self.__bindParams))
    121                 self.__semaphoreB__.acquire()
    122                 try:
    123                     if not self.boundObject:
    124                         if self.__nodeID is None:
    125                             self.__ResolveImpl(sess)
    126                         if sess is None:
    127                             if session and basesession.IsInClientContext():
    128                                 sess = session
    129                             elif session and session.role == ROLE_SERVICE:
    130                                 sess = session.GetActualSession()
    131                             else:
    132                                 sess = basesession.GetServiceSession('util.Moniker')
    133                         else:
    134                             sess = sess.GetActualSession()
    135                         if self.__nodeID == sm.GetService('machoNet').GetNodeID():
    136                             service = sess.ConnectToService(self.__serviceName)
    137                             self.boundObject = service.MachoGetObjectBoundToSession(self.__bindParams, sess)
    138                         else:
    139                             remotesvc = sess.ConnectToRemoteService(self.__serviceName, self.__nodeID)
    140                             self.__PerformSessionCheck()
    141                             if call is not None and call[2]:
    142                                 c2 = {k:v for k, v in call[2].iteritems() if k not in localKeywords}
    143                                 call = (call[0], call[1], c2)
    144                             self.boundObject, retval = remotesvc.MachoBindObject(self.__bindParams, call)
    145                             self.boundObject.persistantObjectID = (self.__serviceName, self.__bindParams)
    146                             return retval
    147                 finally:
    148                     done.add((self.__serviceName, self.__bindParams))
    149                     self.__semaphoreB__.release()
    150 
    151                 if call is not None:
    152                     return self.MonikeredCall(call, sess)
    153                 return
    154             except UpdateMoniker as e:
    155                 if (e.serviceName, e.bindParams) in done:
    156                     log.LogException()
    157                     raise RuntimeError('UpdateMoniker referred us to the same location twice', (e.serviceName, e.bindParams))
    158                 else:
    159                     self.__bindParams = e.bindParams
    160                     self.__serviceName = e.serviceName
    161                     self.__nodeID = e.nodeID
    162                     self.Unbind()
    163                     sys.exc_clear()
    164 
    165     def MonikeredCall(self, call, sess):
    166         retry = 0
    167         while 1:
    168             try:
    169                 self.__PerformSessionCheck()
    170                 if self.boundObject is None:
    171                     return self.Bind(sess, call)
    172                 try:
    173                     return getattr(self.boundObject, call[0])(*call[1], **call[2])
    174                 except UpdateMoniker as e:
    175                     self.__bindParams = e.bindParams
    176                     self.__serviceName = e.serviceName
    177                     self.__nodeID = e.nodeID
    178                     self.Unbind()
    179                     sys.exc_clear()
    180 
    181             except UserError as e:
    182                 if e.msg == 'UnMachoDestination' and not retry:
    183                     retry = 1
    184                     self.Unresolve()
    185                     sys.exc_clear()
    186                     continue
    187                 raise
    188             except UnMachoDestination:
    189                 if not retry:
    190                     retry = 1
    191                     self.Unresolve()
    192                     sys.exc_clear()
    193                     continue
    194                 raise
    195 
    196     def QuickResolve(self):
    197         if self.__nodeID is None and self.__serviceName in sm.services:
    198             self.__nodeID = self.__ResolveImpl()
    199 
    200     def Resolve(self, sess = None):
    201         return self.__ResolveImpl(sess)
    202 
    203     def __ResolveImpl(self, sess = None):
    204         if '__semaphoreR__' not in self.__dict__:
    205             self.__semaphoreR__ = uthread.Semaphore(('moniker::Resolve', self.__serviceName, self.__bindParams))
    206         self.__semaphoreR__.acquire()
    207         try:
    208             if self.__nodeID is not None:
    209                 return self.__nodeID
    210             if machoNet.mode == 'client' or basesession.IsInClientContext():
    211                 self.__nodeID = sm.services['machoNet'].GuessNodeIDFromAddress(self.__serviceName, self.__bindParams)
    212                 if self.__nodeID is not None:
    213                     return self.__nodeID
    214                 if not self.__nodeID:
    215                     self.__nodeID = sm.GetService('machoNet').LookupAddressCache(self.__serviceName, self.__bindParams)
    216                     if self.__nodeID is not None:
    217                         return self.__nodeID
    218             if sess is None:
    219                 if session and session.role == ROLE_SERVICE:
    220                     sess = session.GetActualSession()
    221                 else:
    222                     sess = basesession.GetServiceSession('util.Moniker')
    223             else:
    224                 sess = sess.GetActualSession()
    225             if machoNet.mode == 'client' or basesession.IsInClientContext():
    226                 service = sess.ConnectToRemoteService(self.__serviceName)
    227             else:
    228                 service = sess.ConnectToAnyService(self.__serviceName)
    229             self.__nodeID = service.MachoResolveObject(self.__bindParams)
    230             if self.__nodeID is None:
    231                 raise RuntimeError('Resolution failure:  ResolveObject returned None')
    232             if machoNet.mode == 'client' or basesession.IsInClientContext():
    233                 sm.services['machoNet'].SetNodeOfAddress(self.__serviceName, self.__bindParams, self.__nodeID)
    234             return self.__nodeID
    235         finally:
    236             self.__semaphoreR__.release()
    237 
    238     def Unresolve(self):
    239         while 1:
    240             self.Unbind()
    241             if '__semaphoreR__' not in self.__dict__:
    242                 self.__semaphoreR__ = uthread.Semaphore(('moniker::Resolve', self.__serviceName, self.__bindParams))
    243             self.__semaphoreR__.acquire()
    244             try:
    245                 if self.boundObject is None:
    246                     self.__nodeID = None
    247                     sm.services['machoNet'].SetNodeOfAddress(self.__serviceName, self.__bindParams, None)
    248                     return
    249             finally:
    250                 self.__semaphoreR__.release()
    251 
    252     def Unbind(self, disconnectDelay = 30):
    253         if '__semaphoreB__' not in self.__dict__:
    254             self.__semaphoreB__ = uthread.Semaphore(('moniker::Bind', self.__serviceName, self.__bindParams))
    255         self.__semaphoreB__.acquire()
    256         try:
    257             self.__ClearBoundObject(disconnectDelay)
    258         finally:
    259             self.__semaphoreB__.release()
    260 
    261     def GetNodeID(self):
    262         if self.__nodeID is None:
    263             self.__ResolveImpl()
    264         return self.__nodeID
    265 
    266     def GetSelfLocal(self):
    267         if self.GetNodeID() == sm.services['machoNet'].GetNodeID():
    268             self.Bind()
    269             return self.boundObject.__object__
    270         raise RuntimeError('You are not local %d != %d' % (self.GetNodeID(), sm.services['machoNet'].GetNodeID()))
    271 
    272 
    273 class MonikerCallWrap():
    274 
    275     def __init__(self, moniker, key):
    276         self.moniker = moniker
    277         self.key = key
    278         if key[0] != key[0].upper():
    279             raise RuntimeError("This moniker has no attribute '%s'. Moniker: %s" % (key, moniker))
    280 
    281     def __call__(self, *args, **kw):
    282         try:
    283             return self.moniker.MonikeredCall((self.key, args, kw), None)
    284         finally:
    285             self.__dict__.clear()
    286 
    287 
    288 class UpdateMoniker(Exception):
    289     __passbyvalue__ = 1
    290 
    291     def __init__(self, serviceName = None, bindParams = None, nodeID = None):
    292         Exception.__init__(self, 'Update')
    293         self.serviceName = serviceName
    294         self.nodeID = nodeID
    295         self.bindParams = bindParams