Context/user session handling

Previous: User authentication and group membership ] [ Top: Repository manager ] [ Next: Transactions ]

(November 26, 2002): The context, or user session, is really no more than the history of a particular thread of exchange between the system and a user. Essentially the same construct could be used for some hypothetical multi-user interaction, but for the time being I'm going to assume a single user.

A context stores values, some of which are protected (having been generated by the system) and some of which are user-specified. The context may be stored and retrieved by key. At first I was regarding the context as something managed by the user interface, and separate from the API itself, but then I realized that in order to keep a history (and things like "list last accessed") the API needs direct access -- moreover, since the API manages remote conversations, all context access has to go through the API. So here it is.

The context itself is an xmlobj object referenced by the wftk_session, and gets treated essentially identically to any other object, except that nameless (unstored) context objects may be built and never saved, yet still operate as a context.

The context_save function saves a nameless context and generates an ID for it, or it re-saves the current (already named) context. Contexts are stored in the list "_sessions".
 
WFTK_EXPORT char * repos_context_save (XML * repository)
{
   WFTK_ADAPTOR * ad;
   XML * context;
   char * ret;
   char * mark;
   const char * line;
   const char * end;
   struct _repos_remote * sock = (struct _repos_remote *) xml_getbin (repository);

   if (sock) { /* Remote. */
      xml_setf (sock->parms, "outgoing", "context\n");
      _repos_send (sock);

      line = _repos_receive (sock);
      if (*line == '-') return NULL;
      line = strchr (line, '-') + 1;
      ret = strdup (line);
      mark = strstr (ret, " ++done++");
      if (mark) *mark = '\0';
      else {
         mark = strchr (ret, '\n');
         if (mark) *mark = '\0';
      }
      return (ret);
   }

   context = wftk_session_getcontext (repository);
   if (!context) {
      context = xml_create ("context");
      wftk_session_setcontext (repository, context);
   }
   if (*xml_attrval (context, "key")) { /* This context has already been saved. */
      repos_mod (repository, "_sessions", context, NULL);
   } else {
      repos_add (repository, "_sessions", context);
   }
   return (strdup (xml_attrval (context, "key")));
}
Besides saving sessions (and retrieving handles for them), we also need to be able to switch sessions.
 
WFTK_EXPORT XML * repos_context_switch (XML * repository, const char * contextid)
{
   WFTK_ADAPTOR * ad;
   XML * temp;
   XML * context;
   const char * line;
   const char * end;
   XML * field;
   XML * mark;
   struct _repos_remote * sock = (struct _repos_remote *) xml_getbin (repository);

   if (sock) { /* Remote. */
      xml_setf (sock->parms, "outgoing", "context %s\n", contextid);
      _repos_send (sock);

      line = _repos_receive (sock);
      if (*line == '-') {
         wftk_session_setcontext (repository, NULL);
         return NULL;
      }
      line = strchr (line, '\n') + 1;
      temp = xml_create ("t");
      xml_set (temp, "r", "");
      while (line[0] != '>' || line[1] != '>') {
         end = strchr (line, '\n');
         if (end) {
            xml_attrncat (temp, "r", line, end - line + 1);
         } else {
            xml_attrcat (temp, "r", line);
            break;
         }
         line = end + 1;
      }
      context = xml_parse (xml_attrval (temp, "r"));
      xml_free (temp);
      xml_set (sock->parms, "buffer", "");
      wftk_session_setcontext (repository, context);
      return (context);
   }

   context = repos_get (repository, "_sessions", contextid);
   wftk_session_setcontext (repository, context);

   return (context);
}
Finally, we need our two central context functions: get and set value. These are basically the whole point of the exercise (although we'll probably get more involved later, with logs and attachments and nice things like that.) The get-value function works as a string formatter; if there is a square bracket in the value spec, it will create a value using xmlobj_format.
 
WFTK_EXPORT void repos_context_set (XML * repository, const char * valname, const char * value)
{
   WFTK_ADAPTOR * ad;
   XML * context;
   const char * line;
   const char * end;
   XML * field;
   XML * mark;
   struct _repos_remote * sock = (struct _repos_remote *) xml_getbin (repository);

   if (sock) { /* Remote. */
      xml_setf (sock->parms, "outgoing", "set % %s\n", valname, value);
      _repos_send (sock);

      line = _repos_receive (sock);
      xml_set (sock->parms, "buffer", "");
      return;
   }

   context = wftk_session_getcontext (repository);
   if (!context) {
      context = xml_create ("context");
      wftk_session_setcontext (repository, context);
   }
   xmlobj_set (context, NULL, valname, value);
}
WFTK_EXPORT char * repos_context_get (XML * repository, const char * valname)
{
   WFTK_ADAPTOR * ad;
   XML * context;
   char * ret;
   char * mark;
   const char * line;
   const char * end;
   struct _repos_remote * sock = (struct _repos_remote *) xml_getbin (repository);

   if (sock) { /* Remote. */
      xml_setf (sock->parms, "outgoing", "read %s\n", valname);
      _repos_send (sock);

      line = _repos_receive (sock);
      if (*line == '-') return NULL;
      line = strchr (line, ' ') + 1;
      ret = strdup (line);
      mark = strchr (ret, ' ');
      if (mark) *mark = '\0';
      else {
         mark = strchr (ret, '\n');
         if (mark) *mark = '\0';
      }
      return (ret);
   }

   context = wftk_session_getcontext (repository);
   if (!context) {
      context = xml_create ("context");
      wftk_session_setcontext (repository, context);
      return NULL;
   }
   return (xmlobj_get (context, NULL, valname));
}


Previous: User authentication and group membership ] [ Top: Repository manager ] [ Next: Transactions ]


This code and documentation are released under the terms of the GNU license. They are copyright (c) 2001-2005, Vivtek. All rights reserved except those explicitly granted under the terms of the GNU license.