On Fri, 11 Feb 2011 21:28:35 -0800
"Enlightenment SVN" <[email protected]> wrote:

> Log:
> fix some bugs associated with __post__ directive return value
>   add advanced server functions for people who know what they're doing (tm):
>      EAPI void
> azy_server_module_events_resume(Azy_Server_Module *module); EAPI
> void                    azy_server_module_events_suspend(Azy_Server_Module
> *module); EAPI Eina_Bool
> azy_server_module_events_suspended_get(Azy_Server_Module *module); EAPI
> Eina_Bool               azy_server_module_active_get(Azy_Server_Module
> *module); EAPI Azy_Content
> *azy_server_module_content_get(Azy_Server_Module *module); with this new api,
> it is possible to "pause" a client in the middle of its ecore event, allowing
> for other events, timers, etc to run prior to returning the method call. test
> code updated with examples. 
> 
> Author:       discomfitor
> Date:         2011-02-11 21:28:34 -0800 (Fri, 11 Feb 2011)
> New Revision: 56958
> Trac:         http://trac.enlightenment.org/e/changeset/56958
> 
> Modified:
>   trunk/PROTO/azy/doc/azy.dox.in trunk/PROTO/azy/src/bin/main.c
> trunk/PROTO/azy/src/include/Azy.h trunk/PROTO/azy/src/include/azy_private.h
> trunk/PROTO/azy/src/lib/azy_client.c
> trunk/PROTO/azy/src/lib/azy_server_events.c
> trunk/PROTO/azy/src/lib/azy_server_module.c
> trunk/PROTO/azy/src/tests/client.c trunk/PROTO/azy/src/tests/server.c
> trunk/PROTO/azy/src/tests/test.azy 
> 
> Modified: trunk/PROTO/azy/doc/azy.dox.in
> ===================================================================
> --- trunk/PROTO/azy/doc/azy.dox.in    2011-02-11 21:46:36 UTC (rev 56957)
> +++ trunk/PROTO/azy/doc/azy.dox.in    2011-02-12 05:28:34 UTC (rev 56958)
> @@ -27,6 +27,7 @@
>  @li @ref Azy_Rss_Item
>  @li @ref Azy_Server
>  @li @ref Azy_Server_Module
> +@li @ref Azy_Server_Module_Advanced
>  
>  @verbatim
>  Pants
> 
> Modified: trunk/PROTO/azy/src/bin/main.c
> ===================================================================
> --- trunk/PROTO/azy/src/bin/main.c    2011-02-11 21:46:36 UTC (rev 56957)
> +++ trunk/PROTO/azy/src/bin/main.c    2011-02-12 05:28:34 UTC (rev 56958)
> @@ -1221,6 +1221,9 @@
>          EL(1, "if (azy_content_error_is_set(content))");
>          EL(2, "goto out;");
>          NL;
> +        EL(1, "if (azy_server_module_events_suspended_get(module))");
> +        EL(2, "return EINA_TRUE;");
> +        NL;
>          EL(1, "azy_return_value = %s(azy_return_module);",
> method->return_type->march_name); EL(1, "if (!azy_return_value)");
>          EL(1, "{");
> 
> Modified: trunk/PROTO/azy/src/include/Azy.h
> ===================================================================
> --- trunk/PROTO/azy/src/include/Azy.h 2011-02-11 21:46:36 UTC (rev
> 56957) +++ trunk/PROTO/azy/src/include/Azy.h  2011-02-12 05:28:34 UTC
> (rev 56958) @@ -293,6 +293,11 @@
>     EAPI Azy_Net               *azy_server_module_net_get(Azy_Server_Module
> *module); EAPI Azy_Server_Module_Def *azy_server_module_def_find(Azy_Server
> *server, const char  *name);
> +   EAPI void
> azy_server_module_events_resume(Azy_Server_Module *module);
> +   EAPI void
> azy_server_module_events_suspend(Azy_Server_Module *module);
> +   EAPI Eina_Bool
> azy_server_module_events_suspended_get(Azy_Server_Module *module);
> +   EAPI Eina_Bool
> azy_server_module_active_get(Azy_Server_Module *module);
> +   EAPI Azy_Content
> *azy_server_module_content_get(Azy_Server_Module *module); EAPI
> Eina_Bool               azy_server_module_add(Azy_Server            *server,
> Azy_Server_Module_Def *module); EAPI Eina_Bool
> azy_server_module_del(Azy_Server            *server,
> 
> Modified: trunk/PROTO/azy/src/include/azy_private.h
> ===================================================================
> --- trunk/PROTO/azy/src/include/azy_private.h 2011-02-11 21:46:36 UTC
> (rev 56957) +++ trunk/PROTO/azy/src/include/azy_private.h     2011-02-12
> 05:28:34 UTC (rev 56958) @@ -196,16 +196,32 @@
>     Ecore_Event_Handler *data;
>  
>     Azy_Net    *net;
> -   Azy_Net    *send;
> +   Azy_Net    *current;
>     Azy_Server *server;
>     Eina_List   *modules;
>  
>     Eina_Bool handled : 1;
> +   Eina_Bool dead : 1;
> +   
> +   Eina_Bool suspend : 1;
> +   Eina_List *suspended_nets; /* Azy_Net* */
> +   Azy_Net *resume;
> +   Azy_Content *resume_rpc;
> +   Eina_Bool resume_ret : 1;
>  
>     const char          *session_id;
>     const char          *ip;
>  } Azy_Server_Client;
>  
> +typedef enum
> +{
> +   AZY_SERVER_MODULE_STATE_INIT,
> +   AZY_SERVER_MODULE_STATE_PRE,
> +   AZY_SERVER_MODULE_STATE_METHOD,
> +   AZY_SERVER_MODULE_STATE_POST,
> +   AZY_SERVER_MODULE_STATE_ERR
> +} Azy_Server_Module_State;
> +
>  struct Azy_Server_Module
>  {
>     AZY_MAGIC;
> @@ -213,8 +229,10 @@
>     Azy_Server_Module_Def *def;
>     Azy_Content           *content;
>     Azy_Server_Client     *client;
> -   double                 last_used;
>     Azy_Net_Data           recv;
> +   Eina_Bool              suspend : 1;
> +   Eina_Bool              run_method : 1;
> +   Azy_Server_Module_State state;
>  };
>  
>  struct Azy_Value
> 
> Modified: trunk/PROTO/azy/src/lib/azy_client.c
> ===================================================================
> --- trunk/PROTO/azy/src/lib/azy_client.c      2011-02-11 21:46:36 UTC (rev
> 56957) +++ trunk/PROTO/azy/src/lib/azy_client.c       2011-02-12 05:28:34
> UTC (rev 56958) @@ -418,7 +418,7 @@
>   * @param client The client (NOT #NULL)
>   * @param content The content containing the method name and parameters (NOT
> #NULL)
>   * @param transport The content-type (xml/json/etc) to use
> - * @param cb The deserialization callback to use for the response (NOT #NULL)
> + * @param cb The deserialization callback to use for the response
>   * @return The #Azy_Client_Call_Id of the transmission, to be used with
> azy_client_callback_set,
>   * or 0 on failure
>   */
> @@ -439,7 +439,6 @@
>          return 0;
>       }
>     EINA_SAFETY_ON_NULL_RETURN_VAL(client->net, 0);
> -   EINA_SAFETY_ON_NULL_RETURN_VAL(cb, 0);
>     EINA_SAFETY_ON_NULL_RETURN_VAL(content, 0);
>     EINA_SAFETY_ON_NULL_RETURN_VAL(content->method, 0);
>  
> 
> Modified: trunk/PROTO/azy/src/lib/azy_server_events.c
> ===================================================================
> --- trunk/PROTO/azy/src/lib/azy_server_events.c       2011-02-11 21:46:36
> UTC (rev 56957) +++ trunk/PROTO/azy/src/lib/azy_server_events.c
> 2011-02-12 05:28:34 UTC (rev 56958) @@ -145,6 +145,7 @@
>  
>     s->def = def;
>     s->client = client;
> +   s->run_method = EINA_TRUE;
>  
>     AZY_MAGIC_SET(s, AZY_MAGIC_SERVER_MODULE);
>     if (s->def->init && !s->def->init(s))
> @@ -217,8 +218,6 @@
>  {
>     Azy_Server_Module *module = NULL;
>     Azy_Server_Module_Method *method;
> -   Eina_Bool retval = EINA_FALSE;
> -   Eina_Bool run_method = EINA_TRUE;
>     Azy_Net *new;
>     const char *module_name;
>  
> @@ -236,7 +235,7 @@
>  
>     INFO("Running RPC for %s", content->method);
>     /* get Azy_Server_Module object for current connection and given module
> name */
> -   if (!(module_name = azy_content_module_name_get(content,
> client->net->http.req.http_path)))
> +   if (!(module_name = azy_content_module_name_get(content,
> client->current->http.req.http_path))) {
>          azy_content_error_faultmsg_set(content, -1, "Undefined module
> name."); return EINA_FALSE;
> @@ -269,22 +268,32 @@
>     module->content = content;
>     method = _azy_server_module_method_find(module,
> azy_content_method_get(content)); 
> -   new = azy_net_new(module->client->net->conn);
> -   new->server_client = EINA_TRUE;
> -   if (module->def->pre)
> -     run_method = module->def->pre(module, new);
> +   switch (module->state)
> +     {
> +      case AZY_SERVER_MODULE_STATE_INIT:
> +        new = azy_net_new(module->client->current->conn);
> +        new->server_client = EINA_TRUE;
> +        if (module->def->pre)
> +          module->run_method = module->def->pre(module, new);
>  
> -   /* grab the req path before it gets freed */
> -   new->http.req.http_path = module->client->net->http.req.http_path;
> -   module->client->net->http.req.http_path = NULL;
> -   
> -   azy_net_free(module->client->net);
> -   module->client->net = new;
> +        /* grab the req path before it gets freed */
> +        new->http.req.http_path =
> module->client->current->http.req.http_path;
> +        module->client->current->http.req.http_path = NULL;
> +        new->type = module->client->current->type;
> +        new->transport = module->client->current->transport;
> +        
> +        azy_net_free(module->client->current);
> +        module->client->current = new;
>  
> -   if (run_method)
> -     {
> +        module->state = AZY_SERVER_MODULE_STATE_PRE;
> +        if (module->suspend) return EINA_TRUE;
> +
> +      case AZY_SERVER_MODULE_STATE_PRE:
> +        if (!module->run_method)
> +          goto out;
> +           
>          if (method)
> -          retval = method->method(module, content);
> +          client->resume_ret = method->method(module, content);
>          else if (module->def->fallback)
>            {
>               if (module->def->fallback(module, content))
> @@ -294,15 +303,33 @@
>                 }
>               else if (!azy_content_error_is_set(content))
>                 azy_content_error_faultmsg_set(content, -1, "Method %s not
> found in %s module.", azy_content_method_get(content), module->def->name);
> +             client->resume_ret = EINA_FALSE;
>            }
>          else
> -          azy_content_error_faultmsg_set(content, -1, "Method %s not found
> in %s module.", azy_content_method_get(content), module->def->name);
> +          {
> +             azy_content_error_faultmsg_set(content, -1, "Method %s not
> found in %s module.", azy_content_method_get(content), module->def->name);
> +             client->resume_ret = EINA_FALSE;
> +          }
>  
> +        module->state = AZY_SERVER_MODULE_STATE_METHOD;
> +        if (module->suspend) return EINA_TRUE;
> +      case AZY_SERVER_MODULE_STATE_METHOD:
> +      case AZY_SERVER_MODULE_STATE_ERR:
>          if (module->def->post)
> -          retval = module->def->post(module, content);
> +          client->resume_ret = module->def->post(module, content);
> +
> +        module->state = AZY_SERVER_MODULE_STATE_POST;
> +        if (module->suspend) return EINA_TRUE;
> +      case AZY_SERVER_MODULE_STATE_POST:
> +      default:
> +        break;
>       }
> +out:
> +   module->state = AZY_SERVER_MODULE_STATE_INIT;
>     module->content = NULL;
> -   return retval;
> +   module->run_method = EINA_TRUE;
> +   client->resume_rpc = NULL;
> +   return client->resume_ret;
>  }
>  
>  static void
> @@ -344,6 +371,8 @@
>          AZY_MAGIC_FAIL(client, AZY_MAGIC_SERVER_CLIENT);
>          return;
>       }
> +   client->dead = EINA_TRUE;
> +   if (client->suspend || client->resume) return;
>     AZY_MAGIC_SET(client, AZY_MAGIC_NONE);
>     ecore_con_client_data_set(client->net->conn, NULL);
>  
> @@ -351,6 +380,8 @@
>       _azy_server_module_free(s, EINA_TRUE);
>     azy_net_free(client->net);
>     client->net = NULL;
> +   if (client->current) azy_net_free(client->current);
> +   client->current = NULL;
>     if (client->session_id)
>       eina_stringshare_del(client->session_id);
>  
> @@ -389,7 +420,6 @@
>  _azy_server_client_get_put(Azy_Server_Client *client)
>  {
>     Eina_List *l;
> -   Eina_Bool run_method = EINA_TRUE;
>     Azy_Server_Module *module = NULL;
>     Azy_Server_Module_Def *def;
>     Azy_Net *net;
> @@ -397,24 +427,22 @@
>     Azy_Server_Module_Content_Cb fallback = NULL;
>  
>     DBG("(client=%p)", client);
> -
>     /* for each available module type, check if it has download hook */
>     EINA_LIST_FOREACH(client->server->module_defs, l, def)
>       {
> -        if ((client->net->type == AZY_NET_TYPE_GET) && def->download)
> +        if ((client->current->type == AZY_NET_TYPE_GET) && def->download)
>            {
>               cb = def->download;
>               break;
>            }
> -        if ((client->net->type == AZY_NET_TYPE_PUT) && def->upload)
> +        if ((client->current->type == AZY_NET_TYPE_PUT) && def->upload)
>            {
>               cb = def->upload;
>               break;
>            }
>          if (def->fallback) fallback = def->fallback;
>       }
> -   net = azy_net_new(client->net->conn);
> -   net->server_client = EINA_TRUE;
> +
>     if (cb)
>       {
>          Azy_Server_Module *existing_module;
> @@ -422,49 +450,38 @@
>          /* check if module exists already */
>          EINA_LIST_FOREACH(client->modules, l, existing_module)
>            if (existing_module->def == def)
> -            module = existing_module;
> +            {
> +               module = existing_module;
> +               break;
> +            }
>  
> -        /* it's not, create it now */
>          if (!module)
>            {
>               module = _azy_server_module_new(def, client);
>               client->modules = eina_list_append(client->modules, module);
> +             if (module->suspend) return EINA_TRUE;
>            }
> -        if (def->pre)
> -          run_method = def->pre(module, net);
> -
> -        module->recv.data = client->net->buffer;
> -        module->recv.size = client->net->size;
> -        client->net->buffer = NULL; /* prevent buffer from being freed */
>       }
> -
> -   /* grab the req path before it gets freed */
> -   net->http.req.http_path = client->net->http.req.http_path;
> -   client->net->http.req.http_path = NULL;
>     
> -   azy_net_free(client->net);
> -   client->net = net;
> -
> -
> -   if (cb && run_method)
> +   if ((!module) || (module->state == AZY_SERVER_MODULE_STATE_ERR))
>       {
> -        cb(module);
> -        if (module->def->post)
> -          module->def->post(module, NULL);
> -     }
> -   else if (fallback)
> -     {
> -        if (!fallback(module, NULL))
> -          ERR("Fallback did not return value.");
> -     }
> -   else
> -     {
>          Azy_Net_Data data;
> +not_impl:
> +        net = azy_net_new(client->current->conn);
> +        net->server_client = EINA_TRUE;
>  
> +        /* grab the req path before it gets freed */
> +        net->http.req.http_path = client->current->http.req.http_path;
> +        client->current->http.req.http_path = NULL;
> +        net->type = module->client->current->type;
> +        net->transport = module->client->current->transport;
> +   
> +        azy_net_free(client->current);
> +        client->current = net;
>          net->http.res.http_code = 501;
>          net->http.res.http_msg = azy_net_http_msg_get(501);
>          azy_net_header_set(net, "Content-Type", "text/plain");
> -        if (client->net->type == AZY_NET_TYPE_GET)
> +        if (client->current->type == AZY_NET_TYPE_GET)
>            {
>               data.data = (unsigned char *)"Download hook is not
> implemented."; data.size = 31;
> @@ -475,9 +492,60 @@
>               data.size = 31;
>            }
>          _azy_server_client_send(client, &data, NULL);
> +        if (module && module->recv.data) free(module->recv.data);
> +        if (module)
> +          module->state = AZY_SERVER_MODULE_STATE_INIT;
> +        return EINA_TRUE;
>       }
> -   if (module->recv.data) free(module->recv.data);
> -   return ECORE_CALLBACK_RENEW;
> +
> +   switch (module->state)
> +     {
> +      case AZY_SERVER_MODULE_STATE_INIT:
> +        net = azy_net_new(client->current->conn);
> +        net->server_client = EINA_TRUE;
> +        if (def->pre)
> +          module->run_method = def->pre(module, net);
> +
> +        module->recv.data = client->current->buffer;
> +        module->recv.size = client->current->size;
> +        client->current->buffer = NULL; /* prevent buffer from being freed */
> +
> +        /* grab the req path before it gets freed */
> +        net->http.req.http_path = client->current->http.req.http_path;
> +        client->current->http.req.http_path = NULL;
> +        net->type = module->client->current->type;
> +        net->transport = module->client->current->transport;
> +        
> +        azy_net_free(client->current);
> +        client->current = net;
> +        
> +        module->state = AZY_SERVER_MODULE_STATE_PRE;
> +        if (module->suspend) return EINA_TRUE;
> +        
> +      case AZY_SERVER_MODULE_STATE_PRE:
> +           if (cb && module->run_method)
> +             client->resume_ret = cb(module);
> +           else
> +             client->resume_ret = fallback(module, NULL);
> +                
> +            module->state = client->resume_ret ?
> AZY_SERVER_MODULE_STATE_METHOD : AZY_SERVER_MODULE_STATE_ERR;
> +            if (module->suspend) return EINA_TRUE;
> +
> +      case AZY_SERVER_MODULE_STATE_METHOD:
> +              if (!client->resume_ret) goto not_impl; /* line 444ish (above)
> */
> +              if (module->def->post)
> +                client->resume_ret = module->def->post(module, NULL);
> +                
> +              module->state = AZY_SERVER_MODULE_STATE_POST;
> +              if (module->suspend) return EINA_TRUE;
> +      
> +      default:
> +        if (module->recv.data) free(module->recv.data);
> +        module->recv.data = NULL;
> +     }
> +   module->run_method = EINA_TRUE;
> +   module->state = AZY_SERVER_MODULE_STATE_INIT;
> +   return client->resume_ret;
>  }
>  
>  static void
> @@ -488,7 +556,7 @@
>     Eina_Strbuf *header;
>     Azy_Net *net;
>  
> -   net = client->net;
> +   net = client->current;
>  
>     DBG("(client=%p, data=%p, content=%p)", client, data, content);
>     if (!ecore_con_client_connected_get(net->conn))
> @@ -524,8 +592,7 @@
>          azy_net_header_set(net, "Set-Cookie", idstr);
>       }
>  
> -   if (!net->type)
> -     net->type = AZY_NET_TYPE_RESPONSE;
> +   net->type = AZY_NET_TYPE_RESPONSE;
>     if (!net->http.content_length)
>       {
>          if (content && content->length)
> @@ -562,7 +629,6 @@
>     if (net->http.version == 0)
>       {
>          INFO("Disconnecting for HTTP/1.0 compliance");
> -        ecore_con_client_flush(net->conn);
>          ecore_con_client_del(net->conn);
>       }
>  
> @@ -577,20 +643,28 @@
>     Azy_Content *content;
>     
>     DBG("(client=%p)", client);
> -   content = azy_content_new(NULL);
> +   if (client->resume_rpc)
> +     content = client->resume_rpc;
> +   else
> +     content = azy_content_new(NULL);
>     EINA_SAFETY_ON_NULL_RETURN_VAL(content, EINA_FALSE);
>  
> -   if ((!azy_content_unserialize_request(content, t, (char
> *)client->net->buffer, client->net->size)) &&
> +   if (!client->resume_rpc)
> +     if ((!azy_content_unserialize_request(content, t, (char
> *)client->current->buffer, client->current->size)) && (!content->faultcode))
> -     azy_content_error_faultmsg_set(content, -1, "Unserialize request
> failure.");
> -   else
> +       azy_content_error_faultmsg_set(content, -1, "Unserialize request
> failure."); +
> +   client->resume_rpc = content;
> +   if (!content->error_set)
>       _azy_server_client_method_run(client, content);
>  
> +   if (client->suspend) return EINA_TRUE;
>     azy_content_serialize_response(content, t);
> -   azy_net_transport_set(client->net, t);
> +   azy_net_transport_set(client->current, t);
>     _azy_server_client_send(client, NULL, content);
>  
>     azy_content_free(content);
> +   client->resume_rpc = NULL;
>  
>     return EINA_TRUE;
>  }
> @@ -598,49 +672,70 @@
>  static Eina_Bool
>  _azy_server_client_handler_request(Azy_Server_Client *client)
>  {
> +   Azy_Net *new;
> +   
>     DBG("(client=%p)", client);
> -
>     client->handled = EINA_TRUE;
> -
> -   switch (client->net->type)
> +   EINA_SAFETY_ON_TRUE_RETURN_VAL(client->dead, EINA_TRUE);
> +   if (client->suspend)
>       {
> +        INFO("Storing new call for suspended client");
> +        client->suspended_nets = eina_list_append(client->suspended_nets,
> client->net);
> +        client->net = azy_net_new(client->net->conn);
> +        client->net->server_client = EINA_TRUE;
> +        return EINA_TRUE;
> +     }
> +   if (client->resume)
> +     client->current = client->resume;
> +   else
> +     {
> +        new = azy_net_new(client->net->conn);
> +        new->server_client = EINA_TRUE;
> +        client->current = client->net;
> +        client->net = new;
> +     }
> +   
> +   switch (client->current->type)
> +     {
>        case AZY_NET_TYPE_GET:
>        case AZY_NET_TYPE_PUT:
>          _azy_server_client_get_put(client);
> +        if (!client->suspend)
> +          {
> +             azy_net_free(client->current);
> +             client->current = NULL;
> +             client->resume_ret = EINA_FALSE;
> +          }
>          return ECORE_CALLBACK_RENEW;
>        case AZY_NET_TYPE_POST:
> -        client->net->transport =
> azy_events_net_transport_get(azy_net_header_get(client->net, "content-type"));
> -        switch (client->net->transport)
> +        if (!client->current->transport)
> +          client->current->transport =
> azy_events_net_transport_get(azy_net_header_get(client->current,
> "content-type"));
> +        switch (client->current->transport)
>            {
>             case AZY_NET_TRANSPORT_JSON:
>             case AZY_NET_TRANSPORT_XML:
>             /*case AZY_NET_TRANSPORT_EET:*/
> -             _azy_server_client_rpc(client, client->net->transport);
> -             break;
> +             _azy_server_client_rpc(client, client->current->transport);
> +             if (!client->suspend)
> +               {
> +                  azy_net_free(client->current);
> +                  client->current = NULL;
> +                  client->resume_ret = EINA_FALSE;
> +               }
> +             return ECORE_CALLBACK_RENEW;
>  
>             case AZY_NET_TRANSPORT_TEXT:
>             case AZY_NET_TRANSPORT_HTML:
>             default:
>               /* FIXME: this isn't supported yet but probably should be
> somehow? */
> -             goto error;
> +             break;
>  
>            }
> +      default:
>          break;
> -      default:
> -        goto error;
>       }
> -
> -   { /* reset net object for next request if pipelining */
> -      Azy_Net *net;
> -      net = azy_net_new(client->net->conn);
> -      net->server_client = EINA_TRUE;
> -      azy_net_free(client->net);
> -      client->net = net;
> -   }
>     
> -   return ECORE_CALLBACK_RENEW;
> -error:
> -   azy_events_connection_kill(client->net->conn, EINA_TRUE, error501);
> +   azy_events_connection_kill(client->current->conn, EINA_TRUE, error501);
>     _azy_server_client_free(client);
>     return ECORE_CALLBACK_RENEW;
>  }
> @@ -851,3 +946,113 @@
>     return ECORE_CALLBACK_RENEW;
>  }
>  
> +/**
> + * @defgroup Azy_Server_Module_Advanced Advanced Server Module Functions
> + * @brief Advanced functions which affect #Azy_Server_Module objects
> + * @{
> + */
> +/**
> + * @brief Resume a suspended client's activities
> + * This function is used on a suspended client to resume it,
> + * allowing the current and subsequent transmissions to begin processing
> again.
> + * @param module The suspended module (NOT #NULL)
> + */
> +void
> +azy_server_module_events_resume(Azy_Server_Module *module)
> +{
> +   Azy_Server_Client *client;
> +   Azy_Net *net;
> +   
> +   DBG("(module=%p)", module);
> +   
> +   if (!AZY_MAGIC_CHECK(module, AZY_MAGIC_SERVER_MODULE))
> +     {
> +        AZY_MAGIC_FAIL(module, AZY_MAGIC_SERVER_MODULE);
> +        return;
> +     }
> +   client = module->client;
> +   if (client->dead)
> +     {
> +        azy_net_free(client->resume);
> +        client->resume = NULL;
> +        if (client->resume_rpc) azy_content_free(client->resume_rpc);
> +        client->suspend = EINA_FALSE;
> +        EINA_LIST_FREE(client->suspended_nets, net)
> +          azy_net_free(net);
> +        _azy_server_client_free(module->client);
> +        return;
> +     }
> +   if (!module->suspend)
> +     {
> +        WARN("Module is currently active, this function has no effect!");
> +        return;
> +     }
> +   
> +   module->suspend = EINA_FALSE;
> +   client->suspend = EINA_FALSE;
> +   _azy_server_client_handler_request(client);
> +   if (client->suspend) return;
> +   EINA_LIST_FREE(client->suspended_nets, net)
> +     {
> +        client->resume = net;
> +        _azy_server_client_handler_request(client);
> +        if (client->suspend) return;
> +        client->resume_ret = EINA_FALSE;
> +     }
> +  
> +   client->resume = NULL;
> +   if (client->dead)
> +     _azy_server_client_free(client);
> +}
> +
> +/**
> + * @brief Suspend an active client's activity
> + * This function allows for a module (and therefore its client)
> + * to be suspended, preventing any further action from occurring until
> + * azy_server_module_events_resume is called on it. Since RPC is synchronous
> + * by nature, all subsequent methods sent by the client will be stored until
> + * the client is resumed.
> + * @param module The module
> + */
> +void
> +azy_server_module_events_suspend(Azy_Server_Module *module)
> +{
> +   DBG("(module=%p)", module);
> +   
> +   if (!AZY_MAGIC_CHECK(module, AZY_MAGIC_SERVER_MODULE))
> +     {
> +        AZY_MAGIC_FAIL(module, AZY_MAGIC_SERVER_MODULE);
> +        return;
> +     }
> +   EINA_SAFETY_ON_TRUE_RETURN(module->client->dead);
> +   if (module->suspend)
> +     {
> +        WARN("Module is currently suspended, this function has no effect!");
> +        return;
> +     }
> +
> +
> +   module->suspend = EINA_TRUE;
> +   module->client->suspend = EINA_TRUE;
> +   module->client->resume = module->client->current;
> +}
> +
> +/**
> + * @brief Return the suspend state of a module
> + * Use this function to determine whether a module is currently suspended
> + * @param module The module (NOT #NULL)
> + * @return EINA_TRUE if the module is suspended, else EINA_FALSE
> + */
> +Eina_Bool
> +azy_server_module_events_suspended_get(Azy_Server_Module *module)
> +{
> +   DBG("(module=%p)", module);
> +   
> +   if (!AZY_MAGIC_CHECK(module, AZY_MAGIC_SERVER_MODULE))
> +     {
> +        AZY_MAGIC_FAIL(module, AZY_MAGIC_SERVER_MODULE);
> +        return EINA_FALSE;
> +     }
> +   return module->suspend;
> +}
> +/** @} */
> 
> Modified: trunk/PROTO/azy/src/lib/azy_server_module.c
> ===================================================================
> --- trunk/PROTO/azy/src/lib/azy_server_module.c       2011-02-11 21:46:36
> UTC (rev 56957) +++ trunk/PROTO/azy/src/lib/azy_server_module.c
> 2011-02-12 05:28:34 UTC (rev 56958) @@ -40,7 +40,11 @@
>  Azy_Net_Data *
>  azy_server_module_recv_get(Azy_Server_Module *module)
>  {
> -   EINA_SAFETY_ON_NULL_RETURN_VAL(module, NULL);
> +   if (!AZY_MAGIC_CHECK(module, AZY_MAGIC_SERVER_MODULE))
> +     {
> +        AZY_MAGIC_FAIL(module, AZY_MAGIC_SERVER_MODULE);
> +        return NULL;
> +     }
>     return &module->recv;
>  }
>  
> @@ -57,7 +61,11 @@
>  void *
>  azy_server_module_data_get(Azy_Server_Module *module)
>  {
> -   EINA_SAFETY_ON_NULL_RETURN_VAL(module, NULL);
> +   if (!AZY_MAGIC_CHECK(module, AZY_MAGIC_SERVER_MODULE))
> +     {
> +        AZY_MAGIC_FAIL(module, AZY_MAGIC_SERVER_MODULE);
> +        return NULL;
> +     }
>  
>     return module->data;
>  }
> @@ -74,13 +82,37 @@
>  Azy_Net *
>  azy_server_module_net_get(Azy_Server_Module *module)
>  {
> -   EINA_SAFETY_ON_NULL_RETURN_VAL(module, NULL);
> +   if (!AZY_MAGIC_CHECK(module, AZY_MAGIC_SERVER_MODULE))
> +     {
> +        AZY_MAGIC_FAIL(module, AZY_MAGIC_SERVER_MODULE);
> +        return NULL;
> +     }
>     EINA_SAFETY_ON_NULL_RETURN_VAL(module->client, NULL);
>  
>     return module->client->net;
>  }
>  
>  /**
> + * @brief Return the #Azy_Content object of the current module's connection
> + *
> + * This function is used to return the current module's return content
> object,
> + * allowing manipulation of the return value.
> + * @note This should only be used on a suspended module.
> + * @param module The server module (NOT #NULL)
> + * @return The #Azy_Content object
> + */
> +Azy_Content *
> +azy_server_module_content_get(Azy_Server_Module *module)
> +{
> +   if (!AZY_MAGIC_CHECK(module, AZY_MAGIC_SERVER_MODULE))
> +     {
> +        AZY_MAGIC_FAIL(module, AZY_MAGIC_SERVER_MODULE);
> +        return NULL;
> +     }
> +   return module->content;
> +}
> +
> +/**
>   * @brief Return the #Azy_Server_Module_Def of a server with a given name
>   * 
>   * This function finds the #Azy_Server_Module_Def with @p name in @p server
> and @@ -505,4 +537,22 @@
>     return EINA_TRUE;
>  }
>  
> +/**
> + * @brief Return the state of an #Azy_Server_Module object
> + * The return value of this function represents the connection state of the
> associated client.
> + * @param module The module (NOT #NULL)
> + * @return EINA_TRUE if the client is connected, else EINA_FALSE
> + */
> +Eina_Bool
> +azy_server_module_active_get(Azy_Server_Module *module)
> +{
> +   if (!AZY_MAGIC_CHECK(module, AZY_MAGIC_SERVER_MODULE))
> +     {
> +        AZY_MAGIC_FAIL(module, AZY_MAGIC_SERVER_MODULE);
> +        return EINA_FALSE;
> +     }
> +
> +   return !module->client->dead;
> +}
> +
>  /** @} */
> 
> Modified: trunk/PROTO/azy/src/tests/client.c
> ===================================================================
> --- trunk/PROTO/azy/src/tests/client.c        2011-02-11 21:46:36 UTC (rev
> 56957) +++ trunk/PROTO/azy/src/tests/client.c 2011-02-12 05:28:34 UTC
> (rev 56958) @@ -18,7 +18,7 @@
>       { \
>          if (!azy_client_call_checker(cli, err, ret, X, __PRETTY_FUNCTION__))
> \ { \
> -             printf("%s\n", azy_content_error_message_get(err)); \
> +             /* printf("%s\n", azy_content_error_message_get(err)); \ */ \
>               exit(1); \
>            } \
>       } while (0)
> @@ -110,6 +110,23 @@
>  }
>  
>  static Eina_Error
> +_T_Test2_suspend_ret(Azy_Client *client __UNUSED__, Azy_Content *content,
> void *retval) +{
> +   const char *ret;
> + 
> +   if (azy_content_error_is_set(content))
> +     {
> +        printf("Error encountered: %s\n",
> azy_content_error_message_get(content));
> +        azy_client_close(client);
> +        ecore_main_loop_quit();
> +        return azy_content_error_code_get(content);
> +     }
> +   ret = retval;
> +   printf("%s: Success? %s! %s\n", __PRETTY_FUNCTION__, ret ? "YES" : "NO",
> ret ? ret : "");
> +   return AZY_ERROR_NONE;
> +}
> +
> +static Eina_Error
>  _T_Test2_auth_ret(Azy_Client *client __UNUSED__, Azy_Content *content, void
> *retval) {
>     Eina_Bool ret;
> @@ -175,6 +192,9 @@
>     ret = T_Test1_getAllArrays(cli, err, NULL);
>     CALL_CHECK(_T_Test1_getAllArrays_ret);
>  
> +   ret = T_Test2_suspend(cli, err, NULL);
> +   CALL_CHECK(_T_Test2_suspend_ret);
> +
>     ret = T_Test2_auth(cli, "name", "pass", err, NULL);
>     CALL_CHECK(_T_Test2_auth_ret);
>  
> @@ -195,13 +215,8 @@
>          }
>        azy_value_struct_member_set(struc, "test", azy_value_int_new(100));
>        azy_content_param_add(content, struc);
> -      ret = azy_client_call(cli, content, AZY_NET_TRANSPORT_JSON,
> (Azy_Content_Cb)azy_value_to_T_Struct);
> -           if (!azy_client_call_checker(cli, err, ret,
> _T_Test1_undefined_ret, __PRETTY_FUNCTION__)) 
> -          { 
> -             printf("%s\n", azy_content_error_message_get(err)); 
> -             exit(1); 
> -          } 
> -   //   CALL_CHECK(_T_Test1_undefined_ret);
> +      ret = azy_client_call(cli, content, AZY_NET_TRANSPORT_JSON, NULL);
> +      CALL_CHECK(_T_Test1_undefined_ret);
>        azy_content_free(content);
>     }
>  
> 
> Modified: trunk/PROTO/azy/src/tests/server.c
> ===================================================================
> --- trunk/PROTO/azy/src/tests/server.c        2011-02-11 21:46:36 UTC (rev
> 56957) +++ trunk/PROTO/azy/src/tests/server.c 2011-02-12 05:28:34 UTC
> (rev 56958) @@ -8,6 +8,21 @@
>  #include "T_SQL.azy_server.h"
>  #endif
>  
> +Eina_Bool
> +server_suspend(Azy_Server_Module *m)
> +{
> +   Azy_Value *v;
> +   Azy_Content *content;
> +
> +   if (!azy_server_module_active_get(m)) return EINA_FALSE;
> +   v = azy_value_string_new(eina_stringshare_add("that was crazy!"));
> +   content = azy_server_module_content_get(m);
> +   azy_content_retval_set(content, v);
> +   
> +   azy_server_module_events_resume(m);
> +   return EINA_FALSE;
> +}
> +
>  int
>  main(void)
>  {
> 
> Modified: trunk/PROTO/azy/src/tests/test.azy
> ===================================================================
> --- trunk/PROTO/azy/src/tests/test.azy        2011-02-11 21:46:36 UTC (rev
> 56957) +++ trunk/PROTO/azy/src/tests/test.azy 2011-02-12 05:28:34 UTC
> (rev 56958) @@ -363,8 +363,7 @@
>     __fallback__
>     <% /* Eina_Bool (*Azy_Server_Module_Content_Cb)(Azy_Server_Module
> *module, Azy_Content *content) */ (void)module;
> -     printf("Unknown method called %s!\n",
> azy_content_method_full_get(content));
> -     azy_content_retval_set(content, azy_value_bool_new(EINA_TRUE)); /**<
> retval must be explicitly set here */
> +     azy_content_error_faultmsg_set(content, -1, "Unknown method called:
> %s!", azy_content_method_full_get(content)); return EINA_TRUE; /**< fallback
> will use the default handler if #EINA_FALSE is returned;
>                           * the default handler does almost exactly this
>                           */
> @@ -508,6 +507,13 @@
>     <%
>       return eina_stringshare_ref(data_->username);
>     %>
> +
> +   string suspend()
> +   <%
> +     Eina_Bool server_suspend(Azy_Server_Module *m);
> +     ecore_timer_add(5.0, (Ecore_Task_Cb)server_suspend, module);
> +     azy_server_module_events_suspend(module);
> +   %>
>  }
>  
>  /** slightly more complicated example that uses mysql
> 
> 
I tested this pretty thoroughly before committing it so I think it should work
at least 25-30% of the time.

Note that it IS possible to continually pause and resume the same method call;
remember that it will progress 1 step closer to completion every time you
resume it, however.
Also, pausing/resuming events recursively is supported.

-- 
Mike Blumenkrantz
Zentific: NULL pointer dereferences now 50% off!

------------------------------------------------------------------------------
The ultimate all-in-one performance toolkit: Intel(R) Parallel Studio XE:
Pinpoint memory and threading errors before they happen.
Find and fix more than 250 security defects in the development cycle.
Locate bottlenecks in serial and parallel code that limit performance.
http://p.sf.net/sfu/intel-dev2devfeb
_______________________________________________
enlightenment-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/enlightenment-devel

Reply via email to