def __init__(self, host, port, conf, proto='BSON'): super(GateClient, self).__init__(self) self.logger = LogManager.getLogger('Client.GateClient') self.client = ChannelClient(host, port, self) self.status = GateClient.ST_INIT self.inReconnect = False self.reconnectData = None self.gateStub = None self.encoder = Md5IndexEncoder() # traceback self.tbHandler = None self.proto = proto enforceEncryption = bool(conf.get('enforceEncryption', False)) loginKeyPath = conf.get('loginKeyPath', None) loginKeyContent = conf.get('loginKeyContent', None) useKeyczar = bool(conf.get('useKeyczar', None)) self.zippedEnabled = bool(conf.get('zippedEnabled', False)) self.enableRegMd5Index = bool(conf.get('enableRegMd5Index', False)) self.receivedSeq = 0 self.useMessageCache = False self.sessionPaddingMinLen = 16 self.sessionPaddingMaxLen = 64 self.connectStatus = Common_pb2.ConnectReply.RT_BUSY self.sessionSeed = ClientGate_pb2.SessionSeed() if enforceEncryption: if useKeyczar: from Utils.SessionEncrypter import LoginKeyEncrypter self.keyEncrypter = LoginKeyEncrypter(loginKeyPath) else: from Utils.SessionEncrypter import LoginKeyEncrypterNoKeyczar self.keyEncrypter = LoginKeyEncrypterNoKeyczar(loginKeyPath, loginKeyContent) else: self.keyEncrypter = None self.onEventCallbacks = { GateClient.CB_ON_CONNECT_FAILED: set(), GateClient.CB_ON_CONNECT_SUCCESSED: set(), GateClient.CB_ON_DISCONNECTED: set(), GateClient.CB_ON_CONNECT_REPLY: set(), GateClient.CB_ON_RELIABLE_MSG_UNSENT: set(), }
class GateClient(ClientGate_pb2.SGate2Client): ST_INIT = 0 ST_CONNECTING = 1 ST_RECONNECTING = 3 ST_CONNECT_FAILED = 4 ST_CONNECT_SUCCESSED = 5 ST_DISCONNECTED = 6 CB_ON_CONNECT_FAILED = 1 CB_ON_CONNECT_SUCCESSED = 2 CB_ON_DISCONNECTED = 3 CB_ON_CONNECT_REPLY = 4 CB_ON_RELIABLE_MSG_UNSENT = 5 def __init__(self, host, port, conf, proto='BSON'): super(GateClient, self).__init__(self) self.logger = LogManager.getLogger('Client.GateClient') self.client = ChannelClient(host, port, self) self.status = GateClient.ST_INIT self.inReconnect = False self.reconnectData = None self.gateStub = None self.encoder = Md5IndexEncoder() # traceback self.tbHandler = None self.proto = proto enforceEncryption = bool(conf.get('enforceEncryption', False)) loginKeyPath = conf.get('loginKeyPath', None) loginKeyContent = conf.get('loginKeyContent', None) useKeyczar = bool(conf.get('useKeyczar', None)) self.zippedEnabled = bool(conf.get('zippedEnabled', False)) self.enableRegMd5Index = bool(conf.get('enableRegMd5Index', False)) self.receivedSeq = 0 self.useMessageCache = False self.sessionPaddingMinLen = 16 self.sessionPaddingMaxLen = 64 self.connectStatus = Common_pb2.ConnectReply.RT_BUSY self.sessionSeed = ClientGate_pb2.SessionSeed() if enforceEncryption: if useKeyczar: from Utils.SessionEncrypter import LoginKeyEncrypter self.keyEncrypter = LoginKeyEncrypter(loginKeyPath) else: from Utils.SessionEncrypter import LoginKeyEncrypterNoKeyczar self.keyEncrypter = LoginKeyEncrypterNoKeyczar(loginKeyPath, loginKeyContent) else: self.keyEncrypter = None self.onEventCallbacks = { GateClient.CB_ON_CONNECT_FAILED: set(), GateClient.CB_ON_CONNECT_SUCCESSED: set(), GateClient.CB_ON_DISCONNECTED: set(), GateClient.CB_ON_CONNECT_REPLY: set(), GateClient.CB_ON_RELIABLE_MSG_UNSENT: set(), } def enableMessageCache(self, enabled=True): self.useMessageCache = enabled def setSessionPaddingLength(self, minLen, maxLen): self.sessionPaddingMinLen = minLen self.sessionPaddingMaxLen = maxLen def startGame(self, timeout): self.encoder.reset() self.receivedSeq = 0 assert self.status in (GateClient.ST_INIT, GateClient.ST_DISCONNECTED, GateClient.ST_CONNECT_FAILED), 'startGame: status is wrong, status=%s' % self.status self.status = GateClient.ST_CONNECTING self.doConnect(self.channelCallback, timeout) def resumeGame(self, timeout, entityId, binAuthMsg): assert self.status in (GateClient.ST_INIT, GateClient.ST_DISCONNECTED, GateClient.ST_CONNECT_FAILED), 'resumeGame: status is wrong, status=%s' % self.status self.encoder.reset() self.status = GateClient.ST_RECONNECTING self.reconnectData = {'entityId': entityId, 'binAuthMsg': binAuthMsg} callback = lambda rpcChannel: self.channelCallback(rpcChannel) self.doConnect(callback, timeout) def doConnect(self, channelCallback, timeout): try: self.client.connect(channelCallback, timeout) except: self.logger.logLastExcept() channelCallback(None) def disconnect(self): self.client.disconnect() def channelCallback(self, rpcChannel): pass def onRpcChannelEstablished(self, rpcChannel): if self.inReconnect: self.doReconnectServer(rpcChannel, self.reconnectData) else: self.doConnectServer(rpcChannel) def registerEventCallback(self, cbType, callback): assert cbType in self.onEventCallbacks self.onEventCallbacks[cbType].add(callback) def unregisterEventCallback(self, cbType, callback): assert cbType in self.onEventCallbacks self.onEventCallbacks[cbType].discard(callback) def getEventCallbackList(self, cbType): return list(self.onEventCallbacks[cbType]) def increaseSeq(self): self.receivedSeq += 1 def sessionSeedRequest(self): null = Common_pb2.Null() self.gateStub.seedRequest(None, null) def seedReply(self, controller, seed, done): self.sessionSeed = seed rpcChannel = controller.rpcChannel self.sendSessionKey(rpcChannel) def sendSessionKey(self, rpcChannel): pass def sessionKeyOk(self, controller, null, done): self.onRpcChannelEstablished(controller.rpcChannel) def onChannelDisconnected(self, rpcChannel): self.status = GateClient.ST_DISCONNECTED self.inReconnect = False callbackSet = self.onEventCallbacks[GateClient.CB_ON_DISCONNECTED].copy() filter(lambda cb: cb(), callbackSet) def getDeviceId(self): return MARS_DEVICEID def doConnectServer(self, rpcChannel): request = Common_pb2.ConnectRequest() request.type = Common_pb2.RT_NEWCONNECTION request.clientId = self.getDeviceId() self.gateStub.connectRequest(None, request) self.logger.info('doConnectServer: request to %s', self.client.getPeername()) if self.zippedEnabled: rpcChannel.setCompressor(Compressor()) self.connectStatus = Common_pb2.ConnectReply.RT_BUSY def doReconnectServer(self, rpcChannel, reconnectData): pass def onReliableMessageUnallowedSent(self, opCode): callbackSet = self.onEventCallbacks[GateClient.CB_ON_RELIABLE_MSG_UNSENT].copy() filter(lambda cb: cb(opCode), callbackSet) def getNewServerProxy(self, stub, encoder): if self.useMessageCache: # TODO: else: return ServerProxy(stub, encoder, self.proto) def resetServerProxies(self, avatarId=None): for entity in EntityManager._entities.values(): if not entity.server or not entity.server.isCachable(): serverProxy = self.getNewServerProxy(self.gateStub, self.encoder) serverProxy.setOwner(entity) entity.setServer(serverProxy) else: entity.server.setStub(self.gateStub) def connectReply(self, controller, reply, done): self.connectStatus = reply.type if self.connectStatus == Common_pb2.ConnectReply.RT_RECONNECTOK: r = self.dealReconnectReply(reply) if not r: self.connectStatus = Common_pb2.ConnectReply.RT_RECONNECTFAIL callbackSet = self.onEventCallbacks[GateClient.CB_ON_CONNECT_REPLY].copy() if len(callbackSet) == 0: self.logger.info('GateClient.ConnectReply: connectStatus=%s', sef.connectStatus) return filter(lambda cb: cb(self.connectStatus), callbackSet) def dealReconnectReply(self, reply): pass def chatToClient(self, controller, outbandData, done): pass def createEntity(self, controller, entityData, done): pass def entityRpc(self, controller, entityMsg, done): pass def destroyEntity(self, controller, entityData, done): self.increaseSeq() entityId = IdCreator.bytes2id(entityData.id) entity = EntityManager.getEntity(entityId) if entity != None: try: entity.destroy() except Exception: self.handleLastTraceback('GateClient.destroyEntity: %s(%s) failed' % (entity.__class__.__name__, entityId)) return self.logger.info('GateClient.destroyEntity: %s(%s) success', entity.__class__.__name__, entityId) def reset(self, host=None, port=None): self.client.reset(host, port) self.gateStub = None def setTracebackHandler(self, handler): self.tbHandler = handler def handleLastTraceback(self, strError=None): if self.tbHandler is not None: t, v, tb = sys.exc_info() self.tbHandler(t, v, tb) self.logger.logLastExcept() if err is not None: self.logger.error(err) def regMd5Index(self, controller, md5Index, done): self.encoder.addIndex(md5Index.md5, md5Index.index)