Skip to content

Commit 49de795

Browse files
committed
Added bookstore example
1 parent fd19720 commit 49de795

1 file changed

Lines changed: 130 additions & 0 deletions

File tree

examples/bookstore/bookstore.py

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
"""Keep data in sync between multiple services using ThingsDB.
2+
3+
Make sure you start with an empty collection and configure your token and
4+
collection. (THINGSDB_AUTH_TOKEN and THINGSDB_COLLECTION)
5+
6+
Start the `bookstore.py` multiple times on different ports, for example:
7+
8+
python bookstore.py 5050
9+
python bookstore.py 5051
10+
11+
Call the `add_book` handler on the one of the web servers (For example 5050)
12+
```
13+
curl \
14+
--location \
15+
--request POST 'http://127.0.0.1:5050/add_book' \
16+
--header 'Content-Type: application/json' \
17+
--data-raw '{"title": "A short history of nearly everything"}'
18+
```
19+
20+
Observe that the book is synchronized with the other web server (5051):
21+
22+
```
23+
curl \
24+
--location \
25+
--request GET 'http://127.0.0.1:5051/get_books'
26+
```
27+
"""
28+
from sys import argv
29+
from functools import partial
30+
from asyncio import get_event_loop
31+
from aiohttp import web
32+
from thingsdb.client import Client
33+
from thingsdb.room import Room, event
34+
35+
THINGSDB_AUTH_TOKEN = 'YOUR_TOKEN'
36+
THINGSDB_COLLECTION = '//YOUR_COLLECTION'
37+
38+
bookstore = None
39+
40+
41+
class BookStore(Room):
42+
43+
def on_init(self):
44+
self.books = []
45+
self.add_book = partial(self.client.run, 'add_book')
46+
47+
async def on_join(self):
48+
self.books = await self.client.query("""//ti
49+
.books; // Just return all the books
50+
""")
51+
52+
@event('add-book')
53+
def on_add_boook(self, book):
54+
self.books.append(book)
55+
56+
57+
def on_cleanup():
58+
client.close()
59+
return client.wait_closed()
60+
61+
62+
async def add_book(request):
63+
book = await request.json()
64+
# Use the procedure to add the book
65+
await bookstore.add_book(book)
66+
return web.HTTPNoContent()
67+
68+
69+
# We hve the books in memory
70+
async def get_books(request):
71+
return web.json_response({
72+
"book_titles": [book['title'] for book in bookstore.books]
73+
})
74+
75+
76+
async def setup(client):
77+
global bookstore
78+
79+
await client.connect('playground.thingsdb.net', '9400')
80+
await client.authenticate(THINGSDB_AUTH_TOKEN)
81+
82+
bookstore = BookStore("""//ti
83+
if (!has_type('Book')) {
84+
85+
new_procedure('add_book', |book| {
86+
book = Book(book);
87+
.books.push(book); // add the book to our books list
88+
.ev.emit('add-book', book); // emit the add-book event
89+
});
90+
91+
// Set-up the collection, this will run only the first time.
92+
set_type('Book', {
93+
title: 'str',
94+
});
95+
96+
set_type('BookStore', {
97+
books: '[Book]',
98+
ev: 'room',
99+
});
100+
101+
// Convert the collection to type BookStore. This works
102+
// only on an empty collection, if the collectoins is not empty
103+
// you can use .clear(); first to empty the collection.
104+
.to_type('BookStore');
105+
};
106+
107+
.ev.id(); // Return the event room id
108+
""")
109+
await bookstore.join(client)
110+
111+
112+
if __name__ == '__main__':
113+
port = int(argv[1])
114+
115+
app = web.Application()
116+
117+
# Handlers
118+
app.add_routes([
119+
web.post("/add_book", add_book),
120+
web.get("/get_books", get_books),
121+
])
122+
123+
client = Client(ssl=True)
124+
client.set_default_scope(THINGSDB_COLLECTION)
125+
126+
loop = get_event_loop()
127+
loop.run_until_complete(setup(client))
128+
129+
app.on_cleanup.append(lambda _: on_cleanup())
130+
web.run_app(app, port=port, loop=loop)

0 commit comments

Comments
 (0)