Add RPC API

This commit is contained in:
Sergey Lyubka committed 2022-07-27 00:46:05 +01:00
1 parent 9cacf443e1
commit 0dabc45780
13 files changed
+332 -75

No files matched your search

+2 -2
View File
@@ -64,7 +64,7 @@ static void mg_putchar_iobuf_static(char ch, void *param) {
}
}
void mg_putchar_iobuf(char ch, void *param) {
void mg_pfn_iobuf(char ch, void *param) {
struct mg_iobuf *io = (struct mg_iobuf *) param;
if (io->len + 2 > io->size) mg_iobuf_resize(io, io->size + 64);
if (io->len + 2 <= io->size) {
@@ -75,7 +75,7 @@ void mg_putchar_iobuf(char ch, void *param) {
// We don't use realloc() in mongoose, so resort to inefficient calloc
// Every new character reallocates the whole string
void mg_putchar_realloc(char ch, void *param) {
void mg_pfn_realloc(char ch, void *param) {
char *s, *buf = *(char **) param;
size_t len = buf == NULL ? 0 : strlen(buf);
if ((s = (char *) calloc(1, len + 2)) != NULL) {
+2 -1
View File
@@ -119,9 +119,10 @@ int mg_json_get(const char *s, int len, const char *path, int *toklen) {
if (c == '"') {
int n = mg_pass_string(&s[i + 1], len - i - 1);
if (n < 0) return n;
if (i + 1 + n >= len) return MG_JSON_NOT_FOUND;
// printf("K[%.*s] %d %d\n", n, &s[i + 1], depth, ed);
if (depth == ed && path[pos - 1] == '.' &&
memcmp(&s[i + 1], &path[pos], (size_t) n) == 0) {
strncmp(&s[i + 1], &path[pos], (size_t) n) == 0) {
pos += n;
}
i += n + 1;
+1 -1
View File
@@ -9,7 +9,7 @@ size_t mg_vprintf(struct mg_connection *c, const char *fmt, va_list ap) {
size_t old = c->send.len;
va_list tmp;
va_copy(tmp, ap);
mg_vrprintf(mg_putchar_iobuf, &c->send, fmt, &tmp);
mg_vrprintf(mg_pfn_iobuf, &c->send, fmt, &tmp);
return c->send.len - old;
}
+92
View File
@@ -0,0 +1,92 @@
#include "rpc.h"
struct mg_rpc {
struct mg_rpc *next;
struct mg_str method;
void (*fn)(struct mg_rpc_req *);
void *fn_data;
};
void mg_rpc_add(void **head, struct mg_str method,
void (*fn)(struct mg_rpc_req *), void *fn_data) {
struct mg_rpc *rpc = (struct mg_rpc *) calloc(1, sizeof(*rpc));
rpc->method = mg_strdup(method), rpc->fn = fn, rpc->fn_data = fn_data;
rpc->next = (struct mg_rpc *) *head, *head = rpc;
}
void mg_rpc_free(void **head) {
while (head != NULL && *head != NULL) {
struct mg_rpc *rpc = *(struct mg_rpc **) head;
*head = rpc->next;
free((void *) rpc->method.ptr);
free(rpc);
}
}
void mg_rpc_process(void **head, struct mg_str s, mg_pfn_t pfn, void *pfnd) {
struct mg_rpc_req req = {{s.ptr, s.len}, pfn, pfnd, NULL};
int len, off = mg_json_get(s.ptr, (int) s.len, "$.method", &len);
if (off > 0 && s.ptr[off] == '"') {
struct mg_str m = mg_str_n(&s.ptr[off + 1], (size_t) len - 2);
struct mg_rpc *h = *(struct mg_rpc **) head;
while (h != NULL && !mg_match(m, h->method, NULL)) h = h->next;
if (h != NULL) {
req.fn_data = h->fn_data;
h->fn(&req);
} else {
mg_rpc_err(&req, -32601, "\"%.*s not found\"", (int) m.len, m.ptr);
}
} else {
mg_rpc_err(&req, -32700, "%.*Q", (int) s.len, s.ptr);
}
}
void mg_rpc_vok(struct mg_rpc_req *r, const char *fmt, va_list *ap) {
int len, off = mg_json_get(r->frame.ptr, (int) r->frame.len, "$.id", &len);
if (off > 0) {
mg_rprintf(r->pfn, r->pfn_data, "{%Q:%.*s,%Q:", "id", len,
&r->frame.ptr[off], "result");
mg_vrprintf(r->pfn, r->pfn_data, fmt == NULL ? "null" : fmt, ap);
mg_rprintf(r->pfn, r->pfn_data, "}");
}
}
void mg_rpc_ok(struct mg_rpc_req *r, const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
mg_rpc_vok(r, fmt, &ap);
va_end(ap);
}
void mg_rpc_verr(struct mg_rpc_req *r, int code, const char *fmt, va_list *ap) {
int len, off = mg_json_get(r->frame.ptr, (int) r->frame.len, "$.id", &len);
mg_rprintf(r->pfn, r->pfn_data, "{");
if (off > 0) {
mg_rprintf(r->pfn, r->pfn_data, "%Q:%.*s,", "id", len, &r->frame.ptr[off]);
}
mg_rprintf(r->pfn, r->pfn_data, "%Q:{%Q:%d,%Q:", "error", "code", code,
"message");
mg_vrprintf(r->pfn, r->pfn_data, fmt == NULL ? "null" : fmt, ap);
mg_rprintf(r->pfn, r->pfn_data, "}}");
}
void mg_rpc_err(struct mg_rpc_req *r, int code, const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
mg_rpc_verr(r, code, fmt, &ap);
va_end(ap);
}
static size_t print_methods(mg_pfn_t pfn, void *pfn_data, va_list *ap) {
struct mg_rpc *h, **head = (struct mg_rpc **) va_arg(*ap, void **);
size_t len = 0;
for (h = *head; h != NULL; h = h->next) {
len += mg_rprintf(pfn, pfn_data, "%s%.*Q", h == *head ? "" : ",",
(int) h->method.len, h->method.ptr);
}
return len;
}
void mg_rpc_list(struct mg_rpc_req *r) {
mg_rpc_ok(r, "[%M]", print_methods, r->fn_data);
}
+22
View File
@@ -0,0 +1,22 @@
#pragma once
#include "json.h"
// JSON-RPC request descriptor
struct mg_rpc_req {
struct mg_str frame; // Request, e.g. {"id":1,"method":"add","params":[1,2]}
mg_pfn_t pfn; // Response printing function
void *pfn_data; // Response printing function data
void *fn_data; // Endpoint handler data
};
void mg_rpc_add(void **head, struct mg_str method_pattern,
void (*handler)(struct mg_rpc_req *), void *handler_data);
void mg_rpc_free(void **head);
void mg_rpc_process(void **head, struct mg_str json, mg_pfn_t pfn, void *pfnd);
// Helper functions to print result or error frame
void mg_rpc_ok(struct mg_rpc_req *, const char *fmt, ...);
void mg_rpc_vok(struct mg_rpc_req *, const char *fmt, va_list *ap);
void mg_rpc_err(struct mg_rpc_req *, int code, const char *fmt, ...);
void mg_rpc_verr(struct mg_rpc_req *, int code, const char *fmt, va_list *);
void mg_rpc_list(struct mg_rpc_req *r);
+4 -4
View File
@@ -42,10 +42,10 @@ double mg_atod(const char *buf, int len, int *numlen);
size_t mg_dtoa(char *buf, size_t len, double d, int width);
char *mg_remove_double_dots(char *s);
typedef void (*mg_pc_t)(char, void *); // Custom putchar
typedef size_t (*mg_pm_t)(mg_pc_t, void *, va_list *); // %M printer
void mg_putchar_realloc(char ch, void *param); // Print to malloced str
void mg_putchar_iobuf(char ch, void *param); // Print to iobuf
typedef void (*mg_pfn_t)(char, void *); // Custom putchar
typedef size_t (*mg_pm_t)(mg_pfn_t, void *, va_list *); // %M printer
void mg_pfn_realloc(char ch, void *param); // Print to malloced str
void mg_pfn_iobuf(char ch, void *param); // Print to iobuf
size_t mg_vrprintf(void (*)(char, void *), void *, const char *fmt, va_list *);
size_t mg_rprintf(void (*fn)(char, void *), void *, const char *fmt, ...);