diff --git a/CMakeLists.txt b/CMakeLists.txt index 84b6fb0..c1daeeb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,6 +85,8 @@ add_library(webfuse-adapter-static STATIC lib/webfuse/adapter/impl/operation/close.c lib/webfuse/adapter/impl/operation/read.c lib/webfuse/adapter/impl/jsonrpc/proxy.c + lib/webfuse/adapter/impl/jsonrpc/server.c + lib/webfuse/adapter/impl/jsonrpc/method.c lib/webfuse/adapter/impl/jsonrpc/request.c lib/webfuse/adapter/impl/jsonrpc/response.c lib/webfuse/adapter/impl/jsonrpc/util.c diff --git a/lib/webfuse/adapter/impl/jsonrpc/method.c b/lib/webfuse/adapter/impl/jsonrpc/method.c new file mode 100644 index 0000000..8485471 --- /dev/null +++ b/lib/webfuse/adapter/impl/jsonrpc/method.c @@ -0,0 +1,27 @@ +#include "webfuse/adapter/impl/jsonrpc/method.h" +#include +#include + +struct wf_impl_jsonrpc_method * wf_impl_jsonrpc_method_create( + char const * method_name, + wf_impl_jsonrpc_method_invoke_fn * invoke, + void * user_data) +{ + struct wf_impl_jsonrpc_method * method = malloc(sizeof(struct wf_impl_jsonrpc_method)); + if (NULL != method) + { + method->next = NULL; + method->name = strdup(method_name); + method->invoke = invoke; + method->user_data = user_data; + } + + return method; +} + +void wf_impl_jsonrpc_method_dispose( + struct wf_impl_jsonrpc_method * method) +{ + free(method->name); + free(method); +} diff --git a/lib/webfuse/adapter/impl/jsonrpc/method.h b/lib/webfuse/adapter/impl/jsonrpc/method.h new file mode 100644 index 0000000..739f692 --- /dev/null +++ b/lib/webfuse/adapter/impl/jsonrpc/method.h @@ -0,0 +1,40 @@ +#ifndef WF_ADAPTER_IMPL_JSONRPC_METHOD_H +#define WF_ADAPTER_IMPL_JSONRPC_METHOD_H + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +struct wf_impl_jsonrpc_request; + +typedef void wf_impl_jsonrpc_method_invoke_fn( + struct wf_impl_jsonrpc_request * request, + char const * method_name, + json_t * params, + void * user_data); + +struct wf_impl_jsonrpc_method +{ + struct wf_impl_jsonrpc_method * next; + char * name; + wf_impl_jsonrpc_method_invoke_fn * invoke; + void * user_data; +}; + +extern struct wf_impl_jsonrpc_method * wf_impl_jsonrpc_method_create( + char const * method_name, + wf_impl_jsonrpc_method_invoke_fn * invoke, + void * user_data); + +extern void wf_impl_jsonrpc_method_dispose( + struct wf_impl_jsonrpc_method * method); + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/lib/webfuse/adapter/impl/jsonrpc/proxy.c b/lib/webfuse/adapter/impl/jsonrpc/proxy.c index 2c682ee..46a88b9 100644 --- a/lib/webfuse/adapter/impl/jsonrpc/proxy.c +++ b/lib/webfuse/adapter/impl/jsonrpc/proxy.c @@ -1,7 +1,6 @@ #include "webfuse/adapter/impl/jsonrpc/proxy.h" #include -#include "webfuse/adapter/impl/jsonrpc/request.h" #include "webfuse/adapter/impl/jsonrpc/response.h" #define WF_DEFAULT_TIMEOUT (10 * 1000) @@ -26,10 +25,53 @@ static void wf_impl_jsonrpc_proxy_timeout( } } +static json_t * wf_impl_jsonrpc_request_create( + char const * method, + int id, + char const * param_info, + va_list args) +{ + json_t * request = json_object(); + json_object_set_new(request, "method", json_string(method)); + json_t * params = json_array(); + + for (char const * param_type = param_info; '\0' != *param_type; param_type++) + { + switch(*param_type) + { + case 's': + { + char const * const value = va_arg(args, char const *); + json_array_append_new(params, json_string(value)); + } + break; + case 'i': + { + int const value = va_arg(args, int); + json_array_append_new(params, json_integer(value)); + } + break; + default: + fprintf(stderr, "fatal: unknown param_type '%c'\n", *param_type); + exit(EXIT_FAILURE); + break; + } + } + + + json_object_set_new(request, "params", params); + if (0 != id) + { + json_object_set_new(request, "id", json_integer(id)); + } + + return request; +} + void wf_impl_jsonrpc_proxy_init( struct wf_impl_jsonrpc_proxy * proxy, struct wf_impl_timeout_manager * timeout_manager, - wf_impl_jsonrpc_proxy_send_fn * send, + wf_impl_jsonrpc_send_fn * send, void * user_data) { proxy->send = send; diff --git a/lib/webfuse/adapter/impl/jsonrpc/proxy.h b/lib/webfuse/adapter/impl/jsonrpc/proxy.h index 420fe25..0940ef9 100644 --- a/lib/webfuse/adapter/impl/jsonrpc/proxy.h +++ b/lib/webfuse/adapter/impl/jsonrpc/proxy.h @@ -12,6 +12,7 @@ using std::size_t; #endif #include +#include "webfuse/adapter/impl/jsonrpc/send_fn.h" #include "webfuse/adapter/impl/time/timeout_manager.h" #include "webfuse/adapter/impl/time/timer.h" #include "webfuse/core/status.h" @@ -20,11 +21,6 @@ using std::size_t; extern "C" { #endif -typedef bool wf_impl_jsonrpc_proxy_send_fn( - json_t * request, - void * user_data); - - typedef void wf_impl_jsonrpc_proxy_finished_fn( void * user_data, wf_status status, @@ -43,14 +39,14 @@ struct wf_impl_jsonrpc_request struct wf_impl_jsonrpc_proxy { struct wf_impl_jsonrpc_request request; - wf_impl_jsonrpc_proxy_send_fn * send; + wf_impl_jsonrpc_send_fn * send; void * user_data; }; extern void wf_impl_jsonrpc_proxy_init( struct wf_impl_jsonrpc_proxy * proxy, struct wf_impl_timeout_manager * manager, - wf_impl_jsonrpc_proxy_send_fn * send, + wf_impl_jsonrpc_send_fn * send, void * user_data); extern void wf_impl_jsonrpc_proxy_cleanup( diff --git a/lib/webfuse/adapter/impl/jsonrpc/request.c b/lib/webfuse/adapter/impl/jsonrpc/request.c index 710db11..541635b 100644 --- a/lib/webfuse/adapter/impl/jsonrpc/request.c +++ b/lib/webfuse/adapter/impl/jsonrpc/request.c @@ -1,44 +1,64 @@ #include "webfuse/adapter/impl/jsonrpc/request.h" +#include "webfuse/core/status_intern.h" +#include -json_t * wf_impl_jsonrpc_request_create( - char const * method, - int id, - char const * param_info, - va_list args) +struct wf_impl_jsonrpc_request { - json_t * request = json_object(); - json_object_set_new(request, "method", json_string(method)); - json_t * params = json_array(); - - for (char const * param_type = param_info; '\0' != *param_type; param_type++) - { - switch(*param_type) - { - case 's': - { - char const * const value = va_arg(args, char const *); - json_array_append_new(params, json_string(value)); - } - break; - case 'i': - { - int const value = va_arg(args, int); - json_array_append_new(params, json_integer(value)); - } - break; - default: - fprintf(stderr, "fatal: unknown param_type '%c'\n", *param_type); - exit(EXIT_FAILURE); - break; - } - } - + int id; + wf_impl_jsonrpc_send_fn * send; + void * user_data; +}; - json_object_set_new(request, "params", params); - if (0 != id) - { - json_object_set_new(request, "id", json_integer(id)); - } - - return request; +struct wf_impl_jsonrpc_request * wf_impl_jsonrpc_request_create( + int id, + wf_impl_jsonrpc_send_fn * send, + void * user_data) +{ + struct wf_impl_jsonrpc_request * request = malloc(sizeof(struct wf_impl_jsonrpc_request)); + if (NULL != request) + { + request->id = id; + request->send = send; + request->user_data = user_data; + } + + return request; } + +void wf_impl_jsonrpc_request_dispose( + struct wf_impl_jsonrpc_request * request) +{ + free(request); +} + + +void wf_impl_jsonrpc_respond( + struct wf_impl_jsonrpc_request * request, + json_t * result) +{ + json_t * response = json_object(); + json_object_set_new(response, "result", result); + json_object_set_new(response, "id", json_integer(request->id)); + + request->send(response, request->user_data); + json_decref(response); + wf_impl_jsonrpc_request_dispose(request); +} + +void wf_impl_jsonrpc_respond_error( + struct wf_impl_jsonrpc_request * request, + wf_status status) +{ + json_t * err = json_object(); + json_object_set_new(err, "code", json_integer(status)); + json_object_set_new(err, "message", json_string(wf_status_tostring(status))); + + json_t * response = json_object(); + json_object_set_new(response, "error", err); + json_object_set_new(response, "id", json_integer(request->id)); + + request->send(response, request->user_data); + json_decref(response); + wf_impl_jsonrpc_request_dispose(request); +} + diff --git a/lib/webfuse/adapter/impl/jsonrpc/request.h b/lib/webfuse/adapter/impl/jsonrpc/request.h index 28c9f3d..ff1c8ea 100644 --- a/lib/webfuse/adapter/impl/jsonrpc/request.h +++ b/lib/webfuse/adapter/impl/jsonrpc/request.h @@ -12,17 +12,32 @@ using std::size_t; #endif #include +#include "webfuse/core/status.h" +#include "webfuse/adapter/impl/jsonrpc/send_fn.h" #ifdef __cplusplus extern "C" { #endif -extern json_t * wf_impl_jsonrpc_request_create( - char const * method, - int id, - char const * param_info, - va_list args); +struct wf_impl_jsonrpc_request; + +extern struct wf_impl_jsonrpc_request * wf_impl_jsonrpc_request_create( + int id, + wf_impl_jsonrpc_send_fn * send, + void * user_data); + +extern void wf_impl_jsonrpc_request_dispose( + struct wf_impl_jsonrpc_request * request); + +extern void wf_impl_jsonrpc_respond( + struct wf_impl_jsonrpc_request * request, + json_t * result); + +extern void wf_impl_jsonrpc_respond_error( + struct wf_impl_jsonrpc_request * request, + wf_status status); + #ifdef __cplusplus } diff --git a/lib/webfuse/adapter/impl/jsonrpc/send_fn.h b/lib/webfuse/adapter/impl/jsonrpc/send_fn.h new file mode 100644 index 0000000..baeedf7 --- /dev/null +++ b/lib/webfuse/adapter/impl/jsonrpc/send_fn.h @@ -0,0 +1,23 @@ +#ifndef WF_ADAPTER_IMPL_JSONRPC_SEND_FN_H +#define WF_ADAPTER_IMPL_JSONRPC_SEND_FN_H + +#ifndef __cplusplus +#include +#endif + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +typedef bool wf_impl_jsonrpc_send_fn( + json_t * request, + void * user_data); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/webfuse/adapter/impl/jsonrpc/server.c b/lib/webfuse/adapter/impl/jsonrpc/server.c new file mode 100644 index 0000000..717d71b --- /dev/null +++ b/lib/webfuse/adapter/impl/jsonrpc/server.c @@ -0,0 +1,95 @@ +#include "webfuse/adapter/impl/jsonrpc/server.h" +#include "webfuse/adapter/impl/jsonrpc/method.h" +#include "webfuse/adapter/impl/jsonrpc/request.h" +#include "webfuse/core/util.h" + +#include + +void wf_impl_jsonrpc_server_init( + struct wf_impl_jsonrpc_server * server) +{ + server->methods = NULL; +} + +void wf_impl_jsonrpc_server_cleanup( + struct wf_impl_jsonrpc_server * server) +{ + struct wf_impl_jsonrpc_method * current = server->methods; + while (NULL != current) + { + struct wf_impl_jsonrpc_method * next = current->next; + wf_impl_jsonrpc_method_dispose(current); + current = next; + } + server->methods = NULL; +} + +void wf_impl_jsonrpc_server_add( + struct wf_impl_jsonrpc_server * server, + char const * method_name, + wf_impl_jsonrpc_method_invoke_fn * invoke, + void * user_data) +{ + struct wf_impl_jsonrpc_method * method = wf_impl_jsonrpc_method_create(method_name, invoke, user_data); + method->next = server->methods; + server->methods = method; +} + +static void wf_impl_jsonrpc_server_invalid_method_invoke( + struct wf_impl_jsonrpc_request * request, + char const * WF_UNUSED_PARAM(method_name), + json_t * WF_UNUSED_PARAM(params), + void * WF_UNUSED_PARAM(user_data)) +{ + wf_impl_jsonrpc_respond_error(request, WF_BAD_NOTIMPLEMENTED); +} + +static struct wf_impl_jsonrpc_method const wf_impl_jsonrpc_server_invalid_method = +{ + .next = NULL, + .name = "", + .invoke = &wf_impl_jsonrpc_server_invalid_method_invoke, + .user_data = NULL +}; + +static struct wf_impl_jsonrpc_method const * wf_impl_jsonrpc_server_get_method( + struct wf_impl_jsonrpc_server * server, + char const * method_name) +{ + struct wf_impl_jsonrpc_method const * current = server->methods; + while (NULL != current) + { + if (0 == strcmp(method_name, current->name)) + { + return current; + } + + current = current->next; + } + + return &wf_impl_jsonrpc_server_invalid_method; +} + +void wf_impl_jsonrpc_server_process( + struct wf_impl_jsonrpc_server * server, + json_t * request_data, + wf_impl_jsonrpc_send_fn * send, + void * user_data) +{ + json_t * method_holder = json_object_get(request_data, "method"); + json_t * params = json_object_get(request_data, "params"); + json_t * id_holder = json_object_get(request_data, "id"); + + if (json_is_string(method_holder) && + (json_is_array(params) || (json_is_object(params))) && + json_is_integer(id_holder)) + { + char const * method_name = json_string_value(method_holder); + int id = json_integer_value(id_holder); + struct wf_impl_jsonrpc_request * request = wf_impl_jsonrpc_request_create(id, send, user_data); + struct wf_impl_jsonrpc_method const * method = wf_impl_jsonrpc_server_get_method(server, method_name); + + method->invoke(request, method_name, params, method->user_data); + } +} + diff --git a/lib/webfuse/adapter/impl/jsonrpc/server.h b/lib/webfuse/adapter/impl/jsonrpc/server.h new file mode 100644 index 0000000..51c827b --- /dev/null +++ b/lib/webfuse/adapter/impl/jsonrpc/server.h @@ -0,0 +1,48 @@ +#ifndef WF_ADAPTER_IMPL_JSONRPC_SERVER_H +#define WF_ADAPTER_IMPL_JSONRPC_SERVER_H + +#ifndef __cplusplus +#include +#include +#else +#include +#endif + +#include +#include "webfuse/core/status.h" +#include "webfuse/adapter/impl/jsonrpc/send_fn.h" +#include "webfuse/adapter/impl/jsonrpc/method.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +struct wf_impl_jsonrpc_server +{ + struct wf_impl_jsonrpc_method * methods; +}; + +extern void wf_impl_jsonrpc_server_init( + struct wf_impl_jsonrpc_server * server); + +extern void wf_impl_jsonrpc_server_cleanup( + struct wf_impl_jsonrpc_server * server); + +extern void wf_impl_jsonrpc_server_add( + struct wf_impl_jsonrpc_server * server, + char const * method_name, + wf_impl_jsonrpc_method_invoke_fn * invoke, + void * user_data); + +extern void wf_impl_jsonrpc_server_process( + struct wf_impl_jsonrpc_server * server, + json_t * request, + wf_impl_jsonrpc_send_fn * send, + void * user_data); + +#ifdef __cplusplus +} +#endif + +#endif