]> granicus.if.org Git - transmission/commitdiff
Improve RPC performance for local sessions
authorMike Gelfand <mikedld@mikedld.com>
Mon, 13 Jul 2015 00:32:48 +0000 (00:32 +0000)
committerMike Gelfand <mikedld@mikedld.com>
Mon, 13 Jul 2015 00:32:48 +0000 (00:32 +0000)
Don't unnecessarily de-/serialize JSON data if local session is used.

gtk/details.c
gtk/main.c
gtk/tr-core.c
gtk/tr-core.h
libtransmission/rpc-server.c
libtransmission/rpc-test.c
libtransmission/rpcimpl.c
libtransmission/rpcimpl.h
qt/RpcClient.cc
qt/RpcClient.h

index e9720bc4fc9de4fa791ca20c0a03da86785c435a..5ffae31f1140ecbe1ace741f5feb6730934a425e 100644 (file)
@@ -2442,15 +2442,19 @@ on_add_tracker_response (GtkDialog * dialog, int response, gpointer gdi)
         {
           if (tr_urlIsValidTracker (url))
             {
-              char * json = g_strdup_printf (
-                "{\n"
-                "  \"method\": \"torrent-set\",\n"
-                "  \"arguments\": { \"id\": %d, \"trackerAdd\": [ \"%s\" ] }\n"
-                "}\n",
-              torrent_id, url);
-              gtr_core_exec_json (di->core, json);
+              tr_variant top, * args, * trackers;
+
+              tr_variantInitDict (&top, 2);
+              tr_variantDictAddStr (&top, TR_KEY_method, "torrent-set");
+              args = tr_variantDictAddDict (&top, TR_KEY_arguments, 2);
+              tr_variantDictAddInt (args, TR_KEY_id, torrent_id);
+              trackers = tr_variantDictAddList (args, TR_KEY_trackerAdd, 1);
+              tr_variantListAddStr (trackers, url);
+
+              gtr_core_exec (di->core, &top);
               refresh (di);
-              g_free (json);
+
+              tr_variantFree (&top);
             }
           else
             {
@@ -2518,20 +2522,25 @@ on_tracker_list_remove_button_clicked (GtkButton * button UNUSED, gpointer gdi)
 
   if (gtk_tree_selection_get_selected (sel, &model, &iter))
     {
-      char * json;
       int torrent_id;
       int tracker_id;
+      tr_variant top, * args, * trackers;
+
       gtk_tree_model_get (model, &iter, TRACKER_COL_TRACKER_ID, &tracker_id,
                                         TRACKER_COL_TORRENT_ID, &torrent_id,
                                         -1);
-      json = g_strdup_printf ("{\n"
-                              "  \"method\": \"torrent-set\",\n"
-                              "  \"arguments\": { \"id\": %d, \"trackerRemove\": [ %d ] }\n"
-                              "}\n",
-                              torrent_id, tracker_id);
-      gtr_core_exec_json (di->core, json);
+
+      tr_variantInitDict (&top, 2);
+      tr_variantDictAddStr (&top, TR_KEY_method, "torrent-set");
+      args = tr_variantDictAddDict (&top, TR_KEY_arguments, 2);
+      tr_variantDictAddInt (args, TR_KEY_id, torrent_id);
+      trackers = tr_variantDictAddList (args, TR_KEY_trackerRemove, 1);
+      tr_variantListAddInt (trackers, tracker_id);
+
+      gtr_core_exec (di->core, &top);
       refresh (di);
-      g_free (json);
+
+      tr_variantFree (&top);
     }
 }
 
index 0a8882cafa132d190ef23f6cd0ae791fecfae6c5..53beb35af84cd090d6ec32a85981eb286e8b6bfe 100644 (file)
@@ -1414,10 +1414,7 @@ call_rpc_for_selected_torrents (struct cbdata * data, const char * method)
 
   if (tr_variantListSize (ids) != 0)
     {
-      int json_len;
-      char * json = tr_variantToStr (&top, TR_VARIANT_FMT_JSON_LEAN, &json_len);
-      tr_rpc_request_exec_json (session, json, json_len, NULL, NULL);
-      g_free (json);
+      tr_rpc_request_exec_json (session, &top, NULL, NULL);
       invoked = TRUE;
     }
 
@@ -1467,16 +1464,24 @@ static void
 start_all_torrents (struct cbdata * data)
 {
   tr_session * session = gtr_core_session (data->core);
-  const char * cmd = "{ \"method\": \"torrent-start\" }";
-  tr_rpc_request_exec_json (session, cmd, strlen (cmd), NULL, NULL);
+  tr_variant request;
+
+  tr_variantInitDict (&request, 1);
+  tr_variantDictAddStr (&request, TR_KEY_method, "torrent-start");
+  tr_rpc_request_exec_json (session, &request, NULL, NULL);
+  tr_variantFree (&request);
 }
 
 static void
 pause_all_torrents (struct cbdata * data)
 {
   tr_session * session = gtr_core_session (data->core);
-  const char * cmd = "{ \"method\": \"torrent-stop\" }";
-  tr_rpc_request_exec_json (session, cmd, strlen (cmd), NULL, NULL);
+  tr_variant request;
+
+  tr_variantInitDict (&request, 1);
+  tr_variantDictAddStr (&request, TR_KEY_method, "torrent-stop");
+  tr_rpc_request_exec_json (session, &request, NULL, NULL);
+  tr_variantFree (&request);
 }
 
 static tr_torrent*
index 96340b0c0c95344c49f89fa1647c00b3065c0c34..7572683dc3eba081e14b25fe51faa014b1b5e5dd 100644 (file)
@@ -1726,41 +1726,41 @@ static GHashTable * pendingRequests = NULL;
 static gboolean
 core_read_rpc_response_idle (void * vresponse)
 {
-  tr_variant top;
   int64_t intVal;
-  struct evbuffer * response = vresponse;
+  tr_variant * response = vresponse;
 
-  tr_variantFromJson (&top, evbuffer_pullup (response, -1), evbuffer_get_length (response));
-
-  if (tr_variantDictFindInt (&top, TR_KEY_tag, &intVal))
+  if (tr_variantDictFindInt (response, TR_KEY_tag, &intVal))
     {
       const int tag = (int)intVal;
       struct pending_request_data * data = g_hash_table_lookup (pendingRequests, &tag);
       if (data)
         {
           if (data->response_func)
-            (*data->response_func)(data->core, &top, data->response_func_user_data);
+            (*data->response_func)(data->core, response, data->response_func_user_data);
           g_hash_table_remove (pendingRequests, &tag);
         }
     }
 
-  tr_variantFree (&top);
-  evbuffer_free (response);
+  tr_variantFree (response);
+  tr_free (response);
   return G_SOURCE_REMOVE;
 }
 
 static void
-core_read_rpc_response (tr_session       * session UNUSED,
-                        struct evbuffer  * response,
-                        void             * unused UNUSED)
+core_read_rpc_response (tr_session * session UNUSED,
+                        tr_variant * response,
+                        void       * unused UNUSED)
 {
-  struct evbuffer * buf = evbuffer_new ();
-  evbuffer_add_buffer (buf, response);
-  gdk_threads_add_idle (core_read_rpc_response_idle, buf);
+  tr_variant * response_copy = tr_new (tr_variant, 1);
+
+  *response_copy = *response;
+  tr_variantInitBool (response, false);
+
+  gdk_threads_add_idle (core_read_rpc_response_idle, response_copy);
 }
 
 static void
-core_send_rpc_request (TrCore * core, const char * json, int tag,
+core_send_rpc_request (TrCore * core, const tr_variant * request, int tag,
                        server_response_func * response_func,
                        void * response_func_user_data)
 {
@@ -1787,9 +1787,15 @@ core_send_rpc_request (TrCore * core, const char * json, int tag,
 
       /* make the request */
 #ifdef DEBUG_RPC
-      g_message ("request: [%s]", json);
+      {
+        struct evbuffer * buf = tr_variantToBuf (request, TR_VARIANT_FMT_JSON_LEAN);
+        const size_t buf_len = evbuffer_get_length (buf);
+        g_message ("request: [%*.*s]", (int) buf_len, (int) buf_len, evbuffer_pullup (buf, -1));
+        evbuffer_free (buf);
+      }
 #endif
-      tr_rpc_request_exec_json (session, json, strlen (json), core_read_rpc_response, GINT_TO_POINTER (tag));
+
+      tr_rpc_request_exec_json (session, request, core_read_rpc_response, GINT_TO_POINTER (tag));
     }
 }
 
@@ -1813,10 +1819,14 @@ on_port_test_response (TrCore * core, tr_variant * response, gpointer u UNUSED)
 void
 gtr_core_port_test (TrCore * core)
 {
-  char buf[64];
   const int tag = nextTag++;
-  g_snprintf (buf, sizeof (buf), "{ \"method\": \"port-test\", \"tag\": %d }", tag);
-  core_send_rpc_request (core, buf, tag, on_port_test_response, NULL);
+  tr_variant request;
+
+  tr_variantInitDict (&request, 2);
+  tr_variantDictAddStr (&request, TR_KEY_method, "port-test");
+  tr_variantDictAddInt (&request, TR_KEY_tag, tag);
+  core_send_rpc_request (core, &request, tag, on_port_test_response, NULL);
+  tr_variantFree (&request);
 }
 
 /***
@@ -1842,29 +1852,25 @@ on_blocklist_response (TrCore * core, tr_variant * response, gpointer data UNUSE
 void
 gtr_core_blocklist_update (TrCore * core)
 {
-  char buf[64];
   const int tag = nextTag++;
-  g_snprintf (buf, sizeof (buf), "{ \"method\": \"blocklist-update\", \"tag\": %d }", tag);
-  core_send_rpc_request (core, buf, tag, on_blocklist_response, NULL);
+  tr_variant request;
+
+  tr_variantInitDict (&request, 2);
+  tr_variantDictAddStr (&request, TR_KEY_method, "blocklist-update");
+  tr_variantDictAddInt (&request, TR_KEY_tag, tag);
+  core_send_rpc_request (core, &request, tag, on_blocklist_response, NULL);
+  tr_variantFree (&request);
 }
 
 /***
 ****
 ***/
 
-void
-gtr_core_exec_json (TrCore * core, const char * json)
-{
-  const int tag = nextTag++;
-  core_send_rpc_request (core, json, tag, NULL, NULL);
-}
-
 void
 gtr_core_exec (TrCore * core, const tr_variant * top)
 {
-  char * json = tr_variantToStr (top, TR_VARIANT_FMT_JSON_LEAN, NULL);
-  gtr_core_exec_json (core, json);
-  tr_free (json);
+  const int tag = nextTag++;
+  core_send_rpc_request (core, top, tag, NULL, NULL);
 }
 
 /***
index 5bd75584db702052cd88639e4e61d494ed45cbc3..c04c9bd4e0a5d8ee7733d7694fcf02cea9d8800f 100644 (file)
@@ -155,8 +155,6 @@ void gtr_core_blocklist_update (TrCore * core);
 
 void gtr_core_exec (TrCore * core, const tr_variant * benc);
 
-void gtr_core_exec_json (TrCore * core, const char * json);
-
 void gtr_core_open_folder (TrCore * core, int torrent_id);
 
 
index 6064d820b8dfc6907b4b27a0a28f2f5978b23b6f..df7e69e50c5ce23a9b9b21e193198d7a1f088060 100644 (file)
@@ -265,14 +265,7 @@ handle_upload (struct evhttp_request * req,
             }
 
           if (have_source)
-            {
-              struct evbuffer * json = tr_variantToBuf (&top, TR_VARIANT_FMT_JSON);
-              tr_rpc_request_exec_json (server->session,
-                                        evbuffer_pullup (json, -1),
-                                        evbuffer_get_length (json),
-                                        NULL, NULL);
-              evbuffer_free (json);
-            }
+            tr_rpc_request_exec_json (server->session, &top, NULL, NULL);
 
           tr_variantFree (&top);
         }
@@ -516,19 +509,21 @@ struct rpc_response_data
 };
 
 static void
-rpc_response_func (tr_session      * session UNUSED,
-                   struct evbuffer * response,
-                   void            * user_data)
+rpc_response_func (tr_session * session UNUSED,
+                   tr_variant * response,
+                   void       * user_data)
 {
   struct rpc_response_data * data = user_data;
+  struct evbuffer * response_buf = tr_variantToBuf (response, TR_VARIANT_FMT_JSON_LEAN);
   struct evbuffer * buf = evbuffer_new ();
 
-  add_response (data->req, data->server, buf, response);
+  add_response (data->req, data->server, buf, response_buf);
   evhttp_add_header (data->req->output_headers,
                      "Content-Type", "application/json; charset=UTF-8");
   evhttp_send_reply (data->req, HTTP_OK, "OK", buf);
 
   evbuffer_free (buf);
+  evbuffer_free (response_buf);
   tr_free (data);
 }
 
@@ -538,13 +533,18 @@ handle_rpc_from_json (struct evhttp_request * req,
                       const char            * json,
                       size_t                  json_len)
 {
+  tr_variant top;
+  bool have_content = tr_variantFromJson (&top, json, json_len) == 0;
   struct rpc_response_data * data;
 
   data = tr_new0 (struct rpc_response_data, 1);
   data->req = req;
   data->server = server;
 
-  tr_rpc_request_exec_json (server->session, json, json_len, rpc_response_func, data);
+  tr_rpc_request_exec_json (server->session, have_content ? &top : NULL, rpc_response_func, data);
+
+  if (have_content)
+    tr_variantFree (&top);
 }
 
 static void
index 9688355d83e6706ddf956ed2bc0dfdfe7deb45bd..7330f4b88471a08fca184e7e363964a4f5cdb96c 100644 (file)
@@ -7,10 +7,6 @@
  * $Id$
  */
 
-#include <string.h>
-
-#include <event2/buffer.h>
-
 #include "transmission.h"
 #include "rpcimpl.h"
 #include "utils.h"
@@ -75,18 +71,19 @@ test_list (void)
 ***/
 
 static void
-rpc_response_func (tr_session      * session    UNUSED,
-                   struct evbuffer * response,
-                   void            * setme)
+rpc_response_func (tr_session * session    UNUSED,
+                   tr_variant * response,
+                   void       * setme)
 {
-  tr_variantFromBuf (setme, TR_VARIANT_FMT_JSON, evbuffer_pullup(response,-1), evbuffer_get_length(response), NULL, NULL);
+  *(tr_variant *) setme = *response;
+  tr_variantInitBool (response, false);
 }
 
 static int
 test_session_get_and_set (void)
 {
   tr_session * session;
-  const char * json;
+  tr_variant request;
   tr_variant response;
   tr_variant * args;
   tr_torrent * tor;
@@ -95,10 +92,11 @@ test_session_get_and_set (void)
   tor= libttest_zero_torrent_init (session);
   check (tor != NULL);
 
-  json = "{\"method\":\"session-get\"}";
-  tr_rpc_request_exec_json (session, json, strlen(json), rpc_response_func, &response);
+  tr_variantInitDict (&request, 1);
+  tr_variantDictAddStr (&request, TR_KEY_method, "session-get");
+  tr_rpc_request_exec_json (session, &request, rpc_response_func, &response);
+  tr_variantFree (&request);
 
-  check (tr_variantIsDict(&response));
   check (tr_variantIsDict(&response));
   check (tr_variantDictFindDict (&response, TR_KEY_arguments, &args));
   check (tr_variantDictFind (args, TR_KEY_alt_speed_down) != NULL);
index e119e7249187182d3aa5c07b8ccaf9b3b53ec141..6da1a9ff0f4c87425466f3dd42fac5ff1acf36fe 100644 (file)
@@ -84,29 +84,25 @@ notify (tr_session * session,
  * when the task is complete */
 struct tr_rpc_idle_data
 {
- tr_session            * session;
- tr_variant            * response;
- tr_variant            * args_out;
- tr_rpc_response_func    callback;
- void                  * callback_user_data;
 tr_session            * session;
 tr_variant            * response;
 tr_variant            * args_out;
 tr_rpc_response_func    callback;
 void                  * callback_user_data;
 };
 
 static void
 tr_idle_function_done (struct tr_rpc_idle_data * data, const char * result)
 {
- struct evbuffer * buf;
+  if (result == NULL)
+    result = "success";
+  tr_variantDictAddStr (data->response, TR_KEY_result, result);
 
- if (result == NULL)
-   result = "success";
- tr_variantDictAddStr (data->response, TR_KEY_result, result);
+  (*data->callback)(data->session, data->response, data->callback_user_data);
 
- buf = tr_variantToBuf (data->response, TR_VARIANT_FMT_JSON_LEAN);
- (*data->callback)(data->session, buf, data->callback_user_data);
- evbuffer_free (buf);
-
- tr_variantFree (data->response);
- tr_free (data->response);
- tr_free (data);
+  tr_variantFree (data->response);
+  tr_free (data->response);
+  tr_free (data);
 }
 
 /***
@@ -1450,7 +1446,7 @@ portTested (tr_session       * session UNUSED,
       tr_snprintf (result, sizeof (result), "success");
     }
 
-    tr_idle_function_done (data, result);
+  tr_idle_function_done (data, result);
 }
 
 static const char*
@@ -2177,28 +2173,29 @@ methods[] =
 };
 
 static void
-noop_response_callback (tr_session       * session UNUSED,
-                        struct evbuffer  * response UNUSED,
-                        void             * user_data UNUSED)
+noop_response_callback (tr_session * session UNUSED,
+                        tr_variant * response UNUSED,
+                        void       * user_data UNUSED)
 {
 }
 
-static void
-request_exec (tr_session             * session,
-              tr_variant             * request,
-              tr_rpc_response_func     callback,
-              void                   * callback_user_data)
+void
+tr_rpc_request_exec_json (tr_session            * session,
+                          const tr_variant      * request,
+                          tr_rpc_response_func    callback,
+                          void                  * callback_user_data)
 {
   int i;
   const char * str;
-  tr_variant * args_in = tr_variantDictFind (request, TR_KEY_arguments);
+  tr_variant * const mutable_request = (tr_variant *) request;
+  tr_variant * args_in = tr_variantDictFind (mutable_request, TR_KEY_arguments);
   const char * result = NULL;
 
   if (callback == NULL)
     callback = noop_response_callback;
 
   /* parse the request */
-  if (!tr_variantDictFindStr (request, TR_KEY_method, &str, NULL))
+  if (!tr_variantDictFindStr (mutable_request, TR_KEY_method, &str, NULL))
     {
       result = "no method name";
     }
@@ -2219,17 +2216,14 @@ request_exec (tr_session             * session,
     {
       int64_t tag;
       tr_variant response;
-      struct evbuffer * buf;
 
       tr_variantInitDict (&response, 3);
       tr_variantDictAddDict (&response, TR_KEY_arguments, 0);
       tr_variantDictAddStr (&response, TR_KEY_result, result);
-      if (tr_variantDictFindInt (request, TR_KEY_tag, &tag))
+      if (tr_variantDictFindInt (mutable_request, TR_KEY_tag, &tag))
         tr_variantDictAddInt (&response, TR_KEY_tag, tag);
 
-      buf = tr_variantToBuf (&response, TR_VARIANT_FMT_JSON_LEAN);
-      (*callback)(session, buf, callback_user_data);
-      evbuffer_free (buf);
+      (*callback)(session, &response, callback_user_data);
 
       tr_variantFree (&response);
     }
@@ -2238,7 +2232,6 @@ request_exec (tr_session             * session,
       int64_t tag;
       tr_variant response;
       tr_variant * args_out;
-      struct evbuffer * buf;
 
       tr_variantInitDict (&response, 3);
       args_out = tr_variantDictAddDict (&response, TR_KEY_arguments, 0);
@@ -2246,12 +2239,10 @@ request_exec (tr_session             * session,
       if (result == NULL)
         result = "success";
       tr_variantDictAddStr (&response, TR_KEY_result, result);
-      if (tr_variantDictFindInt (request, TR_KEY_tag, &tag))
+      if (tr_variantDictFindInt (mutable_request, TR_KEY_tag, &tag))
         tr_variantDictAddInt (&response, TR_KEY_tag, tag);
 
-      buf = tr_variantToBuf (&response, TR_VARIANT_FMT_JSON_LEAN);
-      (*callback)(session, buf, callback_user_data);
-      evbuffer_free (buf);
+      (*callback)(session, &response, callback_user_data);
 
       tr_variantFree (&response);
     }
@@ -2262,7 +2253,7 @@ request_exec (tr_session             * session,
       data->session = session;
       data->response = tr_new0 (tr_variant, 1);
       tr_variantInitDict (data->response, 3);
-      if (tr_variantDictFindInt (request, TR_KEY_tag, &tag))
+      if (tr_variantDictFindInt (mutable_request, TR_KEY_tag, &tag))
         tr_variantDictAddInt (data->response, TR_KEY_tag, tag);
       data->args_out = tr_variantDictAddDict (data->response, TR_KEY_arguments, 0);
       data->callback = callback;
@@ -2271,26 +2262,6 @@ request_exec (tr_session             * session,
     }
 }
 
-void
-tr_rpc_request_exec_json (tr_session            * session,
-                          const void            * request_json,
-                          int                     request_len,
-                          tr_rpc_response_func    callback,
-                          void                  * callback_user_data)
-{
-  tr_variant top;
-  int have_content;
-
-  if (request_len < 0)
-    request_len = strlen (request_json);
-
-  have_content = !tr_variantFromJson (&top, request_json, request_len);
-  request_exec (session, have_content ? &top : NULL, callback, callback_user_data);
-
-  if (have_content)
-    tr_variantFree (&top);
-}
-
 /**
  * Munge the URI into a usable form.
  *
@@ -2366,7 +2337,7 @@ tr_rpc_request_exec_uri (tr_session           * session,
       pch = next ? next + 1 : NULL;
     }
 
-  request_exec (session, &top, callback, callback_user_data);
+  tr_rpc_request_exec_json (session, &top, callback, callback_user_data);
 
   /* cleanup */
   tr_variantFree (&top);
index 6b6aab954057874075ccc58dfb8a2a5a7d6a9e1f..147ae75baaa15b39c5d0b3337c648fcc3750803a 100644 (file)
@@ -21,15 +21,13 @@ extern "C" {
 ****  RPC processing
 ***/
 
-struct evbuffer;
+typedef void (*tr_rpc_response_func)(tr_session * session,
+                                     tr_variant * response,
+                                     void       * user_data);
 
-typedef void (*tr_rpc_response_func)(tr_session      * session,
-                                     struct evbuffer * response,
-                                     void            * user_data);
 /* http://www.json.org/ */
 void tr_rpc_request_exec_json (tr_session            * session,
-                               const void            * request_json,
-                               int                     request_len,
+                               const tr_variant      * request,
                                tr_rpc_response_func    callback,
                                void                  * callback_user_data);
 
index dad99d5be7ad6cdf5f701094372afad3d8ede0c4..a10d800994df4b25e165f59e6d08e204eb8356b9 100644 (file)
 
 #define REQUEST_DATA_PROPERTY_KEY "requestData"
 
+namespace
+{
+  void
+  destroyVariant (tr_variant * json)
+  {
+    tr_variantFree (json);
+    tr_free (json);
+  }
+
+  TrVariantPtr
+  createVariant ()
+  {
+    return TrVariantPtr (tr_new0 (tr_variant, 1), &destroyVariant);
+  }
+}
+
 RpcClient::RpcClient (QObject * parent):
   QObject (parent),
   mySession (nullptr),
   myNAM (nullptr)
 {
-  connect (this, SIGNAL (responseReceived (QByteArray)),
-           this, SLOT (parseResponse (QByteArray)));
+  qRegisterMetaType<TrVariantPtr> ("TrVariantPtr");
+
+  connect (this, SIGNAL (responseReceived (TrVariantPtr)),
+           this, SLOT (parseResponse (TrVariantPtr)));
 }
 
 void
@@ -96,28 +114,23 @@ RpcClient::exec (tr_quark method, tr_variant * args, int64_t tag)
 void
 RpcClient::exec (const char* method, tr_variant * args, int64_t tag)
 {
-  tr_variant top;
-  tr_variantInitDict (&top, 3);
-  tr_variantDictAddStr (&top, TR_KEY_method, method);
+  TrVariantPtr json = createVariant ();
+  tr_variantInitDict (json.get (), 3);
+  tr_variantDictAddStr (json.get (), TR_KEY_method, method);
   if (tag >= 0)
-    tr_variantDictAddInt (&top, TR_KEY_tag, tag);
+    tr_variantDictAddInt (json.get (), TR_KEY_tag, tag);
   if (args != nullptr)
-    tr_variantDictSteal (&top, TR_KEY_arguments, args);
-
-  int length;
-  char * str = tr_variantToStr (&top, TR_VARIANT_FMT_JSON_LEAN, &length);
-  sendRequest (QByteArray (str, length));
-  tr_free (str);
+    tr_variantDictSteal (json.get (), TR_KEY_arguments, args);
 
-  tr_variantFree (&top);
+  sendRequest (json);
 }
 
 void
-RpcClient::sendRequest (const QByteArray& json)
+RpcClient::sendRequest (TrVariantPtr json)
 {
   if (mySession != nullptr)
     {
-      tr_rpc_request_exec_json (mySession, json.constData (), json.size (), localSessionCallback, this);
+      tr_rpc_request_exec_json (mySession, json.get (), localSessionCallback, this);
     }
   else if (!myUrl.isEmpty ())
     {
@@ -129,8 +142,13 @@ RpcClient::sendRequest (const QByteArray& json)
       if (!mySessionId.isEmpty ())
         request.setRawHeader (TR_RPC_SESSION_ID_HEADER, mySessionId.toUtf8 ());
 
-      QNetworkReply * reply = networkAccessManager ()->post (request, json);
-      reply->setProperty (REQUEST_DATA_PROPERTY_KEY, json);
+      int rawJsonDataLength;
+      char * rawJsonData = tr_variantToStr (json.get (), TR_VARIANT_FMT_JSON_LEAN, &rawJsonDataLength);
+      QByteArray jsonData (rawJsonData, rawJsonDataLength);
+      tr_free (rawJsonData);
+
+      QNetworkReply * reply = networkAccessManager ()->post (request, jsonData);
+      reply->setProperty (REQUEST_DATA_PROPERTY_KEY, QVariant::fromValue (json));
       connect (reply, SIGNAL (downloadProgress (qint64, qint64)), this, SIGNAL (dataReadProgress ()));
       connect (reply, SIGNAL (uploadProgress (qint64, qint64)), this, SIGNAL (dataSendProgress ()));
       connect (reply, SIGNAL (error (QNetworkReply::NetworkError)), this, SIGNAL (error (QNetworkReply::NetworkError)));
@@ -142,7 +160,7 @@ RpcClient::sendRequest (const QByteArray& json)
                   << ": "
                   << request.rawHeader (b).constData ()
                   << std::endl;
-      std::cerr << "Body:\n" << json.constData () << std::endl;
+      std::cerr << "Body:\n" << jsonData.constData () << std::endl;
 #endif
     }
 }
@@ -165,16 +183,19 @@ RpcClient::networkAccessManager ()
 }
 
 void
-RpcClient::localSessionCallback (tr_session * s, evbuffer * json, void * vself)
+RpcClient::localSessionCallback (tr_session * s, tr_variant * response, void * vself)
 {
   Q_UNUSED (s);
 
   RpcClient * self = static_cast<RpcClient*> (vself);
 
+  TrVariantPtr json = createVariant ();
+  *json = *response;
+  tr_variantInitBool (response, false);
+
   // this callback is invoked in the libtransmission thread, so we don't want
   // to process the response here... let's push it over to the Qt thread.
-  self->responseReceived (QByteArray (reinterpret_cast<const char*> (evbuffer_pullup (json, -1)),
-                                      static_cast<int> (evbuffer_get_length (json))).trimmed ());
+  self->responseReceived (json);
 }
 
 void
@@ -196,7 +217,7 @@ RpcClient::onFinished (QNetworkReply * reply)
       // we got a 409 telling us our session id has expired.
       // update it and resubmit the request.
       mySessionId = QString::fromUtf8 (reply->rawHeader (TR_RPC_SESSION_ID_HEADER));
-      sendRequest (reply->property (REQUEST_DATA_PROPERTY_KEY).toByteArray ());
+      sendRequest (reply->property (REQUEST_DATA_PROPERTY_KEY).value<TrVariantPtr> ());
     }
   else if (reply->error () != QNetworkReply::NoError)
     {
@@ -204,7 +225,12 @@ RpcClient::onFinished (QNetworkReply * reply)
     }
   else
     {
-      parseResponse (reply->readAll ().trimmed ());
+      const QByteArray jsonData = reply->readAll ().trimmed ();
+
+      TrVariantPtr json = createVariant ();
+      if (tr_variantFromJson (json.get (), jsonData.constData (), jsonData.size ()) == 0)
+        parseResponse (json);
+
       emit error (QNetworkReply::NoError);
     }
 
@@ -212,25 +238,19 @@ RpcClient::onFinished (QNetworkReply * reply)
 }
 
 void
-RpcClient::parseResponse (const QByteArray& json)
+RpcClient::parseResponse (TrVariantPtr json)
 {
-  tr_variant top;
-  if (tr_variantFromJson (&top, json.constData (), json.size ()) != 0)
-    return;
-
   int64_t tag;
-  if (!tr_variantDictFindInt (&top, TR_KEY_tag, &tag))
+  if (!tr_variantDictFindInt (json.get (), TR_KEY_tag, &tag))
     tag = -1;
 
   const char * result;
-  if (!tr_variantDictFindStr (&top, TR_KEY_result, &result, nullptr))
+  if (!tr_variantDictFindStr (json.get (), TR_KEY_result, &result, nullptr))
     result = nullptr;
 
   tr_variant * args;
-  if (!tr_variantDictFindDict (&top, TR_KEY_arguments, &args))
+  if (!tr_variantDictFindDict (json.get (), TR_KEY_arguments, &args))
     args = nullptr;
 
   emit executed (tag, result == nullptr ? QString () : QString::fromUtf8 (result), args);
-
-  tr_variantFree (&top);
 }
index 643e77c0f04b3ad14ba0898003cd57d6ea684d98..9a86f9059adf9a198ae34ede593d555594b2c9fc 100644 (file)
@@ -10,6 +10,8 @@
 #ifndef QTR_RPC_CLIENT_H
 #define QTR_RPC_CLIENT_H
 
+#include <memory>
+
 #include <QNetworkReply>
 #include <QObject>
 #include <QString>
 
 #include <libtransmission/transmission.h>
 #include <libtransmission/quark.h>
+#include <libtransmission/variant.h>
 
 class QByteArray;
 class QNetworkAccessManager;
 
+typedef std::shared_ptr<tr_variant> TrVariantPtr;
+Q_DECLARE_METATYPE (TrVariantPtr);
+
 extern "C"
 {
   struct evbuffer;
   struct tr_session;
-  struct tr_variant;
 }
 
 class RpcClient: public QObject
@@ -55,17 +60,17 @@ class RpcClient: public QObject
     void executed (int64_t tag, const QString& result, tr_variant * args);
 
     // private
-    void responseReceived (const QByteArray& json);
+    void responseReceived (TrVariantPtr json);
 
   private:
-    void sendRequest (const QByteArray& json);
+    void sendRequest (TrVariantPtr json);
     QNetworkAccessManager * networkAccessManager ();
 
-    static void localSessionCallback (tr_session * s, evbuffer * json, void * vself);
+    static void localSessionCallback (tr_session * s, tr_variant * response, void * vself);
 
   private slots:
     void onFinished (QNetworkReply * reply);
-    void parseResponse (const QByteArray& json);
+    void parseResponse (TrVariantPtr json);
 
   private:
     tr_session * mySession;