myojs
Version:
JavaScript/ES2015/ES6 client for the Thalmic Labs Myo
180 lines (151 loc) • 4.64 kB
JavaScript
import {EventEmitter} from 'events';
import Frame from './../Frame.js';
export default class BaseConnection extends EventEmitter {
constructor({host = '127.0.0.1', port = 6450} = {}) {
super();
if (typeof host !== 'string') {
throw new Error('Host needs to be of type string');
}
if (port !== parseInt(port, 10)) {
throw new Error('Port needs to be of type integer');
}
this.host = host;
this.port = port;
this.connected = false;
}
getUrl() {
return `ws://${this.host}:${this.port}/`;
}
handleOpen() {
let returnValue = '';
if (!this.connected) {
this.send({
'command': 'requestDeviceInfo'
});
returnValue = 'connecting';
} else {
returnValue = 'connected';
}
return returnValue;
}
handleClose() {
let returnValue = 'disconnected';
if (this.connected) {
this.disconnect();
this.startReconnection();
returnValue = 'disconnecting';
}
return returnValue;
}
startReconnection() {
let returnValue = '';
if (!this.reconnectionTimer) {
this.reconnectionTimer = setInterval(() => {
this.reconnect();
}, 500);
returnValue = 'reconnecting';
} else {
returnValue = 'already reconnecting';
}
return returnValue;
}
stopReconnection() {
this.reconnectionTimer = clearInterval(this.reconnectionTimer);
}
disconnect(allowReconnect) {
if (!allowReconnect) {
this.stopReconnection();
}
if (!this.socket) {
return;
}
this.socket.close();
delete this.socket;
if (this.connected) {
this.connected = false;
this.emit('disconnect');
}
}
reconnect() {
let returnValue = '';
if (this.connected) {
this.stopReconnection();
returnValue = 'stopReconnection';
} else {
this.disconnect(true);
this.connect();
returnValue = 'connect';
}
return returnValue;
}
handleData(data) {
let message = {};
if (!data) {
throw new Error('No data received');
}
// TODO: Profile performance of this try/catch block
try {
message = JSON.parse(data);
} catch (exception) {
throw new Error('Invalid JSON');
}
// Wait for deviceInfo until connected
if (!this.connected && message.hasOwnProperty('frame')) {
const frame = message.frame;
if (frame.hasOwnProperty('deviceInfo')) {
const deviceInfo = frame.deviceInfo;
this.emit('deviceInfo', deviceInfo);
this.connected = true;
this.emit('connect');
return;
}
}
if (!this.connected) {
return;
}
if (message.hasOwnProperty('frame')) {
const frameObject = new Frame(message.frame);
this.emit(frameObject.type, frameObject);
// Emit pose if existing
if (frameObject.pose) {
this.emit('pose', frameObject.pose);
}
// Emit event if existing
if (frameObject.event) {
this.emit('event', frameObject.event);
}
}
}
connect() {
const inBrowser = typeof window !== 'undefined';
if (this.socket) {
return 'socket already created';
}
this.emit('ready');
if (inBrowser) {
this.socket = new WebSocket(this.getUrl());
} else {
const ConnectionType = require('ws');
this.socket = new ConnectionType(this.getUrl());
}
this.socket.onopen = () => {
this.handleOpen();
};
this.socket.onclose = (data) => {
this.handleClose(data.code, data.reason);
};
this.socket.onmessage = (message) => {
this.handleData(message.data);
};
this.socket.onerror = (data) => {
this.handleClose('connectError', data.data);
};
return true;
}
send(data) {
if (typeof data !== 'object' || typeof data === 'string') {
throw new Error('Parameter needs to be an object');
}
this.socket.send(JSON.stringify(data));
}
}