From 049e26023b9183f77b02d8d9f7c11f6bf2122eb4 Mon Sep 17 00:00:00 2001 From: wbt5 Date: Thu, 18 Jun 2020 10:34:09 +0800 Subject: [PATCH] =?UTF-8?q?=E5=BC=B9=E5=B9=95=E8=8E=B7=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../__pycache__/__init__.cpython-38.pyc | Bin 0 -> 2356 bytes .../__pycache__/bilibili.cpython-38.pyc | Bin 0 -> 2686 bytes .../danmaku/__pycache__/douyu.cpython-38.pyc | Bin 0 -> 1885 bytes danmu/danmaku/__pycache__/huya.cpython-38.pyc | Bin 0 -> 2589 bytes .../__pycache__/kuaishou.cpython-38.pyc | Bin 0 -> 9985 bytes danmu/danmaku/tars/EndpointF.py | 69 ++ danmu/danmaku/tars/QueryF.py | 276 +++++++ danmu/danmaku/tars/__TimeoutQueue.py | 300 ++++++++ danmu/danmaku/tars/__adapterproxy.py | 703 ++++++++++++++++++ danmu/danmaku/tars/__async.py | 201 +++++ danmu/danmaku/tars/__init__.py | 85 +++ danmu/danmaku/tars/__logger.py | 103 +++ danmu/danmaku/tars/__packet.py | 104 +++ .../tars/__pycache__/__init__.cpython-38.pyc | Bin 0 -> 3151 bytes .../tars/__pycache__/__packet.cpython-38.pyc | Bin 0 -> 3219 bytes .../tars/__pycache__/__tars.cpython-38.pyc | Bin 0 -> 16056 bytes .../tars/__pycache__/__tup.cpython-38.pyc | Bin 0 -> 3463 bytes .../tars/__pycache__/__util.cpython-38.pyc | Bin 0 -> 9069 bytes .../tars/__pycache__/exception.cpython-38.pyc | Bin 0 -> 2875 bytes danmu/danmaku/tars/__rpc.py | 441 +++++++++++ danmu/danmaku/tars/__servantproxy.py | 358 +++++++++ danmu/danmaku/tars/__tars.py | 546 ++++++++++++++ danmu/danmaku/tars/__trans.py | 575 ++++++++++++++ danmu/danmaku/tars/__tup.py | 118 +++ danmu/danmaku/tars/__util.py | 252 +++++++ danmu/danmaku/tars/core.py | 91 +++ danmu/danmaku/tars/exception.py | 36 + danmu/danmaku/tars/tars/EndpointF.tars | 25 + danmu/danmaku/tars/tars/QueryF.tars | 70 ++ danmu/danmaku/tars/tars/__init__.py | 0 30 files changed, 4353 insertions(+) create mode 100644 danmu/danmaku/__pycache__/__init__.cpython-38.pyc create mode 100644 danmu/danmaku/__pycache__/bilibili.cpython-38.pyc create mode 100644 danmu/danmaku/__pycache__/douyu.cpython-38.pyc create mode 100644 danmu/danmaku/__pycache__/huya.cpython-38.pyc create mode 100644 danmu/danmaku/__pycache__/kuaishou.cpython-38.pyc create mode 100644 danmu/danmaku/tars/EndpointF.py create mode 100644 danmu/danmaku/tars/QueryF.py create mode 100644 danmu/danmaku/tars/__TimeoutQueue.py create mode 100644 danmu/danmaku/tars/__adapterproxy.py create mode 100644 danmu/danmaku/tars/__async.py create mode 100644 danmu/danmaku/tars/__init__.py create mode 100644 danmu/danmaku/tars/__logger.py create mode 100644 danmu/danmaku/tars/__packet.py create mode 100644 danmu/danmaku/tars/__pycache__/__init__.cpython-38.pyc create mode 100644 danmu/danmaku/tars/__pycache__/__packet.cpython-38.pyc create mode 100644 danmu/danmaku/tars/__pycache__/__tars.cpython-38.pyc create mode 100644 danmu/danmaku/tars/__pycache__/__tup.cpython-38.pyc create mode 100644 danmu/danmaku/tars/__pycache__/__util.cpython-38.pyc create mode 100644 danmu/danmaku/tars/__pycache__/exception.cpython-38.pyc create mode 100644 danmu/danmaku/tars/__rpc.py create mode 100644 danmu/danmaku/tars/__servantproxy.py create mode 100644 danmu/danmaku/tars/__tars.py create mode 100644 danmu/danmaku/tars/__trans.py create mode 100644 danmu/danmaku/tars/__tup.py create mode 100644 danmu/danmaku/tars/__util.py create mode 100644 danmu/danmaku/tars/core.py create mode 100644 danmu/danmaku/tars/exception.py create mode 100644 danmu/danmaku/tars/tars/EndpointF.tars create mode 100644 danmu/danmaku/tars/tars/QueryF.tars create mode 100644 danmu/danmaku/tars/tars/__init__.py diff --git a/danmu/danmaku/__pycache__/__init__.cpython-38.pyc b/danmu/danmaku/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..701c26aff6f22061c732dc0729b9e85f0c13de10 GIT binary patch literal 2356 zcmZuz-EJF26rS1N@!D>aw6vjBp)D=y(l$nbxTvb8A`!IwL=^!Q7TRUwna1nvu9KPB zhFFe-)bavcb79}n7eL(e7JJK8c?2X7=ZxbdHmo&g&Ybx>=bLZN_{(N9An@Jz?a#+| z7$JXP4C_L^$LAb7(!Yq6VkyB&@xJUC7!?3NoY>`ykEI4Je?ytG#ls1jV^m?j_jy zNtvYUonBcrSCb-7w#t<(6@_l&630Ia8h4?n_dp1OZiCB|ThB>kbDKL*JKW_S)Gqfq zgWBUY9zgB$I=I!4K1^*R7L(5f1@#FQN0uxG4veRi?EJJ-3`iID*<$h+eS!ziz^YF|nH$cJ4*Y}A>T4DG@Qc3R(R%w< ztMw8C?K5mCYyu@n==5tG!Cz|k^8S35J{3!NC|Hb%b>Kvd*4TnGQE(=vb>Z=~&5JwzaCj>)+$luCO==vIyr*^|n~5a~`u%ZjQOL|%Y3|5|Bv zdbw!rZs^v7y>=&&`2*SOindm*&-PY&T(qP}vYRlq#ew;yk-+~}9H&L9<9KO%uVRzN z30P9y070lX^}9%!6;NyZ`+LEeGra+2)S>+|Q%A8hS*(pWbMhe`Sbm41J_P}cBSTewStl>(TIkCLtQyrf zg^qU>1oxyT>tK;hGzVa6_lg35kr-qZC{gfuV^0eeI&u-mcrXTVifU49#yru9ir7Ro zV2{OXINdkk?W#ASp^*55F4EHgNB@;+Fb>8|VS%_HAq*DxKtU|js-{B|eb+gPuYc|! zW;;ZyM=4={I__U9l$wNkT-4XKRhzs7(pXS0&<9(vpu*MHLMPcn>Fd}1yK}MVD9pe_- zYhOrA{bAi;H^yWh3}e&+F4}OF;#_T34l+Z|L0@HWms-AoqpqO14B~)Gl?_893obj& zXF+T}5peZ^VCEgdcSbFMKpYpKoB$Fn(mAO6=cmz}nl}X~5(?9d0Tiz<1Wk?wZHP6r zF_jOU5gAz%IF3l;8uv{!mA9Gbj*t?`Ew7`viURY^u`A$0rjvRZjLQ5i0FNE;-}|S3 zYT9ozZY^Y(W{M;iaa;v)ocDN{q27ogpC;M3N4}1mAd<&+zj?Uvvw1`dKAd`~e<;Ew<7ILWd&HrpJF-Z){h Y0J}Yo;tn2wLQa4akSQC~{4CG@7duQX0{{R3 literal 0 HcmV?d00001 diff --git a/danmu/danmaku/__pycache__/bilibili.cpython-38.pyc b/danmu/danmaku/__pycache__/bilibili.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ed65ea8646e6867c6e4abf64d8e6e71a17e56e62 GIT binary patch literal 2686 zcmZ`*O>Er86`mOmxg`@ZJ@;S)##{>+P_DTdDb)AKji5LwiTC(s z-kbMk-pu=k@6ONr1fI`6{`6OWuM_egY@B{9X#4~yUjrtHpj{GHUm8+qvo7mdq1EFd zr&Yfl+NGTnI#-FX1pj~te!#+-ptnfVJ_0{vtH})S$L&4i3{(8JvG??I68F2%D+$I5 znV_L1SjdGH+R_nR*dLGs8rDE|M6Hxv;X)M8xNAu_*#;WDdOy!EwOZRMi$y!mb$9FP*o%LGza64bE;=f25go4O`=r6PFUD?*FH_Ff5)uYSM+eY;lPYr}Qpnm}6 zp8^xKAQMQ;lnQHwoF!w@A!DlPgiXmCWD}Bfjr{SiV^*+HBbOX+E(FYvN32 zc2hd$1s8mU2z!N$ZOwOUg{@s&uJ$J0lq^Gp11enMJ+y=`=6=T}z6fBPqvyoD4hjdf zb+BP#;Vi*E(Kui;$wjGfV2(~fC-a3frIg$zKO{e&#ebXJ`AS>YcNYqJk3pIjw?-Ft zwC-bm<9>3Xo9xRk=T&8p-2Lyh-o`IBq9jf9j}!5ur?ho+43FU=*0HHoO3@+Y@P&VV z^vT*xc(Qhc*=}0KL5oBfYnX`8?W;^@`%*R8Q~LT-dZ|f`pUZx%Vx6hn*m2%Yk`a3| zIcng>aA3HvN4Qb=BjHvB|8x= zIXAU@7LF^K_d~Bt0R~kbj8rbLKNIx|e4ehicCwyq-QU)&n-Adls@_eN;mOQf*B`7y z_?D7!_d5`vCE~O)Y@M9){sS`ytBUUDum$%rsCANKZ4tIaIbEX5@CG0;klBAZ zXP-Mj++L>cF)N83bM_h=Ew6o1IH%lwsU$GtSQ6_%`M)7ASO7o_$O7V{Rb7^eV8Z$> zTY4(Z5E$hclu z#XLYvZI2x?^`Wj!+yWtF0bvC}MFbD|#48pio|p$%t4~=`7YmmOav0~8<1Uu^hFGlL z4(nJ`hOmY3b;$bXO8rtorVRW%Cl*UD%isn5mg71MMu0W={l;aI-kkZLEB*hbv|9jR z#pq{d4W88vz6-P+i?5?$T=**l?k<)>TM-;J){x*FDQZ@jgB56X^$iX*kxisqn(s!!+(eU&(9j4B`P+aWo9)5F?@rMimxl=%W+3|9V*( z@-$1Ou~dA&X{jH8R=t6&1+3{SypN5y@qSzOH6WyV0d+58Cm+E*YJ4HVPal9RH=ay~ zJqbuG)mbzb`o_xTz)%VQ1wBKBp^33zn4!BRW>)OmIK^^uLPnr{3EKGx7-1aH4qnFS zDs9m7fPM_VKH#7W7>HQNS)IAmFD;h9q7D{5=<21eQ6eXYmJe-4*s()h;4Z6!$E9P3 z;fO~0`pjnmw3g@@HhS&^K{097yteS4C5mv{qR9AB)XT)Mi*gV}gJImQG-?%QZZH{2 zZ_8Ml#S?K8kJf(NH9@XpowR#W?_@%~3Ih}(@u{TXm7*{+Y8q~h0lZ9IJs8Cwk~hF@<6C%^l=dx-gRFW!MK;JmAr|Cl4FgyklzN7YyA%wimPP+ literal 0 HcmV?d00001 diff --git a/danmu/danmaku/__pycache__/douyu.cpython-38.pyc b/danmu/danmaku/__pycache__/douyu.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..296c315a139d88466183b7a80381287174784e23 GIT binary patch literal 1885 zcmbtV&2t+y6qmHx4?A{}wrN8c7=ovVnrX9TXlV%vm?;eOK&H@PC?4p})=zOZS?{`% zOdEI2CFMWh#K(+%1!;K?HT{(p-w;o!ac0(JuB9ET*KJ=da^m}hVX*TNw$KzlA zynWjzQq?q7GQ|wcD6kbWp_)$Fj9enuF&`h0Z*NRk!KMy4niuqdE|VF3 zsyjPz3TNuhj%+7fds82H!DkFy>+4f;nS6Al{g~V$|Kt? z;n_$B3~Ebc;uk*Duas-yP3tg+H*GAFQsPeM3V%i^foADt{{MN=jooJ9ZZpjP!qy`i z9zMY_UfR)mXy0J)EcM}dp(PV&t)KfG9=v+~%A_rAj>pSY^3%MZWK!G>Wu6Zb=xiFA z9M;g_5Z{L=j>Nu{abwj>lE2F58K17s?&e9>m-%QIVt~%(xDod4df^QmVSC=VYM3V4 z_;Hfki<#!NG!dD;DU?d`%s73ajia~_<6#{-yrT8FmPse#Y&yAvKE-F)KV4zB7MTNGv!b#Y`>^~jWx7PU~ZXA zU1&ga#%8oU<-t5G%&?YVaf6^|4^ABMCpQS3f+aW&XTEo)9$GA~5O}V%T|rwq^$YYu zv3l+Hp6RGug)SNjMGKR=o0=~xLZV+u_qq&2zwGB_!dz>!G4 zE~3cPqiB%BD7E`W6x|)gX{C|NHf(K2#8Tf8u{I~3Zm-)MeHo{wp>(X1-azP`9HhOM zeA5zJRmaGxW$k0)7mlcTBmv%(GtL;TpJKGswY@5dm#nd^A>(0h81;173rdq?F3Sk3 X)+*Sj?*EqUP0D^V0<5!uHk`i!=u6*j literal 0 HcmV?d00001 diff --git a/danmu/danmaku/__pycache__/huya.cpython-38.pyc b/danmu/danmaku/__pycache__/huya.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f01a6944cf85e0ef5dfaacd461e3bdedcbe54763 GIT binary patch literal 2589 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 8192): + break + reqmsg = self.__object.popRequest() + + return blen + + def finishConnect(self): + ''' + @brief: 使用的非阻塞socket连接不能立刻判断是否连接成功, + 在epoll响应后调用此函数处理connect结束后的操作 + @return: 是否连接成功 + @rtype: bool + ''' + tarsLogger.debug('AdapterProxy:finishConnect') + success = True + errmsg = '' + try: + ret = self.__trans.getSock().getsockopt( + socket.SOL_SOCKET, socket.SO_ERROR) + if ret: + success = False + errmsg = os.strerror(ret) + except Exception as msg: + errmsg = msg + success = False + + if not success: + self.__reactor.unregisterAdapter( + self, socket.EPOLLIN | socket.EPOLLOUT) + self.__trans.close() + self.__trans.setConnFailed() + tarsLogger.error( + 'AdapterProxy finishConnect, exception: %s, error: %s', + self.__trans.getEndPointInfo(), errmsg) + return False + self.__trans.setConnected() + self.__reactor.notify(self) + tarsLogger.info('AdapterProxy finishConnect, connect %s success', + self.__trans.getEndPointInfo()) + return True + + def finishInvoke(self, isTimeout): + pass + + # 弹出请求报文 + def popRequest(self): + pass + + def shouldCloseTrans(self): + ''' + @brief: 是否设置关闭连接 + @return: 关闭连接的flag的值 + @rtype: bool + ''' + return self.__closeTrans + + def setCloseTrans(self, closeTrans): + ''' + @brief: 设置关闭连接flag的值 + @param closeTrans: 是否关闭连接 + @type closeTrans: bool + @return: None + @rtype: None + ''' + self.__closeTrans = closeTrans + + +class QueryRegisterCallback(QueryFPrxCallback): + def __init__(self, adpManager): + self.__adpManager = adpManager + super(QueryRegisterCallback, self).__init__() + # QueryFPrxCallback.__init__(self) + + def callback_findObjectById4All(self, ret, activeEp, inactiveEp): + eplist = [EndPointInfo(x.host, x.port, x.timeout, x.weight, x.weightType) + for x in activeEp if ret == 0 and x.istcp] + ieplist = [EndPointInfo(x.host, x.port, x.timeout, x.weight, x.weightType) + for x in inactiveEp if ret == 0 and x.istcp] + self.__adpManager.setEndpoints(eplist, ieplist) + + def callback_findObjectById4All_exception(self, ret): + tarsLogger.error('callback_findObjectById4All_exception ret: %d', ret) + + +class EndpointWeightType(Enum): + E_LOOP = 0 + E_STATIC_WEIGHT = 1 + + +class AdapterProxyManager: + ''' + @brief: 管理Adapter + ''' + + def __init__(self): + tarsLogger.debug('AdapterProxyManager:__init__') + self.__comm = None + self.__object = None + # __adps的key=str(EndPointInfo) value=[EndPointInfo, AdapterProxy, cnt] + # cnt是访问次数 + self.__adps = {} + self.__iadps = {} + self.__newLock = None + self.__isDirectProxy = True + self.__lastFreshTime = 0 + self.__queryRegisterCallback = QueryRegisterCallback(self) + self.__regAdapterProxyDict = {} + self.__lastConHashPrxList = [] + self.__consistentHashWeight = None + self.__weightType = EndpointWeightType.E_LOOP + self.__update = True + self.__lastWeightedProxyData = {} + + def initialize(self, comm, objectProxy, eplist): + ''' + @brief: 初始化 + ''' + tarsLogger.debug('AdapterProxyManager:initialize') + self.__comm = comm + self.__object = objectProxy + self.__newLock = NewLock() + + self.__isDirectProxy = len(eplist) > 0 + if self.__isDirectProxy: + self.setEndpoints(eplist, {}) + else: + self.refreshEndpoints() + + def terminate(self): + ''' + @brief: 释放资源 + ''' + tarsLogger.debug('AdapterProxyManager:terminate') + # self.__lock.acquire() + lock = LockGuard(self.__newLock) + for ep, epinfo in self.__adps.items(): + epinfo[1].terminate() + self.__adps = {} + self.__lock.release() + + def refreshEndpoints(self): + ''' + @brief: 刷新服务器列表 + @return: 新的服务列表 + @rtype: EndPointInfo列表 + ''' + tarsLogger.debug('AdapterProxyManager:refreshEndpoints') + if self.__isDirectProxy: + return + + interval = self.__comm.getProperty( + 'refresh-endpoint-interval', float) / 1000 + locator = self.__comm.getProperty('locator') + + if '@' not in locator: + raise exception.TarsRegistryException( + 'locator is not valid: ' + locator) + + now = time.time() + last = self.__lastFreshTime + epSize = len(self.__adps) + if last + interval < now or (epSize <= 0 and last + 2 < now): + queryFPrx = self.__comm.stringToProxy(QueryFProxy, locator) + # 首次访问是同步调用,之后访问是异步调用 + if epSize == 0 or last == 0: + ret, activeEps, inactiveEps = ( + queryFPrx.findObjectById4All(self.__object.name())) + # 目前只支持TCP + eplist = [EndPointInfo(x.host, x.port, x.timeout, x.weight, x.weightType) + for x in activeEps if ret == 0 and x.istcp] + ieplist = [EndPointInfo(x.host, x.port, x.timeout, x.weight, x.weightType) + for x in inactiveEps if ret == 0 and x.istcp] + self.setEndpoints(eplist, ieplist) + else: + queryFPrx.async_findObjectById4All(self.__queryRegisterCallback, + self.__object.name()) + self.__lastFreshTime = now + + def getEndpoints(self): + ''' + @brief: 获取可用服务列表 如果启用分组,只返回同分组的服务端ip + @return: 获取节点列表 + @rtype: EndPointInfo列表 + ''' + tarsLogger.debug('AdapterProxyManager:getEndpoints') + # self.__lock.acquire() + lock = LockGuard(self.__newLock) + ret = [x[1][0] for x in list(self.__adps.items())] + # self.__lock.release() + + return ret + + def setEndpoints(self, eplist, ieplist): + ''' + @brief: 设置服务端信息 + @para eplist: 活跃的被调节点列表 + @para ieplist: 不活跃的被调节点列表 + ''' + tarsLogger.debug('AdapterProxyManager:setEndpoints') + adps = {} + iadps = {} + comm = self.__comm + isNeedNotify = False + # self.__lock.acquire() + lock = LockGuard(self.__newLock) + isStartStatic = True + + for ep in eplist: + if ep.getWeightType() == 0: + isStartStatic = False + epstr = str(ep) + if epstr in self.__adps: + adps[epstr] = self.__adps[epstr] + continue + isNeedNotify = True + self.__update = True + adapter = AdapterProxy() + adapter.initialize(ep, self.__object, + comm.getReactor(), comm.getAsyncProc()) + adapter.activatestateinreg = True + adps[epstr] = [ep, adapter, 0] + self.__adps, adps = adps, self.__adps + + for iep in ieplist: + iepstr = str(iep) + if iepstr in self.__iadps: + iadps[iepstr] = self.__iadps[iepstr] + continue + isNeedNotify = True + adapter = AdapterProxy() + adapter.initialize(iep, self.__object, + comm.getReactor(), comm.getAsyncProc()) + adapter.activatestateinreg = False + iadps[iepstr] = [iep, adapter, 0] + self.__iadps, iadps = iadps, self.__iadps + + if isStartStatic: + self.__weightType = EndpointWeightType.E_STATIC_WEIGHT + else: + self.__weightType = EndpointWeightType.E_LOOP + + # self.__lock.release() + if isNeedNotify: + self.__notifyEndpoints(self.__adps, self.__iadps) + # 关闭已经失效的连接 + for ep in adps: + if ep not in self.__adps: + adps[ep][1].terminate() + + def __notifyEndpoints(self, actives, inactives): + # self.__lock.acquire() + lock = LockGuard(self.__newLock) + self.__regAdapterProxyDict.clear() + self.__regAdapterProxyDict.update(actives) + self.__regAdapterProxyDict.update(inactives) + # self.__lock.release() + + def __getNextValidProxy(self): + ''' + @brief: 刷新本地缓存列表,如果服务下线了,要求删除本地缓存 + @return: + @rtype: EndPointInfo列表 + @todo: 优化负载均衡算法 + ''' + tarsLogger.debug('AdapterProxyManager:getNextValidProxy') + lock = LockGuard(self.__newLock) + if len(self.__adps) == 0: + raise TarsException("the activate adapter proxy is empty") + + sortedActivateAdp = sorted( + list(self.__adps.items()), key=lambda item: item[1][2]) + # self.refreshEndpoints() + # self.__lock.acquire() + sortedActivateAdpSize = len(sortedActivateAdp) + + while sortedActivateAdpSize != 0: + if sortedActivateAdp[0][1][1].checkActive(): + self.__adps[sortedActivateAdp[0][0]][2] += 1 + # 返回的是 adapterProxy + return self.__adps[sortedActivateAdp[0][0]][1] + sortedActivateAdp.pop(0) + sortedActivateAdpSize -= 1 + # 随机重连一个可用节点 + adpPrx = list(self.__adps.items())[random.randint( + 0, len(self.__adps))][1][1] + adpPrx.checkActive() + return None + # self.__lock.release() + + def __getHashProxy(self, reqmsg): + if self.__weightType == EndpointWeightType.E_LOOP: + if reqmsg.isConHash: + return self.__getConHashProxyForNormal(reqmsg.hashCode) + else: + return self.__getHashProxyForNormal(reqmsg.hashCode) + else: + if reqmsg.isConHash: + return self.__getConHashProxyForWeight(reqmsg.hashCode) + else: + return self.__getHashProxyForWeight(reqmsg.hashCode) + + def __getHashProxyForNormal(self, hashCode): + tarsLogger.debug('AdapterProxyManager:getHashProxyForNormal') + # self.__lock.acquire() + lock = LockGuard(self.__newLock) + regAdapterProxyList = sorted( + list(self.__regAdapterProxyDict.items()), key=lambda item: item[0]) + + allPrxSize = len(regAdapterProxyList) + if allPrxSize == 0: + raise TarsException("the adapter proxy is empty") + hashNum = hashCode % allPrxSize + + if regAdapterProxyList[hashNum][1][1].activatestateinreg and regAdapterProxyList[hashNum][1][1].checkActive(): + epstr = regAdapterProxyList[hashNum][0] + self.__regAdapterProxyDict[epstr][2] += 1 + if epstr in self.__adps: + self.__adps[epstr][2] += 1 + elif epstr in self.__iadps: + self.__iadps[epstr][2] += 1 + return self.__regAdapterProxyDict[epstr][1] + else: + if len(self.__adps) == 0: + raise TarsException("the activate adapter proxy is empty") + activeProxyList = list(self.__adps.items()) + actPrxSize = len(activeProxyList) + while actPrxSize != 0: + hashNum = hashCode % actPrxSize + if activeProxyList[hashNum][1][1].checkActive(): + self.__adps[activeProxyList[hashNum][0]][2] += 1 + return self.__adps[activeProxyList[hashNum][0]][1] + activeProxyList.pop(hashNum) + actPrxSize -= 1 + # 随机重连一个可用节点 + adpPrx = list(self.__adps.items())[random.randint( + 0, len(self.__adps))][1][1] + adpPrx.checkActive() + return None + + def __getConHashProxyForNormal(self, hashCode): + tarsLogger.debug('AdapterProxyManager:getConHashProxyForNormal') + lock = LockGuard(self.__newLock) + if len(self.__regAdapterProxyDict) == 0: + raise TarsException("the adapter proxy is empty") + if self.__consistentHashWeight is None or self.__checkConHashChange(self.__lastConHashPrxList): + self.__updateConHashProxyWeighted() + + if len(self.__consistentHashWeight.nodes) > 0: + conHashIndex = self.__consistentHashWeight.getNode(hashCode) + if conHashIndex in self.__regAdapterProxyDict and self.__regAdapterProxyDict[conHashIndex][1].activatestateinreg and self.__regAdapterProxyDict[conHashIndex][1].checkActive(): + self.__regAdapterProxyDict[conHashIndex][2] += 1 + if conHashIndex in self.__adps: + self.__adps[conHashIndex][2] += 1 + elif conHashIndex in self.__iadps: + self.__iadps[conHashIndex][2] += 1 + return self.__regAdapterProxyDict[conHashIndex][1] + else: + if len(self.__adps) == 0: + raise TarsException("the activate adapter proxy is empty") + activeProxyList = list(self.__adps.items()) + actPrxSize = len(activeProxyList) + while actPrxSize != 0: + hashNum = hashCode % actPrxSize + if activeProxyList[hashNum][1][1].checkActive(): + self.__adps[activeProxyList[hashNum][0]][2] += 1 + return self.__adps[activeProxyList[hashNum][0]][1] + activeProxyList.pop(hashNum) + actPrxSize -= 1 + # 随机重连一个可用节点 + adpPrx = list(self.__adps.items())[random.randint( + 0, len(self.__adps))][1][1] + adpPrx.checkActive() + return None + pass + else: + return self.__getHashProxyForNormal(hashCode) + + def __getHashProxyForWeight(self, hashCode): + return None + pass + + def __getConHashProxyForWeight(self, hashCode): + return None + pass + + def __checkConHashChange(self, lastConHashPrxList): + tarsLogger.debug('AdapterProxyManager:checkConHashChange') + lock = LockGuard(self.__newLock) + if len(lastConHashPrxList) != len(self.__regAdapterProxyDict): + return True + regAdapterProxyList = sorted( + list(self.__regAdapterProxyDict.items()), key=lambda item: item[0]) + regAdapterProxyListSize = len(regAdapterProxyList) + for index in range(regAdapterProxyListSize): + if cmp(lastConHashPrxList[index][0], regAdapterProxyList[index][0]) != 0: + return True + return False + + def __updateConHashProxyWeighted(self): + tarsLogger.debug('AdapterProxyManager:updateConHashProxyWeighted') + lock = LockGuard(self.__newLock) + if len(self.__regAdapterProxyDict) == 0: + raise TarsException("the adapter proxy is empty") + self.__lastConHashPrxList = sorted( + list(self.__regAdapterProxyDict.items()), key=lambda item: item[0]) + nodes = [] + for var in self.__lastConHashPrxList: + nodes.append(var[0]) + if self.__consistentHashWeight is None: + self.__consistentHashWeight = ConsistentHashNew(nodes) + else: + theOldActiveNodes = [ + var for var in nodes if var in self.__consistentHashWeight.nodes] + + theOldInactiveNodes = [ + var for var in self.__consistentHashWeight.nodes if var not in theOldActiveNodes] + for var in theOldInactiveNodes: + self.__consistentHashWeight.removeNode(var) + + theNewActiveNodes = [ + var for var in nodes if var not in theOldActiveNodes] + for var in theNewActiveNodes: + self.__consistentHashWeight.addNode(var) + + self.__consistentHashWeight.nodes = nodes + pass + + def __getWeightedProxy(self): + tarsLogger.debug('AdapterProxyManager:getWeightedProxy') + lock = LockGuard(self.__newLock) + if len(self.__adps) == 0: + raise TarsException("the activate adapter proxy is empty") + + if self.__update is True: + self.__lastWeightedProxyData.clear() + weightedProxyData = {} + minWeight = (list(self.__adps.items())[0][1][0]).getWeight() + for item in list(self.__adps.items()): + weight = (item[1][0].getWeight()) + weightedProxyData[item[0]] = (weight) + if minWeight > weight: + minWeight = weight + + if minWeight <= 0: + addWeight = -minWeight + 1 + for item in list(weightedProxyData.items()): + item[1] += addWeight + + self.__update = False + self.__lastWeightedProxyData = weightedProxyData + + weightedProxyData = self.__lastWeightedProxyData + while len(weightedProxyData) > 0: + total = sum(weightedProxyData.values()) + rand = random.randint(1, total) + temp = 0 + for item in list(weightedProxyData.items()): + temp += item[1] + if rand <= temp: + if self.__adps[item[0]][1].checkActive(): + self.__adps[item[0]][2] += 1 + return self.__adps[item[0]][1] + else: + weightedProxyData.pop(item[0]) + break + # 没有一个活跃的节点 + # 随机重连一个可用节点 + adpPrx = list(self.__adps.items())[random.randint( + 0, len(self.__adps))][1][1] + adpPrx.checkActive() + return None + + def selectAdapterProxy(self, reqmsg): + ''' + @brief: 刷新本地缓存列表,如果服务下线了,要求删除本地缓存,通过一定算法返回AdapterProxy + @param: reqmsg:请求响应报文 + @type reqmsg: ReqMessage + @return: + @rtype: EndPointInfo列表 + @todo: 优化负载均衡算法 + ''' + tarsLogger.debug('AdapterProxyManager:selectAdapterProxy') + self.refreshEndpoints() + if reqmsg.isHash: + return self.__getHashProxy(reqmsg) + else: + if self.__weightType == EndpointWeightType.E_STATIC_WEIGHT: + return self.__getWeightedProxy() + else: + return self.__getNextValidProxy() diff --git a/danmu/danmaku/tars/__async.py b/danmu/danmaku/tars/__async.py new file mode 100644 index 0000000..2964890 --- /dev/null +++ b/danmu/danmaku/tars/__async.py @@ -0,0 +1,201 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# filename: __rpc.py + +# Tencent is pleased to support the open source community by making Tars available. +# +# Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. +# +# Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +''' +@version: 0.01 +@brief: 异步rpc实现 +''' + +import threading +import Queue +from __logger import tarsLogger +from __packet import ResponsePacket +from __servantproxy import ServantProxy + + +class AsyncProcThread: + ''' + @brief: 异步调用线程管理类 + ''' + + def __init__(self): + tarsLogger.debug('AsyncProcThread:__init__') + self.__initialize = False + self.__runners = [] + self.__queue = None + self.__nrunner = 0 + self.__popTimeout = 0.1 + + def __del__(self): + tarsLogger.debug('AsyncProcThread:__del__') + + def initialize(self, nrunner=3): + ''' + @brief: 使用AsyncProcThread前必须先调用此函数 + @param nrunner: 异步线程个数 + @type nrunner: int + @return: None + @rtype: None + ''' + tarsLogger.debug('AsyncProcThread:initialize') + if self.__initialize: + return + self.__nrunner = nrunner + self.__queue = Queue.Queue() + self.__initialize = True + + def terminate(self): + ''' + @brief: 关闭所有异步线程 + @return: None + @rtype: None + ''' + tarsLogger.debug('AsyncProcThread:terminate') + + for runner in self.__runners: + runner.terminate() + + for runner in self.__runners: + runner.join() + self.__runners = [] + + def put(self, reqmsg): + ''' + @brief: 处理数据入队列 + @param reqmsg: 待处理数据 + @type reqmsg: ReqMessage + @return: None + @rtype: None + ''' + tarsLogger.debug('AsyncProcThread:put') + # 异步请求超时 + if not reqmsg.response: + reqmsg.response = ResponsePacket() + reqmsg.response.iVerson = reqmsg.request.iVerson + reqmsg.response.cPacketType = reqmsg.request.cPacketType + reqmsg.response.iRequestId = reqmsg.request.iRequestId + reqmsg.response.iRet = ServantProxy.TARSASYNCCALLTIMEOUT + + self.__queue.put(reqmsg) + + def pop(self): + ''' + @brief: 处理数据出队列 + @return: ReqMessage + @rtype: ReqMessage + ''' + # tarsLogger.debug('AsyncProcThread:pop') + ret = None + try: + ret = self.__queue.get(True, self.__popTimeout) + except Queue.Empty: + pass + return ret + + def start(self): + ''' + @brief: 启动异步线程 + @return: None + @rtype: None + ''' + tarsLogger.debug('AsyncProcThread:start') + for i in xrange(self.__nrunner): + runner = AsyncProcThreadRunner() + runner.initialize(self) + runner.start() + self.__runners.append(runner) + + +class AsyncProcThreadRunner(threading.Thread): + ''' + @brief: 异步调用线程 + ''' + + def __init__(self): + tarsLogger.debug('AsyncProcThreadRunner:__init__') + super(AsyncProcThreadRunner, self).__init__() + # threading.Thread.__init__(self) + self.__terminate = False + self.__initialize = False + self.__procQueue = None + + def __del__(self): + tarsLogger.debug('AsyncProcThreadRunner:__del__') + + def initialize(self, queue): + ''' + @brief: 使用AsyncProcThreadRunner前必须调用此函数 + @param queue: 有pop()的类,用于提取待处理数据 + @type queue: AsyncProcThread + @return: None + @rtype: None + ''' + tarsLogger.debug('AsyncProcThreadRunner:initialize') + self.__procQueue = queue + + def terminate(self): + ''' + @brief: 关闭线程 + @return: None + @rtype: None + ''' + tarsLogger.debug('AsyncProcThreadRunner:terminate') + self.__terminate = True + + def run(self): + ''' + @brief: 线程启动函数,执行异步调用 + ''' + tarsLogger.debug('AsyncProcThreadRunner:run') + while not self.__terminate: + if self.__terminate: + break + reqmsg = self.__procQueue.pop() + if not reqmsg or not reqmsg.callback: + continue + + if reqmsg.adapter: + succ = reqmsg.response.iRet == ServantProxy.TARSSERVERSUCCESS + reqmsg.adapter.finishInvoke(succ) + + try: + reqmsg.callback.onDispatch(reqmsg) + except Exception, msg: + tarsLogger.error('AsyncProcThread excepttion: %s', msg) + + tarsLogger.debug('AsyncProcThreadRunner:run finished') + + +class ServantProxyCallback(object): + ''' + @brief: 异步回调对象基类 + ''' + + def __init__(self): + tarsLogger.debug('ServantProxyCallback:__init__') + + def onDispatch(reqmsg): + ''' + @brief: 分配响应报文到对应的回调函数 + @param queue: 有pop()的类,用于提取待处理数据 + @type queue: AsyncProcThread + @return: None + @rtype: None + ''' + raise NotImplementedError() diff --git a/danmu/danmaku/tars/__init__.py b/danmu/danmaku/tars/__init__.py new file mode 100644 index 0000000..65dcb9f --- /dev/null +++ b/danmu/danmaku/tars/__init__.py @@ -0,0 +1,85 @@ +#! /usr/bin/env python +# -*- coding: utf-8 -*- + + +# Tencent is pleased to support the open source community by making Tars available. +# +# Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. +# +# Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +__version__ = "0.0.1" + +from .__util import util +from .__tars import TarsInputStream +from .__tars import TarsOutputStream +from .__tup import TarsUniPacket + + +class tarscore: + class TarsInputStream(TarsInputStream): + pass + + class TarsOutputStream(TarsOutputStream): + pass + + class TarsUniPacket(TarsUniPacket): + pass + + class boolean(util.boolean): + pass + + class int8(util.int8): + pass + + class uint8(util.uint8): + pass + + class int16(util.int16): + pass + + class uint16(util.uint16): + pass + + class int32(util.int32): + pass + + class uint32(util.uint32): + pass + + class int64(util.int64): + pass + + class float(util.float): + pass + + class double(util.double): + pass + + class bytes(util.bytes): + pass + + class string(util.string): + pass + + class struct(util.struct): + pass + + @staticmethod + def mapclass(ktype, vtype): return util.mapclass(ktype, vtype) + + @staticmethod + def vctclass(vtype): return util.vectorclass(vtype) + + @staticmethod + def printHex(buff): util.printHex(buff) + diff --git a/danmu/danmaku/tars/__logger.py b/danmu/danmaku/tars/__logger.py new file mode 100644 index 0000000..88b5275 --- /dev/null +++ b/danmu/danmaku/tars/__logger.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# filename: __logger.py + +# Tencent is pleased to support the open source community by making Tars available. +# +# Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. +# +# Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +''' +@version: 0.01 +@brief: 日志模块 +''' + +# 仅用于调试 + +import logging +from logging.handlers import RotatingFileHandler +import os +import re + +tarsLogger = logging.getLogger('TARS client') +strToLoggingLevel = { + "critical": logging.CRITICAL, + "error": logging.ERROR, + "warn": logging.WARNING, + "info": logging.INFO, + "debug": logging.DEBUG, + "none": logging.NOTSET +} +#console = logging.StreamHandler() +# console.setLevel(logging.DEBUG) +#filelog = logging.FileHandler('tars.log') +# filelog.setLevel(logging.DEBUG) +#formatter = logging.Formatter('%(asctime)s | %(levelname)8s | [%(name)s] %(message)s', '%Y-%m-%d %H:%M:%S') +# console.setFormatter(formatter) +# filelog.setFormatter(formatter) +# tarsLogger.addHandler(console) +# tarsLogger.addHandler(filelog) +# tarsLogger.setLevel(logging.DEBUG) +# tarsLogger.setLevel(logging.INFO) +# tarsLogger.setLevel(logging.ERROR) + + +def createLogFile(filename): + if filename.endswith('/'): + raise ValueError("The logfile is a dir not a file") + if os.path.exists(filename) and os.path.isfile(filename): + pass + else: + fileComposition = str.split(filename, '/') + print(fileComposition) + currentFile = '' + for item in fileComposition: + if item == fileComposition[-1]: + currentFile += item + if not os.path.exists(currentFile) or not os.path.isfile(currentFile): + while True: + try: + os.mknod(currentFile) + break + except OSError as msg: + errno = re.findall(r"\d+", str(msg)) + if len(errno) > 0 and errno[0] == '17': + currentFile += '.log' + continue + break + currentFile += (item + '/') + if not os.path.exists(currentFile): + os.mkdir(currentFile) + + +def initLog(logpath, logsize, lognum, loglevel): + createLogFile(logpath) + handler = RotatingFileHandler(filename=logpath, maxBytes=logsize, + backupCount=lognum) + formatter = logging.Formatter( + '%(asctime)s | %(levelname)6s | [%(filename)18s:%(lineno)4d] | [%(thread)d] %(message)s', '%Y-%m-%d %H:%M:%S') + handler.setFormatter(formatter) + tarsLogger.addHandler(handler) + if loglevel in strToLoggingLevel: + tarsLogger.setLevel(strToLoggingLevel[loglevel]) + else: + tarsLogger.setLevel(strToLoggingLevel["error"]) + + +if __name__ == '__main__': + tarsLogger.debug('debug log') + tarsLogger.info('info log') + tarsLogger.warning('warning log') + tarsLogger.error('error log') + tarsLogger.critical('critical log') diff --git a/danmu/danmaku/tars/__packet.py b/danmu/danmaku/tars/__packet.py new file mode 100644 index 0000000..91ca184 --- /dev/null +++ b/danmu/danmaku/tars/__packet.py @@ -0,0 +1,104 @@ +# Tencent is pleased to support the open source community by making Tars available. +# +# Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. +# +# Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + + +from .__util import util + + +class RequestPacket(util.struct): + mapcls_context = util.mapclass(util.string, util.string) + mapcls_status = util.mapclass(util.string, util.string) + + def __init__(self): + self.iVersion = 0 + self.cPacketType = 0 + self.iMessageType = 0 + self.iRequestId = 0 + self.sServantName = '' + self.sFuncName = '' + self.sBuffer = bytes() + self.iTimeout = 0 + self.context = RequestPacket.mapcls_context() + self.status = RequestPacket.mapcls_status() + + @staticmethod + def writeTo(oos, value): + oos.write(util.int16, 1, value.iVersion) + oos.write(util.int8, 2, value.cPacketType) + oos.write(util.int32, 3, value.iMessageType) + oos.write(util.int32, 4, value.iRequestId) + oos.write(util.string, 5, value.sServantName) + oos.write(util.string, 6, value.sFuncName) + oos.write(util.bytes, 7, value.sBuffer) + oos.write(util.int32, 8, value.iTimeout) + oos.write(RequestPacket.mapcls_context, 9, value.context) + oos.write(RequestPacket.mapcls_status, 10, value.status) + + @staticmethod + def readFrom(ios): + value = RequestPacket() + value.iVersion = ios.read(util.int16, 1, True, 0) + print(("iVersion = %d" % value.iVersion)) + value.cPacketType = ios.read(util.int8, 2, True, 0) + print(("cPackerType = %d" % value.cPacketType)) + value.iMessageType = ios.read(util.int32, 3, True, 0) + print(("iMessageType = %d" % value.iMessageType)) + value.iRequestId = ios.read(util.int32, 4, True, 0) + print(("iRequestId = %d" % value.iRequestId)) + value.sServantName = ios.read(util.string, 5, True, '22222222') + value.sFuncName = ios.read(util.string, 6, True, '') + value.sBuffer = ios.read(util.bytes, 7, True, value.sBuffer) + value.iTimeout = ios.read(util.int32, 8, True, 0) + value.context = ios.read( + RequestPacket.mapcls_context, 9, True, value.context) + value.status = ios.read( + RequestPacket.mapcls_status, 10, True, value.status) + return value + + +class ResponsePacket(util.struct): + __tars_class__ = "tars.RpcMessage.ResponsePacket" + mapcls_status = util.mapclass(util.string, util.string) + + def __init__(self): + self.iVersion = 0 + self.cPacketType = 0 + self.iRequestId = 0 + self.iMessageType = 0 + self.iRet = 0 + self.sBuffer = bytes() + self.status = RequestPacket.mapcls_status() + + @staticmethod + def writeTo(oos, value): + oos.write(util.int16, 1, value.iVersion) + oos.write(util.int8, 2, value.cPacketType) + oos.write(util.int32, 3, value.iRequestId) + oos.write(util.int32, 4, value.iMessageType) + oos.write(util.int32, 5, value.iRet) + oos.write(util.bytes, 6, value.sBuffer) + oos.write(value.mapcls_status, 7, value.status) + + @staticmethod + def readFrom(ios): + value = ResponsePacket() + value.iVersion = ios.read(util.int16, 1, True) + value.cPacketType = ios.read(util.int8, 2, True) + value.iRequestId = ios.read(util.int32, 3, True) + value.iMessageType = ios.read(util.int32, 4, True) + value.iRet = ios.read(util.int32, 5, True) + value.sBuffer = ios.read(util.bytes, 6, True) + value.status = ios.read(value.mapcls_status, 7, True) + return value diff --git a/danmu/danmaku/tars/__pycache__/__init__.cpython-38.pyc b/danmu/danmaku/tars/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..799222da718629870a4322db0c88fa7302782e8d GIT binary patch literal 3151 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 tbRxSwJ9B~n@Ao-9;vHlb~ literal 0 HcmV?d00001 diff --git a/danmu/danmaku/tars/__pycache__/__tars.cpython-38.pyc b/danmu/danmaku/tars/__pycache__/__tars.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..59cc6f56bf7e6acb6a43efad91a76b4bb6ae79a6 GIT binary patch literal 16056 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 literal 0 HcmV?d00001 diff --git a/danmu/danmaku/tars/__pycache__/__tup.cpython-38.pyc b/danmu/danmaku/tars/__pycache__/__tup.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..762d73cae3cd51e7537b173c4948b6108aa2a855 GIT binary patch literal 3463 zcmbVPTXP#V6qfepwPWYjG-=ubDNq;>r5*-mfYK=~Az?buv{NTM_HFrd^MuBb~F7&e`u=yi+LT7@i;Bd-=;>1;$>| zi4KorcqNE3Tnk&|bwewAaWq{ff`o4@_i) z|AGl$W)JO3PVh1-W>2s)+dARsi#%~+U29;R-wsuDKh~XCm$i~%6Kiv{cDMEFQsJR| z63a+G2&?;2S81zP9~+a~XwjeOB*T?i#S*yq3s$kEBW&TkV28ZoO1JI_cQkW^Co+bU zkr{CO(aaH9kuw}$`ryorW{${rq-9oebR*wbFaHYrU zj#+Vg?8xmi@I0M4q|q0w%#Qh1F{{W*iQf!6)kYXai5F>AYduQb-2*M7%2F_Pl^}p% zm`q!Jnk-Ms?#6q2QYnv4IP*%iE#xsic_bTq$4o6i=jJh@%hVAXPA#eEJARJ#_S)oXgIIA_ zO#N0_m4=d<`116e?#j4MBbhf<>>{Z%O|eU0d~na?!x^p7AU3=Zmi-xJoprIv(U zX4*QkQ+Nu#%K8*jovq4ZdHc@xPC0nEQQrA!J6ON}{l=yuNEaOgUh?u#$C0A=pE#jz z*QQ!!M#(5{=zx6nTe>E>GPCBnV|7<2Z8MTQqs0i#Yj}H_7N;6az5n+c<@L>k6;sbs zm$A!#URTJdx(T8Gzb;8u$;iXU1wqX?-!%}L9kS<6&pF~fj;q^!o5LaN7FO&&tI;QM zde%*(MO@w5O0DcF+B0#VshXC_ECLhaQ(yvY5G2`0Qh%3*Mr2)9bcc?t4>~e&S`<%K z=zY80jwW0ov5^4pftl*YJwD633*(;x5><-o!)HvVU99$yCh80@;(*bbMn=R6blS6) zkq>`2FzZ>X?73|;wFi=$kTfeRMoQZ~Gh4;XSjd5e9O3o>%c8fn*}aMkc1I(f?8aKI zwc2`ZuN}9<+P*xvaW%R|+G6ZpevO#n8+&fUL}aNXyYX99c66=XQtxA~NVCL2P7nhl zst;-TDlK!J@b($&!SoNojmQ}pZ0B(QAJ5Ji$^muOns{Rj&}7*RnnB2~APho)4j=?+ z*udMM1Xcw$0v8;Qk}v3tk+rmclr`S~>6tT~JDQ252*hIAcJ$-8Pv%uIj|;pnOW~ zhHMpWgG5Earea5D!RN^qg@OS5h>{=!{uV8t=PlsS>Mo7rFclt)m2~rwd)>lB!HBH^YI-quhDh4GNs?I(lUXU>k=WMC#*kync-vA=5H+(|H zrfN5hNfc!&RitiYE5t&RKy8#M6}w%FpmObuzj;EE%KLbAP)W=~-8`REHWeE~3I*Iz z=p%DM0TgR}hQfH5%7-!S99?Z%5#d%FGE|C=r@a{Oo*TEa;g1=aC3i)MP`yjt8g*1MDGI;p3+gB*tFNg0n!3~Kz))0dDRN1w zA0ono&;418=WGXU%IIOu^IgB-=lzUtn|F&d>NDEMWJE6r=$}Yh8)HJ@J9Re#Zv`5Y j&q$p@&1>&cjcT@;cDKa8nVRJm**hWt;(|P%{_KAN8Eef< literal 0 HcmV?d00001 diff --git a/danmu/danmaku/tars/__pycache__/__util.cpython-38.pyc b/danmu/danmaku/tars/__pycache__/__util.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ecb77c6eb83a33d51b1582397b62902f64be99a1 GIT binary patch literal 9069 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 literal 0 HcmV?d00001 diff --git a/danmu/danmaku/tars/__pycache__/exception.cpython-38.pyc b/danmu/danmaku/tars/__pycache__/exception.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6b636896405a9476c2be2a6df66f96a6c5c01439 GIT binary patch literal 2875 zcmbW3%TC)s6o#Dy$ekpF5JI5g+KNT%O_x{!nMf`2;AkfEDVNW4eCEuYm&*kM*T>Go*J{=<9thNH2Jj9oc%3qg1A`eX z^$U#~KQk98aGGVn8J+^C!82?YJS#Z^o?}^XR`Luu$MWF3=Z%JMNZ?hfnj^sLferoK#aMXCx7?F%)TEc)E z7b#|3q*)5zO^?cFwg~p`96ktpzSq6ajB=Lc*?n$Vqk?7ieHOViE?L%fWV`Vv_lB6m zU&-$Gp?T@|xq167G>?bQr7il$!vDdYFffmXdp_f);I{iR60XT?uOG?YzKYBcW|NQA zuLeUwH(Est(&%!AWUbk((QK%_=MKy#{5t9h-u1)%yIv4>1^w^j*5eVf&=5Iv3ut3A zv6gvh+I-Xt`gZ7CKBCM+QCF12TFRAa<)L?DyFK>Bb|e0XmX_b5q9xYSHpbd>FNg*M zUxa7F!DGfE3=PFdtYvJHvCG3f-}8`HlWhI}^Q25~Do$c8XM5WD$qy2F%kV5KUSch; z%p=V8)OW6UBIP_3Ek#MJrCg?|V$I$S<5iO+z7uSuG>f)v%Ce{+m9pHq2$CfIFNv28_aZ520YZ;ZaI^h8i4@8e85mQ~Z{J z-NjM1s;8#_usr^?v{hM(h6o literal 0 HcmV?d00001 diff --git a/danmu/danmaku/tars/__rpc.py b/danmu/danmaku/tars/__rpc.py new file mode 100644 index 0000000..f7568f2 --- /dev/null +++ b/danmu/danmaku/tars/__rpc.py @@ -0,0 +1,441 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# filename: __rpc.py + +# Tencent is pleased to support the open source community by making Tars available. +# +# Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. +# +# Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + + +''' +@version: 0.01 +@brief: rpc调用逻辑实现 +''' + +import time +import argparse + +from .__logger import tarsLogger +from .__logger import initLog +from .__trans import EndPointInfo +from .__TimeoutQueue import TimeoutQueue +from .__TimeoutQueue import QueueTimeout +from .__trans import FDReactor +from .__adapterproxy import AdapterProxyManager +from .__servantproxy import ServantProxy +from .exception import (TarsException) +from .__async import AsyncProcThread + + +class Communicator: + ''' + @brief: 通讯器,创建和维护ServantProxy、ObjectProxy、FDReactor线程和超时线程 + ''' + default_config = {'tars': + {'application': + {'client': + {'async-invoke-timeout': 20000, + 'asyncthread': 0, + 'locator': '', + 'loglevel': 'error', + 'logpath': 'tars.log', + 'logsize': 15728640, + 'lognum': 0, + 'refresh-endpoint-interval': 60000, + 'sync-invoke-timeout': 5000}}}} + + def __init__(self, config={}): + tarsLogger.debug('Communicator:__init__') + self.__terminate = False + self.__initialize = False + self.__objects = {} + self.__servants = {} + self.__reactor = None + self.__qTimeout = None + self.__asyncProc = None + self.__config = Communicator.default_config.copy() + self.__config.update(config) + self.initialize() + + def __del__(self): + tarsLogger.debug('Communicator:__del__') + + def initialize(self): + ''' + @brief: 使用通讯器前必须先调用此函数 + ''' + tarsLogger.debug('Communicator:initialize') + if self.__initialize: + return + logpath = self.getProperty('logpath') + logsize = self.getProperty('logsize', int) + lognum = self.getProperty('lognum', int) + loglevel = self.getProperty('loglevel') + initLog(logpath, logsize, lognum, loglevel) + + self.__reactor = FDReactor() + self.__reactor.initialize() + self.__reactor.start() + + self.__qTimeout = QueueTimeout() + self.__qTimeout.setHandler(self.handleTimeout) + self.__qTimeout.start() + + async_num = self.getProperty('asyncthread', int) + self.__asyncProc = AsyncProcThread() + self.__asyncProc.initialize(async_num) + self.__asyncProc.start() + + self.__initialize = True + + def terminate(self): + ''' + @brief: 不再使用通讯器需调用此函数释放资源 + ''' + tarsLogger.debug('Communicator:terminate') + + if not self.__initialize: + return + + self.__reactor.terminate() + self.__qTimeout.terminate() + self.__asyncProc.terminate() + + for objName in self.__servants: + self.__servants[objName]._terminate() + + for objName in self.__objects: + self.__objects[objName].terminate() + + self.__objects = {} + self.__servants = {} + self.__reactor = None + self.__initialize = False + + def parseConnAddr(self, connAddr): + ''' + @brief: 解析connAddr字符串 + @param connAddr: 连接地址 + @type connAddr: str + @return: 解析结果 + @rtype: dict, key是str,val里name是str, + timeout是float,endpoint是EndPointInfo的list + ''' + tarsLogger.debug('Communicator:parseConnAddr') + connAddr = connAddr.strip() + connInfo = { + 'name': '', + 'timeout': -1, + 'endpoint': [] + } + if '@' not in connAddr: + connInfo['name'] = connAddr + return connInfo + + try: + tks = connAddr.split('@') + connInfo['name'] = tks[0] + tks = tks[1].lower().split(':') + parser = argparse.ArgumentParser(add_help=False) + parser.add_argument('-h') + parser.add_argument('-p') + parser.add_argument('-t') + for tk in tks: + argv = tk.split() + if argv[0] != 'tcp': + raise TarsException( + 'unsupport transmission protocal : %s' % connInfo['name']) + mes = parser.parse_args(argv[1:]) + try: + ip = mes.h if mes.h is not None else '' + port = int(mes.p) if mes.p is not None else '-1' + timeout = int(mes.t) if mes.t is not None else '-1' + connInfo['endpoint'].append( + EndPointInfo(ip, port, timeout)) + except Exception: + raise TarsException('Unrecognized option : %s' % mes) + except TarsException: + raise + + except Exception as exp: + raise TarsException(exp) + + return connInfo + + def getReactor(self): + ''' + @brief: 获取reactor + ''' + return self.__reactor + + def getAsyncProc(self): + ''' + @brief: 获取asyncProc + ''' + return self.__asyncProc + + def getProperty(self, name, dt_type=str): + ''' + @brief: 获取配置 + @param name: 配置名称 + @type name: str + @param dt_type: 数据类型 + @type name: type + @return: 配置内容 + @rtype: str + ''' + try: + ret = self.__config['tars']['application']['client'][name] + ret = dt_type(ret) + except: + ret = Communicator.default_config['tars']['application']['client'][name] + + return ret + + def setProperty(self, name, value): + ''' + @brief: 修改配置 + @param name: 配置名称 + @type propertys: str + @param value: 配置内容 + @type propertys: str + @return: 设置是否成功 + @rtype: bool + ''' + try: + self.__config['tars']['application']['client'][name] = value + return True + except: + return False + + def setPropertys(self, propertys): + ''' + @brief: 修改配置 + @param propertys: 配置集合 + @type propertys: map, key type: str, value type: str + @return: 无 + @rtype: None + ''' + pass + + def updateConfig(self): + ''' + @brief: 重新设置配置 + ''' + + def stringToProxy(self, servantProxy, connAddr): + ''' + @brief: 初始化ServantProxy + @param connAddr: 服务器地址信息 + @type connAddr: str + @param servant: servant proxy + @type servant: ServantProxy子类 + @return: 无 + @rtype: None + @note: 如果connAddr的ServantObj连接过,返回连接过的ServantProxy + 如果没有连接过,用参数servant初始化,返回servant + ''' + tarsLogger.debug('Communicator:stringToProxy') + + connInfo = self.parseConnAddr(connAddr) + objName = connInfo['name'] + if objName in self.__servants: + return self.__servants[objName] + + objectPrx = ObjectProxy() + objectPrx.initialize(self, connInfo) + + servantPrx = servantProxy() + servantPrx._initialize(self.__reactor, objectPrx) + self.__objects[objName] = objectPrx + self.__servants[objName] = servantPrx + return servantPrx + + def handleTimeout(self): + ''' + @brief: 处理超时事件 + @return: 无 + @rtype: None + ''' + # tarsLogger.debug('Communicator:handleTimeout') + for obj in self.__objects.values(): + obj.handleQueueTimeout() + + +class ObjectProxy: + ''' + @brief: 一个object name在一个Communicator里有一个objectproxy + 管理收发的消息队列 + ''' + DEFAULT_TIMEOUT = 3.0 + + def __init__(self): + tarsLogger.debug('ObjectProxy:__init__') + self.__name = '' + self.__timeout = ObjectProxy.DEFAULT_TIMEOUT + self.__comm = None + self.__epi = None + self.__adpmanager = None + self.__timeoutQueue = None + # self.__adapter = None + self.__initialize = False + + def __del__(self): + tarsLogger.debug('ObjectProxy:__del__') + + def initialize(self, comm, connInfo): + ''' + @brief: 初始化,使用ObjectProxy前必须调用 + @param comm: 通讯器 + @type comm: Communicator + @param connInfo: 连接信息 + @type comm: dict + @return: None + @rtype: None + ''' + if self.__initialize: + return + tarsLogger.debug('ObjectProxy:initialize') + self.__comm = comm + # async-invoke-timeout来设置队列时间 + async_timeout = self.__comm.getProperty( + 'async-invoke-timeout', float) / 1000 + self.__timeoutQueue = TimeoutQueue(async_timeout) + + self.__name = connInfo['name'] + + self.__timeout = self.__comm.getProperty( + 'sync-invoke-timeout', float) / 1000 + + # 通过Communicator的配置设置超时 + # 不再通过连接信息的-t来设置 + # if connInfo['timeout'] != -1: + # self.__timeout = connInfo['timeout'] + eplist = connInfo['endpoint'] + + self.__adpmanager = AdapterProxyManager() + self.__adpmanager.initialize(comm, self, eplist) + + self.__initialize = True + + def terminate(self): + ''' + @brief: 回收资源,不再使用ObjectProxy时调用 + @return: None + @rtype: None + ''' + tarsLogger.debug('ObjectProxy:terminate') + self.__timeoutQueue = None + self.__adpmanager.terminate() + self.__initialize = False + + def name(self): + ''' + @brief: 获取object name + @return: object name + @rtype: str + ''' + return self.__name + + # def setTimeout(self, timeout): + # ''' + # @brief: 设置超时 + # @param timeout: 超时时间,单位为s + # @type timeout: float + # @return: None + # @rtype: None + # ''' + # self.__timeout = timeout + # self.__timeoutQueue.setTimeout(timeout) + + def timeout(self): + ''' + @brief: 获取超时时间 + @return: 超时时间,单位为s + @rtype: float + ''' + return self.__timeout + + def getTimeoutQueue(self): + ''' + @brief: 获取超时队列 + @return: 超时队列 + @rtype: TimeoutQueue + ''' + return self.__timeoutQueue + + def handleQueueTimeout(self): + ''' + @brief: 超时事件发生时处理超时事务 + @return: None + @rtype: None + ''' + # tarsLogger.debug('ObjectProxy:handleQueueTimeout') + self.__timeoutQueue.timeout() + + def invoke(self, reqmsg): + ''' + @brief: 远程过程调用 + @param reqmsg: 请求响应报文 + @type reqmsg: ReqMessage + @return: 错误码 + @rtype: + ''' + tarsLogger.debug('ObjectProxy:invoke, objname: %s, func: %s', + self.__name, reqmsg.request.sFuncName) + # 负载均衡 + # adapter = self.__adpmanager.getNextValidProxy() + adapter = self.__adpmanager.selectAdapterProxy(reqmsg) + if not adapter: + tarsLogger.error("invoke %s, select adapter proxy return None", + self.__name) + return -2 + + adapter.checkActive(True) + reqmsg.adapter = adapter + return adapter.invoke(reqmsg) + + # 弹出请求报文 + def popRequest(self): + ''' + @brief: 返回消息队列里的请求响应报文,FIFO + 不删除TimeoutQueue里的数据,响应时要用 + @return: 请求响应报文 + @rtype: ReqMessage + ''' + return self.__timeoutQueue.pop(erase=False) + + +if __name__ == '__main__': + connAddr = "apptest.lightServer.lightServantObj@tcp -h 10.130.64.220 -p 10001 -t 10000" + connAddr = 'MTT.BookMarksUnifyServer.BookMarksUnifyObj@tcp -h 172.17.149.77 -t 60000 -p 10023' + comm = Communicator() + comm.initialize() + servant = ServantProxy() + servant = comm.stringToProxy(connAddr, servant) + print(servant.tars_timeout()) + try: + rsp = servant.tars_invoke( + ServantProxy.TARSNORMAL, "test", '', ServantProxy.mapcls_context(), None) + print('Servant invoke success, request id: %d, iRet: %d' % ( + rsp.iRequestId, rsp.iRet)) + except Exception as msg: + print(msg) + finally: + servant.tars_terminate() + time.sleep(2) + print('app closing ...') + comm.terminate() + time.sleep(2) + print('cpp closed') diff --git a/danmu/danmaku/tars/__servantproxy.py b/danmu/danmaku/tars/__servantproxy.py new file mode 100644 index 0000000..5baeef3 --- /dev/null +++ b/danmu/danmaku/tars/__servantproxy.py @@ -0,0 +1,358 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# filename: __servantproxy.py + +# Tencent is pleased to support the open source community by making Tars available. +# +# Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. +# +# Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + + +''' +@version: 0.01 +@brief: rpc抽离出servantproxy +''' +import threading +import time + +from __logger import tarsLogger +from __util import util +from __packet import RequestPacket +# from __packet import ResponsePacket +from __TimeoutQueue import ReqMessage +import exception +from exception import TarsException + + +class ServantProxy(object): + ''' + @brief: 1、远程对象的本地代理 + 2、同名servant在一个通信器中最多只有一个实例 + 3、防止和用户在Tars中定义的函数名冲突,接口以tars_开头 + ''' + + # 服务器响应的错误码 + TARSSERVERSUCCESS = 0 # 服务器端处理成功 + TARSSERVERDECODEERR = -1 # 服务器端解码异常 + TARSSERVERENCODEERR = -2 # 服务器端编码异常 + TARSSERVERNOFUNCERR = -3 # 服务器端没有该函数 + TARSSERVERNOSERVANTERR = -4 # 服务器端五该Servant对象 + TARSSERVERRESETGRID = -5 # 服务器端灰度状态不一致 + TARSSERVERQUEUETIMEOUT = -6 # 服务器队列超过限制 + TARSASYNCCALLTIMEOUT = -7 # 异步调用超时 + TARSPROXYCONNECTERR = -8 # proxy链接异常 + TARSSERVERUNKNOWNERR = -99 # 服务器端未知异常 + + TARSVERSION = 1 + TUPVERSION = 2 + TUPVERSION2 = 3 + + TARSNORMAL = 0 + TARSONEWAY = 1 + + TARSMESSAGETYPENULL = 0 + TARSMESSAGETYPEHASH = 1 + TARSMESSAGETYPEGRID = 2 + TARSMESSAGETYPEDYED = 4 + TARSMESSAGETYPESAMPLE = 8 + TARSMESSAGETYPEASYNC = 16 + + mapcls_context = util.mapclass(util.string, util.string) + + def __init__(self): + tarsLogger.debug('ServantProxy:__init__') + self.__reactor = None + self.__object = None + self.__initialize = False + + def __del__(self): + tarsLogger.debug('ServantProxy:__del__') + + def _initialize(self, reactor, obj): + ''' + @brief: 初始化函数,需要调用才能使用ServantProxy + @param reactor: 网络管理的reactor实例 + @type reactor: FDReactor + @return: None + @rtype: None + ''' + tarsLogger.debug('ServantProxy:_initialize') + + assert(reactor and obj) + if self.__initialize: + return + self.__reactor = reactor + self.__object = obj + self.__initialize = True + + def _terminate(self): + ''' + @brief: 不再使用ServantProxy时调用,会释放相应资源 + @return: None + @rtype: None + ''' + tarsLogger.debug('ServantProxy:_terminate') + self.__object = None + self.__reactor = None + self.__initialize = False + + def tars_name(self): + ''' + @brief: 获取ServantProxy的名字 + @return: ServantProxy的名字 + @rtype: str + ''' + return self.__object.name() + + def tars_timeout(self): + ''' + @brief: 获取超时时间,单位是ms + @return: 超时时间 + @rtype: int + ''' + # 默认的为3S = ObjectProxy.DEFAULT_TIMEOUT + return int(self.__timeout() * 1000) + + def tars_ping(self): + pass + + # def tars_initialize(self): + # pass + + # def tars_terminate(self): + # pass + + def tars_invoke(self, cPacketType, sFuncName, sBuffer, context, status): + ''' + @brief: TARS协议同步方法调用 + @param cPacketType: 请求包类型 + @type cPacketType: int + @param sFuncName: 调用函数名 + @type sFuncName: str + @param sBuffer: 序列化后的发送参数 + @type sBuffer: str + @param context: 上下文件信息 + @type context: ServantProxy.mapcls_context + @param status: 状态信息 + @type status: + @return: 响应报文 + @rtype: ResponsePacket + ''' + tarsLogger.debug('ServantProxy:tars_invoke, func: %s', sFuncName) + req = RequestPacket() + req.iVersion = ServantProxy.TARSVERSION + req.cPacketType = cPacketType + req.iMessageType = ServantProxy.TARSMESSAGETYPENULL + req.iRequestId = 0 + req.sServantName = self.tars_name() + req.sFuncName = sFuncName + req.sBuffer = sBuffer + req.iTimeout = self.tars_timeout() + + reqmsg = ReqMessage() + reqmsg.type = ReqMessage.SYNC_CALL + reqmsg.servant = self + reqmsg.lock = threading.Condition() + reqmsg.request = req + reqmsg.begtime = time.time() + # # test + reqmsg.isHash = True + reqmsg.isConHash = True + reqmsg.hashCode = 123456 + + rsp = None + try: + rsp = self.__invoke(reqmsg) + except exception.TarsSyncCallTimeoutException: + if reqmsg.adapter: + reqmsg.adapter.finishInvoke(True) + raise + except TarsException: + raise + except: + raise TarsException('ServantProxy::tars_invoke excpetion') + + if reqmsg.adapter: + reqmsg.adapter.finishInvoke(False) + + return rsp + + def tars_invoke_async(self, cPacketType, sFuncName, sBuffer, + context, status, callback): + ''' + @brief: TARS协议同步方法调用 + @param cPacketType: 请求包类型 + @type cPacketType: int + @param sFuncName: 调用函数名 + @type sFuncName: str + @param sBuffer: 序列化后的发送参数 + @type sBuffer: str + @param context: 上下文件信息 + @type context: ServantProxy.mapcls_context + @param status: 状态信息 + @type status: + @param callback: 异步调用回调对象 + @type callback: ServantProxyCallback的子类 + @return: 响应报文 + @rtype: ResponsePacket + ''' + tarsLogger.debug('ServantProxy:tars_invoke') + req = RequestPacket() + req.iVersion = ServantProxy.TARSVERSION + req.cPacketType = cPacketType if callback else ServantProxy.TARSONEWAY + req.iMessageType = ServantProxy.TARSMESSAGETYPENULL + req.iRequestId = 0 + req.sServantName = self.tars_name() + req.sFuncName = sFuncName + req.sBuffer = sBuffer + req.iTimeout = self.tars_timeout() + + reqmsg = ReqMessage() + reqmsg.type = ReqMessage.ASYNC_CALL if callback else ReqMessage.ONE_WAY + reqmsg.callback = callback + reqmsg.servant = self + reqmsg.request = req + reqmsg.begtime = time.time() + + rsp = None + try: + rsp = self.__invoke(reqmsg) + except TarsException: + raise + except Exception: + raise TarsException('ServantProxy::tars_invoke excpetion') + + if reqmsg.adapter: + reqmsg.adapter.finishInvoke(False) + + return rsp + + def __timeout(self): + ''' + @brief: 获取超时时间,单位是s + @return: 超时时间 + @rtype: float + ''' + return self.__object.timeout() + + def __invoke(self, reqmsg): + ''' + @brief: 远程过程调用 + @param reqmsg: 请求数据 + @type reqmsg: ReqMessage + @return: 调用成功或失败 + @rtype: bool + ''' + tarsLogger.debug('ServantProxy:invoke, func: %s', + reqmsg.request.sFuncName) + ret = self.__object.invoke(reqmsg) + if ret == -2: + errmsg = ('ServantProxy::invoke fail, no valid servant,' + + ' servant name : %s, function name : %s' % + (reqmsg.request.sServantName, + reqmsg.request.sFuncName)) + raise TarsException(errmsg) + if ret == -1: + errmsg = ('ServantProxy::invoke connect fail,' + + ' servant name : %s, function name : %s, adapter : %s' % + (reqmsg.request.sServantName, + reqmsg.request.sFuncName, + reqmsg.adapter.getEndPointInfo())) + raise TarsException(errmsg) + elif ret != 0: + errmsg = ('ServantProxy::invoke unknown fail, ' + + 'Servant name : %s, function name : %s' % + (reqmsg.request.sServantName, + reqmsg.request.sFuncName)) + raise TarsException(errmsg) + + if reqmsg.type == ReqMessage.SYNC_CALL: + reqmsg.lock.acquire() + reqmsg.lock.wait(self.__timeout()) + reqmsg.lock.release() + + if not reqmsg.response: + errmsg = ('ServantProxy::invoke timeout: %d, servant name' + ': %s, adapter: %s, request id: %d' % ( + self.tars_timeout(), + self.tars_name(), + reqmsg.adapter.trans().getEndPointInfo(), + reqmsg.request.iRequestId)) + raise exception.TarsSyncCallTimeoutException(errmsg) + elif reqmsg.response.iRet == ServantProxy.TARSSERVERSUCCESS: + return reqmsg.response + else: + errmsg = 'servant name: %s, function name: %s' % ( + self.tars_name(), reqmsg.request.sFuncName) + self.tarsRaiseException(reqmsg.response.iRet, errmsg) + + def _finished(self, reqmsg): + ''' + @brief: 通知远程过程调用线程响应报文到了 + @param reqmsg: 请求响应报文 + @type reqmsg: ReqMessage + @return: 函数执行成功或失败 + @rtype: bool + ''' + tarsLogger.debug('ServantProxy:finished') + if not reqmsg.lock: + return False + reqmsg.lock.acquire() + reqmsg.lock.notifyAll() + reqmsg.lock.release() + return True + + def tarsRaiseException(self, errno, desc): + ''' + @brief: 服务器调用失败,根据服务端给的错误码抛出异常 + @param errno: 错误码 + @type errno: int + @param desc: 错误描述 + @type desc: str + @return: 没有返回值,函数会抛出异常 + @rtype: + ''' + if errno == ServantProxy.TARSSERVERSUCCESS: + return + + elif errno == ServantProxy.TARSSERVERDECODEERR: + raise exception.TarsServerDecodeException( + "server decode exception: errno: %d, msg: %s" % (errno, desc)) + + elif errno == ServantProxy.TARSSERVERENCODEERR: + raise exception.TarsServerEncodeException( + "server encode exception: errno: %d, msg: %s" % (errno, desc)) + + elif errno == ServantProxy.TARSSERVERNOFUNCERR: + raise exception.TarsServerNoFuncException( + "server function mismatch exception: errno: %d, msg: %s" % (errno, desc)) + + elif errno == ServantProxy.TARSSERVERNOSERVANTERR: + raise exception.TarsServerNoServantException( + "server servant mismatch exception: errno: %d, msg: %s" % (errno, desc)) + + elif errno == ServantProxy.TARSSERVERRESETGRID: + raise exception.TarsServerResetGridException( + "server reset grid exception: errno: %d, msg: %s" % (errno, desc)) + + elif errno == ServantProxy.TARSSERVERQUEUETIMEOUT: + raise exception.TarsServerQueueTimeoutException( + "server queue timeout exception: errno: %d, msg: %s" % (errno, desc)) + + elif errno == ServantProxy.TARSPROXYCONNECTERR: + raise exception.TarsServerQueueTimeoutException( + "server connection lost: errno: %d, msg: %s" % (errno, desc)) + + else: + raise exception.TarsServerUnknownException( + "server unknown exception: errno: %d, msg: %s" % (errno, desc)) diff --git a/danmu/danmaku/tars/__tars.py b/danmu/danmaku/tars/__tars.py new file mode 100644 index 0000000..520dc4a --- /dev/null +++ b/danmu/danmaku/tars/__tars.py @@ -0,0 +1,546 @@ +# Tencent is pleased to support the open source community by making Tars available. +# +# Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. +# +# Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +import struct +from .__util import util +from .exception import * + + +class BinBuffer: + def __init__(self, buff=bytes()): + self.buffer = buff + self.position = 0 + + def writeBuf(self, buff): + self.buffer += buff + + def getBuffer(self): + return self.buffer + + def length(self): + return len(self.buffer) + + +class DataHead: + EN_INT8 = 0 + EN_INT16 = 1 + EN_INT32 = 2 + EN_INT64 = 3 + EN_FLOAT = 4 + EN_DOUBLE = 5 + EN_STRING1 = 6 + EN_STRING4 = 7 + EN_MAP = 8 + EN_LIST = 9 + EN_STRUCTBEGIN = 10 + EN_STRUCTEND = 11 + EN_ZERO = 12 + EN_BYTES = 13 + + @staticmethod + def writeTo(buff, tag, vtype): + if tag < 15: + helper = (tag << 4) | vtype + buff.writeBuf(struct.pack('!B', helper)) + else: + helper = (0xF0 | vtype) << 8 | tag + buff.writeBuf(struct.pack('!H', helper)) + + +class TarsOutputStream(object): + def __init__(self): + self.__buffer = BinBuffer() + + def __writeBoolean(self, tag, value): + self.__writeInt8(tag, int(value)) + + def __writeInt8(self, tag, value): + if value == 0: + DataHead.writeTo(self.__buffer, tag, DataHead.EN_ZERO) + else: + DataHead.writeTo(self.__buffer, tag, DataHead.EN_INT8) + self.__buffer.writeBuf(struct.pack('!b', value)) + + def __writeInt16(self, tag, value): + if value >= -128 and value <= 127: + self.__writeInt8(tag, value) + else: + DataHead.writeTo(self.__buffer, tag, DataHead.EN_INT16) + self.__buffer.writeBuf(struct.pack('!h', value)) + + def __writeInt32(self, tag, value): + if value >= -32768 and value <= 32767: + self.__writeInt16(tag, value) + else: + DataHead.writeTo(self.__buffer, tag, DataHead.EN_INT32) + self.__buffer.writeBuf(struct.pack('!i', value)) + + def __writeInt64(self, tag, value): + if value >= (-2147483648) and value <= 2147483647: + self.__writeInt32(tag, value) + else: + DataHead.writeTo(self.__buffer, tag, DataHead.EN_INT64) + self.__buffer.writeBuf(struct.pack('!q', value)) + + def __writeFloat(self, tag, value): + DataHead.writeTo(self.__buffer, tag, DataHead.EN_FLOAT) + self.__buffer.writeBuf(struct.pack('!f', value)) + + def __writeDouble(self, tag, value): + DataHead.writeTo(self.__buffer, tag, DataHead.EN_DOUBLE) + self.__buffer.writeBuf(struct.pack('!d', value)) + + def __writeString(self, tag, value): + length = len(value) + if length <= 255: + DataHead.writeTo(self.__buffer, tag, DataHead.EN_STRING1) + self.__buffer.writeBuf(struct.pack('!B', length)) + self.__buffer.writeBuf(str.encode(value)) + else: + DataHead.writeTo(self.__buffer, tag, DataHead.EN_STRING4) + self.__buffer.writeBuf(struct.pack('!I', length)) + self.__buffer.writeBuf(str.encode(value)) + + def __writeBytes(self, tag, value): + DataHead.writeTo(self.__buffer, tag, DataHead.EN_BYTES) + DataHead.writeTo(self.__buffer, 0, DataHead.EN_INT8) + length = len(value) + self.__writeInt32(0, length) + self.__buffer.buffer += value + self.__buffer.position += length + + def __writeMap(self, coder, tag, value): + DataHead.writeTo(self.__buffer, tag, DataHead.EN_MAP) + self.__writeInt32(0, len(value)) + for key in value: + self.write(coder.ktype, 0, key) + self.write(coder.vtype, 1, value.get(key)) + + def __writeVector(self, coder, tag, value): + DataHead.writeTo(self.__buffer, tag, DataHead.EN_LIST) + n = len(value) + self.__writeInt32(0, n) + for i in range(0, n): + self.write(value.vtype, 0, value[i]) + + def __writeStruct(self, coder, tag, value): + DataHead.writeTo(self.__buffer, tag, DataHead.EN_STRUCTBEGIN) + value.writeTo(self, value) + DataHead.writeTo(self.__buffer, 0, DataHead.EN_STRUCTEND) + + def write(self, coder, tag, value): + if coder.__tars_index__ == 999: + self.__writeBoolean(tag, value) + elif coder.__tars_index__ == 0: + self.__writeInt8(tag, value) + elif coder.__tars_index__ == 1: + self.__writeInt16(tag, value) + elif coder.__tars_index__ == 2: + self.__writeInt32(tag, value) + elif coder.__tars_index__ == 3: + self.__writeInt64(tag, value) + elif coder.__tars_index__ == 4: + self.__writeFloat(tag, value) + elif coder.__tars_index__ == 5: + self.__writeDouble(tag, value) + elif coder.__tars_index__ == 13: + self.__writeBytes(tag, value) + elif coder.__tars_index__ == 67: + self.__writeString(tag, value) + elif coder.__tars_index__ == 8: + self.__writeMap(coder, tag, value) + elif coder.__tars_index__ == 9: + self.__writeVector(coder, tag, value) + elif coder.__tars_index__ == 1011: + self.__writeStruct(coder, tag, value) + else: + raise TarsTarsUnsupportType( + "tars unsupport data type:" % coder.__tars_index__) + + def getBuffer(self): + return self.__buffer.getBuffer() + + def printHex(self): + util.printHex(self.__buffer.getBuffer()) + + +class TarsInputStream(object): + def __init__(self, buff): + self.__buffer = BinBuffer(buff) + + def __peekFrom(self): + helper, = struct.unpack_from( + '!B', self.__buffer.buffer, self.__buffer.position) + t = (helper & 0xF0) >> 4 + p = (helper & 0x0F) + l = 1 + if t >= 15: + l = 2 + t, = struct.unpack_from( + '!B', self.__buffer.buffer, self.__buffer.position + 1) + return (t, p, l) + + def __readFrom(self): + t, p, l = self.__peekFrom() + self.__buffer.position += l + return (t, p, l) + + def __skipToStructEnd(self): + t, p, l = self.__readFrom() + while p != DataHead.EN_STRUCTEND: + self.__skipField(p) + t, p, l = self.__readFrom() + + def __skipField(self, p): + if p == DataHead.EN_INT8: + self.__buffer.position += 1 + elif p == DataHead.EN_INT16: + self.__buffer.position += 2 + elif p == DataHead.EN_INT32: + self.__buffer.position += 4 + elif p == DataHead.EN_INT64: + self.__buffer.position += 8 + elif p == DataHead.EN_FLOAT: + self.__buffer.position += 4 + elif p == DataHead.EN_DOUBLE: + self.__buffer.position += 8 + elif p == DataHead.EN_STRING1: + length, = struct.unpack_from( + '!B', self.__buffer.buffer, self.__buffer.position) + self.__buffer.position += length + 1 + elif p == DataHead.EN_STRING4: + length, = struct.unpack_from( + '!i', self.__buffer.buffer, self.__buffer.position) + self.__buffer.position += length + 4 + elif p == DataHead.EN_MAP: + size = self.__readInt32(0, True) + for i in range(0, size * 2): + ti, pi, li = self.__readFrom() + self.__skipField(pi) + elif p == DataHead.EN_LIST: + size = self.__readInt32(0, True) + for i in range(0, size): + ti, pi, li = self.__readFrom() + self.__skipField(pi) + elif p == DataHead.EN_BYTES: + ti, pi, li = self.__readFrom() + if pi != DataHead.EN_INT8: + raise TarsTarsDecodeInvalidValue( + "skipField with invalid type, type value: %d, %d." % (p, pi)) + size = self.__readInt32(0, True) + self.__buffer.position += size + elif p == DataHead.EN_STRUCTBEGIN: + self.__skipToStructEnd() + elif p == DataHead.EN_STRUCTEND: + pass + #self.__buffer.position += length + 1; + elif p == DataHead.EN_ZERO: + pass + #self.__buffer.position += length + 1; + else: + raise TarsTarsDecodeMismatch( + "skipField with invalid type, type value:%d" % p) + + def __skipToTag(self, tag): + length = self.__buffer.length() + while self.__buffer.position < length: + t, p, l = self.__peekFrom() + if tag <= t or p == DataHead.EN_STRUCTEND: + return False if (p == DataHead.EN_STRUCTEND) else (t == tag) + + self.__buffer.position += l + self.__skipField(p) + return False + + def __readBoolean(self, tag, require, default=None): + v = self.__readInt8(tag, require) + if v is None: + return default + else: + return (v != 0) + + def __readInt8(self, tag, require, default=None): + if self.__skipToTag(tag): + t, p, l = self.__readFrom() + if p == DataHead.EN_ZERO: + return 0 + elif p == DataHead.EN_INT8: + value, = struct.unpack_from( + '!b', self.__buffer.buffer, self.__buffer.position) + self.__buffer.position += 1 + return value + else: + raise TarsTarsDecodeMismatch( + "read 'Char' type mismatch, tag: %d , get type: %d." % (tag, p)) + elif require: + raise TarsTarsDecodeRequireNotExist( + "require field not exist, tag: %d" % tag) + return default + + def __readInt16(self, tag, require, default=None): + if self.__skipToTag(tag): + t, p, l = self.__readFrom() + if p == DataHead.EN_ZERO: + return 0 + elif p == DataHead.EN_INT8: + value, = struct.unpack_from( + '!b', self.__buffer.buffer, self.__buffer.position) + self.__buffer.position += 1 + return value + elif p == DataHead.EN_INT16: + value, = struct.unpack_from( + '!h', self.__buffer.buffer, self.__buffer.position) + self.__buffer.position += 2 + return value + else: + raise TarsTarsDecodeMismatch( + "read 'Short' type mismatch, tag: %d , get type: %d." % (tag, p)) + elif require: + raise TarsTarsDecodeRequireNotExist( + "require field not exist, tag: %d" % tag) + return default + + def __readInt32(self, tag, require, default=None): + if self.__skipToTag(tag): + t, p, l = self.__readFrom() + if p == DataHead.EN_ZERO: + return 0 + elif p == DataHead.EN_INT8: + value, = struct.unpack_from( + '!b', self.__buffer.buffer, self.__buffer.position) + self.__buffer.position += 1 + return value + elif p == DataHead.EN_INT16: + value, = struct.unpack_from( + '!h', self.__buffer.buffer, self.__buffer.position) + self.__buffer.position += 2 + return value + elif p == DataHead.EN_INT32: + value, = struct.unpack_from( + '!i', self.__buffer.buffer, self.__buffer.position) + self.__buffer.position += 4 + return value + else: + raise TarsTarsDecodeMismatch( + "read 'Int32' type mismatch, tag: %d, get type: %d." % (tag, p)) + elif require: + raise TarsTarsDecodeRequireNotExist( + "require field not exist, tag: %d" % tag) + return default + + def __readInt64(self, tag, require, default=None): + if self.__skipToTag(tag): + t, p, l = self.__readFrom() + if p == DataHead.EN_ZERO: + return 0 + elif p == DataHead.EN_INT8: + value, = struct.unpack_from( + '!b', self.__buffer.buffer, self.__buffer.position) + self.__buffer.position += 1 + return value + elif p == DataHead.EN_INT16: + value, = struct.unpack_from( + '!h', self.__buffer.buffer, self.__buffer.position) + self.__buffer.position += 2 + return value + elif p == DataHead.EN_INT32: + value, = struct.unpack_from( + '!i', self.__buffer.buffer, self.__buffer.position) + self.__buffer.position += 4 + return value + elif p == DataHead.EN_INT64: + value, = struct.unpack_from( + '!q', self.__buffer.buffer, self.__buffer.position) + self.__buffer.position += 8 + return value + else: + raise TarsTarsDecodeMismatch( + "read 'Int64' type mismatch, tag: %d, get type: %d." % (tag, p)) + elif require: + raise TarsTarsDecodeRequireNotExist( + "require field not exist, tag: %d" % tag) + return default + + def __readString(self, tag, require, default=None): + if self.__skipToTag(tag): + t, p, l = self.__readFrom() + if p == DataHead.EN_STRING1: + length, = struct.unpack_from( + '!B', self.__buffer.buffer, self.__buffer.position) + self.__buffer.position += 1 + value, = struct.unpack_from( + str(length) + "s", self.__buffer.buffer, self.__buffer.position) + self.__buffer.position += length + return value + elif p == DataHead.EN_STRING4: + length, = struct.unpack_from( + '!i', self.__buffer.buffer, self.__buffer.position) + self.__buffer.position += 4 + value, = struct.unpack_from( + str(length) + "s", self.__buffer.buffer, self.__buffer.position) + self.__buffer.position += length + return value + else: + raise TarsTarsDecodeMismatch( + "read 'string' type mismatch, tag: %d, get type: %d." % (tag, p)) + elif require: + raise TarsTarsDecodeRequireNotExist( + "require field not exist, tag: %d" % tag) + return default + + def __readBytes(self, tag, require, default=None): + if self.__skipToTag(tag): + t, p, l = self.__readFrom() + if p == DataHead.EN_BYTES: + ti, pi, li = self.__readFrom() + if pi != DataHead.EN_INT8: + raise TarsTarsDecodeMismatch( + "type mismatch, tag: %d, type: %d, %d" % (tag, p, pi)) + size = self.__readInt32(0, True) + value, = struct.unpack_from( + str(size) + 's', self.__buffer.buffer, self.__buffer.position) + self.__buffer.position += size + return value + else: + raise TarsTarsDecodeMismatch( + "type mismatch, tag: %d, type: %d" % (tag, p)) + elif require: + raise TarsTarsDecodeRequireNotExist( + "require field not exist, tag: %d" % tag) + return default + + def __readFloat(self, tag, require, default=None): + if self.__skipToTag(tag): + t, p, l = self.__readFrom() + if p == DataHead.EN_ZERO: + return 0 + elif p == DataHead.EN_FLOAT: + value, = struct.unpack_from( + '!f', self.__buffer.buffer, self.__buffer.position) + self.__buffer.position += 4 + return value + else: + raise TarsTarsDecodeMismatch( + "read 'Float' type mismatch, tag: %d, get type: %d." % (tag, p)) + elif require: + raise TarsTarsDecodeRequireNotExist( + "require field not exist, tag: %d" % tag) + return default + + def __readDouble(self, tag, require, default=None): + if self.__skipToTag(tag): + t, p, l = self.__readFrom() + if p == DataHead.EN_ZERO: + return 0 + elif p == DataHead.EN_FLOAT: + value, = struct.unpack_from( + '!f', self.__buffer.buffer, self.__buffer.position) + self.__buffer.position += 4 + return value + elif p == DataHead.EN_DOUBLE: + value, = struct.unpack_from( + '!d', self.__buffer.buffer, self.__buffer.position) + self.__buffer.position += 8 + return value + else: + raise TarsTarsDecodeMismatch( + "read 'Double' type mismatch, tag: %d, get type: %d." % (tag, p)) + elif require: + raise TarsTarsDecodeRequireNotExist( + "require field not exist, tag: %d" % tag) + return default + + def __readStruct(self, coder, tag, require, default=None): + if self.__skipToTag(tag): + t, p, l = self.__readFrom() + if p != DataHead.EN_STRUCTBEGIN: + raise TarsTarsDecodeMismatch( + "read 'struct' type mismatch, tag: %d, get type: %d." % (tag, p)) + value = coder.readFrom(self) + self.__skipToStructEnd() + return value + elif require: + raise TarsTarsDecodeRequireNotExist( + "require field not exist, tag: %d" % tag) + return default + + def __readMap(self, coder, tag, require, default=None): + if self.__skipToTag(tag): + t, p, l = self.__readFrom() + if p == DataHead.EN_MAP: + size = self.__readInt32(0, True) + omap = coder() + for i in range(0, size): + k = self.read(coder.ktype, 0, True) + v = self.read(coder.vtype, 1, True) + omap[k] = v + return omap + else: + raise TarsTarsDecodeMismatch( + "read 'map' type mismatch, tag: %d, get type: %d." % (tag, p)) + elif require: + raise TarsTarsDecodeRequireNotExist( + "require field not exist, tag: %d" % tag) + return default + + def __readVector(self, coder, tag, require, default=None): + if self.__skipToTag(tag): + t, p, l = self.__readFrom() + if p == DataHead.EN_LIST: + size = self.__readInt32(0, True) + value = coder() + for i in range(0, size): + k = self.read(coder.vtype, 0, True) + value.append(k) + return value + else: + raise TarsTarsDecodeMismatch( + "read 'vector' type mismatch, tag: %d, get type: %d." % (tag, p)) + elif require: + raise TarsTarsDecodeRequireNotExist( + "require field not exist, tag: %d" % tag) + return default + + def read(self, coder, tag, require, default=None): + if coder.__tars_index__ == 999: + return self.__readBoolean(tag, require, default) + elif coder.__tars_index__ == 0: + return self.__readInt8(tag, require, default) + elif coder.__tars_index__ == 1: + return self.__readInt16(tag, require, default) + elif coder.__tars_index__ == 2: + return self.__readInt32(tag, require, default) + elif coder.__tars_index__ == 3: + return self.__readInt64(tag, require, default) + elif coder.__tars_index__ == 4: + return self.__readFloat(tag, require, default) + elif coder.__tars_index__ == 5: + return self.__readDouble(tag, require, default) + elif coder.__tars_index__ == 13: + return self.__readBytes(tag, require, default) + elif coder.__tars_index__ == 67: + return self.__readString(tag, require, default) + elif coder.__tars_index__ == 8: + return self.__readMap(coder, tag, require, default) + elif coder.__tars_index__ == 9: + return self.__readVector(coder, tag, require, default) + elif coder.__tars_index__ == 1011: + return self.__readStruct(coder, tag, require, default) + else: + raise TarsTarsUnsupportType( + "tars unsupport data type:" % coder.__tars_index__) + + def printHex(self): + util.printHex(self.__buffer.buffer) diff --git a/danmu/danmaku/tars/__trans.py b/danmu/danmaku/tars/__trans.py new file mode 100644 index 0000000..1df078f --- /dev/null +++ b/danmu/danmaku/tars/__trans.py @@ -0,0 +1,575 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# filename: __trans.py + +# Tencent is pleased to support the open source community by making Tars available. +# +# Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. +# +# Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + + +''' +@version: 0.01 +@brief: 网络相关模块 +''' + +import socket +import select +import errno +import threading + +from .__logger import tarsLogger +from .__TimeoutQueue import ReqMessage + + +class EndPointInfo: + ''' + @brief: 保存每个连接端口的信息 + ''' + SOCK_TCP = 'TCP' + SOCK_UDP = 'UDP' + + def __init__(self, + ip='', + port=0, + timeout=-1, + weight=0, + weightType=0, + connType=SOCK_TCP): + self.__ip = ip + self.__port = port + self.__timeout = timeout + self.__connType = connType + self.__weightType = weightType + self.__weight = weight + + def getIp(self): + return self.__ip + + def getPort(self): + return self.__port + + def getConnType(self): + ''' + @return: 传输层连接类型 + @rtype: EndPointInfo.SOCK_TCP 或 EndPointInfo.SOCK_UDP + ''' + return self.__connType + + def getWeightType(self): + return self.__weightType + + def getWeight(self): + return self.__weight + + def __str__(self): + return '%s %s:%s %d:%d' % (self.__connType, self.__ip, self.__port, self.__weightType, self.__weight) + + +class Transceiver: + ''' + @brief: 网络传输基类,提供网络send/recv接口 + ''' + CONNECTED = 0 + CONNECTING = 1 + UNCONNECTED = 2 + + def __init__(self, endPointInfo): + tarsLogger.debug('Transceiver:__init__, %s', endPointInfo) + self.__epi = endPointInfo + self.__sock = None + self.__connStatus = Transceiver.UNCONNECTED + self.__connFailed = False + # 这两个变量要给子类用,不能用name mangling隐藏 + self._sendBuff = '' + self._recvBuf = '' + + def __del__(self): + tarsLogger.debug('Transceiver:__del__') + self.close() + + def getSock(self): + ''' + @return: socket对象 + @rtype: socket.socket + ''' + return self.__sock + + def getFd(self): + ''' + @brief: 获取socket的文件描述符 + @return: 如果self.__sock没有建立返回-1 + @rtype: int + ''' + if self.__sock: + return self.__sock.fileno() + else: + return -1 + + def getEndPointInfo(self): + ''' + @return: 端口信息 + @rtype: EndPointInfo + ''' + return self.__epi + + def isValid(self): + ''' + @return: 是否创建了socket + @rtype: bool + ''' + return self.__sock is not None + + def hasConnected(self): + ''' + @return: 是否连接上了 + @rtype: bool + ''' + return self.isValid() and self.__connStatus == Transceiver.CONNECTED + + def isConnFailed(self): + ''' + @return: 是否连接失败 + @rtype: bool + ''' + return self.__connFailed + + def isConnecting(self): + ''' + @return: 是否正在连接 + @rtype: bool + ''' + return self.isValid() and self.__connStatus == Transceiver.CONNECTING + + def setConnFailed(self): + ''' + @brief: 设置为连接失败 + @return: None + @rtype: None + ''' + self.__connFailed = True + self.__connStatus = Transceiver.UNCONNECTED + + def setConnected(self): + ''' + @brief: 设置为连接完 + @return: None + @rtype: None + ''' + self.__connFailed = False + self.__connStatus = Transceiver.CONNECTED + + def close(self): + ''' + @brief: 关闭连接 + @return: None + @rtype: None + @note: 多次调用不会有问题 + ''' + tarsLogger.debug('Transceiver:close') + if not self.isValid(): + return + self.__sock.close() + self.__sock = None + self.__connStatus = Transceiver.UNCONNECTED + self.__connFailed = False + self._sendBuff = '' + self._recvBuf = '' + tarsLogger.info('trans close : %s' % self.__epi) + + def writeToSendBuf(self, msg): + ''' + @brief: 把数据添加到send buffer里 + @param msg: 发送的数据 + @type msg: str + @return: None + @rtype: None + @note: 没有加锁,多线程调用会有race conditions + ''' + self._sendBuff += msg + + def recv(self, bufsize, flag=0): + raise NotImplementedError() + + def send(self, buf, flag=0): + raise NotImplementedError() + + def doResponse(self): + raise NotImplementedError() + + def doRequest(self): + ''' + @brief: 将请求数据发送出去 + @return: 发送的字节数 + @rtype: int + ''' + tarsLogger.debug('Transceiver:doRequest') + if not self.isValid(): + return -1 + + nbytes = 0 + buf = buffer(self._sendBuff) + while True: + if not buf: + break + ret = self.send(buf[nbytes:]) + if ret > 0: + nbytes += ret + else: + break + + # 发送前面的字节后将后面的字节拷贝上来 + self._sendBuff = buf[nbytes:] + return nbytes + + def reInit(self): + ''' + @brief: 初始化socket,并连接服务器 + @return: 成功返回0,失败返回-1 + @rtype: int + ''' + tarsLogger.debug('Transceiver:reInit') + assert(self.isValid() is False) + if self.__epi.getConnType() != EndPointInfo.SOCK_TCP: + return -1 + try: + self.__sock = socket.socket() + self.__sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + self.__sock.setblocking(0) + self.__sock.connect((self.__epi.getIp(), self.__epi.getPort())) + self.__connStatus = Transceiver.CONNECTED + except socket.error as msg: + if msg.errno == errno.EINPROGRESS: + self.__connStatus = Transceiver.CONNECTING + else: + tarsLogger.info('reInit, %s, faild!, %s', + self.__epi, msg) + self.__sock = None + return -1 + tarsLogger.info('reInit, connect: %s, fd: %d', + self.__epi, self.getFd()) + return 0 + + +class TcpTransceiver(Transceiver): + ''' + @brief: TCP传输实现 + ''' + + def send(self, buf, flag=0): + ''' + @brief: 实现tcp的发送 + @param buf: 发送的数据 + @type buf: str + @param flag: 发送标志 + @param flag: int + @return: 发送字节数 + @rtype: int + ''' + tarsLogger.debug('TcpTransceiver:send') + if not self.isValid(): + return -1 + + nbytes = 0 + try: + nbytes = self.getSock().send(buf, flag) + tarsLogger.info('tcp send, fd: %d, %s, len: %d', + self.getFd(), self.getEndPointInfo(), nbytes) + except socket.error as msg: + if msg.errno != errno.EAGAIN: + tarsLogger.error('tcp send, fd: %d, %s, fail!, %s, close', + self.getFd(), self.getEndPointInfo(), msg) + self.close() + return 0 + return nbytes + + def recv(self, bufsize, flag=0): + ''' + @brief: 实现tcp的recv + @param bufsize: 接收大小 + @type bufsize: int + @param flag: 接收标志 + @param flag: int + @return: 接收的内容,接收出错返回None + @rtype: str + ''' + tarsLogger.debug('TcpTransceiver:recv') + assert(self.isValid()) + + buf = '' + try: + buf = self.getSock().recv(bufsize, flag) + if len(buf) == 0: + tarsLogger.info('tcp recv, fd: %d, %s, recv 0 bytes, close', + self.getFd(), self.getEndPointInfo()) + self.close() + return None + except socket.error as msg: + if msg.errno != errno.EAGAIN: + tarsLogger.info('tcp recv, fd: %d, %s, faild!, %s, close', + self.getFd(), self.getEndPointInfo(), msg) + self.close() + return None + + tarsLogger.info('tcp recv, fd: %d, %s, nbytes: %d', + self.getFd(), self.getEndPointInfo(), len(buf)) + return buf + + def doResponse(self): + ''' + @brief: 处理接收的数据 + @return: 返回响应报文的列表,如果出错返回None + @rtype: list: ResponsePacket + ''' + tarsLogger.debug('TcpTransceiver:doResponse') + if not self.isValid(): + return None + + bufs = [self._recvBuf] + while True: + buf = self.recv(8292) + if not buf: + break + bufs.append(buf) + self._recvBuf = ''.join(bufs) + tarsLogger.info('tcp doResponse, fd: %d, recvbuf: %d', + self.getFd(), len(self._recvBuf)) + + if not self._recvBuf: + return None + + rsplist = None + try: + rsplist, bufsize = ReqMessage.unpackRspList(self._recvBuf) + self._recvBuf = self._recvBuf[bufsize:] + except Exception as msg: + tarsLogger.error( + 'tcp doResponse, fd: %d, %s, tcp recv unpack error: %s', + self.getFd(), self.getEndPointInfo(), msg) + self.close() + + return rsplist + + +class FDReactor(threading.Thread): + ''' + @brief: 监听FD事件并解发注册的handle + ''' + + def __init__(self): + tarsLogger.debug('FDReactor:__init__') + # threading.Thread.__init__(self) + super(FDReactor, self).__init__() + self.__terminate = False + self.__ep = None + self.__shutdown = None + # {fd : adapterproxy} + self.__adapterTab = {} + + def __del__(self): + tarsLogger.debug('FDReactor:__del__') + self.__ep.close() + self.__shutdown.close() + self.__ep = None + self.__shutdown = None + + def initialize(self): + ''' + @brief: 初始化,使用FDReactor前必须调用 + @return: None + @rtype: None + ''' + tarsLogger.debug('FDReactor:initialize') + self.__ep = select.epoll() + self.__shutdown = socket.socket() + self.__ep.register(self.__shutdown.fileno(), + select.EPOLLET | select.EPOLLIN) + tarsLogger.debug('FDReactor init, shutdown fd : %d', + self.__shutdown.fileno()) + + def terminate(self): + ''' + @brief: 结束FDReactor的线程 + @return: None + @rtype: None + ''' + tarsLogger.debug('FDReactor:terminate') + self.__terminate = True + self.__ep.modify(self.__shutdown.fileno(), select.EPOLLOUT) + self.__adapterTab = {} + + def handle(self, adapter, events): + ''' + @brief: 处理epoll事件 + @param adapter: 事件对应的adapter + @type adapter: AdapterProxy + @param events: epoll事件 + @param events: int + @return: None + @rtype: None + ''' + tarsLogger.debug('FDReactor:handle events : %d', events) + assert(adapter) + + try: + if events == 0: + return + + if events & (select.EPOLLERR | select.EPOLLHUP): + tarsLogger.debug('FDReactor::handle EPOLLERR or EPOLLHUP: %s', + adapter.trans().getEndPointInfo()) + adapter.trans().close() + return + + if adapter.shouldCloseTrans(): + tarsLogger.debug('FDReactor::handle should close trans: %s', + adapter.trans().getEndPointInfo()) + adapter.setCloseTrans(False) + adapter.trans().close() + return + + if adapter.trans().isConnecting(): + if not adapter.finishConnect(): + return + + if events & select.EPOLLIN: + self.handleInput(adapter) + + if events & select.EPOLLOUT: + self.handleOutput(adapter) + + except Exception as msg: + tarsLogger.error('FDReactor handle exception: %s', msg) + + def handleExcept(self): + pass + + def handleInput(self, adapter): + ''' + @brief: 处理接收事件 + @param adapter: 事件对应的adapter + @type adapter: AdapterProxy + @return: None + @rtype: None + ''' + + tarsLogger.debug('FDReactor:handleInput') + if not adapter.trans().isValid(): + return + + rsplist = adapter.trans().doResponse() + if not rsplist: + return + for rsp in rsplist: + adapter.finished(rsp) + + def handleOutput(self, adapter): + ''' + @brief: 处理发送事件 + @param adapter: 事件对应的adapter + @type adapter: AdapterProxy + @return: None + @rtype: None + ''' + tarsLogger.debug('FDReactor:handleOutput') + if not adapter.trans().isValid(): + return + while adapter.trans().doRequest() >= 0 and adapter.sendRequest(): + pass + + def notify(self, adapter): + ''' + @brief: 更新adapter对应的fd的epoll状态 + @return: None + @rtype: None + @note: FDReactor使用的epoll是EPOLLET模式,同一事件只通知一次 + 希望某一事件再次通知需调用此函数 + ''' + tarsLogger.debug('FDReactor:notify') + fd = adapter.trans().getFd() + if fd != -1: + self.__ep.modify(fd, + select.EPOLLET | select.EPOLLOUT | select.EPOLLIN) + + def registerAdapter(self, adapter, events): + ''' + @brief: 注册adapter + @param adapter: 收发事件处理类 + @type adapter: AdapterProxy + @param events: 注册事件 + @type events: int + @return: None + @rtype: None + ''' + tarsLogger.debug('FDReactor:registerAdapter events : %d', events) + events |= select.EPOLLET + try: + self.__ep.unregister(adapter.trans().getFd()) + except: + pass + self.__ep.register(adapter.trans().getFd(), events) + self.__adapterTab[adapter.trans().getFd()] = adapter + + def unregisterAdapter(self, adapter): + ''' + @brief: 注销adapter + @param adapter: 收发事件处理类 + @type adapter: AdapterProxy + @return: None + @rtype: None + ''' + tarsLogger.debug('FDReactor:registerAdapter') + self.__ep.unregister(adapter.trans().getFd()) + self.__adapterTab.pop(adapter.trans().getFd(), None) + + def run(self): + ''' + @brief: 线程启动函数,循环监听网络事件 + ''' + tarsLogger.debug('FDReactor:run') + + while not self.__terminate: + try: + eplist = self.__ep.poll(1) + if eplist: + tarsLogger.debug('FDReactor run get eplist : %s, terminate : %s', str( + eplist), self.__terminate) + if self.__terminate: + tarsLogger.debug('FDReactor terminate') + break + for fd, events in eplist: + adapter = self.__adapterTab.get(fd, None) + if not adapter: + continue + self.handle(adapter, events) + except Exception as msg: + tarsLogger.error('FDReactor run exception: %s', msg) + + tarsLogger.debug('FDReactor:run finished') + + +if __name__ == '__main__': + print('hello world') + epi = EndPointInfo('127.0.0.1', 1313) + print(epi) + trans = TcpTransceiver(epi) + print(trans.getSock()) + print(trans.getFd()) + print(trans.reInit()) + print(trans.isConnecting()) + print(trans.hasConnected()) + buf = 'hello world' + print(trans.send(buf)) + buf = trans.recv(1024) + print(buf) + trans.close() diff --git a/danmu/danmaku/tars/__tup.py b/danmu/danmaku/tars/__tup.py new file mode 100644 index 0000000..6f71879 --- /dev/null +++ b/danmu/danmaku/tars/__tup.py @@ -0,0 +1,118 @@ +# Tencent is pleased to support the open source community by making Tars available. +# +# Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. +# +# Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +import struct +import string +from .__util import util +from .__tars import TarsOutputStream +from .__tars import TarsInputStream +from .__packet import RequestPacket + + +class TarsUniPacket(object): + def __init__(self): + self.__mapa = util.mapclass(util.string, util.bytes) + self.__mapv = util.mapclass(util.string, self.__mapa) + self.__buffer = self.__mapv() + self.__code = RequestPacket() + + # @property + # def version(self): + # return self.__code.iVersion + + # @version.setter + # def version(self, value): + # self.__code.iVersion = value + + @property + def servant(self): + return self.__code.sServantName + + @servant.setter + def servant(self, value): + self.__code.sServantName = value + + @property + def func(self): + return self.__code.sFuncName + + @func.setter + def func(self, value): + self.__code.sFuncName = value + + @property + def requestid(self): + return self.__code.iRequestId + + @requestid.setter + def requestid(self, value): + self.__code.iRequestId = value + + @property + def result_code(self): + if ("STATUS_RESULT_CODE" in self.__code.status) == False: + return 0 + + return string.atoi(self.__code.status["STATUS_RESULT_CODE"]) + + @property + def result_desc(self): + if ("STATUS_RESULT_DESC" in self.__code.status) == False: + return '' + + return self.__code.status["STATUS_RESULT_DESC"] + + def put(self, vtype, name, value): + oos = TarsOutputStream() + oos.write(vtype, 0, value) + self.__buffer[name] = {vtype.__tars_class__: oos.getBuffer()} + + def get(self, vtype, name): + if (name in self.__buffer) == False: + raise Exception("UniAttribute not found key:%s,type:%s" % + (name, vtype.__tars_class__)) + + t = self.__buffer[name] + if (vtype.__tars_class__ in t) == False: + raise Exception("UniAttribute not found type:" + + vtype.__tars_class__) + + o = TarsInputStream(t[vtype.__tars_class__]) + return o.read(vtype, 0, True) + + def encode(self): + oos = TarsOutputStream() + oos.write(self.__mapv, 0, self.__buffer) + + self.__code.iVersion = 2 + self.__code.sBuffer = oos.getBuffer() + + sos = TarsOutputStream() + RequestPacket.writeTo(sos, self.__code) + + return struct.pack('!i', 4 + len(sos.getBuffer())) + sos.getBuffer() + + def decode(self, buf): + ois = TarsInputStream(buf[4:]) + self.__code = RequestPacket.readFrom(ois) + + sis = TarsInputStream(self.__code.sBuffer) + self.__buffer = sis.read(self.__mapv, 0, True) + + def clear(self): + self.__code.__init__() + + def haskey(self, name): + return name in self.__buffer diff --git a/danmu/danmaku/tars/__util.py b/danmu/danmaku/tars/__util.py new file mode 100644 index 0000000..baa12fb --- /dev/null +++ b/danmu/danmaku/tars/__util.py @@ -0,0 +1,252 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Tencent is pleased to support the open source community by making Tars available. +# +# Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. +# +# Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + + +import sys +from threading import Lock +import hashlib +from xml.etree import cElementTree as ET +from .exception import TarsException + + +class util: + @staticmethod + def printHex(buff): + count = 0 + for c in buff: + sys.stdout.write("0X%02X " % ord(c)) + count += 1 + if count % 16 == 0: + sys.stdout.write("\n") + sys.stdout.write("\n") + sys.stdout.flush() + + @staticmethod + def mapclass(ktype, vtype): + class mapklass(dict): + def size(self): return len(self) + setattr(mapklass, '__tars_index__', 8) + setattr(mapklass, '__tars_class__', "map<" + + ktype.__tars_class__ + "," + vtype.__tars_class__ + ">") + setattr(mapklass, 'ktype', ktype) + setattr(mapklass, 'vtype', vtype) + return mapklass + + @staticmethod + def vectorclass(vtype): + class klass(list): + def size(self): return len(self) + setattr(klass, '__tars_index__', 9) + setattr(klass, '__tars_class__', "list<" + vtype.__tars_class__ + ">") + setattr(klass, 'vtype', vtype) + return klass + + class boolean: + __tars_index__ = 999 + __tars_class__ = "bool" + + class int8: + __tars_index__ = 0 + __tars_class__ = "char" + + class uint8: + __tars_index__ = 1 + __tars_class__ = "short" + + class int16: + __tars_index__ = 1 + __tars_class__ = "short" + + class uint16: + __tars_index__ = 2 + __tars_class__ = "int32" + + class int32: + __tars_index__ = 2 + __tars_class__ = "int32" + + class uint32: + __tars_index__ = 3 + __tars_class__ = "int64" + + class int64: + __tars_index__ = 3 + __tars_class__ = "int64" + + class float: + __tars_index__ = 4 + __tars_class__ = "float" + + class double: + __tars_index__ = 5 + __tars_class__ = "double" + + class bytes: + __tars_index__ = 13 + __tars_class__ = "list" + + class string: + __tars_index__ = 67 + __tars_class__ = "string" + + class struct: + __tars_index__ = 1011 + + +def xml2dict(node, dic={}): + ''' + @brief: 将xml解析树转成字典 + @param node: 树的根节点 + @type node: cElementTree.Element + @param dic: 存储信息的字典 + @type dic: dict + @return: 转换好的字典 + @rtype: dict + ''' + dic[node.tag] = ndic = {} + [xml2dict(child, ndic) for child in node.getchildren() if child != node] + ndic.update([list(map(str.strip, exp.split('=')[:2])) + for exp in node.text.splitlines() if '=' in exp]) + return dic + + +def configParse(filename): + ''' + @brief: 解析tars配置文件 + @param filename: 文件名 + @type filename: str + @return: 解析出来的配置信息 + @rtype: dict + ''' + tree = ET.parse(filename) + return xml2dict(tree.getroot()) + + +class NewLock(object): + def __init__(self): + self.__count = 0 + self.__lock = Lock() + self.__lockForCount = Lock() + pass + + def newAcquire(self): + self.__lockForCount.acquire() + self.__count += 1 + if self.__count == 1: + self.__lock.acquire() + self.__lockForCount.release() + pass + + def newRelease(self): + self.__lockForCount.acquire() + self.__count -= 1 + if self.__count == 0: + self.__lock.release() + self.__lockForCount.release() + + +class LockGuard(object): + def __init__(self, newLock): + self.__newLock = newLock + self.__newLock.newAcquire() + + def __del__(self): + self.__newLock.newRelease() + + +class ConsistentHashNew(object): + def __init__(self, nodes=None, nodeNumber=3): + """ + :param nodes: 服务器的节点的epstr列表 + :param n_number: 一个节点对应的虚拟节点数量 + :return: + """ + self.__nodes = nodes + self.__nodeNumber = nodeNumber # 每一个节点对应多少个虚拟节点,这里默认是3个 + self.__nodeDict = dict() # 用于记录虚拟节点的hash值与服务器epstr的对应关系 + self.__sortListForKey = [] # 用于存放所有的虚拟节点的hash值,这里需要保持排序,以找出对应的服务器 + if nodes: + for node in nodes: + self.addNode(node) + + @property + def nodes(self): + return self.__nodes + + @nodes.setter + def nodes(self, value): + self.__nodes = value + + def addNode(self, node): + """ + 添加node,首先要根据虚拟节点的数目,创建所有的虚拟节点,并将其与对应的node对应起来 + 当然还需要将虚拟节点的hash值放到排序的里面 + 这里在添加了节点之后,需要保持虚拟节点hash值的顺序 + :param node: + :return: + """ + for i in range(self.__nodeNumber): + nodeStr = "%s%s" % (node, i) + key = self.__genKey(nodeStr) + self.__nodeDict[key] = node + self.__sortListForKey.append(key) + self.__sortListForKey.sort() + + def removeNode(self, node): + """ + 这里一个节点的退出,需要将这个节点的所有的虚拟节点都删除 + :param node: + :return: + """ + for i in range(self.__nodeNumber): + nodeStr = "%s%s" % (node, i) + key = self.__genKey(nodeStr) + del self.__nodeDict[key] + self.__sortListForKey.remove(key) + + def getNode(self, key): + """ + 返回这个字符串应该对应的node,这里先求出字符串的hash值,然后找到第一个小于等于的虚拟节点,然后返回node + 如果hash值大于所有的节点,那么用第一个虚拟节点 + :param : hashNum or keyStr + :return: + """ + keyStr = '' + if isinstance(key, int): + keyStr = "the keyStr is %d" % key + elif isinstance(key, type('a')): + keyStr = key + else: + raise TarsException("the hash code has wrong type") + if self.__sortListForKey: + key = self.__genKey(keyStr) + for keyItem in self.__sortListForKey: + if key <= keyItem: + return self.__nodeDict[keyItem] + return self.__nodeDict[self.__sortListForKey[0]] + else: + return None + + def __genKey(self, keyStr): + """ + 通过key,返回当前key的hash值,这里采用md5 + :param key: + :return: + """ + md5Str = hashlib.md5(keyStr).hexdigest() + return int(md5Str, 16) diff --git a/danmu/danmaku/tars/core.py b/danmu/danmaku/tars/core.py new file mode 100644 index 0000000..3af030d --- /dev/null +++ b/danmu/danmaku/tars/core.py @@ -0,0 +1,91 @@ +#! /usr/bin/env python +# -*- coding: utf-8 -*- + + +# Tencent is pleased to support the open source community by making Tars available. +# +# Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. +# +# Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +__version__ = "0.0.1" + +from __util import util +from __tars import TarsInputStream +from __tars import TarsOutputStream +from __tup import TarsUniPacket + + +class tarscore: + class TarsInputStream(TarsInputStream): + pass + + class TarsOutputStream(TarsOutputStream): + pass + + class TarsUniPacket(TarsUniPacket): + pass + + class boolean(util.boolean): + pass + + class int8(util.int8): + pass + + class uint8(util.uint8): + pass + + class int16(util.int16): + pass + + class uint16(util.uint16): + pass + + class int32(util.int32): + pass + + class uint32(util.uint32): + pass + + class int64(util.int64): + pass + + class float(util.float): + pass + + class double(util.double): + pass + + class bytes(util.bytes): + pass + + class string(util.string): + pass + + class struct(util.struct): + pass + + @staticmethod + def mapclass(ktype, vtype): return util.mapclass(ktype, vtype) + + @staticmethod + def vctclass(vtype): return util.vectorclass(vtype) + + @staticmethod + def printHex(buff): util.printHex(buff) + + +# 被用户引用 +from __util import configParse +from __rpc import Communicator +from exception import * +from __logger import tarsLogger diff --git a/danmu/danmaku/tars/exception.py b/danmu/danmaku/tars/exception.py new file mode 100644 index 0000000..ee61cde --- /dev/null +++ b/danmu/danmaku/tars/exception.py @@ -0,0 +1,36 @@ +# Tencent is pleased to support the open source community by making Tars available. +# +# Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. +# +# Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +class TarsException(Exception): pass + +class TarsTarsDecodeRequireNotExist(TarsException): pass +class TarsTarsDecodeMismatch(TarsException): pass +class TarsTarsDecodeInvalidValue(TarsException): pass +class TarsTarsUnsupportType(TarsException): pass + +class TarsNetConnectException(TarsException): pass +class TarsNetConnectLostException(TarsException): pass +class TarsNetSocketException(TarsException): pass +class TarsProxyDecodeException(TarsException): pass +class TarsProxyEncodeException(TarsException): pass +class TarsServerEncodeException(TarsException): pass +class TarsServerDecodeException(TarsException): pass +class TarsServerNoFuncException(TarsException): pass +class TarsServerNoServantException(TarsException): pass +class TarsServerQueueTimeoutException(TarsException): pass +class TarsServerUnknownException(TarsException): pass +class TarsSyncCallTimeoutException(TarsException): pass +class TarsRegistryException(TarsException): pass +class TarsServerResetGridException(TarsException): pass diff --git a/danmu/danmaku/tars/tars/EndpointF.tars b/danmu/danmaku/tars/tars/EndpointF.tars new file mode 100644 index 0000000..c2d8d5d --- /dev/null +++ b/danmu/danmaku/tars/tars/EndpointF.tars @@ -0,0 +1,25 @@ + +module register +{ + /** + * ˿Ϣ + */ + struct EndpointF + { + 0 require string host; + 1 require int port; + 2 require int timeout; + 3 require int istcp; + 4 require int grid; + 5 optional int groupworkid; + 6 optional int grouprealid; + 7 optional string setId; + 8 optional int qos; + 9 optional int bakFlag; + 11 optional int weight; + 12 optional int weightType; + }; + key[EndpointF, host, port, timeout, istcp, grid, qos, weight, weightType]; +}; + + diff --git a/danmu/danmaku/tars/tars/QueryF.tars b/danmu/danmaku/tars/tars/QueryF.tars new file mode 100644 index 0000000..06cb2e9 --- /dev/null +++ b/danmu/danmaku/tars/tars/QueryF.tars @@ -0,0 +1,70 @@ +#include "EndpointF.tars" + +module register +{ + /** + * ȡendpointqueryӿ + */ + + interface QueryF + { + /** idȡ + * + * @param id + * + * @return иöĻendpointб + */ + vector findObjectById(string id); + + /**idȡж,ͷǻ + * + * @param id + * @param activeEp endpointб + * @param inactiveEp Ǵendpointб + * @return: 0-ɹ others-ʧ + */ + int findObjectById4Any(string id, out vector activeEp, out vector inactiveEp); + + /** idȡendpointб,ͬfindObjectByIdInSameGroup + * + * @param id + * @param activeEp endpointб + * @param inactiveEp Ǵendpointб + * @return: 0-ɹ others-ʧ + */ + int findObjectById4All(string id, out vector activeEp, out vector inactiveEp); + + /** idȡͬendpointб + * + * @param id + * @param activeEp endpointб + * @param inactiveEp Ǵendpointб + * @return: 0-ɹ others-ʧ + */ + int findObjectByIdInSameGroup(string id, out vector activeEp, out vector inactiveEp); + + + /** idȡָصendpointб + * + * @param id + * @param activeEp endpointб + * @param inactiveEp Ǵendpointб + * @return: 0-ɹ others-ʧ + */ + int findObjectByIdInSameStation(string id, string sStation, out vector activeEp, out vector inactiveEp); + + /** idȡͬendpointб + * + * @param id + * @param setId setȫ,ʽΪsetname.setarea.setgroup + * @param activeEp endpointб + * @param inactiveEp Ǵendpointб + * @return: 0-ɹ others-ʧ + */ + int findObjectByIdInSameSet(string id, string setId, out vector activeEp, out vector inactiveEp); + + }; + +}; + + diff --git a/danmu/danmaku/tars/tars/__init__.py b/danmu/danmaku/tars/tars/__init__.py new file mode 100644 index 0000000..e69de29