serviceProxy.py (6053B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\script\sys\serviceProxy.py 2 import zlib 3 import types 4 import inspect 5 import random 6 import uthread 7 from cluster import NODES, NODE_ALL, NODE_ANY, NODE_ALL_SERVER, NODE_ALL_PROXY, NODE_ANY_SERVER, NODE_ANY_PROXY 8 from cluster import SERVICE_MODS, SERVICE_MOD_DEFAULT 9 from eveprefs import prefs 10 11 class ServiceProxy(object): 12 __guid__ = 'service.ServiceProxy' 13 _methods = {} 14 15 def __init__(self, serviceName, session): 16 self._serviceName = serviceName 17 self._session = session 18 if serviceName not in self._methods or prefs.clusterMode == 'LOCAL': 19 self._methods[serviceName] = self._WrapService(serviceName) 20 for methodName, method in self._methods[serviceName].iteritems(): 21 setattr(self, methodName, types.MethodType(method, self, self.__class__)) 22 23 def __repr__(self): 24 return '<ServiceProxy service=%s session=%s>' % (str(self._serviceName), str(self._session)) 25 26 def _WrapService(self, serviceName): 27 import svc 28 serviceClass = getattr(svc, sm.GetServiceImplementation(serviceName)) 29 defaultResolve = getattr(serviceClass, '__serviceproxyresolve__', None) 30 exportedCalls = getattr(serviceClass, '__exportedcalls__', {}) 31 exportedCalls = [ (k, v) for k, v in exportedCalls.iteritems() if isinstance(v, dict) ] 32 wrappedMethods = {} 33 for methodName, definition in exportedCalls: 34 resolve = definition.get('resolve', defaultResolve) 35 if resolve is not None: 36 wrappedMethods[methodName] = self._WrapServiceMethod(methodName, getattr(serviceClass, methodName), resolve) 37 38 return wrappedMethods 39 40 def _WrapServiceMethod(self, methodName, method, resolve): 41 resolveConst, resolveArgument = resolve 42 argspec = inspect.getargspec(method) 43 if isinstance(resolveArgument, str): 44 resolveArgumentIndex = argspec[0].index(resolveArgument) - 1 45 elif isinstance(resolveArgument, int) and resolveArgument in NODES: 46 resolveArgumentIndex = None 47 else: 48 raise RuntimeError("Resolve argument '%s' for ServiceProxy '%s' is invalid" % (str(resolveArgument), self)) 49 50 def wrapped(self, *args, **kwargs): 51 try: 52 if resolveArgumentIndex is None: 53 resolveValue = resolveArgument 54 else: 55 resolveValue = kwargs.get(resolveArgument, args[resolveArgumentIndex]) 56 if isinstance(resolveValue, basestring): 57 resolveValue = zlib.crc32(resolveValue) 58 elif resolveValue is None: 59 resolveValue = 0 60 except ValueError: 61 raise RuntimeError("ServiceProxy could not find the resolve argument '%s' for the method '%s'" % (str(resolveArgument), methodName)) 62 63 if resolveArgument == NODE_ALL: 64 nodes = self._GetNodesFromServiceID(resolveConst, server=True, proxy=True) 65 elif resolveArgument == NODE_ALL_SERVER: 66 nodes = self._GetNodesFromServiceID(resolveConst, server=True) 67 elif resolveArgument == NODE_ALL_PROXY: 68 nodes = self._GetNodesFromServiceID(resolveConst, proxy=True) 69 elif resolveArgument == NODE_ANY: 70 nodes = random.choice(self._GetNodesFromServiceID(resolveConst, server=True, proxy=True)) 71 elif resolveArgument == NODE_ANY_SERVER: 72 nodes = random.choice(self._GetNodesFromServiceID(resolveConst, server=True)) 73 elif resolveArgument == NODE_ANY_PROXY: 74 nodes = random.choice(self._GetNodesFromServiceID(resolveConst, proxy=True)) 75 else: 76 machoNet = sm.GetService('machoNet').session.ConnectToSolServerService('machoNet') 77 serviceMod = SERVICE_MODS.get(resolveConst, SERVICE_MOD_DEFAULT) 78 nodes = machoNet.GetNodeFromAddress(resolveConst, resolveValue % serviceMod) 79 return ServiceProxyCall(self._session, self._serviceName, methodName, nodes)(*args, **kwargs) 80 81 execdict = {'wrapped': wrapped} 82 exec 'def %s%s: return wrapped(%s)' % (methodName, inspect.formatargspec(*argspec), ', '.join(argspec[0])) in execdict 83 wrapped = execdict.get(methodName, wrapped) 84 setattr(wrapped, '__doc__', method.__doc__) 85 setattr(wrapped, '__name__', method.__name__) 86 return wrapped 87 88 def _GetNodesFromServiceID(self, serviceID, server = False, proxy = False): 89 machoNet = sm.GetService('machoNet') 90 serviceMask = 1 << serviceID - 1 91 nodes = machoNet.ResolveServiceMaskToNodeIDs(serviceMask) 92 if serviceMask & machoNet.serviceMask: 93 nodes.add(machoNet.GetNodeID()) 94 if proxy == False: 95 nodes = [ nodeID for nodeID in nodes if nodeID < const.maxNodeID ] 96 if server == False: 97 nodes = [ nodeID for nodeID in nodes if nodeID >= const.maxNodeID ] 98 if not len(nodes): 99 raise RuntimeError('ServiceProxy::GetNodesFromServiceID found no nodes for serviceID=%s (server=%s, proxy=%s)' % (serviceID, server, proxy)) 100 return list(nodes) 101 102 103 class ServiceProxyCall(object): 104 __guid__ = 'service.ServiceProxyCall' 105 106 def __init__(self, session, serviceName, methodName, nodes): 107 self._session = session 108 self._serviceName = serviceName 109 self._methodName = methodName 110 self._nodes = nodes 111 112 def __call__(self, *args, **kwargs): 113 if not isinstance(self._nodes, (list, set, tuple)): 114 return self._CallNode(self._nodes, *args, **kwargs) 115 calls = [ (self._CallNode, [nodeID] + list(args), kwargs) for nodeID in self._nodes ] 116 return uthread.parallel(calls) 117 118 def _CallNode(self, nodeID, *args, **kwargs): 119 service = self._session.ConnectToRemoteService(self._serviceName, nodeID=nodeID) 120 return getattr(service, self._methodName)(*args, **kwargs)