jow-/ucode

Example(s) usage of ubus?

huafu opened this issue · 4 comments

huafu commented

I'm trying to use the ubus library. I've managed to use the call method of ubus connection as it's pretty straight forward, but I'm trying to understand how to use the events system (listener, dispatcher, ...) and I can't figure out the right way to do it.
Are there any example/doc out there?

Update:
Here is an example of what I've tried:

import * as ubus from "ubus";

const ctx = ubus.connect();

function cb(event_name, ...args) {
  printf('Got event "%s" with: %.2J\n', event_name, args);
}

// attach the listener
const listener = ctx.listener("*", cb);

// I guess this is how to free/detach the listener then:
// listener.remove();

Tho the script ends directly. How can I make it run forever until I free the listener for example?

jow- commented

Yes, for "asynchronous" methods the default behavior of the module is not useful. You do need to use it in conjunction with the uloop module to control the shared event loop.

The following should do:

import * as ubus from "ubus";
import * as uloop from "uloop";

const ctx = ubus.connect();

function cb(event_name, ...args) {
  printf('Got event "%s" with: %.2J\n', event_name, args);
}

// attach the listener
const listener = ctx.listener("*", cb);

// remove listener after 10s
uloop.timer(10000, () => {
  printf('Removing listener\n');
  listener.remove();

  // end event loop
  printf('Ending even loop\n');
  uloop.end();
});

// run event loop
printf('Starting loop...\n');
uloop.run();

printf('Event loop terminated!\n');

We could consider implicitly starting the uloop like we do for defer() but I suppose it makes little sense since you typically need to setup a number of other things (timeouts, processes, listeners, file descriptors, ...) in the uloop before you enter the blocking run() call - so you would not want a listener() call to directly enter the uloop

huafu commented

Wowo, thanks a lot for explanations. I'm not familiar with uloop, I guessed I had to deal with it and tried the .run() but of course without any timer nothing was happening. So what's the best way to make my script run forever using uloop so that it listen events forever? or should I just restart a uloop timer each time that timer reaches the end?

EDIT: My bad, I've tried uloop.init()... simply running uloop.run() without any timer or anything works fine! Thanks

EDIT 2: And now I'm stuck at trying to read the data of the call in the publish method handler. req is described as <ubus.request 0x77e019d0>, req.reply() can be used to send the response to the ubus call, but where can I read the request data? I don't see any other method in the C source on request object other than error and reply. I've tried properties name, data and message without success.

// ubus-test.uc
import * as ubus from "ubus";
import * as uloop from "uloop";

const ctx = ubus.connect();

function hello_cb(req) {
  printf(
    " - req: %J\n - req.name: %J\n - req.data: %J\n - req.message: %J\n",
    req,
    req.name,
    req.data,
    req.message
  );
  req.reply({ message: "hello!" });
}

const ubus_obj = ctx.publish("test_obj", {
  hello: {
    call: hello_cb,
    args: {
      name: "string",
    },
  },
});

uloop.run();

then in the dash shell:

ucode ubus-test.uc &
ubus call test_obj hello '{"name": "huafu"}'

will output:

 - req: "<ubus.request 0x413490>"
 - req.name: null
 - req.data: null
 - req.message: null

EDIT 3:
Oh, my bad, for those landing here: it's args and there is also info. See [there].(

ucode/lib/ubus.c

Lines 1306 to 1307 in d64d5d6

ucv_object_add(reqproto, "args", args);
ucv_object_add(reqproto, "info",
)

jow- commented

Right, use req.args to access the argument object (may be null) and req.info for auxiliary information

jow- commented

Closing this as the question seems to be answered.