UNPKG

web-remote-control

Version:

Fast, real-time, remote control of devices (drones, boats, etc) from the web.

166 lines (131 loc) 5.19 kB
/********************************************************************* * * * Copyright 2016 Simon M. Werner * * * * Licensed to the Apache Software Foundation (ASF) under one * * or more contributor license agreements. See the NOTICE file * * distributed with this work for additional information * * regarding copyright ownership. The ASF licenses this file * * to you under the Apache License, Version 2.0 (the * * "License"); you may not use this file except in compliance * * with the License. You may obtain a copy of the License at * * * * http://www.apache.org/licenses/LICENSE-2.0 * * * * Unless required by applicable law or agreed to in writing, * * software distributed under the License is distributed on an * * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * * KIND, either express or implied. See the License for the * * specific language governing permissions and limitations * * under the License. * * * *********************************************************************/ 'use strict'; var messageHandler = require('./messageHandler'); var EventEmitter = require('events').EventEmitter; var util = require('util'); /** * The connection manager will handle the TCP and UDP transport. As well as * the protocol. */ function ClientConnection(options) { if (options.udp4 === true && options.tcp === true) { throw new Error('Both udp and tcp are set as protocol. Devices can only communicate in one protocol.'); } if (options.udp4 === false && options.tcp === false) { throw new Error('Neither UDP or TCP is set. Devices must communicate in one protocol.'); } if (options.udp4) { this.enable_compression = true; this.createProxySocket('udp4', options.proxyUrl, options.port); } else { this.enable_compression = false; this.createProxySocket('tcp', options.proxyUrl, options.port); } this.log = options.log; EventEmitter.call(this); } util.inherits(ClientConnection, EventEmitter); /** * Set up the UDP listener. */ ClientConnection.prototype.createProxySocket = function (protocol, address, port) { this.remoteAddress = address; this.remotePort = port; var self = this; switch (protocol) { case 'udp4': var dgram = require('dgram'); this.udp4 = dgram.createSocket('udp4'); this.udp4.on('error', handleError.bind(this)); this.udp4.on('message', handleMessage.bind(this)); break; case 'tcp': var net = require('net'); this.tcp = new net.Socket(); this.tcp.connect(this.remotePort, this.remoteAddress); this.tcp.on('error', handleError); this.tcp.on('data', handleMessage); this.tcp.on('close', function() { delete self.tcp; }); break; default: throw new Error('invalid protocol: ', protocol); } function handleError(err) { self.log(err); self.emit('error', err); } function handleMessage(message) { var msgObj; try { msgObj = messageHandler.parseIncomingMessage(message, this.enable_compression); } catch (ex) { self.emit('error', ex); return; } // Empty packet arrived, this happens when remote closes connection if (msgObj === null) { return; } self.emit(msgObj.type, msgObj); } }; /** * Close all connections. */ ClientConnection.prototype.closeAll = function() { if (this.udp4) { try { this.udp4.close(); } catch (ex) { this.log('ERROR: ClientConnection.closeAll(): error closing udp4: ', ex); } } if (this.tcp) { this.tcp.destroy(); } }; /** * Sends a message to the remote device. * @param {object} msgObj The message and socket. * @param {function} callback (optional) */ ClientConnection.prototype._send = function(msgObj, callback) { callback = callback || function () {}; var sendBuffer = messageHandler.packOutgoingMessage(msgObj, this.enable_compression); if (this.udp4) { this.udp4.send(sendBuffer, 0, sendBuffer.length, this.remotePort, this.remoteAddress); callback(null, 'sent'); return; } if (this.tcp) { this.tcp.write(sendBuffer, undefined, function () { callback(null, 'sent'); }); return; } callback('Trying to send a message when a protocol has not been configured.', null); }; module.exports = ClientConnection;