From 18ea8c429aa2c1690e4ad4c0d1f3d078ba8e4144 Mon Sep 17 00:00:00 2001 From: Mike Gelfand Date: Mon, 13 Jul 2015 00:32:48 +0000 Subject: [PATCH] Improve RPC performance for local sessions Don't unnecessarily de-/serialize JSON data if local session is used. --- gtk/details.c | 41 ++++++++++------- gtk/main.c | 21 +++++---- gtk/tr-core.c | 72 ++++++++++++++++------------- gtk/tr-core.h | 2 - libtransmission/rpc-server.c | 26 +++++------ libtransmission/rpc-test.c | 22 ++++----- libtransmission/rpcimpl.c | 89 ++++++++++++------------------------ libtransmission/rpcimpl.h | 10 ++-- qt/RpcClient.cc | 86 +++++++++++++++++++++------------- qt/RpcClient.h | 15 ++++-- 10 files changed, 197 insertions(+), 187 deletions(-) diff --git a/gtk/details.c b/gtk/details.c index e9720bc4f..5ffae31f1 100644 --- a/gtk/details.c +++ b/gtk/details.c @@ -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); } } diff --git a/gtk/main.c b/gtk/main.c index 0a8882caf..53beb35af 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -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* diff --git a/gtk/tr-core.c b/gtk/tr-core.c index 96340b0c0..7572683dc 100644 --- a/gtk/tr-core.c +++ b/gtk/tr-core.c @@ -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); } /*** diff --git a/gtk/tr-core.h b/gtk/tr-core.h index 5bd75584d..c04c9bd4e 100644 --- a/gtk/tr-core.h +++ b/gtk/tr-core.h @@ -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); diff --git a/libtransmission/rpc-server.c b/libtransmission/rpc-server.c index 6064d820b..df7e69e50 100644 --- a/libtransmission/rpc-server.c +++ b/libtransmission/rpc-server.c @@ -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 diff --git a/libtransmission/rpc-test.c b/libtransmission/rpc-test.c index 9688355d8..7330f4b88 100644 --- a/libtransmission/rpc-test.c +++ b/libtransmission/rpc-test.c @@ -7,10 +7,6 @@ * $Id$ */ -#include - -#include - #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); diff --git a/libtransmission/rpcimpl.c b/libtransmission/rpcimpl.c index e119e7249..6da1a9ff0 100644 --- a/libtransmission/rpcimpl.c +++ b/libtransmission/rpcimpl.c @@ -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); diff --git a/libtransmission/rpcimpl.h b/libtransmission/rpcimpl.h index 6b6aab954..147ae75ba 100644 --- a/libtransmission/rpcimpl.h +++ b/libtransmission/rpcimpl.h @@ -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); diff --git a/qt/RpcClient.cc b/qt/RpcClient.cc index dad99d5be..a10d80099 100644 --- a/qt/RpcClient.cc +++ b/qt/RpcClient.cc @@ -28,13 +28,31 @@ #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"); + + 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 (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 (evbuffer_pullup (json, -1)), - static_cast (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 ()); } 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); } diff --git a/qt/RpcClient.h b/qt/RpcClient.h index 643e77c0f..9a86f9059 100644 --- a/qt/RpcClient.h +++ b/qt/RpcClient.h @@ -10,6 +10,8 @@ #ifndef QTR_RPC_CLIENT_H #define QTR_RPC_CLIENT_H +#include + #include #include #include @@ -17,15 +19,18 @@ #include #include +#include class QByteArray; class QNetworkAccessManager; +typedef std::shared_ptr 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; -- 2.40.0