refactoring websockects low-level
[src/app-framework-binder.git] / src / session.c
index 329e17a..3e08808 100644 (file)
@@ -23,8 +23,8 @@
 #include <string.h>
 #include <uuid/uuid.h>
 #include <assert.h>
+#include <errno.h>
 
-#include "afb-apis.h"
 #include "session.h"
 
 #define NOW (time(NULL))
@@ -40,6 +40,20 @@ static struct {
   const char *initok;
 } sessions;
 
+void *afb_context_get(struct afb_context *actx)
+{
+       return actx->context;
+}
+
+void afb_context_set(struct afb_context *actx, void *context, void (*free_context)(void*))
+{
+fprintf(stderr, "afb_context_set(%p,%p) was (%p,%p)\n",context, free_context, actx->context, actx->free_context);
+       if (actx->context != NULL && actx->free_context != NULL)
+               actx->free_context(actx->context);
+       actx->context = context;
+       actx->free_context = free_context;
+}
+
 // Free context [XXXX Should be protected again memory abort XXXX]
 static void ctxUuidFreeCB (struct AFB_clientCtx *client)
 {
@@ -49,22 +63,18 @@ static void ctxUuidFreeCB (struct AFB_clientCtx *client)
        assert (client->contexts != NULL);
 
        // Free client handle with a standard Free function, with app callback or ignore it
-       for (idx=0; idx < sessions.apicount; idx ++) {
-               if (client->contexts[idx] != NULL) {
-                       afb_apis_free_context(idx, client->contexts[idx]);
-                       client->contexts[idx] = NULL;
-               }
-       }
+       for (idx=0; idx < sessions.apicount; idx ++)
+               afb_context_set(&client->contexts[idx], NULL, NULL);
 }
 
 // Create a new store in RAM, not that is too small it will be automatically extended
-void ctxStoreInit (int nbSession, int timeout, const char *initok)
+void ctxStoreInit (int max_session_count, int timeout, const char *initok, int context_count)
 {
        // let's create as store as hashtable does not have any
-       sessions.store = calloc (1 + (unsigned)nbSession, sizeof(struct AFB_clientCtx));
-       sessions.max = nbSession;
+       sessions.store = calloc (1 + (unsigned)max_session_count, sizeof(struct AFB_clientCtx));
+       sessions.max = max_session_count;
        sessions.timeout = timeout;
-       sessions.apicount = afb_apis_count();
+       sessions.apicount = context_count;
        if (strlen(initok) >= 37) {
                fprintf(stderr, "Error: initial token '%s' too long (max length 36)", initok);
                exit(1);
@@ -104,7 +114,7 @@ static int ctxStoreDel (struct AFB_clientCtx *client)
 
     for (idx=0; idx < sessions.max; idx++) {
         if (sessions.store[idx] == client) {
-               sessions.store[idx]=NULL;
+               sessions.store[idx] = NULL;
                sessions.count--;
                status = 1;
                goto deleted;
@@ -129,7 +139,7 @@ static int ctxStoreAdd (struct AFB_clientCtx *client)
 
     for (idx=0; idx < sessions.max; idx++) {
         if (NULL == sessions.store[idx]) {
-               sessions.store[idx]= client;
+               sessions.store[idx] = client;
                sessions.count++;
                status = 1;
                goto added;
@@ -191,7 +201,7 @@ TODO remove? not remove?
        /* returns a new one */
         clientCtx = calloc(1, sizeof(struct AFB_clientCtx)); // init NULL clientContext
        if (clientCtx != NULL) {
-               clientCtx->contexts = calloc ((unsigned)sessions.apicount, sizeof (void*));
+               clientCtx->contexts = calloc ((unsigned)sessions.apicount, sizeof(*clientCtx->contexts));
                if (clientCtx->contexts != NULL) {
                        /* generate the uuid */
                        if (uuid == NULL) {
@@ -280,3 +290,95 @@ void ctxTokenNew (struct AFB_clientCtx *clientCtx)
        clientCtx->expiration = NOW + sessions.timeout;
 }
 
+struct afb_event_sender_list
+{
+       struct afb_event_sender_list *next;
+       struct afb_event_sender sender;
+       int refcount;
+};
+
+int ctxClientEventSenderAdd(struct AFB_clientCtx *clientCtx, struct afb_event_sender sender)
+{
+       struct afb_event_sender_list *iter, **prv;
+
+       prv = &clientCtx->senders;
+       for (;;) {
+               iter = *prv;
+               if (iter == NULL) {
+                       iter = calloc(1, sizeof *iter);
+                       if (iter == NULL) {
+                               errno = ENOMEM;
+                               return -1;
+                       }
+                       iter->sender = sender;
+                       iter->refcount = 1;
+                       *prv = iter;
+                       return 0;
+               }
+               if (iter->sender.itf == sender.itf && iter->sender.closure == sender.closure) {
+                       iter->refcount++;
+                       return 0;
+               }
+               prv = &iter->next;
+       }
+}
+
+void ctxClientEventSenderRemove(struct AFB_clientCtx *clientCtx, struct afb_event_sender sender)
+{
+       struct afb_event_sender_list *iter, **prv;
+
+       prv = &clientCtx->senders;
+       for (;;) {
+               iter = *prv;
+               if (iter == NULL)
+                       return;
+               if (iter->sender.itf == sender.itf && iter->sender.closure == sender.closure) {
+                       if (!--iter->refcount) {
+                               *prv = iter->next;
+                               free(iter);
+                       }
+                       return;
+               }
+               prv = &iter->next;
+       }
+}
+
+static int send(struct AFB_clientCtx *clientCtx, const char *event, struct json_object *object)
+{
+       struct afb_event_sender_list *iter;
+       int result;
+
+       result = 0;
+       iter = clientCtx->senders;
+       while (iter != NULL) {
+               iter->sender.itf->send(iter->sender.closure, event, object);
+               result++;
+               iter = iter->next;
+       }
+
+       return result;
+}
+
+int ctxClientEventSend(struct AFB_clientCtx *clientCtx, const char *event, struct json_object *object)
+{
+       long idx;
+       time_t now;
+       int result;
+
+       if (clientCtx != NULL)
+               result = send(clientCtx, event, object);
+       else {
+               result = 0;
+               now = NOW;
+               for (idx=0; idx < sessions.max; idx++) {
+                       clientCtx = sessions.store[idx];
+                       if (clientCtx != NULL && !ctxStoreTooOld(clientCtx, now)) {
+                               clientCtx = ctxClientGet(clientCtx);
+                               result += send(clientCtx, event, object);
+                               ctxClientPut(clientCtx);
+                       }
+               }
+       }
+       return result;
+}
+