|
1 | 1 | import asyncio |
2 | 2 | import base64 |
3 | 3 | import datetime |
4 | | -import io |
5 | | -import itertools |
6 | 4 | import json |
7 | 5 | import logging |
8 | 6 | import struct |
@@ -61,29 +59,42 @@ class FramedBuffer: |
61 | 59 | def __init__(self, loop=None): |
62 | 60 | self.q = asyncio.Queue(loop=loop) |
63 | 61 | self.header = None |
| 62 | + self.framebuffer = bytearray() |
64 | 63 | self.bb = bytearray() |
65 | 64 | self.current_frame = None |
66 | 65 | self.to_read = 0 |
67 | 66 |
|
68 | 67 | async def put(self, data): |
| 68 | + logger.debug("put: %s ... %s", data[:16], data[-16:]) |
69 | 69 | if not self.to_read: |
70 | 70 | return await self.handle_frame(data) |
71 | 71 | await self.consume(data) |
72 | 72 |
|
73 | 73 | async def handle_frame(self, data): |
74 | | - self.current_frame, rest = Frame.from_data(data) |
| 74 | + try: |
| 75 | + self.framebuffer += data |
| 76 | + frame, rest = Frame.from_data(self.framebuffer) |
| 77 | + except struct.error: |
| 78 | + return # We don't have enough data yet |
| 79 | + else: |
| 80 | + self.framebuffer = bytearray() |
75 | 81 |
|
76 | | - if self.current_frame.type not in Frame.Types: |
| 82 | + if frame.type not in Frame.Types: |
77 | 83 | raise Exception("Unknown Frame Type") |
78 | 84 |
|
| 85 | + self.current_frame = frame |
79 | 86 | self.to_read = self.current_frame.length |
80 | 87 | await self.consume(rest) |
81 | 88 |
|
82 | 89 | async def consume(self, data): |
| 90 | + logger.debug("consuming %d bytes; to_read = %d bytes", len(data), self.to_read) |
| 91 | + data, rest = data[:self.to_read], data[self.to_read:] |
83 | 92 | self.to_read -= len(data) |
84 | 93 | self.bb += data |
85 | 94 | if self.to_read == 0: |
86 | 95 | await self.finish() |
| 96 | + if rest: |
| 97 | + await self.handle_frame(rest) |
87 | 98 |
|
88 | 99 | async def finish(self): |
89 | 100 | if self.current_frame.type == Frame.Types.HEADER: |
@@ -124,6 +135,9 @@ def __init__(self, type_, version, length, msg_id, id_): |
124 | 135 | self.msg_id = msg_id |
125 | 136 | self.id = id_ |
126 | 137 |
|
| 138 | + def __repr__(self): |
| 139 | + return f"Frame({self.type}, {self.version}, {self.length}, {self.msg_id}, {self.id})" |
| 140 | + |
127 | 141 | def serialize(self): |
128 | 142 | return self.fmt.pack( |
129 | 143 | bytes([self.type]), bytes([self.version]), |
@@ -158,58 +172,6 @@ def join_uuid(hi, lo): |
158 | 172 | return (hi << 64) | lo |
159 | 173 |
|
160 | 174 |
|
161 | | -def glue(header, payload): |
162 | | - hf = Frame.wrap(header, type_=Frame.Types.HEADER) |
163 | | - pf = Frame.wrap(payload, msg_id=hf.msg_id) |
164 | | - return hf.serialize() + header + pf.serialize() + payload |
165 | | - |
166 | | - |
167 | | -def gen_chunks(data, header, msg_id=None, chunksize=2 ** 8): |
168 | | - if msg_id is None: |
169 | | - msg_id = uuid.uuid4().int |
170 | | - seq = itertools.count() |
171 | | - buf = bytearray(chunksize) |
172 | | - bv = memoryview(buf) |
173 | | - header = json.dumps(header).encode("utf-8") |
174 | | - yield Frame(Frame.Types.HEADER, 1, len(header), msg_id, next(seq)).serialize() + header |
175 | | - yield Frame(Frame.Types.PAYLOAD, 1, len(data), msg_id, next(seq)).serialize() |
176 | | - buffer = io.BytesIO(data) |
177 | | - bytes_read = buffer.readinto(buf) |
178 | | - while bytes_read: |
179 | | - if bytes_read == chunksize: |
180 | | - yield bv.tobytes() |
181 | | - else: |
182 | | - yield bv[:bytes_read].tobytes() |
183 | | - bytes_read = buffer.readinto(buf) |
184 | | - |
185 | | - |
186 | | -class OuterEnvelope: |
187 | | - def __init__(self, frame_id, sender, recipient, route_list, inner): |
188 | | - self.frame_id = frame_id |
189 | | - self.sender = sender |
190 | | - self.recipient = recipient |
191 | | - self.route_list = route_list |
192 | | - self.inner = inner |
193 | | - self.inner_obj = None |
194 | | - |
195 | | - async def deserialize_inner(self, receptor): |
196 | | - self.inner_obj = await Inner.deserialize(receptor, self.inner) |
197 | | - |
198 | | - @classmethod |
199 | | - def from_raw(cls, raw): |
200 | | - doc = json.loads(raw) |
201 | | - return cls(**doc) |
202 | | - |
203 | | - def serialize(self): |
204 | | - return json.dumps(dict( |
205 | | - frame_id=self.frame_id, |
206 | | - sender=self.sender, |
207 | | - recipient=self.recipient, |
208 | | - route_list=self.route_list, |
209 | | - inner=self.inner |
210 | | - )) |
211 | | - |
212 | | - |
213 | 175 | class Inner: |
214 | 176 | def __init__(self, receptor, message_id, sender, recipient, message_type, timestamp, |
215 | 177 | raw_payload, directive=None, in_response_to=None, ttl=None, serial=1, |
|
0 commit comments