JSON RPC 2.0 - liuli-neko/NekoProtoTools GitHub Wiki
This page provides a detailed reference for the core components within the NekoProtoTools JSON-RPC2.0 module.
Tutorial: Implementing JSON-RPC
The JSON-RPC2.0 module provides the necessary tools for implementing JSON RPC services/client.
To use the features of this module, include the following primary header(s):
#include <nekoproto/jsonrpc/jsonrpc.hpp> // Base header for JSON-RPC
The core components of this module reside primarily in the NekoProto
namespace.
- Purpose: Represents a JSON-RPC method, encapsulating its name, parameters, and return type. It provides static methods to create request and response objects.
-
Template Parameters:
-
RpcMethodT
: The type of the RPC method (e.g.,void()
,int(int)
, etc.). -
MethodName
: The name of the method. -
ArgNames
: The names of the method parameters.
-
-
Key Constructors / Creation:
-
RpcMethod()
: Default constructor. -
RpcMethod(const FunctionType& func)
: Constructor that takes a function pointer. -
RpcMethod(const CoroutinesFuncType& func)
: Constructor that takes a coroutine function pointer.
-
-
Key Public Methods:
-
static RequestType request(const JsonRpcIdType& id, ParamsTupleType&& params = {})
: Creates a request object. -
static ResponseType response(const JsonRpcIdType& id, const MethodTraits::ReturnType& result)
: Creates a response object with a result. -
static ResponseType response(const JsonRpcIdType& id, const JsonRpcErrorResponse& error)
: Creates a response object with an error. -
operator=(const FunctionType& func)
: Assigns a function pointer to the method. -
operator=(const CoroutinesFuncType& func)
: Assigns a coroutine function pointer to the method. -
clear()
: Clears the method's function pointer. -
operator bool() const
: Checks if the method has a function pointer assigned. -
std::string description
: A string describing the method.
-
- Interaction with User Types: Users can define their own RPC methods using this class, specifying the method name and parameters. The class handles the serialization and deserialization of the method's parameters and return type.
- Purpose: Represents a JSON-RPC server, handling incoming requests and dispatching them to the appropriate methods. It manages the server's lifecycle and method bindings.
-
Template Parameters:
-
ProtocolT
: The protocol type used for communication (e.g.,A user-defined struct containing only publicRpcMethod<>
members, which will be registered as JSON-RPC methods).
-
-
Key Constructors / Creation:
-
JsonRpcServer(ILIAS_NAMESPACE::IoContext& ctx)
: Constructor that takes anIoContext
object. -
~JsonRpcServer()
: Destructor that callsclose()
to clean up resources.
-
-
Key Public Methods:
-
auto operator->()
: Provides access to the underlying protocol object. -
auto close() -> void
: Closes the server and releases resources. -
auto isListening() const -> bool
: Checks if the server is currently listening for requests. -
auto wait() -> ILIAS_NAMESPACE::Task<void>
: Waits for incoming requests asynchronously. -
template <typename StreamType> auto start(std::string_view url) -> ILIAS_NAMESPACE::IoTask<ILIAS_NAMESPACE::Error>
: Starts the server with a specified URL and stream type. -
auto start(std::string_view url) -> ILIAS_NAMESPACE::Task<bool>
: Starts the server with a specified URL. -
template <traits::ConstexprString... ArgNames, typename RetT, typename... Args> auto bindMethod(std::string_view name, std::function<RetT(Args...)> func) -> void
: Binds a method to the server with a specified name and function. -
template <traits::ConstexprString... ArgNames, typename RetT, typename... Args> auto bindMethod(std::string_view name, std::function<ILIAS_NAMESPACE::IoTask<RetT>(Args...)> func) -> void
: Binds a coroutine method to the server with a specified name and function. -
auto callMethod(std::string_view json) -> ILIAS_NAMESPACE::Task<std::vector<char>>
: Calls a method with a specified JSON string and returns the result. -
auto methodMetadatas() -> std::map<std::string_view, std::unique_ptr<MethodMetadataBase>>&
: Returns a map of method metadata objects.
-
-
Interaction with User Types: Users can bind their own methods to the server using the
bindMethod
function, specifying the method name and function. The server handles the serialization and deserialization of method parameters and return types.
- Purpose: Represents a JSON-RPC client, allowing the client to connect to a server and call remote methods. It manages the client's lifecycle and method calls.
-
Template Parameters:
-
ProtocolT
: The protocol type used for communication (e.g.,A user-defined struct containing only publicRpcMethod<>
members, which will be registered as JSON-RPC methods).
-
-
Key Constructors / Creation:
-
JsonRpcClient(ILIAS_NAMESPACE::IoContext& ctx)
: Constructor that takes anIoContext
object. -
~JsonRpcClient()
: Destructor that callsclose()
to clean up resources.
-
-
Key Public Methods:
-
auto operator->() const
: Provides access to the underlying protocol object. -
auto close() -> void
: Closes the client and releases resources. -
auto wait() -> ILIAS_NAMESPACE::Task<void>
: Waits for incoming responses asynchronously. -
auto isConnected() const -> bool
: Checks if the client is currently connected to a server. -
template <typename StreamType> auto connect(std::string_view url) -> ILIAS_NAMESPACE::IoTask<ILIAS_NAMESPACE::Error>
: Connects the client to a server with a specified URL and stream type. -
auto connect(std::string_view url) -> ILIAS_NAMESPACE::Task<bool>
: Connects the client to a server with a specified URL. -
template <typename RetT, traits::ConstexprString... ArgNames, typename... Args> auto callRemote(std::string_view name, Args... args) -> ILIAS_NAMESPACE::IoTask<RetT>
: Calls a remote method with a specified name and arguments, returning the result. -
template <typename RetT, traits::ConstexprString... ArgNames, typename... Args> auto notifyRemote(std::string_view name, Args... args) -> ILIAS_NAMESPACE::IoTask<RetT>
: Notifies a remote method with a specified name and arguments, without expecting a response.
-
-
Interaction with User Types: Users can call their own remote methods using the
callRemote
andnotifyRemote
functions, specifying the method name and arguments. The client handles the serialization and deserialization of method parameters and return types.
To extend the network backend for the JSON-RPC module, users can specialize the following template:
template <typename T, std::size_t N = 1500>
class DatagramClient;
-
DatagramBase
This is the base class for both server and client implementations. Users can inherit from it and implement the following virtual methods:-
checkProtocol(Type type, std::string_view url) -> bool
: Validates the URL and determines if thisDatagramClient
should handle the connection. -
start(std::string_view url) -> ILIAS_NAMESPACE::IoTask<void>
: Starts the server or client. -
close() -> void
: Closes the connection. -
cancel() -> void
: Cancels the connection.
-
-
DatagramClientBase
For client-specific behavior, inherit from this class and implement:-
recv() -> ILIAS_NAMESPACE::IoTask<std::span<std::byte>>
: Receives data from the remote endpoint (must be valid JSON-RPC requests or responses). -
send(std::span<const std::byte> buffer) -> ILIAS_NAMESPACE::IoTask<void>
: Sends JSON-RPC requests or responses (must send all data or the connection will close). -
isConnected() -> bool
: Checks if the connection is active.
-
-
DatagramServerBase
For server-specific behavior, inherit from this class and implement:-
accept() -> ILIAS_NAMESPACE::IoTask<std::unique_ptr<DatagramClientBase, void(*)(DatagramClientBase*)>>
: Accepts incoming connections and returns a client instance. -
isListening() -> bool
: Checks if the server is actively listening.
-
Once the custom transport classes are implemented, they can be used with the following interface:
template <typename StreamType>
auto start(std::string_view url) -> ILIAS_NAMESPACE::IoTask<ILIAS_NAMESPACE::Error>;
This allows the JSON-RPC server or client to utilize the custom transport backend for communication. For example, you can define a custom protocol (e.g., tcp://
, udp://
) and handle it accordingly in your implementation.
By following this approach, users can seamlessly integrate their own network transport logic into the JSON-RPC framework.
#include <nekoproto/jsonrpc/jsonrpc.hpp>
template <>
class DatagramClient<CustomClient, 1500> : public DatagramBase,public DatagramClientBase {
DatagramClient() = default;
DatagramClient() {}
auto recv() -> ILIAS_NAMESPACE::IoTask<std::span<std::byte>> override {
// Receive data from the remote endpoint
}
auto send(std::span<const std::byte> data) -> ILIAS_NAMESPACE::IoTask<void> override {
// Send data to the remote endpoint
}
auto close() -> void override {
// Close the connection
}
auto cancel() -> void override {
// Cancel the async operation
}
auto checkProtocol([[maybe_unused]] Type type, std::string_view url) -> bool override {
// Check if the URL matches the protocol this client handles
// like return type == Client && url.starts_with("custom://");
}
auto start(std::string_view url) -> ILIAS_NAMESPACE::IoTask<void> override {
// Start the client
}
auto isConnected() -> bool override {
// Check if the client is connected
}
};
int main() {
ILIAS_NAMESPACE::IoContext ctx;
JsonRpcClient<CustomClient> client(ctx);
ilias_wait client.start<CustomClient>("custom://localhost:8080");
}