escobar 0.1.89__py3-none-any.whl → 0.1.91__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.
- escobar/_version.py +1 -1
- escobar/handlers.py +57 -147
- escobar/labextension/package.json +2 -2
- escobar/labextension/schemas/escobar/package.json.orig +1 -1
- escobar/labextension/schemas/escobar/plugin.json +2 -2
- escobar/labextension/static/653.cd0a1dbb61ede2a5de00.js +1 -0
- escobar/labextension/static/{remoteEntry.a8ae0b901c4a30b269e4.js → remoteEntry.48a97be89d680e21e498.js} +1 -1
- {escobar-0.1.89.data → escobar-0.1.91.data}/data/share/jupyter/labextensions/escobar/package.json +2 -2
- {escobar-0.1.89.data → escobar-0.1.91.data}/data/share/jupyter/labextensions/escobar/schemas/escobar/package.json.orig +1 -1
- {escobar-0.1.89.data → escobar-0.1.91.data}/data/share/jupyter/labextensions/escobar/schemas/escobar/plugin.json +2 -2
- escobar-0.1.91.data/data/share/jupyter/labextensions/escobar/static/653.cd0a1dbb61ede2a5de00.js +1 -0
- escobar-0.1.89.data/data/share/jupyter/labextensions/escobar/static/remoteEntry.a8ae0b901c4a30b269e4.js → escobar-0.1.91.data/data/share/jupyter/labextensions/escobar/static/remoteEntry.48a97be89d680e21e498.js +1 -1
- {escobar-0.1.89.dist-info → escobar-0.1.91.dist-info}/METADATA +1 -1
- escobar-0.1.91.dist-info/RECORD +40 -0
- escobar/labextension/static/237.23439249688997c395a8.js +0 -1
- escobar-0.1.89.data/data/share/jupyter/labextensions/escobar/static/237.23439249688997c395a8.js +0 -1
- escobar-0.1.89.dist-info/RECORD +0 -40
- {escobar-0.1.89.data → escobar-0.1.91.data}/data/share/jupyter/labextensions/escobar/install.json +0 -0
- {escobar-0.1.89.data → escobar-0.1.91.data}/data/share/jupyter/labextensions/escobar/static/304.bf7e91be734e5b36cdc9.js +0 -0
- {escobar-0.1.89.data → escobar-0.1.91.data}/data/share/jupyter/labextensions/escobar/static/346.8a1e61ca6789b6fddfa7.js +0 -0
- {escobar-0.1.89.data → escobar-0.1.91.data}/data/share/jupyter/labextensions/escobar/static/379.40dd59dc19d4a6b42d25.js +0 -0
- {escobar-0.1.89.data → escobar-0.1.91.data}/data/share/jupyter/labextensions/escobar/static/57.17e53b4b9a954f39c4d8.js +0 -0
- {escobar-0.1.89.data → escobar-0.1.91.data}/data/share/jupyter/labextensions/escobar/static/648.a7d314faeacc762d891d.js +0 -0
- {escobar-0.1.89.data → escobar-0.1.91.data}/data/share/jupyter/labextensions/escobar/static/666.3bc65aac3a3be183ee19.js +0 -0
- {escobar-0.1.89.data → escobar-0.1.91.data}/data/share/jupyter/labextensions/escobar/static/874.c539726f31a1baa0267e.js +0 -0
- {escobar-0.1.89.data → escobar-0.1.91.data}/data/share/jupyter/labextensions/escobar/static/986.cbcf9d7c1cd8d06be435.js +0 -0
- {escobar-0.1.89.data → escobar-0.1.91.data}/data/share/jupyter/labextensions/escobar/static/style.js +0 -0
- {escobar-0.1.89.data → escobar-0.1.91.data}/data/share/jupyter/labextensions/escobar/static/third-party-licenses.json +0 -0
- {escobar-0.1.89.dist-info → escobar-0.1.91.dist-info}/WHEEL +0 -0
- {escobar-0.1.89.dist-info → escobar-0.1.91.dist-info}/entry_points.txt +0 -0
- {escobar-0.1.89.dist-info → escobar-0.1.91.dist-info}/licenses/LICENSE +0 -0
escobar/_version.py
CHANGED
escobar/handlers.py
CHANGED
@@ -15,10 +15,58 @@ import tornado.websocket
|
|
15
15
|
import aiohttp
|
16
16
|
from traitlets.config import LoggingConfigurable
|
17
17
|
import mimetypes
|
18
|
+
import requests
|
19
|
+
from google.oauth2 import id_token
|
20
|
+
from google.auth.transport import requests as google_requests
|
18
21
|
|
19
22
|
# Default proxy port
|
20
23
|
DEFAULT_PROXY_PORT = 3000
|
21
24
|
|
25
|
+
|
26
|
+
class OAuthCallbackHandler(JupyterHandler):
|
27
|
+
"""
|
28
|
+
Handler for /static/oauth-callback.html endpoint.
|
29
|
+
Serves the OAuth callback HTML file for Google authentication.
|
30
|
+
"""
|
31
|
+
|
32
|
+
async def get(self):
|
33
|
+
"""Handle GET requests to serve the OAuth callback HTML"""
|
34
|
+
try:
|
35
|
+
# Get the path to the static directory
|
36
|
+
import os
|
37
|
+
current_dir = os.path.dirname(os.path.abspath(__file__))
|
38
|
+
project_root = os.path.dirname(current_dir)
|
39
|
+
callback_file_path = os.path.join(project_root, 'static', 'oauth-callback.html')
|
40
|
+
|
41
|
+
self.log.info(f"🔐 CALLBACK: Serving OAuth callback from: {callback_file_path}")
|
42
|
+
|
43
|
+
# Check if file exists
|
44
|
+
if not os.path.exists(callback_file_path):
|
45
|
+
self.log.error(f"🔐 CALLBACK: OAuth callback file not found: {callback_file_path}")
|
46
|
+
self.set_status(404)
|
47
|
+
self.finish("OAuth callback file not found")
|
48
|
+
return
|
49
|
+
|
50
|
+
# Read and serve the HTML file
|
51
|
+
with open(callback_file_path, 'r', encoding='utf-8') as f:
|
52
|
+
html_content = f.read()
|
53
|
+
|
54
|
+
# Set proper headers
|
55
|
+
self.set_header('Content-Type', 'text/html; charset=UTF-8')
|
56
|
+
self.set_header('Cache-Control', 'no-cache, no-store, must-revalidate')
|
57
|
+
self.set_header('Pragma', 'no-cache')
|
58
|
+
self.set_header('Expires', '0')
|
59
|
+
|
60
|
+
# Write the HTML content
|
61
|
+
self.write(html_content)
|
62
|
+
self.log.info(f"🔐 CALLBACK: Successfully served OAuth callback HTML")
|
63
|
+
|
64
|
+
except Exception as e:
|
65
|
+
self.log.error(f"🔐 CALLBACK: Error serving OAuth callback: {e}")
|
66
|
+
self.set_status(500)
|
67
|
+
self.finish(f"Error serving OAuth callback: {str(e)}")
|
68
|
+
|
69
|
+
|
22
70
|
class ProxyHandler(JupyterHandler):
|
23
71
|
"""
|
24
72
|
Handler for /proxy endpoint.
|
@@ -184,16 +232,11 @@ class WebSocketProxyHandler(tornado.websocket.WebSocketHandler):
|
|
184
232
|
# Determine if we're in Docker
|
185
233
|
is_docker = dockerenv_exists or docker_env or cgroup_docker
|
186
234
|
|
187
|
-
print(f"[ESCOBAR-WS] Docker detection indicators: {docker_indicators}")
|
188
|
-
print(f"[ESCOBAR-WS] Final Docker detection result: {is_docker}")
|
189
|
-
|
190
235
|
if not is_docker:
|
191
|
-
print(f"[ESCOBAR-WS] Not in Docker container, using original URL: {url}")
|
192
236
|
return url
|
193
237
|
|
194
238
|
# Parse the URL to extract components
|
195
239
|
parsed = urlparse(url)
|
196
|
-
print(f"[ESCOBAR-WS] Parsed URL - hostname: '{parsed.hostname}', netloc: '{parsed.netloc}'")
|
197
240
|
|
198
241
|
# Check if hostname is localhost or 127.0.0.1
|
199
242
|
if parsed.hostname in ['localhost', '127.0.0.1']:
|
@@ -202,10 +245,7 @@ class WebSocketProxyHandler(tornado.websocket.WebSocketHandler):
|
|
202
245
|
new_parsed = parsed._replace(netloc=new_netloc)
|
203
246
|
new_url = urlunparse(new_parsed)
|
204
247
|
|
205
|
-
print(f"[ESCOBAR-WS] Docker hostname resolution: {url} → {new_url}")
|
206
248
|
return new_url
|
207
|
-
else:
|
208
|
-
print(f"[ESCOBAR-WS] Docker container detected, but hostname '{parsed.hostname}' is not localhost/127.0.0.1, keeping original: {url}")
|
209
249
|
|
210
250
|
return url
|
211
251
|
|
@@ -238,30 +278,22 @@ class WebSocketProxyHandler(tornado.websocket.WebSocketHandler):
|
|
238
278
|
Get user-configured Bonnie URL from bonnie_url query parameter.
|
239
279
|
This allows the frontend to override the environment variable.
|
240
280
|
"""
|
241
|
-
print(f"[ESCOBAR-WS] === READING USER BONNIE URL FROM QUERY PARAMETER ===")
|
242
|
-
|
243
281
|
try:
|
244
282
|
# Get the bonnieUrl from query parameters
|
245
283
|
bonnie_url = self.get_argument('bonnie_url', None)
|
246
|
-
print(f"[ESCOBAR-WS] bonnie_url query parameter value: '{bonnie_url}'")
|
247
284
|
|
248
285
|
if bonnie_url and bonnie_url.strip():
|
249
286
|
# Validate that it's a WebSocket URL
|
250
287
|
if bonnie_url.startswith(('ws://', 'wss://')):
|
251
|
-
print(f"[ESCOBAR-WS] Valid user Bonnie URL from query parameter: {bonnie_url}")
|
252
288
|
return bonnie_url.strip()
|
253
289
|
else:
|
254
|
-
print(f"[ESCOBAR-WS] Invalid Bonnie URL format (must start with ws:// or wss://): {bonnie_url}")
|
255
290
|
return None
|
256
291
|
else:
|
257
|
-
print(f"[ESCOBAR-WS] No bonnie_url query parameter provided")
|
258
292
|
return None
|
259
293
|
|
260
294
|
except Exception as e:
|
261
295
|
print(f"[ESCOBAR-WS] Error reading bonnie_url query parameter: {e}")
|
262
296
|
return None
|
263
|
-
finally:
|
264
|
-
print(f"[ESCOBAR-WS] === END BONNIE URL QUERY PARAMETER READ ===")
|
265
297
|
|
266
298
|
def _get_target_url(self):
|
267
299
|
"""
|
@@ -375,136 +407,38 @@ class WebSocketProxyHandler(tornado.websocket.WebSocketHandler):
|
|
375
407
|
|
376
408
|
async def on_message(self, message):
|
377
409
|
"""Called when a message is received from the client"""
|
378
|
-
print(f"[ESCOBAR-WS] === CLIENT MESSAGE RECEIVED ===")
|
379
|
-
print(f"[ESCOBAR-WS] Message length: {len(message)}")
|
380
|
-
print(f"[ESCOBAR-WS] Message type: {type(message)}")
|
381
|
-
print(f"[ESCOBAR-WS] Message preview: {message[:500]}...")
|
382
|
-
print(f"[ESCOBAR-WS] Target WS exists: {self.target_ws is not None}")
|
383
|
-
print(f"[ESCOBAR-WS] Is closing: {self.is_closing}")
|
384
|
-
|
385
410
|
if self.target_ws and not self.is_closing:
|
386
|
-
# Enhanced debugging before forwarding
|
387
|
-
print(f"[ESCOBAR-WS] === PRE-FORWARD DIAGNOSTICS ===")
|
388
|
-
print(f"[ESCOBAR-WS] Target WS type: {type(self.target_ws)}")
|
389
|
-
print(f"[ESCOBAR-WS] Target WS state: {getattr(self.target_ws, 'state', 'NO_STATE_ATTR')}")
|
390
|
-
|
391
|
-
# Check if connection is actually open
|
392
|
-
try:
|
393
|
-
is_open = self.target_ws.state.name == 'OPEN'
|
394
|
-
print(f"[ESCOBAR-WS] Target WS is OPEN: {is_open}")
|
395
|
-
except AttributeError:
|
396
|
-
print(f"[ESCOBAR-WS] Cannot check target WS state - no state attribute")
|
397
|
-
is_open = True # Assume open and let send() fail with proper error
|
398
|
-
|
399
|
-
# Check connection properties
|
400
|
-
try:
|
401
|
-
print(f"[ESCOBAR-WS] Target WS closed property: {getattr(self.target_ws, 'closed', 'NO_CLOSED_ATTR')}")
|
402
|
-
except:
|
403
|
-
print(f"[ESCOBAR-WS] Cannot access target WS closed property")
|
404
|
-
|
405
|
-
# Message type analysis
|
406
|
-
if isinstance(message, str):
|
407
|
-
print(f"[ESCOBAR-WS] Message is TEXT (string)")
|
408
|
-
elif isinstance(message, bytes):
|
409
|
-
print(f"[ESCOBAR-WS] Message is BINARY (bytes)")
|
410
|
-
else:
|
411
|
-
print(f"[ESCOBAR-WS] Message is UNKNOWN type: {type(message)}")
|
412
|
-
|
413
|
-
print(f"[ESCOBAR-WS] === ATTEMPTING MESSAGE FORWARD ===")
|
414
|
-
|
415
411
|
try:
|
416
412
|
# Forward message to target server
|
417
413
|
await self.target_ws.send(message)
|
418
|
-
print(f"[ESCOBAR-WS] ✅ Message successfully forwarded to target")
|
419
414
|
logging.debug(f"Forwarded message to target: {message[:100]}...")
|
420
415
|
except Exception as e:
|
421
|
-
print(f"[ESCOBAR-WS]
|
422
|
-
print(f"[ESCOBAR-WS]
|
423
|
-
print(f"[ESCOBAR-WS]
|
424
|
-
print(f"[ESCOBAR-WS] Exception args: {getattr(e, 'args', 'NO_ARGS')}")
|
425
|
-
|
426
|
-
# Check target connection state after error
|
427
|
-
try:
|
428
|
-
print(f"[ESCOBAR-WS] Target WS state after error: {self.target_ws.state}")
|
429
|
-
except:
|
430
|
-
print(f"[ESCOBAR-WS] Cannot check target WS state after error")
|
431
|
-
|
432
|
-
# Additional exception details
|
433
|
-
if hasattr(e, '__dict__'):
|
434
|
-
print(f"[ESCOBAR-WS] Exception attributes: {e.__dict__}")
|
435
|
-
if hasattr(e, 'errno'):
|
436
|
-
print(f"[ESCOBAR-WS] Errno: {e.errno}")
|
437
|
-
if hasattr(e, 'strerror'):
|
438
|
-
print(f"[ESCOBAR-WS] Strerror: {e.strerror}")
|
439
|
-
|
440
|
-
# Import specific exception types for better diagnosis
|
441
|
-
import websockets.exceptions
|
442
|
-
if isinstance(e, websockets.exceptions.ConnectionClosed):
|
443
|
-
print(f"[ESCOBAR-WS] ConnectionClosed - code: {e.code}, reason: {e.reason}")
|
444
|
-
elif isinstance(e, websockets.exceptions.InvalidState):
|
445
|
-
print(f"[ESCOBAR-WS] InvalidState - connection in wrong state")
|
446
|
-
elif isinstance(e, websockets.exceptions.PayloadTooBig):
|
447
|
-
print(f"[ESCOBAR-WS] PayloadTooBig - message too large")
|
448
|
-
|
416
|
+
print(f"[ESCOBAR-WS] ERROR forwarding message to target:")
|
417
|
+
print(f"[ESCOBAR-WS] Error: {str(e)}")
|
418
|
+
print(f"[ESCOBAR-WS] Error type: {type(e).__name__}")
|
449
419
|
logging.error(f"Error forwarding message to target: {str(e)}")
|
450
|
-
|
451
|
-
# Don't close immediately - let's see if we can recover
|
452
|
-
print(f"[ESCOBAR-WS] Closing client connection due to forward error")
|
453
|
-
self.close(code=1011, reason=f"Target forward error: {type(e).__name__}")
|
454
|
-
else:
|
455
|
-
print(f"[ESCOBAR-WS] Cannot forward message - target_ws: {self.target_ws}, is_closing: {self.is_closing}")
|
456
|
-
print(f"[ESCOBAR-WS] === END CLIENT MESSAGE ===")
|
420
|
+
self.close(code=1011, reason="Target connection error")
|
457
421
|
|
458
422
|
async def _forward_from_target(self):
|
459
423
|
"""Forward messages from target server to client"""
|
460
|
-
print(f"[ESCOBAR-WS] === STARTING TARGET MESSAGE FORWARDING ===")
|
461
|
-
print(f"[ESCOBAR-WS] Target WS state: {self.target_ws.state if self.target_ws else 'None'}")
|
462
|
-
|
463
424
|
try:
|
464
|
-
message_count = 0
|
465
425
|
async for message in self.target_ws:
|
466
|
-
message_count += 1
|
467
|
-
print(f"[ESCOBAR-WS] === TARGET MESSAGE #{message_count} ===")
|
468
|
-
print(f"[ESCOBAR-WS] Message length: {len(message)}")
|
469
|
-
print(f"[ESCOBAR-WS] Message type: {type(message)}")
|
470
|
-
print(f"[ESCOBAR-WS] Message preview: {message[:500]}...")
|
471
|
-
print(f"[ESCOBAR-WS] Is closing: {self.is_closing}")
|
472
|
-
|
473
426
|
if not self.is_closing:
|
474
|
-
print(f"[ESCOBAR-WS] Forwarding message to client")
|
475
427
|
# Forward message to client
|
476
428
|
self.write_message(message)
|
477
|
-
print(f"[ESCOBAR-WS] Message successfully forwarded to client")
|
478
429
|
logging.debug(f"Forwarded message from target: {message[:100]}...")
|
479
430
|
else:
|
480
|
-
print(f"[ESCOBAR-WS] Breaking forwarding loop - connection is closing")
|
481
431
|
break
|
482
|
-
print(f"[ESCOBAR-WS] === END TARGET MESSAGE #{message_count} ===")
|
483
432
|
|
484
433
|
except websockets.exceptions.ConnectionClosed as e:
|
485
|
-
print(f"[ESCOBAR-WS] === TARGET CONNECTION CLOSED DETAILS ===")
|
486
|
-
print(f"[ESCOBAR-WS] Target websocket connection closed")
|
487
|
-
print(f"[ESCOBAR-WS] Close code: {getattr(e, 'code', 'NO_CODE')}")
|
488
|
-
print(f"[ESCOBAR-WS] Close reason: {getattr(e, 'reason', 'NO_REASON')}")
|
489
|
-
print(f"[ESCOBAR-WS] Exception type: {type(e).__name__}")
|
490
|
-
print(f"[ESCOBAR-WS] Exception str: {str(e)}")
|
491
|
-
print(f"[ESCOBAR-WS] Target WS final state: {getattr(self.target_ws, 'state', 'NO_STATE') if self.target_ws else 'NO_TARGET_WS'}")
|
492
|
-
print(f"[ESCOBAR-WS] Messages processed before disconnect: {message_count}")
|
493
|
-
print(f"[ESCOBAR-WS] === END TARGET CONNECTION CLOSED DETAILS ===")
|
494
|
-
|
495
434
|
logging.info(f"Target websocket connection closed - code: {getattr(e, 'code', 'NO_CODE')}, reason: {getattr(e, 'reason', 'NO_REASON')}")
|
496
435
|
|
497
436
|
if not self.is_closing:
|
498
|
-
print(f"[ESCOBAR-WS] Closing client connection due to target disconnect")
|
499
437
|
self.close(code=1011, reason="Target server disconnected")
|
500
438
|
except Exception as e:
|
501
439
|
print(f"[ESCOBAR-WS] === TARGET MESSAGE FORWARDING ERROR ===")
|
502
440
|
print(f"[ESCOBAR-WS] Error: {str(e)}")
|
503
441
|
print(f"[ESCOBAR-WS] Error type: {type(e).__name__}")
|
504
|
-
print(f"[ESCOBAR-WS] Messages processed before error: {message_count}")
|
505
|
-
print(f"[ESCOBAR-WS] Target WS state: {getattr(self.target_ws, 'state', 'NO_STATE') if self.target_ws else 'NO_TARGET_WS'}")
|
506
|
-
if hasattr(e, '__dict__'):
|
507
|
-
print(f"[ESCOBAR-WS] Error attributes: {e.__dict__}")
|
508
442
|
if hasattr(e, 'errno'):
|
509
443
|
print(f"[ESCOBAR-WS] Errno: {e.errno}")
|
510
444
|
if hasattr(e, 'strerror'):
|
@@ -513,66 +447,37 @@ class WebSocketProxyHandler(tornado.websocket.WebSocketHandler):
|
|
513
447
|
|
514
448
|
logging.error(f"Error receiving from target websocket: {str(e)}")
|
515
449
|
if not self.is_closing:
|
516
|
-
print(f"[ESCOBAR-WS] Closing client connection due to target error")
|
517
450
|
self.close(code=1011, reason="Target connection error")
|
518
|
-
|
519
|
-
print(f"[ESCOBAR-WS] === TARGET MESSAGE FORWARDING ENDED ===")
|
520
451
|
|
521
452
|
def on_close(self):
|
522
453
|
"""Called when websocket connection is closed"""
|
523
|
-
print(f"[ESCOBAR-WS] === CLIENT CONNECTION CLOSED ===")
|
524
|
-
print(f"[ESCOBAR-WS] Setting is_closing flag to True")
|
525
454
|
self.is_closing = True
|
526
|
-
print(f"[ESCOBAR-WS] Target WS exists: {self.target_ws is not None}")
|
527
455
|
|
528
456
|
logging.info("WebSocket connection closed")
|
529
457
|
|
530
458
|
# Close target connection if it exists
|
531
459
|
if self.target_ws:
|
532
|
-
print(f"[ESCOBAR-WS] Scheduling target connection cleanup")
|
533
460
|
asyncio.create_task(self._close_target_connection())
|
534
|
-
else:
|
535
|
-
print(f"[ESCOBAR-WS] No target connection to clean up")
|
536
|
-
|
537
|
-
print(f"[ESCOBAR-WS] === END CLIENT CONNECTION CLOSED ===")
|
538
461
|
|
539
462
|
async def _close_target_connection(self):
|
540
463
|
"""Safely close the target websocket connection"""
|
541
|
-
print(f"[ESCOBAR-WS] === CLOSING TARGET CONNECTION ===")
|
542
464
|
try:
|
543
465
|
if self.target_ws:
|
544
|
-
print(f"[ESCOBAR-WS] Target WS exists, checking state")
|
545
|
-
print(f"[ESCOBAR-WS] Target WS type: {type(self.target_ws)}")
|
546
|
-
print(f"[ESCOBAR-WS] Target WS state: {getattr(self.target_ws, 'state', 'NO_STATE_ATTR')}")
|
547
|
-
|
548
466
|
# Check if connection is already closed using the correct websockets library API
|
549
467
|
try:
|
550
468
|
is_closed = self.target_ws.state.name == 'CLOSED'
|
551
|
-
print(f"[ESCOBAR-WS] Target WS is closed: {is_closed}")
|
552
469
|
except AttributeError:
|
553
470
|
# Fallback: just try to close it regardless of state
|
554
|
-
print(f"[ESCOBAR-WS] Cannot check state, will attempt to close anyway")
|
555
471
|
is_closed = False
|
556
472
|
|
557
473
|
if not is_closed:
|
558
|
-
print(f"[ESCOBAR-WS] Target WS is open, closing it")
|
559
474
|
await self.target_ws.close()
|
560
|
-
print(f"[ESCOBAR-WS] Target connection closed successfully")
|
561
475
|
logging.info("Target websocket connection closed")
|
562
|
-
else:
|
563
|
-
print(f"[ESCOBAR-WS] Target WS already closed")
|
564
|
-
else:
|
565
|
-
print(f"[ESCOBAR-WS] No target WS to close")
|
566
476
|
except Exception as e:
|
567
477
|
print(f"[ESCOBAR-WS] ERROR closing target connection:")
|
568
478
|
print(f"[ESCOBAR-WS] Error: {str(e)}")
|
569
479
|
print(f"[ESCOBAR-WS] Error type: {type(e).__name__}")
|
570
|
-
print(f"[ESCOBAR-WS] Target WS type: {type(self.target_ws) if self.target_ws else 'None'}")
|
571
|
-
if hasattr(e, '__dict__'):
|
572
|
-
print(f"[ESCOBAR-WS] Error attributes: {e.__dict__}")
|
573
480
|
logging.error(f"Error closing target websocket: {str(e)}")
|
574
|
-
|
575
|
-
print(f"[ESCOBAR-WS] === END CLOSING TARGET CONNECTION ===")
|
576
481
|
|
577
482
|
|
578
483
|
def setup_handlers(web_app):
|
@@ -640,9 +545,14 @@ def setup_handlers(web_app):
|
|
640
545
|
for pattern in ws_patterns:
|
641
546
|
print(f"[ESCOBAR-WS] - {pattern}")
|
642
547
|
|
548
|
+
# Register the OAuth callback endpoint
|
549
|
+
oauth_callback_pattern = url_path_join(base_url, "static", "oauth-callback.html")
|
550
|
+
print(f"[ESCOBAR-WS] OAuth callback pattern: {oauth_callback_pattern}")
|
551
|
+
|
643
552
|
# Build handlers list with all WebSocket patterns
|
644
553
|
handlers = [
|
645
554
|
(proxy_pattern, ProxyHandler),
|
555
|
+
(oauth_callback_pattern, OAuthCallbackHandler),
|
646
556
|
*[(pattern, WebSocketProxyHandler) for pattern in ws_patterns]
|
647
557
|
]
|
648
558
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "escobar",
|
3
|
-
"version": "0.1.
|
3
|
+
"version": "0.1.91",
|
4
4
|
"description": "AI CHAT EXTENSION",
|
5
5
|
"keywords": [
|
6
6
|
"jupyter",
|
@@ -123,7 +123,7 @@
|
|
123
123
|
"outputDir": "escobar/labextension",
|
124
124
|
"schemaDir": "schema",
|
125
125
|
"_build": {
|
126
|
-
"load": "static/remoteEntry.
|
126
|
+
"load": "static/remoteEntry.48a97be89d680e21e498.js",
|
127
127
|
"extension": "./extension",
|
128
128
|
"style": "./style"
|
129
129
|
}
|
@@ -38,8 +38,8 @@
|
|
38
38
|
},
|
39
39
|
"googleClientId": {
|
40
40
|
"type": "string",
|
41
|
-
"title": "Google
|
42
|
-
"description": "Google OAuth
|
41
|
+
"title": "Google Client ID",
|
42
|
+
"description": "Google OAuth Client ID for authentication. Get this from Google Cloud Console.",
|
43
43
|
"default": ""
|
44
44
|
}
|
45
45
|
},
|