rpcd/examples/ucode/example-plugin.uc
Jo-Philipp Wich ae5afea283 ucode: parse ucode plugin scripts in raw mode, init search path
It makes little sense to execute rpcd ucode plugin scripts in template
mode since those scripts are supposed to output structured JSON data,
so change the parse config to compile scripts in raw mode.

Also initialize the default library search path which is required in
recent ucode versions.

Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2022-08-12 21:14:27 +02:00

149 lines
4.7 KiB
Ucode

'use strict';
let ubus = require('ubus').connect();
/*
* An ucode plugin script is supposed to return a signature object on
* invocation which describes the ubus objects the plugin script wants to
* register, as well as the related methods and their argument signatures.
*/
return {
/*
* Each toplevel key of the returned signature object corresponds to the
* name of an ubus object to register.
*
* The value of each key must be a nested dictionary describing the object
* methods.
*/
example_object_1: {
/*
* Each key within the nested dictionary refers to the name of a method
* to define for the parent object.
*
* The value of each method name key must be another nested dictionary
* describing the method.
*/
method_1: {
/*
* At the very least, each method description dictionary *must*
* contain a key "call" with the ucode callback function to call
* when the corresponding ubus object method is invoked.
*
* The callback function is supposed to return a dictionary which
* is automatically translated into a nested blobmsg structure and
* sent back as ubus reply.
*
* Non-dictionary return values are discarded and the ubus method
* call will fail with UBUS_STATUS_NO_DATA.
*/
call: function() {
return { hello: "world" };
}
},
method_2: {
/*
* Additionally, method descriptions *may* supply an "args" key
* referring to a dictionary describing the ubus method call
* arguments accepted.
*
* The resulting method argument policy is also published to ubus
* and visible with "ubus -v list".
*
* The callback function will receive a dictionary containing the
* received named arguments as first argument. Only named arguments
* present in the "args" dictionary are accepted. Attempts to invoke
* ubus methods with arguments not mentioned here or with argument
* values not matching the given type hints are rejected with
* UBUS_STATUS_INVALID_ARGUMENT.
*
* The expected data type of each named argument is inferred from
* the ucode value within the "args" dictionary:
*
* ucode type | ucode value | blob type
* -----------+-------------+--------------------
* integer | 8 | BLOBMSG_TYPE_INT8
* integer | 16 | BLOBMSG_TYPE_INT16
* integer | 64 | BLOBMSG_TYPE_INT64
* integer | any integer | BLOBMSG_TYPE_INT32
* boolean | true, false | BLOBMSG_TYPE_INT8
* string | any string | BLOBMSG_TYPE_STRING
* double | any double | BLOBMSG_TYPE_DOUBLE
* array | any array | BLOBMSG_TYPE_ARRAY
* object | any object | BLOBMSG_TYPE_TABLE
*
* The ucode callback function will also receive auxillary status
* information about the ubus request within a dictionary passed as
* second argument to it. The dictionary will contain details about
* the invoked object, the invoked method name (useful in case
* multiple methods share the same callback) and the effective ubusd
* ACL for this request.
*/
args: {
foo: 32,
bar: 64,
baz: true,
qrx: "example"
},
call: function(request) {
return {
got_args: request.args,
got_info: request.info
};
}
},
method_3: {
call: function(request) {
/*
* Process exit codes are automatically translated to ubus
* error status codes. Exit code values outside of the
* representable status range are converted to
* UBUS_STATUS_UNKNOWN_ERROR.
*/
if (request.info.acl.user != "root")
exit(UBUS_STATUS_PERMISSION_DENIED);
/*
* To invoke nested ubus requests without potentially blocking
* rpcd's main loop, use the ubus.defer() method to start an
* asynchronous request and issue request.reply() from within
* the completion callback. It is important to return the deferred
* request value produced by ubus.call_async() to instruct rpcd to
* await the completion of the nested request.
*/
return ubus.defer('example_object_2', 'method_a', { number: 5 },
function(code, reply) {
request.reply({
res: reply,
req: request.info
}, UBUS_STATUS_OK);
});
}
},
method_4: {
call: function() {
/*
* Runtime exceptions are catched by rpcd, the corresponding
* request is replied to with UBUS_STATUS_UNKNOWN_ERROR.
*/
die("An error occurred");
}
}
},
example_object_2: {
method_a: {
args: { number: 123 },
call: function(request) {
/*
* Instead of returning the reply, we can also use the reply
* method of the request object.
*/
request.reply({ got_number: request.args.number });
}
}
}
};