Skip to content

Commit

Permalink
fix: resume in new ws
Browse files Browse the repository at this point in the history
  • Loading branch information
Bluefissure committed Nov 21, 2023
1 parent 7de9710 commit 6f7d9d5
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 30 deletions.
55 changes: 35 additions & 20 deletions qqbot/QQBot.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,51 @@
import threading
import time
import requests
import websockets
import inspect
from collections import defaultdict
from consts import EVENT_INTENT
from consts import EVENT_INTENT, ClientState

class QQBot(object):
def __init__(self, config, ws) -> None:
def __init__(self, config) -> None:
self.token = None
self.expiration = 0
self.config = config
self.app_id = str(config['app_id'])
self.ws = ws
self.ws = None
self._s = 0
self.username = 'Unknown QQBot'
self.bot = True
self.version = None
self.session_id = None
self.id = None
self.logged_in = False
self._log = logging.getLogger('QQBot')
self.http = requests.Session()
self._heartbeat_thread = None
self._subscriptions = defaultdict(list)
self._state = ClientState.INIT
self._refresh_token()

def __str__(self) -> str:
return f'QQBot {self.username}'

async def run(self):
reconnect_count = 0
while reconnect_count < 50:
try:
self._log.info('Connecting to QQ...')
async with websockets.connect("wss://api.sgroup.qq.com/websocket/") as websocket:
self.ws = websocket
async for message in websocket:
jdata = json.loads(message)
await self.handle(jdata)
except websockets.exceptions.ConnectionClosedError:
self._log.info('Connection closed, try reconnecting...')
reconnect_count += 1
except Exception as e:
raise e


def _refresh_token(self):
if time.time() >= self.expiration:
self._log.info('Refreshing token...')
Expand Down Expand Up @@ -73,22 +91,17 @@ def headers(self) -> dict:
def s(self) -> int:
return self._s

@property
def log(self):
return self._log

@s.setter
def s(self, value: int):
self._s = value

@property
def log(self):
return self._log

async def _heartbeat(self):
first_hearbeat = True
session_id = self.session_id
while True:
if self.session_id != session_id:
self._log.debug('%s session id changed.', self)
break
self._refresh_token()
await self.ws.send(json.dumps({
"op": 1,
Expand Down Expand Up @@ -116,8 +129,8 @@ def _update_info(self, ready_data: dict):
self.bot = user['bot']
self.username = user['username']

def _logged_in(self, ready_data: dict):
self.logged_in = True
def _on_ready(self, ready_data: dict):
self._state = ClientState.READY
self._update_info(ready_data)
self._spawn_heartbeat()

Expand Down Expand Up @@ -190,22 +203,24 @@ def reply_channel_message(self, message:dict, content: str, image: str = None):
async def handle(self, message: dict):
op = message['op']
s = message.get('s', -1)
if s > -1:
if self._state == ClientState.READY and s > -1:
self.s = s
if op == 10:
self._log.debug('QQ says hello.')
if not self.logged_in:
if self._state == ClientState.INIT:
await self.try_login()
elif self._state == ClientState.RECONNECT:
await self.reconnect()
elif op == 7:
self._log.debug('QQ requires reconnect.')
await self.reconnect()
self._state = ClientState.RECONNECT
elif op == 0:
t = message['t']
if t == 'READY':
if not self.logged_in:
self._logged_in(message['d'])
self._log.info('%s logged in.', self)
self._on_ready(message['d'])
self._log.info('%s is ready.', self)
elif t == "RESUMED":
self._state = ClientState.READY
self._log.info('%s resumed.', self)
elif t in self._subscriptions:
for func in self._subscriptions[t]:
Expand Down
4 changes: 4 additions & 0 deletions qqbot/consts.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,7 @@ class IntentOffset(Enum):
for vv in v:
EVENT_INTENT[vv] = k

class ClientState(Enum):
INIT = 0
READY = 1
RECONNECT = 2
13 changes: 3 additions & 10 deletions qqbot/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,13 @@
with open("config.yaml", "r", encoding='utf-8') as f:
BOT_CONFIG = yaml.load(f, Loader=yaml.FullLoader)

async def handler(websocket):
Q = QQBot(BOT_CONFIG, websocket)
Q.subscribe(events)
async for message in websocket:
jdata = json.loads(message)
await Q.handle(jdata)


async def main():
while True:
try:
_log.info("=== OtterBot QQ Bot v0.0.0.1 ===")
async with websockets.connect("wss://api.sgroup.qq.com/websocket/") as ws:
await handler(ws)
Q = QQBot(BOT_CONFIG)
Q.subscribe(events)
await Q.run()
except Exception as e:
_log.error(e)
traceback.print_exc()
Expand Down

0 comments on commit 6f7d9d5

Please sign in to comment.