working web browser client (with quasar) uses json packets and specifically works with uci-websocket

This commit is contained in:
David Kebler 2018-04-05 15:11:59 -07:00
parent 83ec3849dd
commit b6be936f44
7 changed files with 237 additions and 0 deletions

34
.eslintrc.js Normal file
View file

@ -0,0 +1,34 @@
module.exports = {
"ecmaFeatures": {
"modules": true,
"spread" : true,
"restParams" : true
},
"env": {
"es6": true,
"node": true,
"mocha": true
},
"parserOptions": {
"ecmaVersion": 2017,
"sourceType": "module",
"parser": 'babel-eslint',
},
"extends": "eslint:recommended",
"rules": {
"indent": [
"error",
2
],
"no-console": 0,
"semi": ["error", "never"],
"linebreak-style": [
"error",
"unix"
],
"quotes": [
"error",
"single"
]
}
}

47
.eslintrc.js.off2 Normal file
View file

@ -0,0 +1,47 @@
module.exports = {
root: true,
parserOptions: {
parser: 'babel-eslint',
sourceType: 'module'
},
env: {
browser: true
},
extends: [
// https://github.com/vuejs/eslint-plugin-vue#priority-a-essential-error-prevention
// consider switching to `plugin:vue/strongly-recommended` or `plugin:vue/recommended` for stricter rules.
// 'plugin:vue/essential',
// https://github.com/standard/standard/blob/master/docs/RULES-en.md
'standard'
],
// required to lint *.vue files
plugins: [
// 'vue'
],
globals: {
'ga': true, // Google Analytics
'cordova': true,
'__statics': true
},
// add your custom rules here
'rules': {
// allow async-await
'generator-star-spacing': 'off',
// allow paren-less arrow functions
'arrow-parens': 0,
'one-var': 0,
'import/first': 0,
'import/named': 2,
'import/namespace': 2,
'import/default': 2,
'import/export': 2,
'import/extensions': 0,
'import/no-unresolved': 0,
'import/no-extraneous-dependencies': 0,
// allow debugger during development
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0
}
}

5
.gitignore vendored Normal file
View file

@ -0,0 +1,5 @@
/node_modules/
/coverage/
/syncd/
*.log
/temp/

4
.npmignore Normal file
View file

@ -0,0 +1,4 @@
tests/
test/
*.test.js
testing/

92
browser-client.js Normal file
View file

@ -0,0 +1,92 @@
// Websocket is a native global for vanilla JS
/* globals WebSocket:true */
import btc from 'better-try-catch'
import EventEmitter from 'eventemitter3'
import autoBind from 'auto-bind'
class Consumer extends EventEmitter {
constructor (url, opts = {}) {
super()
this.name = opts.name || 'browser'
this.instanceID = new Date().getTime()
this.url = url
this.protocol = opts.protocol
autoBind(this)
}
async connect () {
return new Promise((resolve,reject) => {
const socket = new WebSocket(this.url, this.protocol)
// Connection opened
socket.addEventListener('open', open.bind(this))
function open () {
this.socket = socket
resolve(`socket open to server at : ${this.url}`)
}
setTimeout(function () {
reject(new Error('Socket did not connect in 5 seconds'))
}, 5000)
socket.addEventListener('error', function () {
// console.log('Web Socket error occurred')
reject(new Error('Could not connect to socket server '))
})
})
}
listen (func) {
this.socket.addEventListener('message', handler.bind(this))
function handler (event) {
let packet = {}
if (this.socket.readyState === 1) {
let [err, parsed] = btc(JSON.parse)(event.data)
if (err) packet = {error: `Could not parse JSON: ${event.data}`}
else packet = parsed
} else {
packet = {error: `Connection not Ready, CODE:${this.socket.readyState}`}
}
if (func) func(packet)
this.emit(packet._header.id, packet)
}
}
async send (packet) {
return new Promise((resolve, reject) => {
if (this.socket.readyState !== 1) reject(new Error(`Connection not Ready, CODE:${this.socket.readyState}`))
packet._header =
{ id: Math.random().toString().slice(2), // need this for when multiple sends for different consumers use same packet instanceack
sender: { name: this.name, instanceID: this.instanceID },
url: this.url
}
let [err, message] = btc(JSON.stringify)(packet)
if (err) reject(new Error(`Could not JSON stringify: ${packet}`))
// console.log('message to send', message)
this.socket.send(message)
// listen for when packet comes back with unique header id
this.once(packet._header.id, async function (reply) {
// console.log('reply emitted', reply)
let res = await this._packetProcess(reply)
if (!res) { // if process was not promise returning like just logged to console
res = reply
console.log('consumer function was not promise returning - resolving unprocessed')
}
if (res.cmd ==='reply') resolve(res.response)
else resolve(res)
}) // end reply listener
})
}
registerPacketProcessor (func) {
this._packetProcess = func
}
async _packetProcess (packet) {
return Promise.resolve(packet)
}
} // end Consumer Class
export default Consumer

34
package.json Normal file
View file

@ -0,0 +1,34 @@
{
"name": "@uci/websocket-client",
"version": "0.1.2",
"description": "JSON packet browser client over web socket",
"main": "browser-client",
"scripts": {
"test": ""
},
"author": "David Kebler",
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/uCOMmandIt/websocket-client.git"
},
"keywords": [
"node.js",
"socket",
"websocket",
"net",
"JSON",
"packet",
"serialize",
"TCP"
],
"bugs": {
"url": "https://github.com/uCOMmandIt/websocket-client/issues"
},
"homepage": "https://github.com/uCOMmandIt/websocket-client#readme",
"devDependencies": {},
"dependencies": {
"auto-bind": "^1.2.0",
"eventemitter3": "^3.0.1"
}
}

21
readme.md Normal file
View file

@ -0,0 +1,21 @@
# UComandIt Websocket Class for Browsers sending and receiving JSON packets
## What is it
## TL/DR;
## What's it good for
## Why Bother
## Getting Started
"babel-eslint": "^8.2.1",
"eslint": "^4.18.2",
"eslint-config-standard": "^11.0.0",
"eslint-friendly-formatter": "^3.0.0",
"eslint-loader": "^2.0.0",
"eslint-plugin-import": "^2.9.0",
"eslint-plugin-node": "^6.0.1",
"eslint-plugin-promise": "^3.7.0",
"eslint-plugin-standard": "^3.0.1"