Skip to content

Commit 8cfa151

Browse files
moved waggle message stuff into minimal module
0 parents  commit 8cfa151

File tree

6 files changed

+184
-0
lines changed

6 files changed

+184
-0
lines changed

.github/workflows/cicd.yaml

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
name: CI/CD
2+
on: push
3+
jobs:
4+
build:
5+
name: Build
6+
runs-on: ubuntu-latest
7+
steps:
8+
- name: Checkout
9+
uses: actions/checkout@v2
10+
- name: Set release version
11+
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
12+
if: startsWith(github.ref, 'refs/tags/')
13+
- name: Build wheel
14+
run: python3 setup.py bdist_wheel
15+
- name: Upload wheel
16+
uses: actions/upload-artifact@v2
17+
with:
18+
name: dist
19+
path: dist/*.whl
20+
21+
test:
22+
name: Test
23+
runs-on: ubuntu-latest
24+
needs: build
25+
strategy:
26+
matrix:
27+
python-version: [3.6, 3.7, 3.8, 3.9]
28+
steps:
29+
- name: Checkout
30+
uses: actions/checkout@v2
31+
- name: Download wheel
32+
uses: actions/download-artifact@v2
33+
with:
34+
name: dist
35+
- name: Install wheel
36+
run: pip3 install *.whl
37+
- name: Run tests
38+
run: python3 -m unittest
39+
40+
release:
41+
name: Release
42+
runs-on: ubuntu-latest
43+
needs: test
44+
if: startsWith(github.ref, 'refs/tags/')
45+
steps:
46+
- name: Download wheel
47+
uses: actions/download-artifact@v2
48+
with:
49+
name: dist
50+
- name: Create release
51+
uses: softprops/action-gh-release@v1
52+
with:
53+
files: |
54+
*.whl

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
build/
2+
dist/
3+
*.egg-info/
4+
__pycache__/
5+
venv/
6+
.DS_Store

README.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# pywagglemsg
2+
3+
Tiny Python library for (de)serializing Waggle messages. Although this is a public module, it's
4+
mostly geared towards building internal tools and services.
5+
6+
## Example
7+
8+
```python3
9+
import wagglemsg
10+
11+
msg = wagglemsg.Message(
12+
name='env.temperature.htu21d',
13+
value=10,
14+
timestamp=1602704769215113000,
15+
meta={
16+
"device": "bme280",
17+
},
18+
)
19+
20+
data = wagglemsg.dump(msg)
21+
22+
# ... send data over the network ....
23+
```

setup.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from setuptools import setup
2+
from os import getenv
3+
4+
setup(
5+
name="wagglemsg",
6+
version=getenv("RELEASE_VERSION", "0.0.0"),
7+
description="Official Waggle Python message module",
8+
url="https://github.com/waggle-sensor/pywagglemsg",
9+
packages=[
10+
"wagglemsg",
11+
],
12+
python_requires=">=3.6",
13+
)

test.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import unittest
2+
import wagglemsg
3+
4+
5+
class TestMain(unittest.TestCase):
6+
7+
def test_fail(self):
8+
test_cases = [
9+
wagglemsg.Message(
10+
name='env.temperature.htu21d',
11+
value=10,
12+
timestamp=1602704769215113000,
13+
meta={},
14+
),
15+
wagglemsg.Message(
16+
name='env.temperature.htu21d',
17+
value=21.2,
18+
timestamp=1602704769215113000,
19+
meta={},
20+
),
21+
wagglemsg.Message(
22+
name='env.temperature.htu21d',
23+
value=b'some binary data',
24+
timestamp=1602704769215113000,
25+
meta={},
26+
),
27+
wagglemsg.Message(
28+
name='env.temperature.htu21d',
29+
value='some string data',
30+
timestamp=1602704769215113000,
31+
meta={
32+
"id": "meta-test-id"
33+
},
34+
)
35+
]
36+
37+
for msg in test_cases:
38+
out = wagglemsg.load(wagglemsg.dump(msg))
39+
self.assertEqual(msg, out)
40+
41+
42+
43+
if __name__ == "__main__":
44+
unittest.main()

wagglemsg/__init__.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import base64
2+
import json
3+
from typing import NamedTuple, Any, Dict
4+
5+
6+
class Message(NamedTuple):
7+
"""Message contains message data."""
8+
name: str
9+
value: Any
10+
timestamp: int
11+
meta: Dict[str, str]
12+
13+
14+
def dump(msg: Message) -> bytes:
15+
"""dump serializes a Message object."""
16+
payload = {
17+
"name": msg.name,
18+
"ts": msg.timestamp,
19+
"meta": msg.meta,
20+
}
21+
22+
# binary data is encoded to base64 by default. all other
23+
# data is shipped as-is for now.
24+
if isinstance(msg.value, (bytes, bytearray)):
25+
payload["enc"] = "b64"
26+
payload["val"] = base64.b64encode(msg.value).decode()
27+
else:
28+
payload["val"] = msg.value
29+
30+
return json.dumps(payload, separators=(",", ":"))
31+
32+
33+
def load(body: bytes) -> Message:
34+
"""dump deserializes a Message object."""
35+
data = json.loads(body)
36+
37+
if data.get("enc") == "b64":
38+
data["val"] = base64.b64decode(data["val"])
39+
40+
return Message(
41+
name=data["name"],
42+
value=data["val"],
43+
timestamp=data["ts"],
44+
meta=data["meta"])

0 commit comments

Comments
 (0)