Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor sniff to be in kering instead of Parser class method. This i… #687

Merged
merged 1 commit into from
Feb 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/keri/app/httping.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ def streamCESRRequests(client, ims, dest, path=None):
"""
path = path if path is not None else "/"

cold = parsing.Parser.sniff(ims) # check for spurious counters at front of stream
cold = kering.sniff(ims) # check for spurious counters at front of stream
if cold in (parsing.Colds.txt, parsing.Colds.bny): # not message error out to flush stream
# replace with pipelining here once CESR message format supported.
raise kering.ColdStartError("Expecting message counter tritet={}"
Expand Down
95 changes: 5 additions & 90 deletions src/keri/core/parsing.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,58 +15,11 @@
from . import serdering
from .. import help
from .. import kering
from ..kering import ColdDex, Colds, sniff

logger = help.ogler.getLogger()


@dataclass(frozen=True)
class ColdCodex:
"""
ColdCodex is codex of cold stream start tritets of first byte
Only provide defined codes.
Undefined are left out so that inclusion(exclusion) via 'in' operator works.

First three bits:
0o0 = 000 free
0o1 = 001 cntcode B64
0o2 = 010 opcode B64
0o3 = 011 json
0o4 = 100 mgpk
0o5 = 101 cbor
0o6 = 110 mgpk
007 = 111 cntcode or opcode B2

status is one of ('evt', 'txt', 'bny' )
'evt' if tritet in (ColdDex.JSON, ColdDex.MGPK1, ColdDex.CBOR, ColdDex.MGPK2)
'txt' if tritet in (ColdDex.CtB64, ColdDex.OpB64)
'bny' if tritet in (ColdDex.CtOpB2,)

otherwise raise ColdStartError

