diff --git a/docs/README.md b/docs/README.md index 73e104a5..3b776e25 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2979,6 +2979,10 @@ Parameters: - `handler` - the RPC function performing the action for this method - `handler_data` - Arbitrary function data +NOTE: +if `method_pattern` is an empty string, this handler will be called to process +JSON-RPC responses. Handling responses might be necessary if the JSON requests +are initiated by both sides. Usage example: diff --git a/mongoose.c b/mongoose.c index 605b7a3f..9a6a26b9 100644 --- a/mongoose.c +++ b/mongoose.c @@ -3550,20 +3550,27 @@ void mg_rpc_del(struct mg_rpc **head, void (*fn)(struct mg_rpc_req *)) { } } +static void mg_rpc_call(struct mg_rpc_req *r, struct mg_str method) { + struct mg_rpc *h = r->head == NULL ? NULL : *r->head; + while (h != NULL && !mg_match(method, h->method, NULL)) h = h->next; + if (h != NULL) { + r->rpc = h; + h->fn(r); + } else { + mg_rpc_err(r, -32601, "\"%.*s not found\"", (int) method.len, method.ptr); + } +} + void mg_rpc_process(struct mg_rpc_req *r) { int len, off = mg_json_get(r->frame, "$.method", &len); if (off > 0 && r->frame.ptr[off] == '"') { - struct mg_str m = mg_str_n(&r->frame.ptr[off + 1], (size_t) len - 2); - struct mg_rpc *h = r->head == NULL ? NULL : *r->head; - while (h != NULL && !mg_match(m, h->method, NULL)) h = h->next; - if (h != NULL) { - r->rpc = h; - h->fn(r); - } else { - mg_rpc_err(r, -32601, "\"%.*s not found\"", (int) m.len, m.ptr); - } + struct mg_str method = mg_str_n(&r->frame.ptr[off + 1], (size_t) len - 2); + mg_rpc_call(r, method); + } else if ((off = mg_json_get(r->frame, "$.result", &len)) > 0 || + (off = mg_json_get(r->frame, "$.error", &len)) > 0) { + mg_rpc_call(r, mg_str("")); // JSON response! call "" method handler } else { - mg_rpc_err(r, -32700, "%.*Q", (int) r->frame.len, r->frame.ptr); + mg_rpc_err(r, -32700, "%.*Q", (int) r->frame.len, r->frame.ptr); // Invalid } } diff --git a/src/rpc.c b/src/rpc.c index c35e9c5e..befd0ced 100644 --- a/src/rpc.c +++ b/src/rpc.c @@ -20,20 +20,27 @@ void mg_rpc_del(struct mg_rpc **head, void (*fn)(struct mg_rpc_req *)) { } } +static void mg_rpc_call(struct mg_rpc_req *r, struct mg_str method) { + struct mg_rpc *h = r->head == NULL ? NULL : *r->head; + while (h != NULL && !mg_match(method, h->method, NULL)) h = h->next; + if (h != NULL) { + r->rpc = h; + h->fn(r); + } else { + mg_rpc_err(r, -32601, "\"%.*s not found\"", (int) method.len, method.ptr); + } +} + void mg_rpc_process(struct mg_rpc_req *r) { int len, off = mg_json_get(r->frame, "$.method", &len); if (off > 0 && r->frame.ptr[off] == '"') { - struct mg_str m = mg_str_n(&r->frame.ptr[off + 1], (size_t) len - 2); - struct mg_rpc *h = r->head == NULL ? NULL : *r->head; - while (h != NULL && !mg_match(m, h->method, NULL)) h = h->next; - if (h != NULL) { - r->rpc = h; - h->fn(r); - } else { - mg_rpc_err(r, -32601, "\"%.*s not found\"", (int) m.len, m.ptr); - } + struct mg_str method = mg_str_n(&r->frame.ptr[off + 1], (size_t) len - 2); + mg_rpc_call(r, method); + } else if ((off = mg_json_get(r->frame, "$.result", &len)) > 0 || + (off = mg_json_get(r->frame, "$.error", &len)) > 0) { + mg_rpc_call(r, mg_str("")); // JSON response! call "" method handler } else { - mg_rpc_err(r, -32700, "%.*Q", (int) r->frame.len, r->frame.ptr); + mg_rpc_err(r, -32700, "%.*Q", (int) r->frame.len, r->frame.ptr); // Invalid } } diff --git a/test/unit_test.c b/test/unit_test.c index dda44f1a..7852939f 100644 --- a/test/unit_test.c +++ b/test/unit_test.c @@ -2493,6 +2493,11 @@ static void test_json(void) { } } +static void resp_rpc(struct mg_rpc_req *r) { + int len = 0, off = mg_json_get(r->frame, "$.result", &len); + mg_xprintf(r->pfn, r->pfn_data, "%.*s", len, &r->frame.ptr[off]); +} + static void test_rpc(void) { struct mg_rpc *head = NULL; struct mg_iobuf io = {0, 0, 0, 256}; @@ -2541,10 +2546,30 @@ static void test_rpc(void) { const char *resp = "{\"error\":{\"code\":-32700,\"message\":\"haha\"}}"; req.frame = mg_str("haha"); mg_rpc_process(&req); + // MG_INFO(("-> %s", io.buf)); ASSERT(strcmp((char *) io.buf, resp) == 0); mg_iobuf_free(&io); } + { + const char *resp = + "{\"id\":1,\"error\":{\"code\":-32601,\"message\":\" not found\"}}"; + req.frame = mg_str("{\"id\":1,\"result\":123}"); + mg_rpc_process(&req); + // MG_INFO(("-> %s", io.buf)); + ASSERT(strcmp((char *) io.buf, resp) == 0); + mg_iobuf_free(&io); + } + + { + req.frame = mg_str("{\"id\":1,\"result\":123}"); + mg_rpc_add(&head, mg_str(""), resp_rpc, NULL); + mg_rpc_process(&req); + MG_INFO(("-> %s", io.buf)); + ASSERT(strcmp((char *) io.buf, "123") == 0); + mg_iobuf_free(&io); + } + mg_rpc_del(&head, NULL); ASSERT(head == NULL); }