borecli 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bore/__init__.py +0 -0
- bore/auth.py +104 -0
- bore/cli.py +378 -0
- bore/config.py +132 -0
- bore/frames.py +376 -0
- bore/handlers/__init__.py +0 -0
- bore/handlers/error_pages.py +223 -0
- bore/handlers/http_handler.py +694 -0
- bore/handlers/websocket_handler.py +975 -0
- bore/parse_duration.py +32 -0
- bore/protocol.py +72 -0
- bore/tunnel/__init__.py +0 -0
- bore/tunnel/client.py +311 -0
- bore/tunnel/dispatcher.py +277 -0
- bore/tunnel/heartbeat.py +154 -0
- bore/tunnel.py +43 -0
- bore/websocket/__init__.py +0 -0
- bore/websocket/connection.py +108 -0
- bore/websocket/frames.py +162 -0
- bore/websocket/manager.py +174 -0
- bore/websocket/proxy.py +147 -0
- bore/websocket_client.py +338 -0
- borecli-1.0.0.dist-info/METADATA +231 -0
- borecli-1.0.0.dist-info/RECORD +28 -0
- borecli-1.0.0.dist-info/WHEEL +5 -0
- borecli-1.0.0.dist-info/entry_points.txt +2 -0
- borecli-1.0.0.dist-info/licenses/LICENSE +0 -0
- borecli-1.0.0.dist-info/top_level.txt +1 -0
bore/parse_duration.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import re
|
|
2
|
+
|
|
3
|
+
DEFAULT_TOKEN_LIFETIME = 3600
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def parse_duration(value: str) -> int:
|
|
7
|
+
"""
|
|
8
|
+
Converts:
|
|
9
|
+
30m -> 1800
|
|
10
|
+
2h -> 7200
|
|
11
|
+
1d -> 86400
|
|
12
|
+
90s -> 90
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
match = re.fullmatch(r"(\d+)([smhd])", value.lower())
|
|
16
|
+
|
|
17
|
+
if not match:
|
|
18
|
+
raise ValueError(
|
|
19
|
+
"Time must look like 30m, 8h, 2d or 45s."
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
amount = int(match.group(1))
|
|
23
|
+
unit = match.group(2)
|
|
24
|
+
|
|
25
|
+
multipliers = {
|
|
26
|
+
"s": 1,
|
|
27
|
+
"m": 60,
|
|
28
|
+
"h": 3600,
|
|
29
|
+
"d": 86400,
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return amount * multipliers[unit]
|
bore/protocol.py
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# borecli/bore/protocol.py
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
PROTOCOL_VERSION = "borehook/1.0"
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class MessageType:
|
|
9
|
+
"""
|
|
10
|
+
BoreHook tunnel protocol message types.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# =====================================================
|
|
15
|
+
# Tunnel lifecycle
|
|
16
|
+
# =====================================================
|
|
17
|
+
|
|
18
|
+
TUNNEL_REGISTER = "tunnel.register"
|
|
19
|
+
|
|
20
|
+
TUNNEL_STATUS = "tunnel.status"
|
|
21
|
+
|
|
22
|
+
TUNNEL_CLOSE = "tunnel.close"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# =====================================================
|
|
27
|
+
# HTTP tunneling
|
|
28
|
+
# =====================================================
|
|
29
|
+
|
|
30
|
+
HTTP_REQUEST = "http.request"
|
|
31
|
+
|
|
32
|
+
HTTP_RESPONSE = "http.response"
|
|
33
|
+
|
|
34
|
+
HTTP_RESPONSE_CHUNK = (
|
|
35
|
+
"http.response.chunk"
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
# =====================================================
|
|
41
|
+
# WebSocket tunneling
|
|
42
|
+
# =====================================================
|
|
43
|
+
|
|
44
|
+
WS_CONNECT = "ws.connect"
|
|
45
|
+
|
|
46
|
+
WS_CONNECTED = "ws.connected"
|
|
47
|
+
|
|
48
|
+
WS_MESSAGE = "ws.message"
|
|
49
|
+
|
|
50
|
+
WS_CLOSE = "ws.close"
|
|
51
|
+
|
|
52
|
+
WS_ERROR = "ws.error"
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
# =====================================================
|
|
57
|
+
# Heartbeat
|
|
58
|
+
# =====================================================
|
|
59
|
+
|
|
60
|
+
PING = "ping"
|
|
61
|
+
|
|
62
|
+
PONG = "pong"
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
# =====================================================
|
|
67
|
+
# System
|
|
68
|
+
# =====================================================
|
|
69
|
+
|
|
70
|
+
ERROR = "error"
|
|
71
|
+
|
|
72
|
+
METRICS = "metrics"
|
bore/tunnel/__init__.py
ADDED
|
File without changes
|
bore/tunnel/client.py
ADDED
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
# borecli/bore/tunnel/client.py
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import logging
|
|
5
|
+
|
|
6
|
+
import websockets
|
|
7
|
+
|
|
8
|
+
from bore.frames import (receive_frame,send_frame,make_frame,)
|
|
9
|
+
from bore.protocol import MessageType
|
|
10
|
+
from bore.tunnel.dispatcher import ( MessageDispatcher,)
|
|
11
|
+
from bore.tunnel.heartbeat import (Heartbeat,)
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class TunnelClient:
|
|
16
|
+
"""
|
|
17
|
+
BoreHook async tunnel client.
|
|
18
|
+
|
|
19
|
+
Handles:
|
|
20
|
+
|
|
21
|
+
- websocket lifecycle
|
|
22
|
+
- protocol receive loop
|
|
23
|
+
- dispatcher
|
|
24
|
+
- heartbeat
|
|
25
|
+
- reconnect
|
|
26
|
+
- graceful shutdown
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
def __init__(
|
|
30
|
+
self,
|
|
31
|
+
*,
|
|
32
|
+
ws_url: str,
|
|
33
|
+
local_port: int,
|
|
34
|
+
tunnel_id: str,
|
|
35
|
+
reconnect_delay: int = 5,
|
|
36
|
+
):
|
|
37
|
+
|
|
38
|
+
self.ws_url = ws_url
|
|
39
|
+
|
|
40
|
+
self.local_port = local_port
|
|
41
|
+
|
|
42
|
+
self.tunnel_id = tunnel_id
|
|
43
|
+
|
|
44
|
+
self.reconnect_delay = reconnect_delay
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
self.websocket = None
|
|
48
|
+
|
|
49
|
+
self.heartbeat = None
|
|
50
|
+
|
|
51
|
+
self.dispatcher = None
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
self._shutdown = False
|
|
55
|
+
|
|
56
|
+
self._tasks = set()
|
|
57
|
+
|
|
58
|
+
async def _safe_dispatch(self, frame):
|
|
59
|
+
try:
|
|
60
|
+
await self.dispatcher.dispatch(frame)
|
|
61
|
+
except asyncio.CancelledError:
|
|
62
|
+
raise
|
|
63
|
+
except Exception:
|
|
64
|
+
logger.exception("Dispatcher crashed")
|
|
65
|
+
|
|
66
|
+
async def start(
|
|
67
|
+
self,
|
|
68
|
+
should_shutdown=lambda: False,
|
|
69
|
+
):
|
|
70
|
+
|
|
71
|
+
"""
|
|
72
|
+
Start tunnel forever.
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
while not self._shutdown:
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
if should_shutdown():
|
|
79
|
+
|
|
80
|
+
break
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
try:
|
|
84
|
+
|
|
85
|
+
await self._connect()
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
await self._receive_loop(
|
|
89
|
+
should_shutdown
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
except asyncio.CancelledError:
|
|
94
|
+
|
|
95
|
+
break
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
except Exception:
|
|
99
|
+
|
|
100
|
+
logger.exception(
|
|
101
|
+
"Tunnel connection failed"
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
finally:
|
|
106
|
+
|
|
107
|
+
await self._cleanup()
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
if self._shutdown:
|
|
112
|
+
|
|
113
|
+
break
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
if should_shutdown():
|
|
118
|
+
|
|
119
|
+
break
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
logger.info(
|
|
124
|
+
"Reconnecting in %s seconds",
|
|
125
|
+
self.reconnect_delay,
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
# await asyncio.sleep(
|
|
130
|
+
# self.reconnect_delay
|
|
131
|
+
# )
|
|
132
|
+
for _ in range(self.reconnect_delay * 10):
|
|
133
|
+
if should_shutdown():
|
|
134
|
+
return
|
|
135
|
+
await asyncio.sleep(0.1)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
# async def stop(self):
|
|
139
|
+
|
|
140
|
+
# self._shutdown = True
|
|
141
|
+
|
|
142
|
+
# await self._cleanup()
|
|
143
|
+
|
|
144
|
+
async def stop(self):
|
|
145
|
+
self._shutdown = True
|
|
146
|
+
|
|
147
|
+
if self.websocket:
|
|
148
|
+
await self.websocket.close()
|
|
149
|
+
|
|
150
|
+
await self._cleanup()
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
async def _connect(self):
|
|
155
|
+
|
|
156
|
+
logger.info(
|
|
157
|
+
"Connecting %s",
|
|
158
|
+
self.ws_url,
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
self.websocket = await websockets.connect(
|
|
163
|
+
|
|
164
|
+
self.ws_url,
|
|
165
|
+
|
|
166
|
+
ping_interval=None,
|
|
167
|
+
|
|
168
|
+
max_size=None,
|
|
169
|
+
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
logger.info(
|
|
174
|
+
"Tunnel websocket connected"
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
#
|
|
179
|
+
# Create dispatcher
|
|
180
|
+
#
|
|
181
|
+
|
|
182
|
+
self.heartbeat = Heartbeat(
|
|
183
|
+
self.websocket
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
self.dispatcher = MessageDispatcher(
|
|
188
|
+
|
|
189
|
+
websocket=self.websocket,
|
|
190
|
+
|
|
191
|
+
local_port=self.local_port,
|
|
192
|
+
|
|
193
|
+
heartbeat=self.heartbeat,
|
|
194
|
+
|
|
195
|
+
)
|
|
196
|
+
await self.heartbeat.start()
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
async def _receive_loop(
|
|
201
|
+
self,
|
|
202
|
+
should_shutdown,
|
|
203
|
+
):
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
while True:
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
if self._shutdown:
|
|
210
|
+
|
|
211
|
+
break
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
if should_shutdown():
|
|
215
|
+
|
|
216
|
+
break
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
try:
|
|
220
|
+
frame = await asyncio.wait_for(
|
|
221
|
+
receive_frame(self.websocket),
|
|
222
|
+
timeout=1,
|
|
223
|
+
)
|
|
224
|
+
except asyncio.TimeoutError:
|
|
225
|
+
continue
|
|
226
|
+
# frame = await receive_frame(
|
|
227
|
+
# self.websocket
|
|
228
|
+
# )
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
if frame is None:
|
|
232
|
+
|
|
233
|
+
break
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
# task = asyncio.create_task(
|
|
238
|
+
|
|
239
|
+
# self.dispatcher.dispatch(
|
|
240
|
+
# frame
|
|
241
|
+
# )
|
|
242
|
+
|
|
243
|
+
# )
|
|
244
|
+
|
|
245
|
+
task = asyncio.create_task(
|
|
246
|
+
self._safe_dispatch(frame)
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
self._tasks.add(task)
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
task.add_done_callback(
|
|
253
|
+
self._tasks.discard
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
async def _cleanup(self):
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
#
|
|
262
|
+
# cancel handlers
|
|
263
|
+
#
|
|
264
|
+
|
|
265
|
+
for task in list(self._tasks):
|
|
266
|
+
task.cancel()
|
|
267
|
+
|
|
268
|
+
if self._tasks:
|
|
269
|
+
await asyncio.gather(
|
|
270
|
+
*self._tasks,
|
|
271
|
+
return_exceptions=True,
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
self._tasks.clear()
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
#
|
|
279
|
+
# stop heartbeat
|
|
280
|
+
#
|
|
281
|
+
|
|
282
|
+
if self.heartbeat:
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
await self.heartbeat.stop()
|
|
286
|
+
|
|
287
|
+
self.heartbeat = None
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
#
|
|
292
|
+
# close websocket
|
|
293
|
+
#
|
|
294
|
+
|
|
295
|
+
if self.websocket:
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
try:
|
|
299
|
+
|
|
300
|
+
await self.websocket.close()
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
except Exception:
|
|
304
|
+
|
|
305
|
+
pass
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
self.websocket = None
|
|
309
|
+
|
|
310
|
+
logger.info("Cancelling %d tasks", len(self._tasks))
|
|
311
|
+
self.dispatcher = None
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
# borecli/bore/tunnel/dispatcher.py
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
|
|
5
|
+
from bore.protocol import (
|
|
6
|
+
PROTOCOL_VERSION,
|
|
7
|
+
MessageType,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
from bore.frames import (
|
|
11
|
+
send_frame,
|
|
12
|
+
make_frame,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
from bore.handlers.http_handler import (
|
|
16
|
+
process_request,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
from bore.handlers.websocket_handler import (
|
|
20
|
+
handle_ws_connect,
|
|
21
|
+
handle_ws_message,
|
|
22
|
+
handle_ws_close,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
logger = logging.getLogger(__name__)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class MessageDispatcher:
|
|
30
|
+
"""
|
|
31
|
+
Routes BoreHook protocol frames.
|
|
32
|
+
|
|
33
|
+
The dispatcher does NOT:
|
|
34
|
+
- open connections
|
|
35
|
+
- forward HTTP
|
|
36
|
+
- manage websockets
|
|
37
|
+
|
|
38
|
+
It only decides who handles each frame.
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
def __init__(
|
|
42
|
+
self,
|
|
43
|
+
websocket,
|
|
44
|
+
local_port,
|
|
45
|
+
heartbeat,
|
|
46
|
+
):
|
|
47
|
+
|
|
48
|
+
self.websocket = websocket
|
|
49
|
+
|
|
50
|
+
self.local_port = local_port
|
|
51
|
+
|
|
52
|
+
self.heartbeat = heartbeat
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
async def dispatch(
|
|
56
|
+
self,
|
|
57
|
+
frame: dict,
|
|
58
|
+
):
|
|
59
|
+
|
|
60
|
+
#
|
|
61
|
+
# Validate protocol
|
|
62
|
+
#
|
|
63
|
+
|
|
64
|
+
protocol = frame.get(
|
|
65
|
+
"protocol"
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
if protocol != PROTOCOL_VERSION:
|
|
69
|
+
|
|
70
|
+
logger.warning(
|
|
71
|
+
"Unsupported protocol: %s",
|
|
72
|
+
protocol,
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
return
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
message_type = frame.get(
|
|
79
|
+
"type"
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
if not message_type:
|
|
84
|
+
|
|
85
|
+
logger.warning(
|
|
86
|
+
"Frame missing type"
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
return
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
logger.debug(
|
|
93
|
+
"Dispatching %s",
|
|
94
|
+
message_type,
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
#
|
|
99
|
+
# -----------------------------
|
|
100
|
+
# HTTP
|
|
101
|
+
# -----------------------------
|
|
102
|
+
#
|
|
103
|
+
|
|
104
|
+
# if message_type == MessageType.HTTP_REQUEST:
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
# await process_request(
|
|
108
|
+
|
|
109
|
+
# websocket=self.websocket,
|
|
110
|
+
|
|
111
|
+
# local_port=self.local_port,
|
|
112
|
+
|
|
113
|
+
# frame=frame,
|
|
114
|
+
|
|
115
|
+
# )
|
|
116
|
+
|
|
117
|
+
# return
|
|
118
|
+
|
|
119
|
+
if message_type == MessageType.HTTP_REQUEST:
|
|
120
|
+
try:
|
|
121
|
+
await process_request(
|
|
122
|
+
websocket=self.websocket,
|
|
123
|
+
local_port=self.local_port,
|
|
124
|
+
frame=frame,
|
|
125
|
+
)
|
|
126
|
+
except Exception:
|
|
127
|
+
logger.exception("Failed to process HTTP request")
|
|
128
|
+
return
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
#
|
|
133
|
+
# -----------------------------
|
|
134
|
+
# WebSocket
|
|
135
|
+
# -----------------------------
|
|
136
|
+
#
|
|
137
|
+
|
|
138
|
+
if message_type == MessageType.WS_CONNECT:
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
await handle_ws_connect(
|
|
142
|
+
|
|
143
|
+
websocket=self.websocket,
|
|
144
|
+
|
|
145
|
+
local_port=self.local_port,
|
|
146
|
+
|
|
147
|
+
frame=frame,
|
|
148
|
+
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
return
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
if message_type == MessageType.WS_MESSAGE:
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
await handle_ws_message(
|
|
159
|
+
|
|
160
|
+
frame=frame,
|
|
161
|
+
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
return
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
if message_type == MessageType.WS_CLOSE:
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
await handle_ws_close(
|
|
172
|
+
|
|
173
|
+
frame=frame,
|
|
174
|
+
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
return
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
#
|
|
182
|
+
# -----------------------------
|
|
183
|
+
# Heartbeat
|
|
184
|
+
# -----------------------------
|
|
185
|
+
#
|
|
186
|
+
|
|
187
|
+
if message_type == MessageType.PING:
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
await send_frame(
|
|
191
|
+
|
|
192
|
+
self.websocket,
|
|
193
|
+
|
|
194
|
+
make_frame(
|
|
195
|
+
|
|
196
|
+
MessageType.PONG
|
|
197
|
+
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
return
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
if message_type == MessageType.PONG:
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
if self.heartbeat:
|
|
210
|
+
|
|
211
|
+
self.heartbeat.pong()
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
return
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
#
|
|
219
|
+
# -----------------------------
|
|
220
|
+
# Server messages
|
|
221
|
+
# -----------------------------
|
|
222
|
+
#
|
|
223
|
+
|
|
224
|
+
if message_type == MessageType.ERROR:
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
logger.error(
|
|
228
|
+
|
|
229
|
+
"Server error: %s",
|
|
230
|
+
|
|
231
|
+
frame.get(
|
|
232
|
+
"message",
|
|
233
|
+
"Unknown error",
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
return
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
if message_type == MessageType.TUNNEL_STATUS:
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
logger.info(
|
|
246
|
+
|
|
247
|
+
"Tunnel status: %s",
|
|
248
|
+
|
|
249
|
+
frame.get(
|
|
250
|
+
"status"
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
return
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
if message_type == MessageType.METRICS:
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
logger.debug(
|
|
263
|
+
"Metrics received: %s",
|
|
264
|
+
frame,
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
return
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
logger.warning(
|
|
272
|
+
|
|
273
|
+
"Unknown message type: %s",
|
|
274
|
+
|
|
275
|
+
message_type,
|
|
276
|
+
|
|
277
|
+
)
|