generated from mononoki/pyproj
144 lines
4.5 KiB
Python
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()
|
|
|
|
|