import requests, json, uuid, time, threading, sys sys.stdout.reconfigure(encoding='utf-8') BASE = 'http://192.168.5.100:8009' # Login r = requests.post(f'{BASE}/api/auth/login', json={'userName':'nanxun','password':'123456'}) d = r.json()['data'] token, uid = d['token'], d['userId'] print(f'Logged in: {uid[:8]}...') # Negotiate nr = requests.post(f'{BASE}/chat/negotiate?access_token={token}&negotiateVersion=1', headers={'X-Requested-With': 'XMLHttpRequest'}) neg = nr.json() conn_id = neg['connectionId'] conn_token = neg['connectionToken'] print(f'Negotiate OK: connId={conn_id[:12]}... token={conn_token[:12]}...') # WebSocket connect (proper SignalR protocol) import websocket ws_url = f'ws://192.168.5.100:8009/chat?id={conn_token}' print(f'WS URL: {ws_url[:80]}...') # Custom WebSocket with proper headers class SignalRTracker: def __init__(self): self.open = False self.msgs = [] self.errors = [] self.closed = False def on_open(self, ws): self.open = True # Send the SignalR handshake ws.send('{"protocol":"json","version":1}\x1e') print('[SIGNALR] Handshake sent') def on_message(self, ws, msg): self.msgs.append(msg) # SignalR messages are terminated with \x1e (record separator) for m in msg.split('\x1e'): m = m.strip() if not m: continue try: data = json.loads(m) t = data.get('type', 0) if t == 1: print(f'[SIGNALR] Invocation: {str(data)[:200]}') elif t == 6: print(f'[SIGNALR] Ping') elif 'error' in data: print(f'[SIGNALR] Error: {data.get("error")}') else: print(f'[SIGNALR] Msg type={t}: {str(data)[:200]}') except: print(f'[SIGNALR] Raw: {m[:200]}') def on_error(self, ws, err): self.errors.append(str(err)) print(f'[SIGNALR] Error: {str(err)[:150]}') def on_close(self, ws, code, reason): self.closed = True print(f'[SIGNALR] Close: code={code} reason={str(reason)[:100]}') tracker = SignalRTracker() ws = websocket.WebSocketApp(ws_url, on_open=tracker.on_open, on_message=tracker.on_message, on_error=tracker.on_error, on_close=tracker.on_close, header={'Authorization': f'Bearer {token}'}) t = threading.Thread(target=lambda: ws.run_forever(ping_interval=10), daemon=True) t.start() time.sleep(4) if not tracker.open: print('FAILED: WebSocket did not open') print('Errors:', tracker.errors) else: print('SUCCESS: WebSocket connected!') print(f'Received {len(tracker.msgs)} handshake responses') # Now send a message cid = str(uuid.uuid4()) mr = requests.post(f'{BASE}/api/message/send', json={ 'ClientMsgId': cid, 'TargetId': '4eb50000-a3ad-9631-f5fe-08ded40a21f7', 'ChatType': 0, 'MsgType': 0, 'Text': f'signalr-push-test-{int(time.time())}' }, headers={'Authorization': f'Bearer {token}'}) print(f'Send msg: code={mr.json()["code"]}') time.sleep(5) print(f'Total msgs received: {len(tracker.msgs)}') for m in tracker.msgs: print(f' MSG: {m[:300]}') if tracker.closed: print(f'\nConnection was closed') print(f'\nSummary: connected={tracker.open} msgs={len(tracker.msgs)} errors={len(tracker.errors)}')