UNPKG

edbot

Version:

Edbot Node.js API module

409 lines (377 loc) 9.28 kB
/* * Edbot Software API Node.js module. * * Uses native Promise mechanism for asynchronous processing. */ const os = require("os"); const axios = require("axios"); const merge = require("deepmerge"); const WebSocket = require("isomorphic-ws"); class Deferred { constructor(value) { if(value !== undefined) { this.value = value; } this.promise = new Promise((resolve, reject) => { this.reject = reject; this.resolve = resolve; }); } } class EdbotClient { /////////////////////////////////////////////////////////////////////////////// // // Public functions. // /////////////////////////////////////////////////////////////////////////////// constructor(server, port, opts) { this.server = server; this.port = port; this.opts = opts; try { this.user = os.userInfo().username; } catch(e) { this.user = ""; } this.client = "Node.js"; this.connected = false; if(opts) { if(opts.user) { this.user = opts.user; } if(opts.client) { this.client = opts.client; } } this.deferred = {}; this.deferred.speechComplete = []; this.deferred.motionComplete = []; this.deferred.disconnect = new Deferred(); } // // Applies to: Edbot, Edbot Dream, Edbot Play&Code. // connect() { if(this.connected) { throw "Already connected to server"; } var i = this; var url = `ws://${i.server}:${i.port}/api/reporter/${i.enc(i.user)}/${i.enc(i.client)}/3`; return new Promise(function(resolve, reject) { i.ws = new WebSocket(url); i.ws.onopen = function(event) { i.connected = true; i.data = {}; i.motionSeq = 0; i.speechSeq = 0; if(i.opts && i.opts.onopen) { i.opts.onopen(event); } } i.ws.onmessage = function(event) { var d = JSON.parse(event.data); i.data = merge(i.data, d, { arrayMerge: (destinationArray, sourceArray, options) => sourceArray }); if(i.opts && i.opts.onmessage) { i.opts.onmessage(event); } if(i.data.initComplete) { resolve(i); } Object.keys(i.data.robots).forEach(name => { try { if(i.data.robots[name].reporters["speechComplete"]) { if(i.data.robots[name].reporters["speechComplete"] == i.deferred.speechComplete[name].value) { i.deferred.speechComplete[name].resolve(true); } } if(i.data.robots[name].reporters["motionComplete"]) { if(i.data.robots[name].reporters["motionComplete"] == i.deferred.motionComplete[name].value) { i.deferred.motionComplete[name].resolve(true); } } } catch(err) {} }); }; i.ws.onclose = function(event) { if(i.connected) { i.connected = false; i.data = {}; if(i.opts && i.opts.onclose) { i.opts.onclose(event); } i.deferred.disconnect.resolve(true); resolve(); } }; i.ws.onerror = function(e) { reject(e.message); }; }); } // // Applies to: Edbot, Edbot Dream, Edbot Play&Code. // getConnected() { return this.connected; } // // Applies to: Edbot, Edbot Dream, Edbot Play&Code. // disconnect() { if(!this.connected) { throw "Not connected to server"; } this.ws.close(1000, "Closed by client"); return this.deferred.disconnect.promise; } // // Applies to: Edbot, Edbot Dream, Edbot Play&Code. // getRobotNames(model) { if(!this.connected) { throw "Not connected to server"; } if(model) { var result = []; Object.keys(this.data.robots).forEach(name => { if(this.data.robots[name].model.key == model) { result.push(name); } }); return result; } else { return Object.keys(this.data.robots); } } // // Applies to: Edbot, Edbot Dream, Edbot Play&Code. // getRobot(name) { if(!this.connected) { throw "Not connected to server"; } if(this.data.robots[name]) { return this.data.robots[name]; } else { throw(name + " is not configured on this server"); } } // // Applies to: Edbot, Edbot Dream, Edbot Play&Code. // getData() { if(!this.connected) { throw "Not connected to server"; } return this.data; } // // Applies to: Edbot, Edbot Dream, Edbot Play&Code. // isActive(name) { if(!this.connected) { throw "Not connected to server"; } var robot = this.getRobot(name); if(robot.activeUser) { return robot.activeUser == this.data.user; } return true; } // // Applies to: Edbot, Edbot Dream, Edbot Play&Code. // setServoSpeed(name, path) { if(!this.connected) { throw "Not connected to server"; } return this.apiRequest(`servo_speed/${this.enc(name)}/${path}`); } // // Applies to: Edbot, Edbot Dream, Edbot Play&Code. // say(name, text) { if(!this.connected) { throw "Not connected to server"; } var value = this.data.auth + "_s_" + (++this.speechSeq); this.deferred.speechComplete[name] = new Deferred(value); var i = this; var response = null; return this.apiRequest(`say/${this.enc(name)}/${this.enc(text)}`, { busy: value }) .then(function(res) { response = res; if(response.success) { return i.deferred.speechComplete[name].promise .then(function() { return response; }); } else { return response; } }); } // // Applies to: Edbot, Edbot Dream, Edbot Play&Code. // reset(name) { if(!this.connected) { throw "Not connected to server"; } return this.apiRequest(`reset/${this.enc(name)}`); } // // Applies to: Edbot, Edbot Dream, Edbot Play&Code. // setOptions(name, path) { if(!this.connected) { throw "Not connected to server"; } return this.apiRequest(`options/${this.enc(name)}/${path}`); } // // Applies to: Edbot, Edbot Dream, Edbot Play&Code. // setCustom(name, path) { if(!this.connected) { throw "Not connected to server"; } return this.apiRequest(`custom/${this.enc(name)}/${path}`); } // // Applies to: Edbot, Edbot Dream. // setServoTorque(name, path) { if(!this.connected) { throw "Not connected to server"; } return this.apiRequest(`servo_torque/${this.enc(name)}/${path}`); } // // Applies to: Edbot, Edbot Dream. // setServoPosition(name, path) { if(!this.connected) { throw "Not connected to server"; } return this.apiRequest(`servo_position/${this.enc(name)}/${path}`); } // // Applies to: Edbot Dream, Edbot Play&Code. // setBuzzer(name, path) { if(!this.connected) { throw "Not connected to server"; } return this.apiRequest(`buzzer/${this.enc(name)}/${path}`); } // // Applies to: Edbot. // getMotions(name) { if(!this.connected) { throw "Not connected to server"; } var url = `http://${this.server}:${this.port}/api/motions/${this.enc(name)}`; return axios.get(url, { headers: { "X-Edbot-Auth": this.data.auth } }) .then(response => { return response.data; }); } // // Applies to: Edbot. // getDefaultMotions(model) { if(!this.connected) { throw "Not connected to server"; } var url = `http://${this.server}:${this.port}/api/def_motions/${this.enc(model)}`; return axios.get(url, { headers: { "X-Edbot-Auth": this.data.auth } }) .then(response => { return response.data; }); } // // Applies to: Edbot. // runMotion(name, motionId) { if(!this.connected) { throw "Not connected to server"; } var value = this.data.auth + "_m_" + (++this.motionSeq); this.deferred.motionComplete[name] = new Deferred(value); var i = this; var response = null; return this.apiRequest(`motion/${this.enc(name)}/${motionId}`, { busy: value }) .then(function(res) { response = res; if(response.success) { return i.deferred.motionComplete[name].promise .then(function() { return response; }); } else { return response; } }); } // // Applies to: Edbot. // setServoLED(name, path) { if(!this.connected) { throw "Not connected to server"; } return this.apiRequest(`servo_led/${this.enc(name)}/${path}`); } // // Applies to: Edbot. // setServoPID(name, path) { if(!this.connected) { throw "Not connected to server"; } return this.apiRequest(`servo_pid/${this.enc(name)}/${path}`); } // // Applies to: Edbot Dream. // setServoMode(name, path) { if(!this.connected) { throw "Not connected to server"; } return this.apiRequest(`servo_mode/${this.enc(name)}/${path}`); } /////////////////////////////////////////////////////////////////////////////// // // Private functions. // /////////////////////////////////////////////////////////////////////////////// getRemoteServers() { if(!this.connected) { throw "Not connected to server"; } var url = `http://${this.server}:${this.port}/api/remote_servers`; return axios.get(url, { headers: { "X-Edbot-Auth": this.data.auth } }) .then(response => { return response.data; }); } setServoCombined(name, path) { if(!this.connected) { throw "Not connected to server"; } return this.apiRequest(`servo_combined/${this.enc(name)}/${path}`); } apiRequest(path, params) { var url = `http://${this.server}:${this.port}/api/${path}`; return axios.get(url, { headers: { "X-Edbot-Auth": this.data.auth }, params: params }) .then(response => { return response.data.status; }); } enc(str) { return encodeURIComponent(str); } } module.exports = EdbotClient;