x = bytearray([0x2d, 0x5f])
x == bytearray(b'-_')
x[0] >> 5 == 0o1
True
"""
Free: int = 0o0 # not taken
CtB64: int = 0o1 # CountCode Base64
OpB64: int = 0o2 # OpCode Base64
JSON: int = 0o3 # JSON Map Event Start
MGPK1: int = 0o4 # MGPK Fixed Map Event Start
CBOR: int = 0o5 # CBOR Map Event Start
MGPK2: int = 0o6 # MGPK Big 16 or 32 Map Event Start
CtOpB2: int = 0o7 # CountCode or OpCode Base2

def __iter__(self):
return iter(astuple(self))


ColdDex = ColdCodex() # Make instance

Coldage = namedtuple("Coldage", 'msg txt bny') # stream cold start status
Colds = Coldage(msg='msg', txt='txt', bny='bny')


class Parser:
"""
Parser is stream parser that processes an incoming message stream.
Expand Down Expand Up @@ -126,45 +79,7 @@ def __init__(self, ims=None, framed=True, pipeline=False, kvy=None,
self.vry = vry
self.local = True if local else False

@staticmethod
def sniff(ims):
"""
Returns status string of cold start of stream ims bytearray by looking
at first triplet of first byte to determin if message or counter code
and if counter code whether Base64 or Base2 representation

First three bits:
0o0 = 000 free
0o1 = 001 cntcode B64
0o2 = 010 opcode B64
0o3 = 011 json
0o4 = 100 mgpk
0o5 = 101 cbor
0o6 = 110 mgpk
007 = 111 cntcode or opcode B2

counter B64 in (0o1, 0o2) return 'txt'
counter B2 in (0o7) return 'bny'
event in (0o3, 0o4, 0o5, 0o6) return 'evt'
unexpected in (0o0) raise ColdStartError
Colds = Coldage(msg='msg', txt='txt', bny='bny')

'msg' if tritet in (ColdDex.JSON, ColdDex.MGPK1, ColdDex.CBOR, ColdDex.MGPK2)
'txt' if tritet in (ColdDex.CtB64, ColdDex.OpB64)
'bny' if tritet in (ColdDex.CtOpB2,)
"""
if not ims:
raise kering.ShortageError("Need more bytes.")

tritet = ims[0] >> 5
if tritet in (ColdDex.JSON, ColdDex.MGPK1, ColdDex.CBOR, ColdDex.MGPK2):
return Colds.msg
if tritet in (ColdDex.CtB64, ColdDex.OpB64):
return Colds.txt
if tritet in (ColdDex.CtOpB2,):
return Colds.bny

raise kering.ColdStartError("Unexpected tritet={} at stream start.".format(tritet))

@staticmethod
def extract(ims, klas, cold=Colds.txt):
Expand Down Expand Up @@ -770,7 +685,7 @@ def msgParsator(self, ims=None, framed=True, pipeline=False,
while not ims:
yield

cold = self.sniff(ims) # check for spurious counters at front of stream
cold = sniff(ims) # check for spurious counters at front of stream
if cold in (Colds.txt, Colds.bny): # not message error out to flush stream
# replace with pipelining here once CESR message format supported.
raise kering.ColdStartError("Expecting message counter tritet={}"
Expand Down Expand Up @@ -811,7 +726,7 @@ def msgParsator(self, ims=None, framed=True, pipeline=False,
# extract attachments must start with counter so know if txt or bny.
while not ims:
yield
cold = self.sniff(ims) # expect counter at front of attachments
cold = sniff(ims) # expect counter at front of attachments
if cold != Colds.msg: # not new message so process attachments
ctr = yield from self._extractor(ims=ims, klas=Counter, cold=cold)
if ctr.code == CtrDex.AttachedMaterialQuadlets: # pipeline ctr?
Expand Down Expand Up @@ -1036,15 +951,15 @@ def msgParsator(self, ims=None, framed=True, pipeline=False,
# group may switch stream state txt or bny
if not ims: # end of frame
break
cold = self.sniff(ims)
cold = sniff(ims)
if cold == Colds.msg: # new message so attachments done
break # finished attachments since new message
else: # process until next message
# because not all in one pipeline group, each attachment
# group may switch stream state txt or bny
while not ims:
yield # no frame so must wait for next message
cold = self.sniff(ims) # ctr or msg
cold = sniff(ims) # ctr or msg
if cold == Colds.msg: # new message
break # finished attachments since new message

Expand Down
119 changes: 81 additions & 38 deletions src/keri/kering.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import sys
import re
from collections import namedtuple

from dataclasses import dataclass, astuple

FALSEY = (False, 0, None, "?0", "no", "false", "False", "off")
TRUTHY = (True, 1, "?1", "yes" "true", "True", 'on')
Expand Down Expand Up @@ -93,21 +93,9 @@ def deversify(vs, version=None):
raise ValueError("Invalid version string = {}".format(vs))



MAXVSOFFSET = 12
SMELLSIZE = MAXVSOFFSET + VERFULLSIZE # min buffer size to inhale

#"""
#Smellage (results of smelling a version string such as in a Serder)
#proto (str): protocol type value of Protos examples 'KERI', 'ACDC'
#major (str): single char hex string of major version number
#minor (str): single char hex string of minor version number
#kind (str): serialization value of Serials examples 'JSON', 'CBOR', 'MGPK'
#size (str): hex string of size of raw serialization

#"""
#Smellage = namedtuple("Smellage", "proto major minor kind size")

"""
Smellage (results of smelling a version string such as in a Serder)
protocol (str): protocol type value of Protos examples 'KERI', 'ACDC'
Expand Down Expand Up @@ -170,38 +158,93 @@ def smell(raw, *, version=None):
return Smellage(protocol=protocol, version=vrsn, kind=kind, size=size)


def smelly(raw, *, version=None):
"""Extract and return instance of Smellage from version string inside
raw serialization.
@dataclass(frozen=True)
class ColdCodex:
"""
ColdCodex is codex of cold stream start tritets of first byte
Only provide defined codes.
Undefined are left out so that inclusion(exclusion) via 'in' operator works.

Returns:
smellage (Smellage): named Tuple of (protocol, version, kind, size)
First three bits:
0o0 = 000 free
0o1 = 001 cntcode B64
0o2 = 010 opcode B64
0o3 = 011 json
0o4 = 100 mgpk
0o5 = 101 cbor
0o6 = 110 mgpk
007 = 111 cntcode or opcode B2

Parameters:
raw (bytearray) of serialized incoming message stream. Assumes start
of stream is JSON, CBOR, or MGPK field map with first field
is labeled 'v' and value is version string.
version (Versionage | None): instance supported protocol version
None means do not enforce a supported version
status is one of ('evt', 'txt', 'bny' )
'evt' if tritet in (ColdDex.JSON, ColdDex.MGPK1, ColdDex.CBOR, ColdDex.MGPK2)
'txt' if tritet in (ColdDex.CtB64, ColdDex.OpB64)
'bny' if tritet in (ColdDex.CtOpB2,)

otherwise raise ColdStartError

x = bytearray([0x2d, 0x5f])
x == bytearray(b'-_')
x[0] >> 5 == 0o1
True
"""
if len(raw) < SMELLSIZE:
raise ShortageError(f"Need more raw bytes to smell full version string.")
Free: int = 0o0 # not taken
CtB64: int = 0o1 # CountCode Base64
OpB64: int = 0o2 # OpCode Base64
JSON: int = 0o3 # JSON Map Event Start
MGPK1: int = 0o4 # MGPK Fixed Map Event Start
CBOR: int = 0o5 # CBOR Map Event Start
MGPK2: int = 0o6 # MGPK Big 16 or 32 Map Event Start
CtOpB2: int = 0o7 # CountCode or OpCode Base2

match = Rever.search(raw) # Rever regex takes bytes/bytearray not str
if not match or match.start() > MAXVSOFFSET:
raise VersionError(f"Invalid version string from smelled raw = "
f"{raw[: SMELLSIZE]}.")
def __iter__(self):
return iter(astuple(self))

smellage = Smellage(*match.group("proto", "major", "minor", "kind", "size"))

# Global version compatibility check. Serder instances also peform version check
vrsn = Versionage(major=int(smellage.major, 16), minor=int(smellage.minor, 16))
if version: # test here for compatible code version with message vrsn
if (vrsn.major > version.major or
(vrsn.major == version.major and vrsn.minor > version.minor)):
pass # raise error here?
ColdDex = ColdCodex() # Make instance

Coldage = namedtuple("Coldage", 'msg txt bny') # stream cold start status
Colds = Coldage(msg='msg', txt='txt', bny='bny')


def sniff(ims):
"""
Returns status string of cold start of stream ims bytearray by looking
at first triplet of first byte to determin if message or counter code
and if counter code whether Base64 or Base2 representation

First three bits:
0o0 = 000 free
0o1 = 001 cntcode B64
0o2 = 010 opcode B64
0o3 = 011 json
0o4 = 100 mgpk
0o5 = 101 cbor
0o6 = 110 mgpk
007 = 111 cntcode or opcode B2

counter B64 in (0o1, 0o2) return 'txt'
counter B2 in (0o7) return 'bny'
event in (0o3, 0o4, 0o5, 0o6) return 'evt'
unexpected in (0o0) raise ColdStartError
Colds = Coldage(msg='msg', txt='txt', bny='bny')

'msg' if tritet in (ColdDex.JSON, ColdDex.MGPK1, ColdDex.CBOR, ColdDex.MGPK2)
'txt' if tritet in (ColdDex.CtB64, ColdDex.OpB64)
'bny' if tritet in (ColdDex.CtOpB2,)
"""
if not ims:
raise ShortageError("Need more bytes.")

tritet = ims[0] >> 5
if tritet in (ColdDex.JSON, ColdDex.MGPK1, ColdDex.CBOR, ColdDex.MGPK2):
return Colds.msg
if tritet in (ColdDex.CtB64, ColdDex.OpB64):
return Colds.txt
if tritet in (ColdDex.CtOpB2,):
return Colds.bny

raise ColdStartError("Unexpected tritet={} at stream start.".format(tritet))

return smellage

"""
ilk is short for packet or message type for a given protocol
Expand Down
Loading