MCPcopy Create free account
hub / github.com/TheSmallHanCat/flow2api / ExtensionCaptchaService

Class ExtensionCaptchaService

src/services/browser_captcha_extension.py:21–214  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

19
20
21class ExtensionCaptchaService:
22 _instance: Optional["ExtensionCaptchaService"] = None
23 _lock = asyncio.Lock()
24
25 def __init__(self, db=None):
26 self.db = db
27 self.active_connections: list[ExtensionConnection] = []
28 self.pending_requests: dict[str, tuple[asyncio.Future, WebSocket]] = {}
29
30 @classmethod
31 async def get_instance(cls, db=None) -> "ExtensionCaptchaService":
32 if cls._instance is None:
33 async with cls._lock:
34 if cls._instance is None:
35 cls._instance = cls(db=db)
36 elif db is not None and cls._instance.db is None:
37 cls._instance.db = db
38 return cls._instance
39
40 async def connect(self, websocket: WebSocket):
41 await websocket.accept()
42 conn = ExtensionConnection(
43 websocket=websocket,
44 route_key=(websocket.query_params.get("route_key") or "").strip(),
45 client_label=(websocket.query_params.get("client_label") or "").strip(),
46 )
47 self.active_connections.append(conn)
48 debug_logger.log_info(
49 f"[Extension Captcha] Client connected. Total: {len(self.active_connections)}, "
50 f"route_key={conn.route_key or '-'}, label={conn.client_label or '-'}"
51 )
52
53 def disconnect(self, websocket: WebSocket):
54 for conn in list(self.active_connections):
55 if conn.websocket is websocket:
56 self.active_connections.remove(conn)
57 debug_logger.log_info(
58 f"[Extension Captcha] Client disconnected. Total: {len(self.active_connections)}, "
59 f"route_key={conn.route_key or '-'}, label={conn.client_label or '-'}"
60 )
61 return
62
63 def _find_connection(self, websocket: WebSocket) -> Optional[ExtensionConnection]:
64 for conn in self.active_connections:
65 if conn.websocket is websocket:
66 return conn
67 return None
68
69 def _select_connection(self, route_key: str) -> Optional[ExtensionConnection]:
70 normalized_key = (route_key or "").strip()
71 if normalized_key:
72 for conn in self.active_connections:
73 if conn.route_key == normalized_key:
74 return conn
75 return None
76 # Empty token routes are only allowed to use an empty extension route.
77 # A keyed route such as "9223" belongs to a specific browser/account
78 # and must never be borrowed by another token just because it is the

Callers

nothing calls this directly

Calls

no outgoing calls

Tested by

no test coverage detected