Created
June 4, 2019 20:28
-
-
Save pohy/9e3adfb186797bffa28bc0aae88e8d9c to your computer and use it in GitHub Desktop.
Async mJS RPC Handler
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
load('rpc.js'); | |
let testWiFi = ffi('bool mgos_captive_portal_wifi_setup_test(char*,char*,void(*)(bool,char*,char*,userdata),userdata)'); | |
RPC.addHandlerAsync('ConnectToWifi', function(respond, args) { | |
if ( | |
typeof args !== 'object' | |
|| typeof args.ssid !== 'string' || args.ssid.length < 1 | |
|| typeof args.pass !== 'string' || args.pass.length < 1 | |
) { | |
return respond(FHSConnectToWiFiError()); | |
} | |
print('Testing wifi', args.ssid, args.pass); | |
testWiFi( | |
args.ssid, | |
args.pass, | |
function(success, ssid, pass) { | |
print('Test result', ssid, pass, JSON.stringify(success)); | |
return respond({ | |
ssid: ssid, | |
pass: pass, | |
success: success | |
}); | |
}, | |
null, | |
); | |
}); | |
function FHSConnectToWiFiError() { | |
return { | |
error: -1, | |
message: 'Bad request. Expected: {"ssid": "wifi-ssid", "pass": "wifi-pass"}', | |
}; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
let RPC = { | |
_sdup: ffi('void *strdup(char *)'), | |
_ah: ffi('void *mgos_rpc_add_handler(void *, void (*)(void *, char *, char *, userdata), userdata)'), | |
_resp: ffi('bool mgos_rpc_send_response(void *, char *)'), | |
_call: ffi('bool mgos_rpc_call(char *, char *, char *, void (*)(char *, int, char *, userdata), userdata)'), | |
_err: ffi('bool mg_rpc_send_errorf(void *, int, char *, char *)'), | |
_ahcb: function(ri, args, src, ud) { | |
// NOTE(lsm): not using `this` here deliberately. Calleth from C. | |
let resp = ud.cb(JSON.parse(args || 'null'), src, ud.ud); | |
RPC._rh(ri, resp); | |
// NOTE: we don't call ffi_cb_free here because this handler might be used | |
// more than once | |
}, | |
_ahcba: function(ri, args, src, ud) { | |
// TODO: Handle timeout | |
ud.cb( | |
function(resp) { | |
// TODO: Error when request has already been handled and respond function is called again | |
RPC._rh(ri, resp); | |
}, | |
JSON.parse(args || 'null'), | |
src, | |
ud.ud | |
); | |
}, | |
_rh: function (ri, resp) { | |
if (typeof(resp) === 'undefined') resp = null; | |
if (typeof(resp) === 'object' && typeof(resp.error) === 'number') { | |
RPC._err(ri, resp.error, '%s', resp.message || ''); | |
} else { | |
RPC._resp(ri, JSON.stringify(resp)); | |
} | |
}, | |
_ccb: function(res, code, msg, ud) { | |
ud.cb(res ? JSON.parse(res) : null, code, msg, ud.ud); | |
ffi_cb_free(RPC._ccb, ud); | |
}, | |
LOCAL: "RPC.LOCAL", | |
// ## **`RPC.addHandler(name, handler)`** | |
// Add RPC handler. `name` is a string like `'MyMethod'`, `handler` | |
// is a callback function which takes `args` arguments object. | |
// If a handler returns an object with a numeric `error` attribute and | |
// optional `message` string attribute, the caller will get a failure. | |
// | |
// Return value: none. | |
// | |
// Example: | |
// ```javascript | |
// RPC.addHandler('Sum', function(args) { | |
// if (typeof(args) === 'object' && typeof(args.a) === 'number' && | |
// typeof(args.b) === 'number') { | |
// return args.a + args.b; | |
// } else { | |
// return {error: -1, message: 'Bad request. Expected: {"a":N1,"b":N2}'}; | |
// } | |
// }); | |
// ``` | |
addHandler: function(name, cb, ud) { | |
let data = {cb: cb, ud: ud}; | |
// TODO(lsm): get rid of this strdup() leak. One-off, but still ugly. | |
this._ah(this._sdup(name), this._ahcb, data); | |
}, | |
addHandlerAsync: function(name, cb, ud) { | |
let data = {cb: cb, ud: ud}; | |
this._ah(this._sdup(name), this._ahcba, data); | |
}, | |
// ## **`RPC.call(dst, method, args, callback)`** | |
// Call remote or local RPC service. | |
// Return value: true in case of success, false otherwise. | |
// | |
// If `dst` is empty, connected server is implied. `method` is a string | |
// like "MyMethod", `callback` is a callback function which takes the following | |
// arguments: res (results object), err_code (0 means success, or error code | |
// otherwise), err_msg (error messasge for non-0 error code), userdata. Example: | |
// | |
// ```javascript | |
// RPC.call(RPC.LOCAL, 'Config.Save', {reboot: true}, function (resp, ud) { | |
// print('Response:', JSON.stringify(resp)); | |
// }, null); | |
// ``` | |
call: function(dst, name, args, cb, ud) { | |
let data = {cb: cb, ud: ud}; | |
return this._call(dst, name, JSON.stringify(args), this._ccb, data); | |
}, | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment