ucode: parse ucode plugin scripts in raw mode, init search path
[project/rpcd.git] / examples / ucode / example-plugin.uc
1 'use strict';
2
3 let ubus = require('ubus').connect();
4
5 /*
6 * An ucode plugin script is supposed to return a signature object on
7 * invocation which describes the ubus objects the plugin script wants to
8 * register, as well as the related methods and their argument signatures.
9 */
10 return {
11 /*
12 * Each toplevel key of the returned signature object corresponds to the
13 * name of an ubus object to register.
14 *
15 * The value of each key must be a nested dictionary describing the object
16 * methods.
17 */
18 example_object_1: {
19 /*
20 * Each key within the nested dictionary refers to the name of a method
21 * to define for the parent object.
22 *
23 * The value of each method name key must be another nested dictionary
24 * describing the method.
25 */
26 method_1: {
27 /*
28 * At the very least, each method description dictionary *must*
29 * contain a key "call" with the ucode callback function to call
30 * when the corresponding ubus object method is invoked.
31 *
32 * The callback function is supposed to return a dictionary which
33 * is automatically translated into a nested blobmsg structure and
34 * sent back as ubus reply.
35 *
36 * Non-dictionary return values are discarded and the ubus method
37 * call will fail with UBUS_STATUS_NO_DATA.
38 */
39 call: function() {
40 return { hello: "world" };
41 }
42 },
43
44 method_2: {
45 /*
46 * Additionally, method descriptions *may* supply an "args" key
47 * referring to a dictionary describing the ubus method call
48 * arguments accepted.
49 *
50 * The resulting method argument policy is also published to ubus
51 * and visible with "ubus -v list".
52 *
53 * The callback function will receive a dictionary containing the
54 * received named arguments as first argument. Only named arguments
55 * present in the "args" dictionary are accepted. Attempts to invoke
56 * ubus methods with arguments not mentioned here or with argument
57 * values not matching the given type hints are rejected with
58 * UBUS_STATUS_INVALID_ARGUMENT.
59 *
60 * The expected data type of each named argument is inferred from
61 * the ucode value within the "args" dictionary:
62 *
63 * ucode type | ucode value | blob type
64 * -----------+-------------+--------------------
65 * integer | 8 | BLOBMSG_TYPE_INT8
66 * integer | 16 | BLOBMSG_TYPE_INT16
67 * integer | 64 | BLOBMSG_TYPE_INT64
68 * integer | any integer | BLOBMSG_TYPE_INT32
69 * boolean | true, false | BLOBMSG_TYPE_INT8
70 * string | any string | BLOBMSG_TYPE_STRING
71 * double | any double | BLOBMSG_TYPE_DOUBLE
72 * array | any array | BLOBMSG_TYPE_ARRAY
73 * object | any object | BLOBMSG_TYPE_TABLE
74 *
75 * The ucode callback function will also receive auxillary status
76 * information about the ubus request within a dictionary passed as
77 * second argument to it. The dictionary will contain details about
78 * the invoked object, the invoked method name (useful in case
79 * multiple methods share the same callback) and the effective ubusd
80 * ACL for this request.
81 */
82 args: {
83 foo: 32,
84 bar: 64,
85 baz: true,
86 qrx: "example"
87 },
88
89 call: function(request) {
90 return {
91 got_args: request.args,
92 got_info: request.info
93 };
94 }
95 },
96
97 method_3: {
98 call: function(request) {
99 /*
100 * Process exit codes are automatically translated to ubus
101 * error status codes. Exit code values outside of the
102 * representable status range are converted to
103 * UBUS_STATUS_UNKNOWN_ERROR.
104 */
105 if (request.info.acl.user != "root")
106 exit(UBUS_STATUS_PERMISSION_DENIED);
107
108 /*
109 * To invoke nested ubus requests without potentially blocking
110 * rpcd's main loop, use the ubus.defer() method to start an
111 * asynchronous request and issue request.reply() from within
112 * the completion callback. It is important to return the deferred
113 * request value produced by ubus.call_async() to instruct rpcd to
114 * await the completion of the nested request.
115 */
116 return ubus.defer('example_object_2', 'method_a', { number: 5 },
117 function(code, reply) {
118 request.reply({
119 res: reply,
120 req: request.info
121 }, UBUS_STATUS_OK);
122 });
123 }
124 },
125
126 method_4: {
127 call: function() {
128 /*
129 * Runtime exceptions are catched by rpcd, the corresponding
130 * request is replied to with UBUS_STATUS_UNKNOWN_ERROR.
131 */
132 die("An error occurred");
133 }
134 }
135 },
136
137 example_object_2: {
138 method_a: {
139 args: { number: 123 },
140 call: function(request) {
141 /*
142 * Instead of returning the reply, we can also use the reply
143 * method of the request object.
144 */
145 request.reply({ got_number: request.args.number });
146 }
147 }
148 }
149 };