diff options
| author | Maxim Anisimov | 2026-04-20 08:48:48 +0000 |
|---|---|---|
| committer | Maxim Anisimov | 2026-04-20 08:48:48 +0000 |
| commit | a545f008da91e06d0391a887c26e3e14531d8204 (patch) | |
| tree | d4c97e35ef5025f43cd52596ebc859bd390cd4a5 | |
| parent | 5b078674a5929a5c90043c66721d45e1d8eae73d (diff) | |
| download | rpcd-a545f008da91e06d0391a887c26e3e14531d8204.tar.gz | |
ucode: add request.defer() for async method handling
Add a new "rpcd.ucode.deferred" resource type and a request.defer()
method to support asynchronous ucode handlers.
When a method handler calls request.defer() and returns the resulting
value, rpcd keeps the request pending - installing a guard timer and
preserving the request context until request.reply() or request.error()
is eventually called from within an async callback.
This mirrors the existing ubus.deferred mechanism but is not tied to
nested ubus calls, allowing handlers to defer replies from any
asynchronous context.
Signed-off-by: Maxim Anisimov <maxim.anisimov.ua@gmail.com>
| -rw-r--r-- | ucode.c | 28 |
1 files changed, 27 insertions, 1 deletions
@@ -52,6 +52,7 @@ typedef struct { struct list_head list; uc_vm_t vm; uc_resource_type_t *requesttype; + uc_resource_type_t *deferredtype; uc_value_t *pending_replies; char *path; } rpc_ucode_script_t; @@ -449,7 +450,8 @@ rpc_ucode_script_call(struct ubus_context *ctx, struct ubus_object *obj, res = uc_vm_stack_pop(&script->vm); /* The handler function invoked a nested aync ubus request and returned it */ - if (ucv_resource_data(res, "ubus.deferred")) { + if (ucv_resource_data(res, "ubus.deferred") || + ucv_resource_data(res, "rpcd.ucode.deferred")) { /* Install guard timer in case the reply callback is never called */ callctx->timeout.cb = rpc_ucode_request_timeout; uloop_timeout_set(&callctx->timeout, request_timeout); @@ -803,6 +805,28 @@ free: } static uc_value_t * +rpc_ucode_request_defer(uc_vm_t *vm, size_t nargs) +{ + rpc_ucode_call_ctx_t **callctx = uc_fn_this("rpcd.ucode.request"); + + if (!callctx || !*callctx) { + uc_vm_raise_exception(vm, EXCEPTION_RUNTIME, + "Cannot invoke defer() on invalid self"); + + return NULL; + } + + if ((*callctx)->replied) { + uc_vm_raise_exception(vm, EXCEPTION_RUNTIME, + "Reply has already been sent"); + + return NULL; + } + + return uc_resource_new((*callctx)->script->deferredtype, *callctx); +} + +static uc_value_t * rpc_ucode_request_reply(uc_vm_t *vm, size_t nargs) { rpc_ucode_call_ctx_t **callctx = uc_fn_this("rpcd.ucode.request"); @@ -887,6 +911,7 @@ rpc_ucode_request_error(uc_vm_t *vm, size_t nargs) } static const uc_function_list_t rpc_ucode_request_fns[] = { + { "defer", rpc_ucode_request_defer }, { "reply", rpc_ucode_request_reply }, { "error", rpc_ucode_request_error }, }; @@ -927,6 +952,7 @@ rpc_ucode_init_globals(rpc_ucode_script_t *script) script->requesttype = uc_type_declare(vm, "rpcd.ucode.request", rpc_ucode_request_fns, rpc_ucode_request_gc); + script->deferredtype = ucv_resource_type_add(vm, "rpcd.ucode.deferred", NULL, NULL); } static rpc_ucode_script_t * |