Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add JSON-RPC capability #1373

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

kannibalox
Copy link
Contributor

Based off the work in https://github.com/jesec/rtorrent, this implements the 2.0 specification: https://www.jsonrpc.org/specification. It adds a new RpcManager class and a little SCGI logic to handle switching between XML and JSON seamlessly. If the CONTENT_TYPE header is present and set to application/json (or text/xml for XML-RPC), it'll use that, otherwise it will peek at the body to auto-detect it.

The main benefit is reduced message size, as seen on this synthetic set of 10k torrents:

$ rtxmlrpc -U scgi://localhost:8888?rpc=xml d.multicall2 '' main d.name= d.hash= d.size_bytes= --debug |& grep stats
DEBUG:pyrosimple.scripts.rtxmlrpc.RtorrentXmlRpc:RPC stats: 1 requests (387 bytes) in 0.029s (response 1.9 MiB)

$ rtxmlrpc -U scgi://localhost:8888?rpc=json d.multicall2 '' main d.name= d.hash= d.size_bytes= --debug |& grep stats
DEBUG:pyrosimple.scripts.rtxmlrpc.RtorrentXmlRpc:RPC stats: 1 requests (106 bytes) in 0.024s (response 710.9 KiB)

One limitation of JSON-RPC is that it doesn't have a dedicated binary data type. Due to that, base64 data URI support has been added to all the load.* commands. Those are currently the only commands which normally need to take binary data, but any future commands would have to follow the same pattern or implement their own scheme.

Note for Flood users When Flood detects the presence of JSON-RPC, it assumes that the full jesec/rtorrent capabilities are available, which breaks a couple things. Thankfully, it's pretty easy to provide some stubs/redirects to get it working:
method.redirect=load.throw,load.normal
method.redirect=load.start_throw,load.start
method.insert=d.down.sequential,value|const,0
method.insert=d.down.sequential.set,value|const,0

Inline nlohmann/json for the JSON parsing itself, and handle requests
with the same SCGI interface as XML-RPC.

Based off the work in https://github.com/jesec/rtorrent
[](const char* hash) { return control->core()->download_list()->find_hex_ptr(hash); },
[](core::Download* d, uint32_t index) { return rpc_find_file(d, index); },
[](core::Download* d, uint32_t index) { return rpc_find_tracker(d, index); },
[](core::Download* d, const torrent::HashString& hash) { return rpc_find_peer(d, hash); });
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a fan of this style without assignment being done to named slots.

const unsigned long start = uri.find("base64,", 5) + 7;
if (start >= uri.size())
throw torrent::input_error("Empty base64.");
auto output = utils::decode_base64(uri.substr(start));
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Create a function decode_data_uri that does both the check and decoding.


#include "parse_commands.h"

#include "rpc/rpc_manager.h"
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unneeded empty newlines.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants