Files
core/src/session/session.py
FoxVoland c16ed7915a [+!] all but small
some small modifications, tests added
2026-10-07 22:42:46 +03:00

144 lines
4.5 KiB
Python

from time import monotonic as now
import asyncio
from .versions import VERSION
class Session:
def __init__(self, uid, connection, on_timeout):
self.uid = uid
self.connection = connection
self.timeout = now() + 60 #TODO move timeout to env
self.watcher_task = asyncio.create_task(self.watch(on_timeout))
self.state = "new"
self.err_count = 0
self.timeout_attempt = 0
self.upf = hash(now())
self.pv = "v1" #default protocol version
self.static_meta = {
# "name" : "unnamed",
# "type" : "unknown",
# "in" : set(),
# "out" : set(),
}
self.dynamic_meta = {
# "active_in" : set()
# "active_out" : set()
}
self.last_data = {}
async def feed (self, package):
'''
package here is hust a dict with dialect
we meet here to solve the dialect
'''
com = package.get(VERSION[self.pv]["COMMAND"])
data = package.get(VERSION[self.pv]["PAYLOAD"])
if com is None : return {"type" : "disconnect"} #BAN
if self.state == "new" and com == VERSION[self.pv]["CONNECT"]:
...
#TODO
#process new connection? auth? get and fill some data
self.static_meta["name"] = data.get("name", "unnamed")
self.static_meta["type"] = data.get("type", "unknown")
self.static_meta["in"] = set(data.get("in", []))
self.dynamic_meta["active_in"] = set()
self.static_meta["out"] = set(data.get("out", []))
self.dynamic_meta["active_out"] = set()
self.static_meta["com"] = set(data.get("com", []))
self.static_meta["auth"] = data.get("token")
self.state = "token"
self.send({VERSION[self.pv]["COMMAND"] : VERSION[self.pv]["TOKEN_ASK"],
VERSION[self.pv]["PAYLOAD"] : self.uid,
VERSION[self.pv]["UPF"] : self.upf})
return
if self.state == "token" and com == VERSION[self.pv]["TOKEN_ANS"]:
self.state = "ready"
self.send({VERSION[self.pv]["COMMAND"] : VERSION[self.pv]["HANDSHAKE_ASK"]})
old_token = data.get(VERSION[self.pv]["TOKEN"])
old_upf = data.get(VERSION[self.pv]["UPF"])
if old_token and old_upf:
return {"type" : "reconnect",
"uid" : old_token,
"upf" : old_upf}
return
if self.state == "ready" and com == VERSION[self.pv]["HANDSHAKE_ANS"]:
if not data.get(VERSION[self.pv]["STATUS"]):
if self.timeout_attempt == 5 : return {"type" : "disconnect"}
self.timeout_attempt += 1
await asyncio.sleep(self.timeout_attempt)
self.send({VERSION[self.pv]["COMMAND"] : VERSION[self.pv]["HANDSHAKE_ASK"]})
return {"type" : "await handshake", "state" : data.get(VERSION[self.pv]["STATE"])}
self.state = "air"
return {"type" : "connect", "uid" : self.uid}
if self.state == "air":
data = package[VERSION[self.pv]["PAYLOAD"]]
if com == VERSION[self.pv]["HEARTBEAT_ASK"]:
#TODO update deadline
self.timeout = now() + 5 #TODO move to env
self.send({VERSION[self.pv]["COMMAND"] : VERSION[self.pv]["HEARTBEAT_ANS"]})
return
self.update(com, data)
return {"type" : "data", "data" : com}
self.err_count += 1
if self.err_count == 5 : return {"type" : "disconnect"} #BAN
async def watch(self, on_timeout):
while self.state not in {"stop", "migrated"}:
await asyncio.sleep(1)
if self.state in {"stop", "migrated"}:
return
if now() >= self.timeout:
await on_timeout(
self.uid,
{"type": "disconnect"},
)
return
def update(self, command, data):
self.last_data[command] = data
def send(self, package):
#TODO
#decide if we want dialect pack here or not
if self.state in {"stop", "migrated"} : return
asyncio.create_task( self.connection.send(package) )
async def stop(self):
self.state = "stop"
await self.connection.close()