1
1
from __future__ import annotations
2
+
3
+ import datetime
2
4
import typing
3
5
import asyncio
4
6
from asyncio import transports
7
+ from collections import defaultdict
5
8
from typing import Optional , Tuple
6
9
7
10
import ConnBase
8
- from ConnBase import ROLE_TYPE_ACTIVE
9
- from RudpConn import RudpConn
10
11
from common import gv
11
- import TcpConn
12
12
from core .mobilelog .LogManager import LogManager
13
+ from core .util .TimerHub import TimerHub
13
14
from core .util .UtilApi import Singleton
14
15
16
+ from core .common .sanic_jwt_extended import JWT , refresh_jwt_required , jwt_required , jwt_optional
17
+ from core .common .sanic_jwt_extended .tokens import Token
18
+
15
19
if typing .TYPE_CHECKING :
16
- from RpcHandler import RpcHandler
20
+ from RpcHandler import RpcHandler , RPC_TYPE_REQUEST
21
+ import TcpConn
17
22
18
23
19
24
CONN_TYPE_TCP = 0
20
25
CONN_TYPE_RUDP = 1
21
26
27
+ RECONNECT_MAX_TIMES = 6
28
+ RECONNECT_INTERVAL = 0.6 # sec
29
+
30
+ ROLE_TYPE_ACTIVE = 0
31
+ ROLE_TYPE_PASSIVE = 1
32
+
33
+
34
+ class TcpServerProtocol (asyncio .Protocol ):
35
+ # def __init__(self, role_type, create_tcp_conn_cb):
36
+ def __init__ (self ):
37
+ # def __init__(self, rpc_handler=None):
38
+ # self._role_type = role_type
39
+ # self._create_tcp_conn_cb = create_tcp_conn_cb
40
+ self ._conn = None # type: Optional[TcpConn.TcpConn]
41
+ # self._rpc_handler = rpc_handler # type: Optional[RpcHandler]
42
+
43
+ def connection_made (self , transport : transports .BaseTransport ) -> None :
44
+ # assert callable(self._create_tcp_conn_cb)
45
+ # self._conn = self._create_tcp_conn_cb(self._role_type, transport)
46
+ self ._conn = ConnMgr .instance ().add_conn (
47
+ ROLE_TYPE_PASSIVE , CONN_TYPE_TCP , transport ,
48
+ # self._rpc_handler
49
+ )
50
+
51
+ addr = transport .get_extra_info ('peername' ) # type: typing.Tuple[str, int]
52
+ LogManager .get_logger ().info (f"{ addr !r} is connected !!!!" )
53
+
54
+ def data_received (self , data : bytes ) -> None :
55
+ self ._conn .handle_read (data )
56
+
57
+ def connection_lost (self , exc : Optional [Exception ]) -> None :
58
+ self ._conn .handle_close (str (exc ))
59
+
60
+
61
+ # {kSyn = 66, kAck, kPsh, kRst};
62
+ RUDP_HANDSHAKE_SYN = b'new_byte_hello_its_me'
63
+ RUDP_HANDSHAKE_SYN_ACK_PREFIX = b'new_byte_welcome:'
64
+ RUDP_HANDSHAKE_ACK_PREFIX = b'new_byte_ack:'
65
+
66
+ RUDP_CONV = 0
67
+
68
+
69
+ class RudpServerProtocol (asyncio .DatagramProtocol ):
70
+ # def __init__(self, create_kcp_conn_cb):
71
+ def __init__ (self ):
72
+ # self._create_kcp_conn_cb = create_kcp_conn_cb
73
+ self .transport = None
74
+
75
+ def connection_made (self , transport ):
76
+ self .transport = transport
77
+
78
+ def datagram_received (self , data : bytes , addr ):
79
+ global RUDP_CONV
80
+ global RUDP_HANDSHAKE_SYN
81
+ global RUDP_HANDSHAKE_SYN_ACK_PREFIX
82
+ global RUDP_HANDSHAKE_ACK_PREFIX
83
+ # assert callable(self._create_kcp_conn_cb)
84
+ # self._create_kcp_conn_cb(addr)
85
+ if data == RUDP_HANDSHAKE_SYN :
86
+ RUDP_CONV += 1
87
+ access_token_jwt : bytes = JWT .create_access_token (
88
+ identity = str (RUDP_CONV ), expires_delta = datetime .timedelta (seconds = 6 )).encode ()
89
+ self .transport .sendto (RUDP_HANDSHAKE_SYN_ACK_PREFIX + access_token_jwt , addr )
90
+ elif data .startswith (RUDP_HANDSHAKE_ACK_PREFIX ):
91
+ parts = data .split (RUDP_HANDSHAKE_ACK_PREFIX , 2 )
92
+ if len (parts ) != 2 :
93
+ raise Exception (f"Expected value '{ RUDP_HANDSHAKE_ACK_PREFIX } <JWT>'" )
94
+ raw_jwt = parts [1 ].decode ()
95
+ token_obj = Token (raw_jwt )
96
+ if token_obj .type != "access" :
97
+ raise Exception ("Only access tokens are allowed" )
98
+ conv = token_obj .identity
99
+
100
+ ConnMgr .instance ().add_conn (
101
+ ROLE_TYPE_PASSIVE , CONN_TYPE_RUDP , self .transport ,
102
+ rudp_conv = conv , rudp_peer_addr = addr
103
+ # self._rpc_handler
104
+ )
105
+ # addr = transport.get_extra_info('peername') # type: typing.Tuple[str, int]
106
+ LogManager .get_logger ().info (f"{ addr !r} is connected !!!!" )
107
+ else :
108
+ _cur_conn = ConnMgr .instance ().get_conn (addr , CONN_TYPE_RUDP )
109
+ if _cur_conn :
110
+ _cur_conn .handle_read (data )
111
+
22
112
23
113
@Singleton
24
114
class ConnMgr :
25
115
26
116
def __init__ (self ):
27
- self ._addr_2_conn_map = {} # type: typing.Dict[typing.Tuple[str, int], TcpConn.TcpConn]
117
+ self ._timer_hub = TimerHub ()
28
118
self ._logger = LogManager .get_logger ()
29
119
self ._is_proxy = False
120
+ self ._conn_type_2_addr_2_conn = {CONN_TYPE_TCP : {}, CONN_TYPE_RUDP : {}}
121
+ self ._addr_2_try_connect_times = defaultdict (int )
30
122
31
123
def set_is_proxy (self , is_proxy ):
32
124
self ._is_proxy = is_proxy
33
125
34
- def get_conn (self , addr , conn_type ) -> ConnBase :
35
- return self ._addr_2_conn_map .get (addr , None )
126
+ def get_conn (self , addr , conn_type = None ) -> ConnBase :
127
+ if conn_type is not None :
128
+ return self ._conn_type_2_addr_2_conn [conn_type ].get (addr , None )
129
+ _conn = self ._conn_type_2_addr_2_conn [CONN_TYPE_RUDP ].get (addr , None )
130
+ if _conn is None :
131
+ _conn = self ._conn_type_2_addr_2_conn [CONN_TYPE_TCP ].get (addr , None )
132
+ return _conn
36
133
37
- def create_conn (
134
+ def add_conn (
38
135
self , role_type , conn_type , transport : transports .BaseTransport ,
39
136
rudp_conv : int = 0 , rudp_peer_addr : Optional [Tuple [str , int ]] = None
40
137
# rpc_handler: Optional[RpcHandler] = None
41
- ) -> TcpConn .TcpConn :
42
- addr = transport .get_extra_info ('peername' ) # type: typing.Tuple[str, int]
43
-
138
+ ) -> ConnBase :
44
139
if conn_type == CONN_TYPE_TCP :
140
+ import TcpConn
141
+ addr = transport .get_extra_info ('peername' ) # type: typing.Tuple[str, int]
45
142
_conn = TcpConn .TcpConn (
46
- role_type , addr , close_cb = self ._remove_conn , is_proxy = self ._is_proxy ,
143
+ role_type , addr ,
144
+ close_cb = lambda ct = conn_type , a = addr : self ._remove_conn (ct , a ),
145
+ is_proxy = self ._is_proxy ,
47
146
transport = transport )
48
147
else :
49
148
pass # todo: rudp
149
+ from RudpConn import RudpConn
50
150
assert rudp_conv > 0
151
+ addr = rudp_peer_addr
51
152
_conn = RudpConn (
52
- rudp_conv , role_type , rudp_peer_addr , close_cb = self ._remove_conn , is_proxy = self ._is_proxy ,
153
+ rudp_conv , role_type , addr ,
154
+ close_cb = lambda ct = conn_type , a = addr : self ._remove_conn (ct , a ),
155
+ is_proxy = self ._is_proxy ,
53
156
transport = transport )
54
157
55
- self ._addr_2_conn_map [addr ] = _conn
158
+ self ._conn_type_2_addr_2_conn [ conn_type ] [addr ] = _conn
56
159
return _conn
57
160
58
- async def get_conn_by_addr (
161
+ async def create_conn_by_addr (
59
162
self , conn_type , addr : typing .Tuple [str , int ],
60
163
rpc_handler : RpcHandler = None
61
- ) -> TcpConn :
62
- from TcpServer import TcpServerProtocol
63
- _conn = self ._addr_2_conn_map .get (addr , None )
164
+ ) -> ConnBase :
165
+ _conn = self ._conn_type_2_addr_2_conn [conn_type ].get (addr , None )
64
166
if _conn is None :
65
- if conn_type == CONN_TYPE_TCP :
66
- # reader, writer = await asyncio.open_connection(addr[0], addr[1])
67
- transport , protocol = await gv .EV_LOOP .create_connection (
167
+ if conn_type == CONN_TYPE_RUDP :
168
+ _conn = await self ._try_create_rudp_conn (addr )
169
+ if _conn is None :
170
+ _conn = await self ._try_create_tcp_conn (addr )
171
+ if _conn is not None and rpc_handler is not None :
172
+ _conn .add_rpc_handler (rpc_handler )
173
+ return _conn
174
+
175
+ async def _try_create_rudp_conn (self , addr ):
176
+ pass
177
+
178
+ async def _try_create_tcp_conn (self , addr ):
179
+ while self ._addr_2_try_connect_times [addr ] < RECONNECT_MAX_TIMES :
180
+ try :
181
+ from TcpServer import TcpServerProtocol
182
+ self ._addr_2_try_connect_times [addr ] += 1
183
+ transport , protocol = await gv .get_ev_loop ().create_connection (
68
184
lambda : TcpServerProtocol (),
69
- # lambda: TcpServerProtocol(rpc_handler),
70
185
addr [0 ], addr [1 ])
71
- _conn = self ._addr_2_conn_map [addr ]
186
+ except Exception as e :
187
+ self ._logger .error (str (e ))
188
+ await asyncio .sleep (RECONNECT_INTERVAL )
189
+ # if self._addr_2_try_connect_times[addr] < RECONNECT_MAX_TIMES:
190
+ self ._logger .warning (f"try reconnect tcp: { str (addr )} ... { self ._addr_2_try_connect_times [addr ]} " )
191
+ await self ._try_create_tcp_conn (addr )
72
192
else :
73
- pass # todo: rudp
74
- if rpc_handler is not None :
75
- _conn .add_rpc_handler (rpc_handler )
76
- return _conn
193
+ self ._addr_2_try_connect_times [addr ] = 0
194
+ return self ._conn_type_2_addr_2_conn [CONN_TYPE_TCP ][addr ]
195
+ else :
196
+ pass # todo
197
+ self ._logger .error (f"try { RECONNECT_MAX_TIMES } times , still can't connect remote addr: { addr } " )
198
+ self ._addr_2_try_connect_times [addr ] = 0
199
+ return None
77
200
78
- def _remove_conn (self , addr : typing .Tuple [str , int ]):
79
- self ._addr_2_conn_map .pop (addr , None )
201
+ def _remove_conn (self , conn_type , addr : typing .Tuple [str , int ]):
202
+ self ._conn_type_2_addr_2_conn [ conn_type ] .pop (addr , None )
80
203
81
204
# def add_conn(
82
205
# self,
@@ -95,7 +218,7 @@ def _remove_conn(self, addr: typing.Tuple[str, int]):
95
218
# self._addr_2_conn_map[addr] = conn
96
219
# return conn
97
220
#
98
- # async def get_conn_by_addr (
221
+ # async def create_conn_by_addr (
99
222
# self, addr: typing.Tuple[str, int], rpc_handler: RpcHandler = None) -> TcpConn:
100
223
# _conn = self._addr_2_conn_map.get(addr, None)
101
224
# if _conn is None:
0 commit comments