unetmsg: add support for sending requests/messages to specific hosts

Makes it possible to implement unetmsg APIs for host control

Signed-off-by: Felix Fietkau <nbd@nbd.name>
This commit is contained in:
Felix Fietkau 2025-05-16 13:44:38 +02:00
parent d95e8a59bb
commit 12f4814c41
4 changed files with 56 additions and 19 deletions

View file

@ -51,11 +51,14 @@ let obj = ubus.publish("unetmsg", {
args: { args: {
name: "", name: "",
type: "", type: "",
host: "",
data: {}, data: {},
}, },
call: function(req) { call: function(req) {
try { try {
core.handle_request(null, req, req.args, true); let host = req.args.host;
delete req.args.host;
core.handle_request(null, req, req.args, true, host);
} catch (e) { } catch (e) {
core.exception(e); core.exception(e);
} }

View file

@ -44,14 +44,26 @@ function subscribe(name, message_cb, update_cb)
this.channel.request("subscribe", { name }); this.channel.request("subscribe", { name });
} }
function send(name, type, data) function send_ext(data)
{ {
this.channel.request({ this.channel.request({
method: "message", method: "message",
return: "ignore", return: "ignore",
data: { data
name, type, data });
}, }
function send_host(host, name, type, data)
{
this.send_ext({
host, name, type, data
});
}
function send(name, type, data)
{
this.send_ext({
name, type, data
}); });
} }
@ -59,7 +71,7 @@ function default_complete_cb()
{ {
} }
function request(name, type, data, data_cb, complete_cb) function request_ext(data, data_cb, complete_cb)
{ {
if (!this.channel) if (!this.channel)
this.connect(); this.connect();
@ -69,9 +81,7 @@ function request(name, type, data, data_cb, complete_cb)
let req = this.channel.defer({ let req = this.channel.defer({
method: "request", method: "request",
data: { data,
name, type, data
},
data_cb, data_cb,
cb: complete_cb cb: complete_cb
}); });
@ -82,6 +92,20 @@ function request(name, type, data, data_cb, complete_cb)
req.await(); req.await();
} }
function request_host(host, name, type, data, data_cb, complete_cb)
{
return this.request_ext({
host, name, type, data
}, data_cb, complete_cb);
}
function request(name, type, data, data_cb, complete_cb)
{
return this.request_ext({
name, type, data
}, data_cb, complete_cb);
}
function connect() function connect()
{ {
if (this.channel) if (this.channel)
@ -113,7 +137,9 @@ function connect()
} }
const client_proto = { const client_proto = {
connect, publish, subscribe, send, request, connect, publish, subscribe,
send, send_ext, send_host,
request, request_ext, request_host,
close: function() { close: function() {
for (let sub in this.sub_cb) { for (let sub in this.sub_cb) {
if (!sub.timer) if (!sub.timer)

View file

@ -65,14 +65,14 @@ function client_request(cl, req)
if (type(name) != "string" || type(args.type) != "string" || type(args.data) != "object") if (type(name) != "string" || type(args.type) != "string" || type(args.data) != "object")
return libubus.STATUS_INVALID_ARGUMENT; return libubus.STATUS_INVALID_ARGUMENT;
let data = prepare_data(req.args); let data = prepare_data(args);
let handle; let handle;
switch (req.type) { switch (req.type) {
case "message": case "message":
handle = cl.publish[name]; handle = cl.publish[name];
if (!handle) if (!handle)
return libubus.STATUS_INVALID_ARGUMENT; return libubus.STATUS_INVALID_ARGUMENT;
return core.handle_message(handle, data, true); return core.handle_message(handle, data, true, args.host);
case "request": case "request":
handle = cl.subscribe[name]; handle = cl.subscribe[name];
if (!handle && if (!handle &&
@ -80,7 +80,7 @@ function client_request(cl, req)
return libubus.STATUS_PERMISSION_DENIED; return libubus.STATUS_PERMISSION_DENIED;
handle ??= { client: cl.id }; handle ??= { client: cl.id };
return core.handle_request(handle, req, data, true); return core.handle_request(handle, req, data, true, args.host);
} }
} }

View file

@ -62,10 +62,15 @@ function pubsub_del(kind, name, data)
remote.pubsub_set(kind, name, length(list) > 0); remote.pubsub_set(kind, name, length(list) > 0);
} }
function get_handles(handle, local, remote) function get_handles(handle, local, remote, host)
{ {
let handles = []; let handles = [];
if (host == "")
remote = {};
else if (host != null)
local = {};
for (let cur_id, cur in local) { for (let cur_id, cur in local) {
if (handle) { if (handle) {
if (handle.id == cur_id) if (handle.id == cur_id)
@ -80,19 +85,22 @@ function get_handles(handle, local, remote)
if (!remote) if (!remote)
return handles; return handles;
for (let cur_id, cur in remote) for (let cur_id, cur in remote) {
if (host != null && cur.name != host)
continue;
push(handles, cur); push(handles, cur);
}
return handles; return handles;
} }
function handle_request(handle, req, data, remote) function handle_request(handle, req, data, remote, host)
{ {
let name = data.name; let name = data.name;
let local = this.publish[name]; let local = this.publish[name];
if (remote) if (remote)
remote = this.remote_publish[name]; remote = this.remote_publish[name];
let handles = get_handles(handle, local, remote); let handles = get_handles(handle, local, remote, host);
let context = { let context = {
pending: length(handles), pending: length(handles),
@ -134,13 +142,13 @@ function handle_request(handle, req, data, remote)
} }
} }
function handle_message(handle, data, remote) function handle_message(handle, data, remote, host)
{ {
let name = data.name; let name = data.name;
let local = this.subscribe[name]; let local = this.subscribe[name];
if (remote) if (remote)
remote = this.remote_subscribe[name]; remote = this.remote_subscribe[name];
let handles = get_handles(handle, local, remote); let handles = get_handles(handle, local, remote, host);
for (let cur in handles) { for (let cur in handles) {
if (!cur || !cur.get_channel) if (!cur || !cur.get_channel)
continue; continue;