Skip to content

Commit 19938f8

Browse files
authored
Fixed #32 and #33 (#34)
* Fixed #32 and #33
1 parent 7a82874 commit 19938f8

File tree

6 files changed

+71
-3
lines changed

6 files changed

+71
-3
lines changed

README.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
* [join](#join)
3030
* [leave](#leave)
3131
* [emit](#emit)
32+
* [Failed packages](#failed-packages)
3233
---------------------------------------
3334

3435
## Installation
@@ -550,3 +551,27 @@ Emit an event to a room.
550551
Future which should be awaited. The result of the future will
551552
be set to `None` when successful.
552553

554+
555+
## Failed packages
556+
557+
```python
558+
set_package_fail_file(fn: str = '') -> None
559+
```
560+
561+
Configure a file name to dump the last failed package.
562+
563+
Only the MessagePack data will be stored in this file, not the package
564+
header. This is useful for debugging packages which fail to unpack.
565+
Note that only a single fail file can be used which is active (or not) for
566+
all clients.
567+
568+
When empty (`''`), a failed package will *not* be dumped to file.
569+
570+
```python
571+
from thingsdb.client import set_package_fail_file
572+
573+
set_package_fail_file('/tmp/thingsdb-invalid-data.mp')
574+
575+
# When a package is received which fails to unpack, the data from this package
576+
# will be stored to file.
577+
```

thingsdb/client/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
from .client import Client
2+
from .package import set_package_fail_file

thingsdb/client/package.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,24 @@
11
import struct
22
import msgpack
3+
import logging
4+
from typing import Optional
5+
6+
7+
_fail_file = ''
8+
9+
10+
def set_package_fail_file(fn: Optional[str] = ''):
11+
"""Configure a file name to dump the last failed package.
12+
13+
Only the MessagePack data will be dumped in this file, not the package
14+
header. This is useful for debugging packages which fail to unpack.
15+
Note that only a single fail file can be used which is active (or not) for
16+
all clients.
17+
18+
When empty, a failed package will not be dumped to file.
19+
"""
20+
global _fail_file
21+
_fail_file = fn
322

423

524
class Package(object):
@@ -20,6 +39,18 @@ def extract_data_from(self, barray: bytearray) -> None:
2039
barray[self.__class__.st_package.size:self.total],
2140
raw=False) \
2241
if self.length else None
42+
except Exception as e:
43+
if _fail_file:
44+
try:
45+
with open(_fail_file, 'wb') as f:
46+
f.write(
47+
barray[self.__class__.st_package.size:self.total])
48+
except Exception:
49+
logging.exception('')
50+
else:
51+
logging.warn(
52+
f'Wrote the content from {self} to `{_fail_file}`')
53+
raise e
2354
finally:
2455
del barray[:self.total]
2556

thingsdb/client/protocol.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,8 @@ def data_received(self, data: bytes) -> None:
194194
except Exception:
195195
logging.exception('')
196196
# empty the byte-array to recover from this error
197+
logging.error(
198+
f'Exception above came from package: {self.package}')
197199
self._buffered_data.clear()
198200
else:
199201
tp = self.package.tp

thingsdb/room/roombase.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,8 +152,17 @@ def on_leave(self) -> None:
152152
pass
153153

154154
async def _on_first_join(self):
155-
await self.on_join()
156-
self._wait_join.set_result(None)
155+
fut = self._wait_join
156+
self._wait_join = None
157+
# Instead of using finally to set the result, we could also catch the
158+
# exception and choose to set the exception to the future. (And only
159+
# set the future result to None on success). That implementation
160+
# would result in getting an exception from the join() method when the
161+
# wait argument is used.
162+
try:
163+
await self.on_join()
164+
finally:
165+
fut.set_result(None)
157166

158167
def _on_join(self, _data):
159168
loop = self.client.get_event_loop()

thingsdb/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = '1.0.0'
1+
__version__ = '1.0.1'

0 commit comments

Comments
 (0)