Exemple #1
0
    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(),
        }
Exemple #2
0
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)