def B_Hotfix_Hotfile(self, componentType, hotFilenameList): '''热更新文件 参数: 组件类型 1 = baseapp 2 = cellapp 3 = common 参数: 要热更的文件列表 Ps. 以下目录会自动映射成根目录 server_common common base base\interfaces cell cell\interfaces data 调用示例: .B_Hotfix_Hotfile(1, ['Account']) 更新 BaseApp Account.py 文件 .B_Hotfix_Hotfile(1, ['parent.C1']) 更新 BaseApp parent.C1.py 文件 .B_Hotfix_Hotfile(2, ['Account']) 更新 CellApp Account.py 文件 .B_Hotfix_Hotfile(3, ['CustomClass']) 更新 BaseApp与CellApp 的 CustomClass.py 文件 ''' component = None if componentType == 1: component = 'baseapp' elif componentType == 2: component = 'cellapp' elif componentType == 3: component = 'common' else: KBEDebug.ERROR_MSG( "Hotfix_Ent.B_Hotfix_Hotfile. component(%i) illegal" % (component)) return nowtime = int(time.time()) oldHData = Hotfix.getHotfixList(component) if oldHData is None: oldHData = {} for filename in hotFilenameList: classData = oldHData.get(filename, None) newClassData = None if classData is None: newClassData = { 'var': 1, 'local_import': False, 'hotime': nowtime } else: newClassData = { 'var': classData['var'] + 1, 'local_import': False, 'hotime': nowtime } oldHData[filename] = newClassData Hotfix.setHotfixList(component, oldHData) KBEDebug.INFO_MSG("Hotfix_Ent.B_Hotfix_Hotfile. broadcast done")
def onRecv(self, fileno): if self._socket.fileno() == fileno: sock, addr = self._socket.accept() self._clients[sock.fileno()] = (sock, addr) KBEngine.registerReadFileDescriptor(sock.fileno(), self.onRecv) KBEDebug.DEBUG_MSG("Poller::onRecv: new channel[%s/%i]" % (addr, sock.fileno())) else: sock, addr = self._clients.get(fileno, None) if sock is None: return data = sock.recv(2048) if len(data) == 0: KBEDebug.DEBUG_MSG("Poller::onRecv: %s/%i disconnect!" % (addr, sock.fileno())) KBEngine.deregisterReadFileDescriptor(sock.fileno()) sock.close() del self._clients[fileno] return KBEDebug.DEBUG_MSG("Poller::onRecv: %s/%i get data, size=%i" % (addr, sock.fileno(), len(data))) self.processData(sock, data)
def Hotfix_Update(self): self.__hot_common() hdataList = getHotfixList() if hdataList is None: return bNeedHot = False for k, v in self.parentClass.items(): hdata = hdataList.get(k, None) if hdata is not None and hdata['var'] > v['var']: if hdata['local_import'] == False: try: v['module'] = importlib.reload(v['module']) hdata['local_import'] = True v['var'] = hdata['var'] bNeedHot = True except ImportError as e: KBEDebug.ERROR_MSG( "%s Hotfix.update parentClass ImportError:%s" % (self.__module__, e)) continue else: v['var'] = hdata['var'] bNeedHot = True # do something 可以优化 只 reload 一次 if bNeedHot == True: self.selfClass = importlib.reload(self.selfClass) hdata = hdataList.get(self.__module__, None) if hdata is not None and hdata['var'] > self.var: if hdata['local_import'] == False: try: self.selfClass = importlib.reload(self.selfClass) hdata['local_import'] = True self.var = hdata['var'] bNeedHot = True except ImportError as e: KBEDebug.ERROR_MSG( "%s Hotfix.update selfClass ImportError:%s" % (self.__module__, e)) else: self.var = hdata['var'] bNeedHot = True if bNeedHot: self.__hot()
def onRequestAccountLogin(loginName, password, datas): """ KBEngine method. 请求登陆账号回调 @param loginName: 客户端请求时所提交的名称 @type loginName: string @param password: 密码 @type password: string @param datas: 客户端请求时所附带的数据,可将数据转发第三方平台 @type datas: bytes """ KBEDebug.INFO_MSG('onRequestAccountLogin: registerName=%s' % (loginName)) commitName = loginName # 默认账号名就是提交时的名 realAccountName = commitName # 此处可通过http等手段将请求提交至第三方平台,平台返回的数据也可放入datas # datas将会回调至客户端 # 如果使用http访问,因为interfaces是单线程的,同步http访问容易卡住主线程,建议使用 # KBEngine.urlopen("https://www.baidu.com",onHttpCallback)异步访问。也可以结合异步socket的方式与平台交互(参考Poller.py)。 # 如果返回码为KBEngine.SERVER_ERR_LOCAL_PROCESSING则表示验证登陆成功,但dbmgr需要检查账号密码,KBEngine.SERVER_SUCCESS则无需再检查密码 KBEngine.accountLoginResponse(commitName, realAccountName, datas, KBEngine.SERVER_ERR_LOCAL_PROCESSING)
def onRequestCreateAccount(registerName, password, datas): """ KBEngine method. 请求创建账号回调 @param registerName: 客户端请求时所提交的名称 @type registerName: string @param password: 密码 @type password: string @param datas: 客户端请求时所附带的数据,可将数据转发第三方平台 @type datas: bytes """ KBEDebug.INFO_MSG('onRequestCreateAccount: registerName=%s' % (registerName)) commitName = registerName # 默认账号名就是提交时的名 realAccountName = commitName # 此处可通过http等手段将请求提交至第三方平台,平台返回的数据也可放入datas # datas将会回调至客户端 # 如果使用http访问,因为interfaces是单线程的,同步http访问容易卡住主线程,建议使用 # KBEngine.urlopen("https://www.baidu.com",onHttpCallback)异步访问。也可以结合异步socket的方式与平台交互(参考Poller.py)。 KBEngine.createAccountResponse(commitName, realAccountName, datas, KBEngine.SERVER_SUCCESS)
def onInterfaceAppShutDown(): """ KBEngine method. 这个interfaces被关闭前的回调函数 """ KBEDebug.INFO_MSG('onInterfaceAppShutDown()') g_poller.stop()
def onLogOnAttempt(self, ip, port, password): """ KBEngine method. 客户端登陆失败时会回调到这里 """ KBEDebug.INFO_MSG(ip, port, password) return KBEngine.LOG_ON_ACCEPT
def onClientDeath(self): """ KBEngine method. 客户端对应实体已经销毁 """ KBEDebug.DEBUG_MSG("Account[%i].onClientDeath:" % self.id) self.destroy()
def __deco(*args, **kwargs): b = getCurrentTime() result = func(*args, **kwargs) KBEDebug.ERROR_MSG( str(func) + " run time is " + str(getCurrentTime() - b)) return result
def onDBMgrReady(): """ KBEngine method. dbmgr已经准备好了 """ KBEDebug.INFO_MSG('onDBMgrReady: bootstrapGroupIndex=%s, bootstrapGlobalIndex=%s' % \ (os.getenv("KBE_BOOTIDX_GROUP"), os.getenv("KBE_BOOTIDX_GLOBAL")))
def onInit(isReload): """ KBEngine method. 当引擎启动后初始化完所有的脚本后这个接口被调用 @param isReload: 是否是被重写加载脚本后触发的 @type isReload: bool """ KBEDebug.DEBUG_MSG('onInit::isReload:%s' % isReload)
def onClientEnabled(self): """ KBEngine method. 该entity被正式激活为可使用, 此时entity已经建立了client对应实体, 可以在此创建它的 cell部分。 """ KBEDebug.INFO_MSG("account[%i] entities enable. entityCall:%s" % (self.id, self.client))
def onLoseChargeCB(ordersID, dbid, success, datas): """ KBEngine method. 有一个不明订单被处理, 可能是超时导致记录被billing 清除, 而又收到第三方充值的处理回调 """ KBEDebug.DEBUG_MSG('onLoseChargeCB: ordersID=%s, dbid=%i, success=%i, datas=%s' % \ (ordersID, dbid, success, datas))
def onCreateAccountCallbackFromDB(accountName, errorno, datas): """ KBEngine method. 账号请求注册后db验证回调 errorno: KBEngine.SERVER_ERR_* """ KBEDebug.INFO_MSG( 'onCreateAccountCallbackFromDB() accountName=%s, errorno=%s' % (accountName, errorno))
def onBaseAppReady(isBootstrap): """ KBEngine method. baseapp已经准备好了 @param isBootstrap: 是否为第一个启动的baseapp @type isBootstrap: BOOL """ KBEDebug.INFO_MSG('onBaseAppReady: isBootstrap=%s, appID=%s, bootstrapGroupIndex=%s, bootstrapGlobalIndex=%s' % \ (isBootstrap, os.getenv("KBE_COMPONENTID"), os.getenv("KBE_BOOTIDX_GROUP"), os.getenv("KBE_BOOTIDX_GLOBAL")))
def onReadyForShutDown(): """ KBEngine method. 进程询问脚本层:我要shutdown了,脚本是否准备好了? 如果返回True,则进程会进入shutdown的流程,其它值会使得进程在过一段时间后再次询问。 用户可以在收到消息时进行脚本层的数据清理工作,以让脚本层的工作成果不会因为shutdown而丢失。 """ KBEDebug.INFO_MSG('onReadyForShutDown()') return True
def onInterfaceAppReady(): """ KBEngine method. interfaces已经准备好了 """ KBEDebug.INFO_MSG('onInterfaceAppReady: bootstrapGroupIndex=%s, bootstrapGlobalIndex=%s' % \ (os.getenv("KBE_BOOTIDX_GROUP"), os.getenv("KBE_BOOTIDX_GLOBAL"))) #KBEngine.addTimer(0.01, 1.0, onTick) g_poller.start("localhost", 30040)
def onBaseAppShutDown(state): """ KBEngine method. 这个baseapp被关闭前的回调函数 @param state: 0 : 在断开所有客户端之前 1 : 在将所有entity写入数据库之前 2 : 所有entity被写入数据库之后 @type state: int """ KBEDebug.INFO_MSG('onBaseAppShutDown: state=%i' % state)
def onLoginCallbackFromDB(loginName, accountName, errorno, datas): """ KBEngine method. 账号请求登陆后db验证回调 loginName:登录名既登录时客户端输入的名称。 accountName: 账号名则是dbmgr查询得到的名称。 errorno: KBEngine.SERVER_ERR_* 这个机制用于一个账号多名称系统或者多个第三方账号系统登入服务器。 客户端得到baseapp地址的同时也会返回这个账号名称,客户端登陆baseapp应该使用这个账号名称登陆 """ KBEDebug.INFO_MSG( 'onLoginCallbackFromDB() loginName=%s, accountName=%s, errorno=%s' % (loginName, accountName, errorno))
def load_whitelists(): try: import KBEngine import KBEDebug p = './scripts/data/whitelists.txt' if KBEngine.hasRes(p): fs = KBEngine.open(p, 'r') lines = fs.readlines() for line in lines: if line.strip() != '': whitelists.append(int(line.strip())) KBEDebug.DEBUG_MSG("whitelists: {}".format(whitelists)) except: pass
def onRequestCreateAccount(accountName, password, datas): """ KBEngine method. 请求账号创建时回调 """ KBEDebug.INFO_MSG('onRequestCreateAccount() %s' % (accountName)) errorno = KBEngine.SERVER_SUCCESS if len(accountName) > 64: errorno = KBEngine.SERVER_ERR_NAME if len(password) > 64: errorno = KBEngine.SERVER_ERR_PASSWORD return (errorno, accountName, password, datas)
def __hot_common(self): ''' Hot 公用类的文件 ''' hdataList = getHotfixList('common') if hdataList is None: return for filename, hdata in hdataList.items(): if hdata['local_import'] == True: continue hdata['local_import'] = True mod = sys.modules.get(filename, None) if mod is not None: sys.modules[filename] = importlib.reload(mod) KBEDebug.INFO_MSG("%s hotfix done" % (filename))
def onRequestLogin(loginName, password, clientType, datas): """ KBEngine method. 账号请求登陆时回调 此处还可以对登陆进行排队,将排队信息存放于datas """ KBEDebug.INFO_MSG('onRequestLogin() loginName=%s, clientType=%s' % (loginName, clientType)) errorno = KBEngine.SERVER_SUCCESS if len(loginName) > 64: errorno = KBEngine.SERVER_ERR_NAME if len(password) > 64: errorno = KBEngine.SERVER_ERR_PASSWORD return (errorno, loginName, password, clientType, datas)
def onRequestCharge(ordersID, entityDBID, datas): """ KBEngine method. 请求计费回调 @param ordersID: 订单的ID @type ordersID: uint64 @param entityDBID: 提交订单的实体DBID @type entityDBID: uint64 @param datas: 客户端请求时所附带的数据,可将数据转发第三方平台 @type datas: bytes """ KBEDebug.INFO_MSG('onRequestCharge: entityDBID=%s, entityDBID=%s' % (ordersID, entityDBID)) # 此处可通过http等手段将请求提交至第三方平台,平台返回的数据也可放入datas # datas将会回调至baseapp的订单回调中,具体参考API手册charge # 如果使用http访问,因为interfaces是单线程的,同步http访问容易卡住主线程,建议使用 # KBEngine.urlopen("https://www.baidu.com",onHttpCallback)异步访问。也可以结合异步socket的方式与平台交互(参考Poller.py)。 KBEngine.chargeResponse(ordersID, datas, KBEngine.SERVER_SUCCESS)
def getUpdateSql(tableName, setValueMap, filterValueMap, hasIndex=True): if setValueMap is None: KBEDebug.ERROR_MSG("you setValueMap is None!") return indexStr = "" if hasIndex: indexStr = "sm_" setStr = "" whereStr = "" for k, v in setValueMap.items(): setStr += "sm_" + k + "='" + str(v) + "'," for k, v in filterValueMap.items(): whereStr += "sm_" + k + "='" + str(v) + "' and " setStr = setStr[:-1] if whereStr != "": whereStr = whereStr[:-4] sql = "update " + tableName + " set " + setStr + ' where ' + whereStr print("now run update sql " + sql) return sql
def onDBMgrShutDown(): """ KBEngine method. 这个dbmgr被关闭前的回调函数 """ KBEDebug.INFO_MSG('onDBMgrShutDown()')
def onTick(timerID): """ """ KBEDebug.INFO_MSG('onTick()')
def onBaseAppData(key, value): """ KBEngine method. baseAppData有改变 """ KBEDebug.DEBUG_MSG('onBaseAppData: %s' % key)
def onGlobalDataDel(key): """ KBEngine method. globalData有删除 """ KBEDebug.DEBUG_MSG('onDelGlobalData: %s' % key)
def onGlobalData(key, value): """ KBEngine method. globalData有改变 """ KBEDebug.DEBUG_MSG('onGlobalData: %s' % key)