Hello guys, As you all know there is a new JSONRPC implementation that is up for review <https://github.com/apache/trafficserver/pull/7478> which is intended to land in the 10-Dev branch. As a part of this effort and to use all the benefits of having such protocol in our ATS, I am proposing to add a Plugin API support so plugins can easily implement their own RPC endpoints which would let them to have bidirectional communication with ATS JSONRPC clients such as *traffic_ctl* or any other implementation willing to talk JSONRPC 2.0 with ATS.
Current state Currently If a plugin wants to handle external messages they need to implement the TS_EVENT_LIFECYCLE_MSG hook. This provides a one way only message system for plugins, plugins can only receive the message but cannot respond to them directly. *Proposal* The goal of this proposal is to take advantage of the JSONRPC admin node implementation and let plugins be able to expose JSONRPC nodes(handlers) to the exterior and have bidirectional communication with clients. All this can be found in the online generated docs <https://brbzull0.github.io/ats_plugin_api/developer-guide/api/functions/TSRPCRegister.en.html> To achieve this we are proposing to introduce a new set of API: To be added into apidefs.h.in // JSONRPC 2.0 related interface. typedef struct tsapi_rpcproviderhandle *TSRPCProviderHandle; typedef struct tsapi_yaml *TSYaml; TSRPCProviderHandle will be mapped internally to: // RPC registration info, this should show information about the rpc endpoint provider. // By default all non plugin handlers are part of the same provider with the following text: Traffic Server JSONRPC 2.0 API struct RPCRegistryInfo { std::string_view provider; }; TSYaml (possible TSYamlNode would be a better name) will be mapped to YAML::Node internally. Please check Binary compatibility notes at the end of this email. JSONRPC callback signatures // Methods typedef void (*TSRPCMethodCb)(const char *id, TSYaml params); // Notifications, no id needed typedef void (*TSRPCNotificationCb)(TSYaml params); JSONRPC Registration Plugins to perform a registration and validation when they are expected to handle JSONRPC calls should invoke: tsapi TSRPCProviderHandle TSRPCRegister(const char *provider_name, const char *yamlcpp_lib_version); provider_name: a string with the Plugin's description. yamlcpp_lib_version: a string with the yamlcpp library version. A null terminated string is expected. Why do we need this? check Binary compatibility down below. This function returns a new TSRPCProviderHandle or nullptr if the yamlcpp_lib_version was not set or the yamlcpp version does not match with the one used internally in TS. The returned TSRPCProviderHandle will be set with the passed provider's name. The caller should pass the returned TSRPCProviderHandle object to each subsequent TSRPCRegisterMethod/Notification call. ------------------------------ Add a new registered method handler to the JSON RPC manager. tsapi TSReturnCode TSRPCRegisterMethodHandler(const char *name, TSRPCMethodCb callback, TSRPCProviderHandle info); name: Call name to be exposed by the JSONRPC server. callback: The function to be registered. info: TSRPCProviderHandle pointer, this will be used to provide more context information about this call. This object This function returns TS_SUCCESS if the handler was successfully registered, TS_ERROR if the handler is already registered. ------------------------------ Add a new registered notification handler to the JSON RPC manager. tsapi TSReturnCode TSRPCRegisterNotificationHandler(const char *name, TSRPCNotificationCb callback, TSRPCProviderHandle info); info: TSRPCProviderHandle pointer, this will be used to provide more description to the RPC description. This object should be the one returned by the TSRPCRegister API. name: Call name to be exposed by the JSONRPC server. callback : The function to be registered. This function returns TS_SUCCESS if the handler was successfully registered, TS_ERROR if the handler is already registered. ------------------------------ Function to notify the JSONRPC server that the current handler is done working. tsapi TSReturnCode TSRPCHandlerDone(TSYaml resp); This function must be used only when implementing a method JSONRPC handler. Once the work is done and the response is ready to be sent back to the client, this function should be called. Is expected to set the YAML node as response. If the response is empty a success <https://brbzull0.github.io/ats/developer-guide/jsonrpc/jsonrpc-architecture.en.html#result> message will be added to the client's response. This function returns TS_SUCCESS if there are no issues. TS_ERROR otherwise. ------------------------------ Function to notify the JSONRPC server that the current handler is done working and an error has arisen. tsapi TSReturnCode TSRPCHandlerError(int code, const char *descr); This should not be used if you registered your handler as a notification: TSRPCNotificationCb call. code: Error code. descr: A text with a description of the error. This function returns TS_SUCCES if there are no issues. TS_ERROR otherwise. ------------------------------ Internals This JSONRPC implementation is based on an iterative server(his own thread) which handles a single request at a time, this blocks till the response is handed back to the rpc manager. For plugins this is a bit different as they need the asynchronous style to deal with some specifics tasks, plugins needs to be able to run tasks possibly on different thread and at a different time that they get called to handle the JSONRPC call, so to achieve this the JSONRPC server implements a notification mechanism( TSRPCHandlerDone, TSRPCHandlerError) which will let the JSONRPC manager knows that the plugin handling is complete, either with an error or with a particular content. Plugins will be able to reschedule the JSONRPC handling work as they see fit. Examples on how to use this are documented in the proposal PR. Binary compatibility with YAMLCPP Having plugins with different version of YAMLCPP could be an issue, so as with plugins, we cannot guarantee that a will be compatible across major versions, so It would be feasible to only provide binary compatibility within the lifespan of a major release, no new version of YAMLCPP should be introduced in minor versions. Eventually plugins will need to recompile/link YAMLCPP version check To help the plugin developers to spot issues, plugins should check-in (using TSRPCRegister) with TS before registering any handler and validate that their yamlcpp version is the same as used internally in TS. Plugins will inform which version they have and internally we will compare this against the one used in ATS (this could be an issue as we can use an external version of YAMLCPP and not the one shipped with ATS) You can find some examples here <https://brbzull0.github.io/ats_plugin_api/developer-guide/jsonrpc/jsonrpc-handler-development.en.html#plugin-api> . I have detailed all the new API that is needed in this PR proposal <https://github.com/brbzull0/trafficserver/pull/4>which is a branch of the jsonrpc implementation(PR up above) Best Regards, Damian.