typing
This commit is contained in:
parent
41b1579785
commit
5f49cd7f46
@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="SqlDialectMappings">
|
||||
<file url="file://$PROJECT_DIR$/report.sql" dialect="GenericSQL" />
|
||||
<file url="PROJECT" dialect="SQLite" />
|
||||
</component>
|
||||
</project>
|
@ -1,4 +1,5 @@
|
||||
import json
|
||||
from contextlib import closing
|
||||
from subprocess import run
|
||||
from sys import stderr
|
||||
from threading import Thread
|
||||
@ -145,6 +146,43 @@ class PushState(Base):
|
||||
return True
|
||||
|
||||
|
||||
class TypingState(Base):
|
||||
__tablename__ = 'typingstate'
|
||||
|
||||
sf = Column(LargeBinary(crypto_sign_PUBLICKEYBYTES), primary_key=True)
|
||||
st = Column(LargeBinary(crypto_sign_PUBLICKEYBYTES), primary_key=True)
|
||||
last = Column(REAL)
|
||||
|
||||
@classmethod
|
||||
def _get(cls, sfrom: Subject, sto: Subject, session) -> Tuple['TypingState', 'TypingState']:
|
||||
sf = sfrom.vkey.encode()
|
||||
st = sto.vkey.encode()
|
||||
try:
|
||||
statef = session.query(TypingState).filter_by(sf=sf, st=st).one()
|
||||
except NoResultFound:
|
||||
statef = TypingState(sf=sf, st=st, last=0)
|
||||
session.add(statef)
|
||||
try:
|
||||
statet = session.query(TypingState).filter_by(sf=st, st=sf).one()
|
||||
except NoResultFound:
|
||||
statet = TypingState(sf=st, st=sf, last=0)
|
||||
session.add(statet)
|
||||
return statef, statet
|
||||
|
||||
@classmethod
|
||||
def typing(cls, sfrom: Subject, sto: Subject, last: float, session) -> float:
|
||||
statef, statet = cls._get(sfrom, sto, session)
|
||||
statef.last = max(statef.last, last)
|
||||
session.commit()
|
||||
return statet.last
|
||||
|
||||
@classmethod
|
||||
def reset(cls, m: Message, session):
|
||||
statef, _ = cls._get(m.sfrom, m.sto, session)
|
||||
statef.last = 0
|
||||
session.commit()
|
||||
|
||||
|
||||
class DBStorage(PushStorage):
|
||||
def __init__(self, *args):
|
||||
self.args = args
|
||||
@ -153,8 +191,7 @@ class DBStorage(PushStorage):
|
||||
self.Session = sessionmaker(bind=self.engine)
|
||||
|
||||
def check(self, subject: Subject) -> dict:
|
||||
session = self.Session()
|
||||
try:
|
||||
with closing(self.Session()) as session:
|
||||
sssj = session.query(SSSJ).filter_by(subject=subject.vkey.encode()).one_or_none()
|
||||
status = json.loads(sssj.status) if sssj else {}
|
||||
if 'contacts' in status:
|
||||
@ -169,29 +206,23 @@ class DBStorage(PushStorage):
|
||||
contacts.add(st)
|
||||
status['contacts'] = list(map(Encoding.encode, contacts))
|
||||
return status
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
def push(self, m: Message) -> None:
|
||||
session = self.Session()
|
||||
try:
|
||||
with closing(self.Session()) as session:
|
||||
msg = Msg.from_message(m)
|
||||
session.add(msg)
|
||||
session.add(msg.sgn())
|
||||
self.event(session, m, EVENT_PUSH)
|
||||
session.commit()
|
||||
if m.sfrom == m.sto:
|
||||
return
|
||||
state = PushState.of(m.sto, session)
|
||||
state.pushmsg = True
|
||||
session.commit()
|
||||
finally:
|
||||
session.close()
|
||||
if m.sfrom != m.sto:
|
||||
state = PushState.of(m.sto, session)
|
||||
state.pushmsg = True
|
||||
session.commit()
|
||||
TypingState.reset(m, session)
|
||||
|
||||
def edit(self, old: Message, new: Message):
|
||||
assert old.edited(new), 'edit misuse'
|
||||
session = self.Session()
|
||||
try:
|
||||
with closing(self.Session()) as session:
|
||||
msg = self.one_alike(session, old)
|
||||
assert msg.en == old.editnonce, 'edit misuse'
|
||||
msgn = Msg.from_message(new)
|
||||
@ -200,27 +231,22 @@ class DBStorage(PushStorage):
|
||||
msg.flags = msgn.flags
|
||||
self.event(session, new, EVENT_EDIT)
|
||||
session.commit()
|
||||
finally:
|
||||
session.close()
|
||||
TypingState.reset(new, session)
|
||||
|
||||
@staticmethod
|
||||
def one_alike(session, m: Message) -> Msg:
|
||||
return session.query(Msg).filter_by(sf=m.sfrom.vkey.encode(), st=m.sto.vkey.encode(), idn=m.idnonce).one()
|
||||
|
||||
def delete(self, m: Message):
|
||||
session = self.Session()
|
||||
try:
|
||||
with closing(self.Session()) as session:
|
||||
session.delete(self.one_alike(session, m))
|
||||
self.event(session, m, EVENT_DELETE)
|
||||
session.commit()
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
def pull(self, pair: Tuple[Subject, Subject], params: Optional[dict] = None) -> Iterable[Message]:
|
||||
if params is None:
|
||||
params = {}
|
||||
session = self.Session()
|
||||
try:
|
||||
with closing(self.Session()) as session:
|
||||
cquery: Query = session.query(Msg).filter(or_(
|
||||
and_(
|
||||
Msg.sf == pair[0].vkey.encode(),
|
||||
@ -249,39 +275,28 @@ class DBStorage(PushStorage):
|
||||
if 'limit' in params:
|
||||
query = query.limit(params['limit'])
|
||||
return map(Msg.to_message, list(query.from_self().order_by(Msg.oid)))
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
def flags(self, m: Message, flags: str):
|
||||
assert not Flags(flags).quable(), 'flags misuse'
|
||||
session = self.Session()
|
||||
try:
|
||||
with closing(self.Session()) as session:
|
||||
msg: Msg = self.one_alike(session, m)
|
||||
assert msg.en == m.editnonce, 'flags misuse'
|
||||
assert Flags(msg.flags).quable(), 'flags misuse'
|
||||
msg.flags = flags
|
||||
session.commit()
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
def clearsssj(self):
|
||||
session = self.Session()
|
||||
try:
|
||||
with closing(self.Session()) as session:
|
||||
session.query(SSSJ).delete()
|
||||
session.commit()
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
def ssssj(self, subject: str, status: str):
|
||||
"""set SSSJ"""
|
||||
session = self.Session()
|
||||
try:
|
||||
with closing(self.Session()) as session:
|
||||
subject = Subject(Encoding.decode(subject)).vkey.encode()
|
||||
session.query(SSSJ).filter_by(subject=subject).delete()
|
||||
session.add(SSSJ(subject=subject, status=status))
|
||||
session.commit()
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
@staticmethod
|
||||
def event(session, m: Message, code: int):
|
||||
@ -294,8 +309,7 @@ class DBStorage(PushStorage):
|
||||
return query.filter_by(en=en).one()
|
||||
|
||||
def events(self, sfrom: Subject, sto: Subject, after: Optional[bytes]) -> Iterable[Tuple[bytes, bytes]]:
|
||||
session = self.Session()
|
||||
try:
|
||||
with closing(self.Session()) as session:
|
||||
PushState.of(sto, session).online()
|
||||
session.commit()
|
||||
query: Query = session.query(MsgEvent)
|
||||
@ -308,37 +322,26 @@ class DBStorage(PushStorage):
|
||||
query = query.order_by(MsgEvent.oid)
|
||||
ev: MsgEvent
|
||||
return [(ev.en, ev.idn) for ev in query.all()]
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
def cleanevents(self):
|
||||
session = self.Session()
|
||||
try:
|
||||
with closing(self.Session()) as session:
|
||||
session.query(MsgEvent).delete(MsgEvent.ts < time() - 604800)
|
||||
session.commit()
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
def subscribe(self, subject: Subject, subscription: dict):
|
||||
session = self.Session()
|
||||
try:
|
||||
with closing(self.Session()) as session:
|
||||
subject = subject.vkey.encode()
|
||||
session.query(PushSub).filter_by(subject=subject).delete()
|
||||
session.add(PushSub(subject=subject, subscription=json.dumps(subscription)))
|
||||
session.commit()
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
def subscription(self, subject: Subject) -> Optional[dict]:
|
||||
session = self.Session()
|
||||
try:
|
||||
with closing(self.Session()) as session:
|
||||
subscription: Optional[PushSub] = session.query(PushSub).filter_by(
|
||||
subject=subject.vkey.encode()).one_or_none()
|
||||
if subscription is None:
|
||||
return None
|
||||
return json.loads(subscription.subscription)
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
@staticmethod
|
||||
def pushsubscription(subscription: dict):
|
||||
@ -353,23 +356,17 @@ class DBStorage(PushStorage):
|
||||
}), encoding='utf-8').returncode, "push subprocess failed"
|
||||
|
||||
def pushpush(self, subject: Subject):
|
||||
session = self.Session()
|
||||
try:
|
||||
with closing(self.Session()) as session:
|
||||
notify = PushState.of(subject, session).notify()
|
||||
session.commit()
|
||||
finally:
|
||||
session.close()
|
||||
if notify:
|
||||
subscription = self.subscription(subject)
|
||||
if subscription:
|
||||
self.pushsubscription(subscription)
|
||||
|
||||
def push_once(self):
|
||||
session = self.Session()
|
||||
try:
|
||||
with closing(self.Session()) as session:
|
||||
subs: List[PushSub] = session.query(PushSub).all()
|
||||
finally:
|
||||
session.close()
|
||||
for sub in subs:
|
||||
try:
|
||||
self.pushpush(Subject(sub.subject))
|
||||
@ -391,3 +388,7 @@ class DBStorage(PushStorage):
|
||||
def pushing(self):
|
||||
self.push_forever()
|
||||
return self
|
||||
|
||||
def typing(self, sfrom: Subject, sto: Subject, last: float) -> float:
|
||||
with closing(self.Session()) as session:
|
||||
return TypingState.typing(sfrom, sto, last, session)
|
||||
|
@ -44,3 +44,7 @@ class SecureStorage(PushStorage):
|
||||
def subscribe(self, subject: Subject, subscription: dict):
|
||||
assert self.subject == subject, self.asrt()
|
||||
return self.storage.subscribe(subject, subscription)
|
||||
|
||||
def typing(self, sfrom: Subject, sto: Subject, last: float) -> float:
|
||||
assert self.subject == sfrom, self.asrt()
|
||||
return self.storage.typing(sfrom, sto, last)
|
||||
|
@ -29,6 +29,9 @@ class EventStorage(AbstractStorage, ABC):
|
||||
def events(self, sfrom: Subject, sto: Subject, after: Optional[bytes]) -> Iterable[Tuple[bytes, bytes]]:
|
||||
raise NotImplementedError
|
||||
|
||||
def typing(self, sfrom: Subject, sto: Subject, last: float) -> float:
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
EVENT_PUSH = 0
|
||||
EVENT_EDIT = 1
|
||||
|
@ -80,3 +80,11 @@ class API(Flask):
|
||||
def subscribe():
|
||||
return self.nomessassertcall(lambda d, storage: storage.subscribe(Subject.loads(d['subject']),
|
||||
d['subscription']))
|
||||
|
||||
@app.route('/typing', methods=['POST'])
|
||||
def typing():
|
||||
return self.nomessassertcall(lambda d, storage: storage.typing(
|
||||
Subject.loads(d['sfrom']),
|
||||
Subject.loads(d['sto']),
|
||||
d['last']
|
||||
))
|
||||
|
Loading…
Reference in New Issue
Block a user