Changeset: 0c61a0ebc2b9 for MonetDB
URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=0c61a0ebc2b9
Modified Files:
clients/iotapi/documentation/websockets_api.rst
clients/iotapi/src/Streams/streams.py
clients/iotapi/src/Streams/streamscontext.py
clients/iotapi/src/WebSockets/websockets.py
Branch: iot
Log Message:
Finished first version of documentation for web api. Added pattern for response
messages during a WebSocket session.
diffs (truncated from 401 to 300 lines):
diff --git a/clients/iotapi/documentation/websockets_api.rst
b/clients/iotapi/documentation/websockets_api.rst
--- a/clients/iotapi/documentation/websockets_api.rst
+++ b/clients/iotapi/documentation/websockets_api.rst
@@ -18,7 +18,7 @@ The following sections explain the avail
sub
---
-Subscribes for new basket creations from a specific stream. Whenever a basket
is created, the server sends a notification message indicating the number of
inserted tuples in the new basket. The user has to specify the stream's name
and schema.
+Subscribes for new basket creations from a specific stream. Whenever a basket
is created, the server sends a notification message indicating the number of
inserted tuples in the new basket. The user has to specify the stream's name
and schema. To subscribe to a temperature stream, the following would suffice:
.. code-block:: json
@@ -33,6 +33,14 @@ unsub
Unsubscribes a previous subscribed stream for a client. The user has to
specify the stream's name and schema. The example is the same as above, just
changing the request keyword.
+.. code-block:: json
+
+ {
+ "request": "unsub",
+ "schema": "measures",
+ "stream": "temperature"
+ }
+
read
----
@@ -40,7 +48,7 @@ Reads output result from baskets generat
.. important:: The user has not to be subscribed to the stream in order to
read data from it!
-It's possible to provide an offset, a limit and a basket number where the read
should start. The request will always provide a result, even if the query
provides no tuples to read. The user has to specify the stream's name and
schema.
+It's possible to provide an offset, a limit and a basket number where the read
should start. The request will always provide a result, even if the query
provides no tuples to read. The user has to specify the stream's name and
schema. A possible query for the temperatures stream:
.. code-block:: json
@@ -54,7 +62,7 @@ It's possible to provide an offset, a li
info
----
-Retrieves information about a giving stream if a stream's name and schema are
provided, or all the existing streams in the system otherwise.
+Retrieves information about a giving stream if a stream's name and schema are
provided, or all the existing streams in the system otherwise. To request
information of temperature stream:
.. code-block:: json
@@ -66,3 +74,178 @@ Retrieves information about a giving str
Responses
=========
+
+The response messages, are also provided with JSON. They contain a
:code:`response` field, identifying the type of the message.
+
+error
+-----
+
+An internal error occurred in the server during a client's request. The
:code:`message` contains a string explaining the error. The following error
message happens when the user attempts to unsubscribed to a non subscribed
stream:
+
+.. code-block:: json
+
+ {
+ "response": "error",
+ "message": "Stream measures.temperature not present in the user's
subscriptions!"
+ }
+
+subscribed
+----------
+
+Message confirming the subscription to new baskets notifications of a stream.
+
+.. code-block:: json
+
+ {
+ "response": "subscribed",
+ "schema": "measures",
+ "stream": "temperature"
+ }
+
+unsubscribed
+------------
+
+Message confirming the removal of a subscription to new baskets notifications
of a stream.
+
+.. code-block:: json
+
+ {
+ "response": "unsubscribed",
+ "schema": "measures",
+ "stream": "temperature"
+ }
+
+removed
+-------
+
+If a stream is removed on MonetDB's engine, but the client is still
subscribed, then this message is sent.
+
+.. code-block:: json
+
+ {
+ "response": "removed",
+ "schema": "measures",
+ "stream": "temperature"
+ }
+
+notification
+------------
+
+Notification of a new basket creation from a subscribed stream. The message
contains the basket number and the number of tuples in the new basket. A
possible notification example for the above stream:
+
+.. code-block:: json
+
+ {
+ "response": "notification",
+ "schema": "measures",
+ "stream": "temperature",
+ "basket": 2,
+ "count": 50
+ }
+
+read
+----
+
+Response message for a read query. Contains the reconstructed tuples
listening. The tuples are listened in the say they are inserted in the RESTful
webserver. If a column has a null value, the JSON's :code:`null` value will be
listened. A possible query result for the above stream:
+
+.. code-block:: json
+
+ {
+ "response": "read",
+ "schema": "measures",
+ "stream": "temperature",
+ "count": 3,
+ "tuples": [
+ {
+ "sensorid": "living room",
+ "temperature": 32.6
+ },
+ {
+ "sensorid": "kitchen",
+ "temperature": 34.2
+ },
+ {
+ "sensorid": "bathroom",
+ "temperature": 28.9
+ }
+ ]
+ }
+
+info
+----
+
+Message with details about a stream including both columns and baskets
details. Note that the possible types list are restricted to the MonetDB
kernel. A possible example for the above stream:
+
+.. code-block:: json
+
+ {
+ "response": "info",
+ "schema": "measures",
+ "stream": "temperature",
+ "columns": [
+ {
+ "name": "sensorid",
+ "type": "clob"
+ },
+ {
+ "name": "temperature",
+ "type": "real"
+ }
+ ],
+ "baskets_count": 3,
+ "baskets_listing": [
+ {
+ "number": 1,
+ "count": 20
+ },
+ {
+ "number": 2,
+ "count": 25
+ },
+ {
+ "number": 3,
+ "count": 12
+ }
+ ]
+ }
+
+data
+----
+
+Return a info messaging regarding all the streams in the system. An example
with the temperatures stream:
+
+.. code-block:: json
+
+ {
+ "response": "data",
+ "streams_count": 1,
+ "streams_listing": [
+ "schema": "measures",
+ "stream": "temperature",
+ "columns": [
+ {
+ "name": "sensorid",
+ "type": "clob"
+ },
+ {
+ "name": "temperature",
+ "type": "real"
+ }
+ ],
+ "baskets_count": 3,
+ "baskets_listing": [
+ {
+ "number": 1,
+ "count": 20
+ },
+ {
+ "number": 2,
+ "count": 25
+ },
+ {
+ "number": 3,
+ "count": 12
+ }
+ ]
+ ]
+ }
diff --git a/clients/iotapi/src/Streams/streams.py
b/clients/iotapi/src/Streams/streams.py
--- a/clients/iotapi/src/Streams/streams.py
+++ b/clients/iotapi/src/Streams/streams.py
@@ -31,7 +31,8 @@ class StreamBasketsHandler(FileSystemEve
if isinstance(event, DirCreatedEvent):
basket_string = os.path.basename(os.path.normpath(event.src_path))
count = self._stream.append_basket(basket_string)
- notify_stream_inserts_to_clients(self._stream.get_schema_name(),
self._stream.get_stream_name(), count)
+ notify_stream_inserts_to_clients(self._stream.get_schema_name(),
self._stream.get_stream_name(),
+ int(basket_string), count)
def on_deleted(self, event):
if isinstance(event, DirDeletedEvent):
@@ -65,10 +66,11 @@ class IOTStream(object):
dic = OrderedDict({'schema': self._schema_name, 'stream':
self._stream_name,
'columns': [value.to_json_representation() for
value in self._columns.values()]})
self._baskets_lock.acquire_read()
- baskets = {'count': len(self._baskets),
- 'details': [{'number': k, 'total': v} for k, v in
self._baskets.items()]}
+ count = len(self._baskets)
+ listing = [{'number': k, 'count': v} for k, v in self._baskets.items()]
self._baskets_lock.release()
- dic['baskets'] = baskets
+ dic['baskets_count'] = count
+ dic['baskets_listing'] = listing
return dic
def append_basket(self, path):
@@ -142,4 +144,4 @@ class IOTStream(object):
keys = results.keys() # TODO check if this is viable for many tuples!!
tuples = [dict(zip(keys, values)) for values in zip(*(results[k] for k
in keys))]
- return {'total': read_tuples, 'tuples': tuples}
+ return {'schema': self._schema_name, 'stream': self._stream_name,
'count': read_tuples, 'tuples': tuples}
diff --git a/clients/iotapi/src/Streams/streamscontext.py
b/clients/iotapi/src/Streams/streamscontext.py
--- a/clients/iotapi/src/Streams/streamscontext.py
+++ b/clients/iotapi/src/Streams/streamscontext.py
@@ -39,8 +39,8 @@ class IOTStreams(object):
def get_streams_data(self):
self._locker.acquire_read()
- res = {'count': len(self._context),
- 'details': [value.get_data_dictionary() for value in
self._context.values()]}
+ res = {'streams_count': len(self._context),
+ 'streams_listing': [value.get_data_dictionary() for value in
self._context.values()]}
self._locker.release()
return res
diff --git a/clients/iotapi/src/WebSockets/websockets.py
b/clients/iotapi/src/WebSockets/websockets.py
--- a/clients/iotapi/src/WebSockets/websockets.py
+++ b/clients/iotapi/src/WebSockets/websockets.py
@@ -26,11 +26,10 @@ def unsubscribe_removed_streams(concaten
from Streams.streamscontext import Streams_Context, IOTStreams # avoid
circular dependency
-def notify_stream_inserts_to_clients(schema_name, stream_name, count):
- concatenated_name = IOTStreams.get_context_entry_name(schema_name,
stream_name)
+def notify_stream_inserts_to_clients(schema_name, stream_name, basket_number,
count):
WebClientsLock.acquire_read()
for client in WebClients:
- client.send_notification_message(concatenated_name, schema_name,
stream_name, count)
+ client.send_notification_message(schema_name, stream_name,
basket_number, count)
WebClientsLock.release()
@@ -43,8 +42,8 @@ class IOTAPI(WebSocket):
self._subscriptions_locker = RWLock()
def sendJSONMessage(self, response, message): # IMPORTANT always use this
method to send messages to clients!!!!!
- json_message = json.dumps({'response': response, 'message': message})
- super(IOTAPI, self).sendMessage(json_message) # send JSON Strings to
clients
+ message['response'] = response
+ super(IOTAPI, self).sendMessage(json.dumps(message)) # send JSON
Strings to clients
def handleConnected(self): # overriden
WebClientsLock.acquire_write()
_______________________________________________
checkin-list mailing list
[email protected]
https://www.monetdb.org/mailman/listinfo/checkin-list