mirror of
https://github.com/transmission/transmission.git
synced 2025-12-20 02:18:42 +00:00
feat: new JSON-RPC 2.0 RPC API (#7269)
* feat: add enum for JSON-RPC error codes * feat: new `tr_rpc_request_exec()` overload that accepts string * feat: add JSON-RPC parse error handling * feat: add logic for branching to JSON-RPC or legacy API * feat: error codes for existing errors strings * refactor: async handlers now take the done cb as parameter * feat: support non-batch JSON-RPC requests * feat: support batch JSON-RPC requests * refactor: move JSON-RPC error codes to header * test: new tests for JSON-RPC * refactor(webui): use jsonrpc api * docs: update docs for jsonrpc * fix: clang-tidy warning * perf: avoid copying callback in batch mode * code review: don't commit to dropping old RPC * chore: fix shadowed variable warnings
This commit is contained in:
@@ -65,6 +65,7 @@ auto constexpr MyStatic = std::array<std::string_view, TR_N_KEYS>{
|
||||
"clientIsChoked"sv,
|
||||
"clientIsInterested"sv,
|
||||
"clientName"sv,
|
||||
"code"sv,
|
||||
"comment"sv,
|
||||
"compact-view"sv,
|
||||
"complete"sv,
|
||||
@@ -77,6 +78,7 @@ auto constexpr MyStatic = std::array<std::string_view, TR_N_KEYS>{
|
||||
"creator"sv,
|
||||
"cumulative-stats"sv,
|
||||
"current-stats"sv,
|
||||
"data"sv,
|
||||
"date"sv,
|
||||
"dateCreated"sv,
|
||||
"default-trackers"sv,
|
||||
@@ -170,6 +172,7 @@ auto constexpr MyStatic = std::array<std::string_view, TR_N_KEYS>{
|
||||
"isStalled"sv,
|
||||
"isUTP"sv,
|
||||
"isUploadingTo"sv,
|
||||
"jsonrpc"sv,
|
||||
"labels"sv,
|
||||
"lastAnnouncePeerCount"sv,
|
||||
"lastAnnounceResult"sv,
|
||||
@@ -200,6 +203,7 @@ auto constexpr MyStatic = std::array<std::string_view, TR_N_KEYS>{
|
||||
"maxConnectedPeers"sv,
|
||||
"memory-bytes"sv,
|
||||
"memory-units"sv,
|
||||
"message"sv,
|
||||
"message-level"sv,
|
||||
"metadataPercentComplete"sv,
|
||||
"metadata_size"sv,
|
||||
@@ -215,6 +219,7 @@ auto constexpr MyStatic = std::array<std::string_view, TR_N_KEYS>{
|
||||
"nodes6"sv,
|
||||
"open-dialog-dir"sv,
|
||||
"p"sv,
|
||||
"params"sv,
|
||||
"path"sv,
|
||||
"paused"sv,
|
||||
"pausedTorrentCount"sv,
|
||||
|
||||
@@ -67,6 +67,7 @@ enum // NOLINT(performance-enum-size)
|
||||
TR_KEY_clientIsChoked,
|
||||
TR_KEY_clientIsInterested,
|
||||
TR_KEY_clientName,
|
||||
TR_KEY_code,
|
||||
TR_KEY_comment,
|
||||
TR_KEY_compact_view,
|
||||
TR_KEY_complete,
|
||||
@@ -79,6 +80,7 @@ enum // NOLINT(performance-enum-size)
|
||||
TR_KEY_creator,
|
||||
TR_KEY_cumulative_stats,
|
||||
TR_KEY_current_stats,
|
||||
TR_KEY_data,
|
||||
TR_KEY_date,
|
||||
TR_KEY_dateCreated,
|
||||
TR_KEY_default_trackers,
|
||||
@@ -172,6 +174,7 @@ enum // NOLINT(performance-enum-size)
|
||||
TR_KEY_isStalled,
|
||||
TR_KEY_isUTP,
|
||||
TR_KEY_isUploadingTo,
|
||||
TR_KEY_jsonrpc,
|
||||
TR_KEY_labels,
|
||||
TR_KEY_lastAnnouncePeerCount,
|
||||
TR_KEY_lastAnnounceResult,
|
||||
@@ -202,6 +205,7 @@ enum // NOLINT(performance-enum-size)
|
||||
TR_KEY_maxConnectedPeers,
|
||||
TR_KEY_memory_bytes,
|
||||
TR_KEY_memory_units,
|
||||
TR_KEY_message,
|
||||
TR_KEY_message_level,
|
||||
TR_KEY_metadataPercentComplete,
|
||||
TR_KEY_metadata_size,
|
||||
@@ -217,6 +221,7 @@ enum // NOLINT(performance-enum-size)
|
||||
TR_KEY_nodes6,
|
||||
TR_KEY_open_dialog_dir,
|
||||
TR_KEY_p,
|
||||
TR_KEY_params,
|
||||
TR_KEY_path,
|
||||
TR_KEY_paused,
|
||||
TR_KEY_pausedTorrentCount,
|
||||
|
||||
@@ -356,20 +356,23 @@ void handle_web_client(struct evhttp_request* req, tr_rpc_server const* server)
|
||||
|
||||
void handle_rpc_from_json(struct evhttp_request* req, tr_rpc_server* server, std::string_view json)
|
||||
{
|
||||
if (auto otop = tr_variant_serde::json().inplace().parse(json); otop)
|
||||
{
|
||||
tr_rpc_request_exec(
|
||||
server->session,
|
||||
*otop,
|
||||
[req, server](tr_session* /*session*/, tr_variant&& content)
|
||||
tr_rpc_request_exec(
|
||||
server->session,
|
||||
json,
|
||||
[req, server](tr_session* /*session*/, tr_variant&& content)
|
||||
{
|
||||
if (!content.has_value())
|
||||
{
|
||||
auto* const output_headers = evhttp_request_get_output_headers(req);
|
||||
auto* const response = make_response(req, server, tr_variant_serde::json().compact().to_string(content));
|
||||
evhttp_add_header(output_headers, "Content-Type", "application/json; charset=UTF-8");
|
||||
evhttp_send_reply(req, HTTP_OK, "OK", response);
|
||||
evbuffer_free(response);
|
||||
});
|
||||
}
|
||||
evhttp_send_reply(req, HTTP_NOCONTENT, "OK", nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
auto* const output_headers = evhttp_request_get_output_headers(req);
|
||||
auto* const response = make_response(req, server, tr_variant_serde::json().compact().to_string(content));
|
||||
evhttp_add_header(output_headers, "Content-Type", "application/json; charset=UTF-8");
|
||||
evhttp_send_reply(req, HTTP_OK, "OK", response);
|
||||
evbuffer_free(response);
|
||||
});
|
||||
}
|
||||
|
||||
void handle_rpc(struct evhttp_request* req, tr_rpc_server* server)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -10,6 +10,35 @@
|
||||
struct tr_session;
|
||||
struct tr_variant;
|
||||
|
||||
namespace JsonRpc
|
||||
{
|
||||
auto constexpr Version = std::string_view{ "2.0" };
|
||||
|
||||
namespace Error
|
||||
{
|
||||
enum Code : int16_t
|
||||
{
|
||||
PARSE_ERROR = -32700,
|
||||
INVALID_REQUEST = -32600,
|
||||
METHOD_NOT_FOUND = -32601,
|
||||
INVALID_PARAMS = -32602,
|
||||
INTERNAL_ERROR = -32603,
|
||||
SUCCESS = 0,
|
||||
SET_ANNOUNCE_LIST,
|
||||
INVALID_TRACKER_LIST,
|
||||
PATH_NOT_ABSOLUTE,
|
||||
UNRECOGNIZED_INFO,
|
||||
SYSTEM_ERROR,
|
||||
FILE_IDX_OOR,
|
||||
PIECE_IDX_OOR,
|
||||
HTTP_ERROR,
|
||||
CORRUPT_TORRENT
|
||||
};
|
||||
}
|
||||
} // namespace JsonRpc
|
||||
|
||||
using tr_rpc_response_func = std::function<void(tr_session* session, tr_variant&& response)>;
|
||||
|
||||
void tr_rpc_request_exec(tr_session* session, tr_variant const& request, tr_rpc_response_func&& callback = {});
|
||||
|
||||
void tr_rpc_request_exec(tr_session* session, std::string_view request, tr_rpc_response_func&& callback = {});
|
||||
|
||||
@@ -2438,7 +2438,7 @@ void renameTorrentFileString(tr_torrent* tor, std::string_view oldpath, std::str
|
||||
void tr_torrent::rename_path_in_session_thread(
|
||||
std::string_view const oldpath,
|
||||
std::string_view const newname,
|
||||
tr_torrent_rename_done_func const callback,
|
||||
tr_torrent_rename_done_func const& callback,
|
||||
void* const callback_user_data)
|
||||
{
|
||||
using namespace rename_helpers;
|
||||
@@ -2482,19 +2482,19 @@ void tr_torrent::rename_path_in_session_thread(
|
||||
{
|
||||
auto const szold = tr_pathbuf{ oldpath };
|
||||
auto const sznew = tr_pathbuf{ newname };
|
||||
(*callback)(this, szold.c_str(), sznew.c_str(), error, callback_user_data);
|
||||
callback(this, szold.c_str(), sznew.c_str(), error, callback_user_data);
|
||||
}
|
||||
}
|
||||
|
||||
void tr_torrent::rename_path(
|
||||
std::string_view oldpath,
|
||||
std::string_view newname,
|
||||
tr_torrent_rename_done_func callback,
|
||||
tr_torrent_rename_done_func&& callback,
|
||||
void* callback_user_data)
|
||||
{
|
||||
this->session->run_in_session_thread(
|
||||
[this, oldpath = std::string(oldpath), newname = std::string(newname), callback, callback_user_data]()
|
||||
{ rename_path_in_session_thread(oldpath, newname, callback, callback_user_data); });
|
||||
[this, oldpath = std::string(oldpath), newname = std::string(newname), cb = std::move(callback), callback_user_data]()
|
||||
{ rename_path_in_session_thread(oldpath, newname, std::move(cb), callback_user_data); });
|
||||
}
|
||||
|
||||
void tr_torrentRenamePath(
|
||||
@@ -2507,7 +2507,7 @@ void tr_torrentRenamePath(
|
||||
oldpath = oldpath != nullptr ? oldpath : "";
|
||||
newname = newname != nullptr ? newname : "";
|
||||
|
||||
tor->rename_path(oldpath, newname, callback, callback_user_data);
|
||||
tor->rename_path(oldpath, newname, std::move(callback), callback_user_data);
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
@@ -183,7 +183,7 @@ struct tr_torrent
|
||||
void rename_path(
|
||||
std::string_view oldpath,
|
||||
std::string_view newname,
|
||||
tr_torrent_rename_done_func callback,
|
||||
tr_torrent_rename_done_func&& callback,
|
||||
void* callback_user_data);
|
||||
|
||||
// these functions should become private when possible,
|
||||
@@ -1323,7 +1323,7 @@ private:
|
||||
void rename_path_in_session_thread(
|
||||
std::string_view oldpath,
|
||||
std::string_view newname,
|
||||
tr_torrent_rename_done_func callback,
|
||||
tr_torrent_rename_done_func const& callback,
|
||||
void* callback_user_data);
|
||||
|
||||
void start_in_session_thread();
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <time.h> // time_t
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#else
|
||||
@@ -853,12 +854,8 @@ void tr_torrentStart(tr_torrent* torrent);
|
||||
/** @brief Stop (pause) a torrent */
|
||||
void tr_torrentStop(tr_torrent* torrent);
|
||||
|
||||
using tr_torrent_rename_done_func = void (*)( //
|
||||
tr_torrent* torrent,
|
||||
char const* oldpath,
|
||||
char const* newname,
|
||||
int error,
|
||||
void* user_data);
|
||||
using tr_torrent_rename_done_func = std::function<
|
||||
void(tr_torrent* torrent, char const* oldpath, char const* newname, int error, void* user_data)>;
|
||||
|
||||
/**
|
||||
* @brief Rename a file or directory in a torrent.
|
||||
|
||||
Reference in New Issue
Block a user