Notifications

If you want to follow the state of some specific projections without being forced to do checks on a regular basis, you are in the right section !
As notifications is both good for you and me, because you will be updated on time and i won’t have to deal with tons of reads (which about 90% of them will be useless) on server-side, there is a bit of documentation to read before using those.

How to create a Trigger ?

There it is, first, make sure to understand the subtile difference between a trigger and a notification.
A trigger is what produces a notification, it contains some metadata to guide the production of the notification and is only triggered when its binded resource has been modified, it stays server side.
A notification contains the resource after modification

So, what you will create are Triggers. Triggers are binded to resource, for now you may only bind it to a single projection, in the future you will have the means to create trigger upon a namespace but this will be done after we do the rework onto the namespace. At least you have something to look forward to :).

To create a trigger, here is the needed payload in JSON:

{
 "type": "string", <-- Either ["WEBSOCKET", "WEBHOOK"]
 "websocket_client_id": "string", <-- Only if type = "WEBSOCKET"
 "web_hook_address": "string", <-- Only if type = "WEBHOOK"
 "service": "string",
 "uuid_projection": "string"
}

Triggers can be created either as WEBSOCKET trigger or WEBHOOK trigger, depending on the mode you choose you will have either to set a client id or a web hook url. For now there is no need to pass through an API to register yourself as a client for the websocket which gives you a key and so on... This will come later.

As i said just earlier, trigger are activated when their binded resource are modified, in fact if you update a projection with the exact data as before the trigger will still be triggered. A notification payload looks like this :

{
 "id" : "bba76c17-5378-49f2-b1c9-146e1cb0ac0d",
 "uuid_projection" : "fdc46d60-6586-42c5-89ec-14a73849c02c",
 "method" : "UPDATE",
 "projection" : {
   "_depth" : 0,
   "_class" : "http://knoesis.wright.edu/ssw/ont/sensor-observation.owl#System",
   "_ori" : "http://knoesis.wright.edu/ssw/System_C1692",
   "_uuid" : "fdc46d60-6586-42c5-89ec-14a73849c02c",
   "_last_updated" : 1510151744979,
   "_rwid" : "@mac####ff:ff:ff:ff:ff:ff",
   "ont_sensor_observation_owl_ID" : "C1692",
   "_outE" : [ {
     "_property" : "ont_sensor_observation_owl_parameter",
     "_ori" : "http://sonicbanana.cs.wright.edu/ssw/ont/weather.owl#_WindSpeed",
     "_uuid" : "b915eff3-04a0-4d8e-bbc2-cc89f5977355"
   }, {
     "_property" : "ont_sensor_observation_owl_processLocation",
     "_ori" : "http://knoesis.wright.edu/ssw/point_C1692",
     "_uuid" : "2e3d728c-806d-4dd0-96da-8cdb6f2d56ee"
   }, {
     "_property" : "ont_sensor_observation_owl_hasLocatedNearRel",
     "_ori" : "http://knoesis.wright.edu/ssw/LocatedNearRelC1692",
     "_uuid" : "92d6ab39-5b76-4fed-85ab-0b85ddd86e9b"
   }, {
     "_property" : "ont_sensor_observation_owl_parameter",
     "_ori" : "http://sonicbanana.cs.wright.edu/ssw/ont/weather.owl#_WindGust",
     "_uuid" : "4e985579-7fcf-464d-a62d-034f704a4721"
   }, {
     "_property" : "ont_sensor_observation_owl_parameter",
     "_ori" : "http://sonicbanana.cs.wright.edu/ssw/ont/weather.owl#_RelativeHumidity",
     "_uuid" : "85cc7f7b-940a-439a-8ba0-0d7aa6aa9611"
   }, {
     "_property" : "ont_sensor_observation_owl_parameter",
     "_ori" : "http://sonicbanana.cs.wright.edu/ssw/ont/weather.owl#_WindDirection",
     "_uuid" : "fa47fdda-dc24-44c9-8be6-a7c482e9027d"
   }, {
     "_property" : "ont_sensor_observation_owl_parameter",
     "_ori" : "http://sonicbanana.cs.wright.edu/ssw/ont/weather.owl#_DewPoint",
     "_uuid" : "15d55a49-2ec4-4951-96ed-2f328b2e905d"
   }, {
     "_property" : "ont_sensor_observation_owl_parameter",
     "_ori" : "http://sonicbanana.cs.wright.edu/ssw/ont/weather.owl#_AirTemperature",
     "_uuid" : "1c8e7396-9f4b-4a8f-a8d6-c6cf7801b9cf"
   } ]
 },
 "timestamp" : 1684363575416,
 "client_id" : "client_id_1" <-- (Only in case of websocket notification)
}

