and some untested `exact` and `flag` code also
This commit is contained in:
AF 2021-12-22 13:30:05 +03:00
parent 5f49cd7f46
commit da1d9a23d6
7 changed files with 46 additions and 19 deletions

View File

@ -1,2 +1,3 @@
# v25 # v25
replace public keys in `dev-config.json` and `staging-config.json` with your own to allow messaging

View File

@ -1,6 +1,6 @@
__all__ = ('Flags',) import nacl.hash
Q_FLAG = '<?>' __all__ = ('Flags',)
class Flags: class Flags:
@ -9,14 +9,17 @@ class Flags:
def __init__(self, flags: str): def __init__(self, flags: str):
self.flags: str = flags self.flags: str = flags
def quable(self) -> bool: def hash(self):
return Q_FLAG in self.flags return nacl.hash.sha256(self.flags.encode()).decode()
def deq(self) -> str: def joint(self, flags: str):
return Flags(self.flags.replace(Q_FLAG, '')).deq() if self.quable() else self.flags return flags.startswith(self.hash())
def enq(self) -> str: def join(self, flags: str):
return self.flags if self.quable() else self.flags + Q_FLAG h = self.hash()
if flags.startswith(h):
return flags
return h + flags
Flags.default = Flags('<unedited>').enq() Flags.default = '<unedited>'

View File

@ -95,7 +95,7 @@ class Message:
def edit(self, pcontent: bytes) -> 'Message': def edit(self, pcontent: bytes) -> 'Message':
return Message(self.sfrom, self.sto, self.idnonce, None, return Message(self.sfrom, self.sto, self.idnonce, None,
Encoding.nonce(), pcontent, None, Encoding.nonce(), pcontent, None,
Flags(self.flags.replace('<unedited>', '<edited>')).enq()).sealed() self.flags.replace('<unedited>', '<edited>')).sealed()
def edit_(self): def edit_(self):
return self.flags_(self.flags) return self.flags_(self.flags)

View File

@ -258,30 +258,36 @@ class DBStorage(PushStorage):
), ),
)) ))
query: Query = cquery query: Query = cquery
if 'ts' in params:
if '>' in params:
query = query.filter(Msg.ts > params['ts']['>'])
if '<' in params:
query = query.filter(Msg.ts < params['ts']['<'])
if params.get('before'): if params.get('before'):
query = query.filter(Msg.oid < cquery.filter(Msg.idn == Encoding.decode(params['before'])).one().oid) query = query.filter(Msg.oid < cquery.filter(Msg.idn == Encoding.decode(params['before'])).one().oid)
if params.get('after'): if params.get('after'):
query = query.filter(Msg.oid > cquery.filter(Msg.idn == Encoding.decode(params['after'])).one().oid) query = query.filter(Msg.oid > cquery.filter(Msg.idn == Encoding.decode(params['after'])).one().oid)
if params.get('exact'): if params.get('exact'):
query = query.filter_by(idn=Encoding.decode(params['exact'])) query = query.filter_by(idn=Encoding.decode(params['exact']), sf=pair[0].vkey.encode())
for flag in params.get('flags', ()): for flag in params.get('flags', ()):
query = query.filter(Msg.flags.contains(flag)) query = query.filter(Msg.flags.contains(flag))
query = query.order_by(Msg.oid.desc()) query = query.order_by(Msg.oid.desc())
if 'limit' in params: if 'limit' in params:
query = query.limit(params['limit']) query = query.limit(params['limit'])
return map(Msg.to_message, list(query.from_self().order_by(Msg.oid))) res = map(Msg.to_message, list(query.from_self().order_by(Msg.oid)))
if 'edit_' in params:
res = (m.edit_() for m in res)
return res
def exact(self, sfrom: Subject, sto: Subject, idnonce: bytes, editnonce: Optional[bytes]) -> Optional[Message]:
with closing(self.Session()) as session:
query: Query = session.query(Msg)
query = query.filter_by(sf=sfrom, st=sto, idn=idnonce)
if editnonce:
query = query.filter_by(en=editnonce)
msg: Optional[Msg] = query.one_or_none()
return msg or msg.to_message()
def flags(self, m: Message, flags: str): def flags(self, m: Message, flags: str):
assert not Flags(flags).quable(), 'flags misuse'
with closing(self.Session()) as session: with closing(self.Session()) as session:
msg: Msg = self.one_alike(session, m) msg: Msg = self.one_alike(session, m)
assert msg.en == m.editnonce, 'flags misuse' assert msg.en == m.editnonce, 'flags misuse'
assert Flags(msg.flags).quable(), 'flags misuse' assert Flags(msg.flags).joint(flags)
msg.flags = flags msg.flags = flags
session.commit() session.commit()

View File

@ -33,6 +33,10 @@ class SecureStorage(PushStorage):
assert self.subject in pair, self.asrt() assert self.subject in pair, self.asrt()
return self.storage.pull(pair, params) return self.storage.pull(pair, params)
def exact(self, sfrom: Subject, sto: Subject, idnonce: bytes, editnonce: Optional[bytes]) -> Optional[Message]:
assert self.subject in (sfrom, sto)
return self.storage.exact(sfrom, sto, idnonce, editnonce)
def flags(self, m: Message, flags: str): def flags(self, m: Message, flags: str):
assert self.subject in m.pair, self.asrt() assert self.subject in m.pair, self.asrt()
return self.storage.flags(m, flags) return self.storage.flags(m, flags)

View File

@ -21,6 +21,9 @@ class AbstractStorage(ABC):
def pull(self, pair: Tuple[Subject, Subject], params: Optional[dict] = None) -> Iterable[Message]: def pull(self, pair: Tuple[Subject, Subject], params: Optional[dict] = None) -> Iterable[Message]:
raise NotImplementedError raise NotImplementedError
def exact(self, sfrom: Subject, sto: Subject, idnonce: bytes, editnonce: Optional[bytes]) -> Optional[Message]:
raise NotImplementedError
def flags(self, m: Message, flags: str): def flags(self, m: Message, flags: str):
raise NotImplementedError raise NotImplementedError

View File

@ -42,6 +42,9 @@ class RemoteStorage(PushStorage):
return map(Message.loads, return map(Message.loads,
self.req('pull', {'params': params, 'pair': [subject.dumps() for subject in pair]})) self.req('pull', {'params': params, 'pair': [subject.dumps() for subject in pair]}))
def exact(self, sfrom: Subject, sto: Subject, idnonce: bytes, editnonce: Optional[bytes]) -> Optional[Message]:
raise NotImplementedError
def flags(self, m: Message, flags: str): def flags(self, m: Message, flags: str):
self.req('flags', {'m': m.dumps(), 'flags': flags}) self.req('flags', {'m': m.dumps(), 'flags': flags})
@ -50,6 +53,13 @@ class RemoteStorage(PushStorage):
self.req('events', {'sfrom': sfrom.dumps(), 'sto': sto.dumps(), self.req('events', {'sfrom': sfrom.dumps(), 'sto': sto.dumps(),
'after': Encoding.encode(after)})] 'after': Encoding.encode(after)})]
def typing(self, sfrom: Subject, sto: Subject, last: float) -> float:
return self.req('typing', {
'sfrom': sfrom.dumps(),
'sto': sto.dumps(),
'last': last
})
def subscribe(self, subject: Subject, subscription: dict): def subscribe(self, subject: Subject, subscription: dict):
self.req('subscribe', { self.req('subscribe', {
'subject': subject.dumps(), 'subject': subject.dumps(),