It can be summerized like this :

{
 "id" : Id of the generated notification,
 "uuid_projection" : Read to the left.,
 "method" : Either "UPDATE" or "DELETE" depending on what triggered this notification,
 "projection" : The payload of the projection after the modification,
 "client_id" : "client_id_1" <-- (Only in case of websocket notification)
}

If the projection is deleted the field projection will not be set.
If the notification is made through web hook the field client_id will not be set.

Note that there may a slight delay between the notification you receive and the actual modification into the database, it should never be more than a few seconds, but there is a delay. Also, notification are handled in a lazy manner and may, in some case, not give you back the exact state resulting of the modification. For example, if you perform two updates basically at the same time, if by the time we generate the first notification, the second update is already finished, the first notification will show the state of the second update.

We could implement a better way to handle the notification but it would also cost more resources and we don’t want to do that right now.
All we can promise you is that the state showed in the notification will always be after the modification of the first request. In order to detect this kind of behavior you can use the timestamp in the notification, it is generated right at the end of the modification in a synchronous manner, if you have two notification the first one will ALWAYS (this is safe.) be the one with the smallest timestamp.

Websocket Server

The websocket server endpoint is "the hostname we kindly gave you to access the api" + /websocket
So if you can address the API at the following endpoint : http://ziggy-api-int.nprpaas.ddns.integ.dns-orange.fr/api/, the websocket server will be here : http://ziggy-api-int.nprpaas.ddns.integ.dns-orange.fr/websocket/

At this endpoint, if you go there with a web browser you should see a little client we wrote to help you devellop your own websocket client and check if your modifications are properly notified through the websocket server. When you arrive on the webclient, first you need to register yourself using the subscribe button, to subscribe use the client_id you used to create your triggers ("client_id_1" in the example above).

You should see a message like "subscribe - ACK" into the chat, this means that we received your subscription and every time we will receive a notification concerning your client id, you will be informed. Also even though the connection will be automatically removed after a certain time you can also have manners and tell us goodbye properly using the unsubscribe button :).

WARNING : There is today a limitation on the clients actually subscribed to the websocket. As two great warrior fighting each other in a glorious battle : " HONOR TO THE LAST ONE STANDING ! ", only the last connection to subscribe with a client_id will receive the notification. The websocket server is very stupid about the way it handles subscribed client_id right now. You need to implement a keep alive in order to remain subscribed, the timeout is of 90 seconds, after that you will receive no longer the nofication and will have to subscribe again.

The websocket server has an in-memory buffer which allow him to save undelivered notifications for up the 24 hours, if you were not connected at the time the notification arrived on the websocket server, you should be able to retrieve them as long as you stay within that 24 hours time limit.

To help you write your own client, you can download the page and check the javascript code, it is quite easy.

/!\ WARNING WARNING WARNING /!\

There is currently a default in our Apache configuration and some requests are not properly redirected including the infamous "/socket.io" namespace related to the websockets.
It means when you tell your websocket client to connect to http://ziggy-api-int.nprpaas.ddns.integ.dns-orange.fr/websocket/, it will send its requests to http://ziggy-api-int.nprpaas.ddns.integ.dns-orange.fr/websocket/socket.io whereas requests are expected to be at http://ziggy-api-int.nprpaas.ddns.integ.dns-orange.fr/socket.io thus making the connection fail.

To avoid this problem, open the websocket connection to the following url :

io("http://ziggy-api-int.nprpaas.ddns.integ.dns-orange.fr/")

/!\ WARNING WARNING WARNING /!}}

Keep in mind that it is still under development, if something is not working feel free to bother ( ;) ) us !