diff --git a/example/client/package.json b/example/client/package.json index 1630df6..d86aae7 100644 --- a/example/client/package.json +++ b/example/client/package.json @@ -1,27 +1,31 @@ { - "name": "test-client-new", + "name": "example-client", "version": "0.0.1", - "description": "a test websocket client for uci websocket server", - "productName": "Quasar App", + "description": "a websocket client example for use with @uci/websocket-client", + "productName": "Websocket Client", "cordovaId": "org.cordova.quasar.app", "author": "David Kebler ", "private": true, "scripts": { "lint": "eslint --ext .js,.vue src", - "tc": "./node_modules/.bin/quasar dev", - "tc:nas": "WSS='ws://ws.kebler.net' npm run tc" + "client": "quasar dev" }, "dependencies": { - "@quasar/extras": "^1.2.0", - "quasar": "^1.0.0" + "@quasar/extras": "^1.3.1", + "@uci/websocket-client": "file:../..", + "auto-bind": "^2.1.0", + "better-try-catch": "^0.6.2", + "delay": "^4.3.0", + "quasar": "^1.1.0", + "rfs": "^9.0.0" }, "devDependencies": { - "@quasar/app": "^1.0.0", + "@quasar/app": "^1.0.6", "@vue/eslint-config-standard": "^4.0.0", - "babel-eslint": "^10.0.1", - "eslint": "^5.10.0", - "eslint-loader": "^2.1.1", - "eslint-plugin-vue": "^5.0.0" + "babel-eslint": "^10.0.3", + "eslint": "^6.3.0", + "eslint-loader": "^3.0.0", + "eslint-plugin-vue": "^5.2.3" }, "engines": { "node": ">= 8.9.0", diff --git a/example/client/quasar.conf.js b/example/client/quasar.conf.js index be3bca9..486da1c 100644 --- a/example/client/quasar.conf.js +++ b/example/client/quasar.conf.js @@ -46,7 +46,9 @@ module.exports = function (ctx) { 'QSelect', 'QField', 'QFooter', - 'QTooltip' + 'QTooltip', + 'QBadge', + 'QScrollArea' ], directives: [ diff --git a/example/client/src/boot/socket.js b/example/client/src/boot/socket.js index fd37649..3b26564 100644 --- a/example/client/src/boot/socket.js +++ b/example/client/src/boot/socket.js @@ -1,5 +1,4 @@ -// import WebSocket from '@uci/websocket-client' -import WebSocket from '../../../../src' +import WebSocket from '@uci/websocket-client' const ws = new WebSocket(process.env.WSS || 'ws://0.0.0.0:8090') diff --git a/example/client/src/css/app.styl b/example/client/src/css/app.styl index 16e5398..c1c263e 100644 --- a/example/client/src/css/app.styl +++ b/example/client/src/css/app.styl @@ -1,4 +1,37 @@ // app global css +// from https://github.com/quasarframework/quasar/tree/dev/ui/src/css + + +@import "../../node_modules/rfs/stylus" + +$rfs-base-font-size = 1.25rem +// $rfs-font-size-unit = rem +$rfs-breakpoint = 1400px +// $rfs-breakpoint-unit = px +// $rfs-factor = 10 +// $rfs-rem-value = 16 +$rfs-two-dimensional = true +// $rfs-class = false + +$field-font-factor = 1.3 +$field-label-font-factor = 1 + +.q-field__native +.q-item__label + rfs($rfs-base-font-size * $field-font-factor) + +.q-field__label + &.no-pointer-events + rfs($rfs-base-font-size * $field-font-factor) + +.q-field__label + rfs($rfs-base-font-size * $field-label-font-factor) + padding-bottom .3em // needs to be dynamic based on font size + +.q-field__control + // height +??px // needs to be computed based on font size. + + .q-page-container background $accent display: flex; @@ -20,3 +53,7 @@ .q-item padding 0 margin 0 +.greyedout + opacity 0.5 +input + fontsize-12 diff --git a/example/client/src/css/variables.styl.core b/example/client/src/css/variables.styl.core new file mode 100644 index 0000000..cdcfd51 --- /dev/null +++ b/example/client/src/css/variables.styl.core @@ -0,0 +1,639 @@ +$space-base ?= 16px +$space-x-base ?= $space-base +$space-y-base ?= $space-base +$spaces ?= { + none: { + x: 0, + y: 0 + }, + xs: { + x: ($space-x-base * .25), + y: ($space-y-base * .25) + }, + sm: { + x: ($space-x-base * .5), + y: ($space-y-base * .5) + }, + md: { + x: $space-x-base, + y: $space-y-base + }, + lg: { + x: ($space-x-base * 1.5), + y: ($space-y-base * 1.5) + }, + xl: { + x: ($space-x-base * 3), + y: ($space-y-base * 3) + } +} + +// Max width at which point +// current size ends +$breakpoint-xs ?= 599px +$breakpoint-sm ?= 1023px +$breakpoint-md ?= 1439px +$breakpoint-lg ?= 1919px + +$flex-cols ?= 12 +$flex-gutter-xs ?= ($space-base * .25) +$flex-gutter-sm ?= ($space-base * .5) +$flex-gutter-md ?= $space-base +$flex-gutter-lg ?= ($space-base * 1.5) +$flex-gutter-xl ?= ($space-base * 3) + +$body-font-size ?= 14px +$body-line-height ?= 1.5 + +$flex-gutter ?= { + none: 0, + xs: $flex-gutter-xs, + sm: $flex-gutter-sm, + md: $flex-gutter-md, + lg: $flex-gutter-lg, + xl: $flex-gutter-xl +} +$sizes ?= { + xs: 0, // Extra small screen + sm: $breakpoint-xs + 1, // Small screen + md: $breakpoint-sm + 1, // Medium screen + lg: $breakpoint-md + 1, // Large screen + xl: $breakpoint-lg + 1 // Extra large screen +} + +$breakpoint-xs-min ?= 0 +$breakpoint-xs-max ?= $breakpoint-xs + +$breakpoint-sm-min ?= $sizes.sm +$breakpoint-sm-max ?= $breakpoint-sm + +$breakpoint-md-min ?= $sizes.md +$breakpoint-md-max ?= $breakpoint-md + +$breakpoint-lg-min ?= $sizes.lg +$breakpoint-lg-max ?= $breakpoint-lg + +$breakpoint-xl-min ?= $sizes.xl +$breakpoint-xl-max ?= 9999px + +$headings ?= { + h1: { + size: 6rem, + line-height: 6rem, + weight: 300, + letter-spacing: -.01562em + }, + h2: { + size: 3.75rem, + line-height: 3.75rem, + letter-spacing: -.00833em, + weight: 300 + }, + h3: { + size: 3rem, + line-height: 3.125rem, + letter-spacing: normal, + weight: 400 + }, + h4: { + size: 2.125rem, + line-height: 2.5rem, + letter-spacing: .00735em, + weight: 400 + }, + h5: { + size: 1.5rem, + line-height: 2rem, + letter-spacing: normal, + weight: 400 + }, + h6: { + size: 1.25rem, + line-height: 2rem, + letter-spacing: .0125em, + weight: 500 + }, + subtitle1: { + size: 1rem, + line-height: 1.75rem, + letter-spacing: .00937em, + weight: 400 + }, + subtitle2: { + size: .875rem, + line-height: 1.375rem, + letter-spacing: .00714em, + weight: 500 + }, + body1: { + size: 1rem, + line-height: 1.5rem, + letter-spacing: .03125em, + weight: 400 + }, + body2: { + size: .875rem, + line-height: 1.25rem, + letter-spacing: .01786em, + weight: 400 + }, + overline: { + size: .75rem, + line-height: 2rem, + letter-spacing: .16667em, + weight: 500 + }, + caption: { + size: .75rem, + line-height: 1.25rem, + letter-spacing: .03333em, + weight: 400 + } +} + +$h-tags ?= { + h1: $headings.h1, + h2: $headings.h2, + h3: $headings.h3, + h4: $headings.h4, + h5: $headings.h5, + h6: $headings.h6 +} + +$text-weights ?= { + thin: 100, + light: 300, + regular: 400, + medium: 500, + bold: 700, + bolder: 900 +} + +$primary ?= #027BE3 +$secondary ?= #26A69A +$accent ?= #9C27B0 + +$positive ?= #21BA45 +$negative ?= #C10015 +$info ?= #31CCEC +$warning ?= #F2C037 + +$light ?= #bdbdbd +$dark ?= #424242 +$faded ?= #777 + +$dimmed-background ?= rgba(0, 0, 0, .4) +$light-dimmed-background ?= rgba(255, 255, 255, .6) + +$separator-color ?= rgba(0, 0, 0, .12) +$separator-dark-color ?= rgba(255, 255, 255, .48) + +$red ?= #f44336 +$red-1 ?= #ffebee +$red-2 ?= #ffcdd2 +$red-3 ?= #ef9a9a +$red-4 ?= #e57373 +$red-5 ?= #ef5350 +$red-6 ?= #f44336 +$red-7 ?= #e53935 +$red-8 ?= #d32f2f +$red-9 ?= #c62828 +$red-10 ?= #b71c1c +$red-11 ?= #ff8a80 +$red-12 ?= #ff5252 +$red-13 ?= #ff1744 +$red-14 ?= #d50000 +$pink ?= #e91e63 +$pink-1 ?= #fce4ec +$pink-2 ?= #f8bbd0 +$pink-3 ?= #f48fb1 +$pink-4 ?= #f06292 +$pink-5 ?= #ec407a +$pink-6 ?= #e91e63 +$pink-7 ?= #d81b60 +$pink-8 ?= #c2185b +$pink-9 ?= #ad1457 +$pink-10 ?= #880e4f +$pink-11 ?= #ff80ab +$pink-12 ?= #ff4081 +$pink-13 ?= #f50057 +$pink-14 ?= #c51162 +$purple ?= #9c27b0 +$purple-1 ?= #f3e5f5 +$purple-2 ?= #e1bee7 +$purple-3 ?= #ce93d8 +$purple-4 ?= #ba68c8 +$purple-5 ?= #ab47bc +$purple-6 ?= #9c27b0 +$purple-7 ?= #8e24aa +$purple-8 ?= #7b1fa2 +$purple-9 ?= #6a1b9a +$purple-10 ?= #4a148c +$purple-11 ?= #ea80fc +$purple-12 ?= #e040fb +$purple-13 ?= #d500f9 +$purple-14 ?= #aa00ff +$deep-purple ?= #673ab7 +$deep-purple-1 ?= #ede7f6 +$deep-purple-2 ?= #d1c4e9 +$deep-purple-3 ?= #b39ddb +$deep-purple-4 ?= #9575cd +$deep-purple-5 ?= #7e57c2 +$deep-purple-6 ?= #673ab7 +$deep-purple-7 ?= #5e35b1 +$deep-purple-8 ?= #512da8 +$deep-purple-9 ?= #4527a0 +$deep-purple-10 ?= #311b92 +$deep-purple-11 ?= #b388ff +$deep-purple-12 ?= #7c4dff +$deep-purple-13 ?= #651fff +$deep-purple-14 ?= #6200ea +$indigo ?= #3f51b5 +$indigo-1 ?= #e8eaf6 +$indigo-2 ?= #c5cae9 +$indigo-3 ?= #9fa8da +$indigo-4 ?= #7986cb +$indigo-5 ?= #5c6bc0 +$indigo-6 ?= #3f51b5 +$indigo-7 ?= #3949ab +$indigo-8 ?= #303f9f +$indigo-9 ?= #283593 +$indigo-10 ?= #1a237e +$indigo-11 ?= #8c9eff +$indigo-12 ?= #536dfe +$indigo-13 ?= #3d5afe +$indigo-14 ?= #304ffe +$blue ?= #2196f3 +$blue-1 ?= #e3f2fd +$blue-2 ?= #bbdefb +$blue-3 ?= #90caf9 +$blue-4 ?= #64b5f6 +$blue-5 ?= #42a5f5 +$blue-6 ?= #2196f3 +$blue-7 ?= #1e88e5 +$blue-8 ?= #1976d2 +$blue-9 ?= #1565c0 +$blue-10 ?= #0d47a1 +$blue-11 ?= #82b1ff +$blue-12 ?= #448aff +$blue-13 ?= #2979ff +$blue-14 ?= #2962ff +$light-blue ?= #03a9f4 +$light-blue-1 ?= #e1f5fe +$light-blue-2 ?= #b3e5fc +$light-blue-3 ?= #81d4fa +$light-blue-4 ?= #4fc3f7 +$light-blue-5 ?= #29b6f6 +$light-blue-6 ?= #03a9f4 +$light-blue-7 ?= #039be5 +$light-blue-8 ?= #0288d1 +$light-blue-9 ?= #0277bd +$light-blue-10 ?= #01579b +$light-blue-11 ?= #80d8ff +$light-blue-12 ?= #40c4ff +$light-blue-13 ?= #00b0ff +$light-blue-14 ?= #0091ea +$cyan ?= #00bcd4 +$cyan-1 ?= #e0f7fa +$cyan-2 ?= #b2ebf2 +$cyan-3 ?= #80deea +$cyan-4 ?= #4dd0e1 +$cyan-5 ?= #26c6da +$cyan-6 ?= #00bcd4 +$cyan-7 ?= #00acc1 +$cyan-8 ?= #0097a7 +$cyan-9 ?= #00838f +$cyan-10 ?= #006064 +$cyan-11 ?= #84ffff +$cyan-12 ?= #18ffff +$cyan-13 ?= #00e5ff +$cyan-14 ?= #00b8d4 +$teal ?= #009688 +$teal-1 ?= #e0f2f1 +$teal-2 ?= #b2dfdb +$teal-3 ?= #80cbc4 +$teal-4 ?= #4db6ac +$teal-5 ?= #26a69a +$teal-6 ?= #009688 +$teal-7 ?= #00897b +$teal-8 ?= #00796b +$teal-9 ?= #00695c +$teal-10 ?= #004d40 +$teal-11 ?= #a7ffeb +$teal-12 ?= #64ffda +$teal-13 ?= #1de9b6 +$teal-14 ?= #00bfa5 +$green ?= #4caf50 +$green-1 ?= #e8f5e9 +$green-2 ?= #c8e6c9 +$green-3 ?= #a5d6a7 +$green-4 ?= #81c784 +$green-5 ?= #66bb6a +$green-6 ?= #4caf50 +$green-7 ?= #43a047 +$green-8 ?= #388e3c +$green-9 ?= #2e7d32 +$green-10 ?= #1b5e20 +$green-11 ?= #b9f6ca +$green-12 ?= #69f0ae +$green-13 ?= #00e676 +$green-14 ?= #00c853 +$light-green ?= #8bc34a +$light-green-1 ?= #f1f8e9 +$light-green-2 ?= #dcedc8 +$light-green-3 ?= #c5e1a5 +$light-green-4 ?= #aed581 +$light-green-5 ?= #9ccc65 +$light-green-6 ?= #8bc34a +$light-green-7 ?= #7cb342 +$light-green-8 ?= #689f38 +$light-green-9 ?= #558b2f +$light-green-10 ?= #33691e +$light-green-11 ?= #ccff90 +$light-green-12 ?= #b2ff59 +$light-green-13 ?= #76ff03 +$light-green-14 ?= #64dd17 +$lime ?= #cddc39 +$lime-1 ?= #f9fbe7 +$lime-2 ?= #f0f4c3 +$lime-3 ?= #e6ee9c +$lime-4 ?= #dce775 +$lime-5 ?= #d4e157 +$lime-6 ?= #cddc39 +$lime-7 ?= #c0ca33 +$lime-8 ?= #afb42b +$lime-9 ?= #9e9d24 +$lime-10 ?= #827717 +$lime-11 ?= #f4ff81 +$lime-12 ?= #eeff41 +$lime-13 ?= #c6ff00 +$lime-14 ?= #aeea00 +$yellow ?= #ffeb3b +$yellow-1 ?= #fffde7 +$yellow-2 ?= #fff9c4 +$yellow-3 ?= #fff59d +$yellow-4 ?= #fff176 +$yellow-5 ?= #ffee58 +$yellow-6 ?= #ffeb3b +$yellow-7 ?= #fdd835 +$yellow-8 ?= #fbc02d +$yellow-9 ?= #f9a825 +$yellow-10 ?= #f57f17 +$yellow-11 ?= #ffff8d +$yellow-12 ?= #ffff00 +$yellow-13 ?= #ffea00 +$yellow-14 ?= #ffd600 +$amber ?= #ffc107 +$amber-1 ?= #fff8e1 +$amber-2 ?= #ffecb3 +$amber-3 ?= #ffe082 +$amber-4 ?= #ffd54f +$amber-5 ?= #ffca28 +$amber-6 ?= #ffc107 +$amber-7 ?= #ffb300 +$amber-8 ?= #ffa000 +$amber-9 ?= #ff8f00 +$amber-10 ?= #ff6f00 +$amber-11 ?= #ffe57f +$amber-12 ?= #ffd740 +$amber-13 ?= #ffc400 +$amber-14 ?= #ffab00 +$orange ?= #ff9800 +$orange-1 ?= #fff3e0 +$orange-2 ?= #ffe0b2 +$orange-3 ?= #ffcc80 +$orange-4 ?= #ffb74d +$orange-5 ?= #ffa726 +$orange-6 ?= #ff9800 +$orange-7 ?= #fb8c00 +$orange-8 ?= #f57c00 +$orange-9 ?= #ef6c00 +$orange-10 ?= #e65100 +$orange-11 ?= #ffd180 +$orange-12 ?= #ffab40 +$orange-13 ?= #ff9100 +$orange-14 ?= #ff6d00 +$deep-orange ?= #ff5722 +$deep-orange-1 ?= #fbe9e7 +$deep-orange-2 ?= #ffccbc +$deep-orange-3 ?= #ffab91 +$deep-orange-4 ?= #ff8a65 +$deep-orange-5 ?= #ff7043 +$deep-orange-6 ?= #ff5722 +$deep-orange-7 ?= #f4511e +$deep-orange-8 ?= #e64a19 +$deep-orange-9 ?= #d84315 +$deep-orange-10 ?= #bf360c +$deep-orange-11 ?= #ff9e80 +$deep-orange-12 ?= #ff6e40 +$deep-orange-13 ?= #ff3d00 +$deep-orange-14 ?= #dd2c00 +$brown ?= #795548 +$brown-1 ?= #efebe9 +$brown-2 ?= #d7ccc8 +$brown-3 ?= #bcaaa4 +$brown-4 ?= #a1887f +$brown-5 ?= #8d6e63 +$brown-6 ?= #795548 +$brown-7 ?= #6d4c41 +$brown-8 ?= #5d4037 +$brown-9 ?= #4e342e +$brown-10 ?= #3e2723 +$brown-11 ?= #d7ccc8 +$brown-12 ?= #bcaaa4 +$brown-13 ?= #8d6e63 +$brown-14 ?= #5d4037 +$grey ?= #9e9e9e +$grey-1 ?= #fafafa +$grey-2 ?= #f5f5f5 +$grey-3 ?= #eeeeee +$grey-4 ?= #e0e0e0 +$grey-5 ?= #bdbdbd +$grey-6 ?= #9e9e9e +$grey-7 ?= #757575 +$grey-8 ?= #616161 +$grey-9 ?= #424242 +$grey-10 ?= #212121 +$grey-11 ?= #f5f5f5 +$grey-12 ?= #eeeeee +$grey-13 ?= #bdbdbd +$grey-14 ?= #616161 +$blue-grey ?= #607d8b +$blue-grey-1 ?= #eceff1 +$blue-grey-2 ?= #cfd8dc +$blue-grey-3 ?= #b0bec5 +$blue-grey-4 ?= #90a4ae +$blue-grey-5 ?= #78909c +$blue-grey-6 ?= #607d8b +$blue-grey-7 ?= #546e7a +$blue-grey-8 ?= #455a64 +$blue-grey-9 ?= #37474f +$blue-grey-10 ?= #263238 +$blue-grey-11 ?= #cfd8dc +$blue-grey-12 ?= #b0bec5 +$blue-grey-13 ?= #78909c +$blue-grey-14 ?= #455a64 + +$ios-statusbar-height ?= 20px + +$z-fab ?= 990 +$z-side ?= 1000 +$z-marginals ?= 2000 +$z-fixed-drawer ?= 3000 +$z-fullscreen ?= 6000 +$z-menu ?= 6000 +$z-top ?= 7000 +$z-tooltip ?= 9000 +$z-notify ?= 9500 +$z-max ?= 9998 + +$shadow-color ?= black +$shadow-transition ?= box-shadow .28s cubic-bezier(.4, 0, .2, 1) +$inset-shadow ?= 0 7px 9px -7px rgba($shadow-color, .7) inset + +$elevation-umbra ?= rgba($shadow-color, .2) +$elevation-penumbra ?= rgba($shadow-color, .14) +$elevation-ambient ?= rgba($shadow-color, .12) + +$shadow-0 ?= 0 0 0 $elevation-umbra, 0 0 0 $elevation-penumbra, 0 0 0 $elevation-ambient +$shadow-1 ?= 0 1px 3px $elevation-umbra, 0 1px 1px $elevation-penumbra, 0 2px 1px -1px $elevation-ambient +$shadow-2 ?= 0 1px 5px $elevation-umbra, 0 2px 2px $elevation-penumbra, 0 3px 1px -2px $elevation-ambient +$shadow-3 ?= 0 1px 8px $elevation-umbra, 0 3px 4px $elevation-penumbra, 0 3px 3px -2px $elevation-ambient +$shadow-4 ?= 0 2px 4px -1px $elevation-umbra, 0 4px 5px $elevation-penumbra, 0 1px 10px $elevation-ambient +$shadow-5 ?= 0 3px 5px -1px $elevation-umbra, 0 5px 8px $elevation-penumbra, 0 1px 14px $elevation-ambient +$shadow-6 ?= 0 3px 5px -1px $elevation-umbra, 0 6px 10px $elevation-penumbra, 0 1px 18px $elevation-ambient +$shadow-7 ?= 0 4px 5px -2px $elevation-umbra, 0 7px 10px 1px $elevation-penumbra, 0 2px 16px 1px $elevation-ambient +$shadow-8 ?= 0 5px 5px -3px $elevation-umbra, 0 8px 10px 1px $elevation-penumbra, 0 3px 14px 2px $elevation-ambient +$shadow-9 ?= 0 5px 6px -3px $elevation-umbra, 0 9px 12px 1px $elevation-penumbra, 0 3px 16px 2px $elevation-ambient +$shadow-10 ?= 0 6px 6px -3px $elevation-umbra, 0 10px 14px 1px $elevation-penumbra, 0 4px 18px 3px $elevation-ambient +$shadow-11 ?= 0 6px 7px -4px $elevation-umbra, 0 11px 15px 1px $elevation-penumbra, 0 4px 20px 3px $elevation-ambient +$shadow-12 ?= 0 7px 8px -4px $elevation-umbra, 0 12px 17px 2px $elevation-penumbra, 0 5px 22px 4px $elevation-ambient +$shadow-13 ?= 0 7px 8px -4px $elevation-umbra, 0 13px 19px 2px $elevation-penumbra, 0 5px 24px 4px $elevation-ambient +$shadow-14 ?= 0 7px 9px -4px $elevation-umbra, 0 14px 21px 2px $elevation-penumbra, 0 5px 26px 4px $elevation-ambient +$shadow-15 ?= 0 8px 9px -5px $elevation-umbra, 0 15px 22px 2px $elevation-penumbra, 0 6px 28px 5px $elevation-ambient +$shadow-16 ?= 0 8px 10px -5px $elevation-umbra, 0 16px 24px 2px $elevation-penumbra, 0 6px 30px 5px $elevation-ambient +$shadow-17 ?= 0 8px 11px -5px $elevation-umbra, 0 17px 26px 2px $elevation-penumbra, 0 6px 32px 5px $elevation-ambient +$shadow-18 ?= 0 9px 11px -5px $elevation-umbra, 0 18px 28px 2px $elevation-penumbra, 0 7px 34px 6px $elevation-ambient +$shadow-19 ?= 0 9px 12px -6px $elevation-umbra, 0 19px 29px 2px $elevation-penumbra, 0 7px 36px 6px $elevation-ambient +$shadow-20 ?= 0 10px 13px -6px $elevation-umbra, 0 20px 31px 3px $elevation-penumbra, 0 8px 38px 7px $elevation-ambient +$shadow-21 ?= 0 10px 13px -6px $elevation-umbra, 0 21px 33px 3px $elevation-penumbra, 0 8px 40px 7px $elevation-ambient +$shadow-22 ?= 0 10px 14px -6px $elevation-umbra, 0 22px 35px 3px $elevation-penumbra, 0 8px 42px 7px $elevation-ambient +$shadow-23 ?= 0 11px 14px -7px $elevation-umbra, 0 23px 36px 3px $elevation-penumbra, 0 9px 44px 8px $elevation-ambient +$shadow-24 ?= 0 11px 15px -7px $elevation-umbra, 0 24px 38px 3px $elevation-penumbra, 0 9px 46px 8px $elevation-ambient + +$shadow-up-0 ?= 0 0 0 $elevation-umbra, 0 0 0 $elevation-penumbra, 0 0 0 $elevation-ambient +$shadow-up-1 ?= 0 -1px 3px $elevation-umbra, 0 -1px 1px $elevation-penumbra, 0 -2px 1px -1px $elevation-ambient +$shadow-up-2 ?= 0 -1px 5px $elevation-umbra, 0 -2px 2px $elevation-penumbra, 0 -3px 1px -2px $elevation-ambient +$shadow-up-3 ?= 0 -1px 8px $elevation-umbra, 0 -3px 4px $elevation-penumbra, 0 -3px 3px -2px $elevation-ambient +$shadow-up-4 ?= 0 -2px 4px -1px $elevation-umbra, 0 -4px 5px $elevation-penumbra, 0 -1px 10px $elevation-ambient +$shadow-up-5 ?= 0 -3px 5px -1px $elevation-umbra, 0 -5px 8px $elevation-penumbra, 0 -1px 14px $elevation-ambient +$shadow-up-6 ?= 0 -3px 5px -1px $elevation-umbra, 0 -6px 10px $elevation-penumbra, 0 -1px 18px $elevation-ambient +$shadow-up-7 ?= 0 -4px 5px -2px $elevation-umbra, 0 -7px 10px 1px $elevation-penumbra, 0 -2px 16px 1px $elevation-ambient +$shadow-up-8 ?= 0 -5px 5px -3px $elevation-umbra, 0 -8px 10px 1px $elevation-penumbra, 0 -3px 14px 2px $elevation-ambient +$shadow-up-9 ?= 0 -5px 6px -3px $elevation-umbra, 0 -9px 12px 1px $elevation-penumbra, 0 -3px 16px 2px $elevation-ambient +$shadow-up-10 ?= 0 -6px 6px -3px $elevation-umbra, 0 -10px 14px 1px $elevation-penumbra, 0 -4px 18px 3px $elevation-ambient +$shadow-up-11 ?= 0 -6px 7px -4px $elevation-umbra, 0 -11px 15px 1px $elevation-penumbra, 0 -4px 20px 3px $elevation-ambient +$shadow-up-12 ?= 0 -7px 8px -4px $elevation-umbra, 0 -12px 17px 2px $elevation-penumbra, 0 -5px 22px 4px $elevation-ambient +$shadow-up-13 ?= 0 -7px 8px -4px $elevation-umbra, 0 -13px 19px 2px $elevation-penumbra, 0 -5px 24px 4px $elevation-ambient +$shadow-up-14 ?= 0 -7px 9px -4px $elevation-umbra, 0 -14px 21px 2px $elevation-penumbra, 0 -5px 26px 4px $elevation-ambient +$shadow-up-15 ?= 0 -8px 9px -5px $elevation-umbra, 0 -15px 22px 2px $elevation-penumbra, 0 -6px 28px 5px $elevation-ambient +$shadow-up-16 ?= 0 -8px 10px -5px $elevation-umbra, 0 -16px 24px 2px $elevation-penumbra, 0 -6px 30px 5px $elevation-ambient +$shadow-up-17 ?= 0 -8px 11px -5px $elevation-umbra, 0 -17px 26px 2px $elevation-penumbra, 0 -6px 32px 5px $elevation-ambient +$shadow-up-18 ?= 0 -9px 11px -5px $elevation-umbra, 0 -18px 28px 2px $elevation-penumbra, 0 -7px 34px 6px $elevation-ambient +$shadow-up-19 ?= 0 -9px 12px -6px $elevation-umbra, 0 -19px 29px 2px $elevation-penumbra, 0 -7px 36px 6px $elevation-ambient +$shadow-up-20 ?= 0 -10px 13px -6px $elevation-umbra, 0 -20px 31px 3px $elevation-penumbra, 0 -8px 38px 7px $elevation-ambient +$shadow-up-21 ?= 0 -10px 13px -6px $elevation-umbra, 0 -21px 33px 3px $elevation-penumbra, 0 -8px 40px 7px $elevation-ambient +$shadow-up-22 ?= 0 -10px 14px -6px $elevation-umbra, 0 -22px 35px 3px $elevation-penumbra, 0 -8px 42px 7px $elevation-ambient +$shadow-up-23 ?= 0 -11px 14px -7px $elevation-umbra, 0 -23px 36px 3px $elevation-penumbra, 0 -9px 44px 8px $elevation-ambient +$shadow-up-24 ?= 0 -11px 15px -7px $elevation-umbra, 0 -24px 38px 3px $elevation-penumbra, 0 -9px 46px 8px $elevation-ambient + + +$generic-border-radius ?= 4px +$generic-hover-transition ?= .3s cubic-bezier(.25, .8, .5, 1) +$typography-font-family ?= 'Roboto', '-apple-system', 'Helvetica Neue', Helvetica, Arial, sans-serif +$min-line-height ?= 1.12 + +$button-border-radius ?= 3px +$button-padding ?= 4px 16px +$button-dense-padding ?= .285em +$button-transition ?= $generic-hover-transition +$button-font-size ?= 14px +$button-line-height ?= 1.718em +$button-font-weight ?= 500 +$button-shadow ?= $shadow-2 +$button-shadow-active ?= $shadow-5 +$button-rounded-border-radius ?= 28px +$button-push-border-radius ?= 7px + +$chat-message-received-color ?= black +$chat-message-received-bg ?= $green-4 +$chat-message-sent-color ?= black +$chat-message-sent-bg ?= $grey-4 +$chat-message-avatar-size ?= 48px +$chat-message-border-radius ?= $generic-border-radius +$chat-message-distance ?= 8px +$chat-message-text-padding ?= 8px + +$item-base-color ?= $grey-5 + +$editor-border-color ?= $separator-color +$editor-content-padding ?= 10px +$editor-content-min-height ?= 10em +$editor-toolbar-padding ?= 4px +$editor-hr-color ?= $editor-border-color +$editor-button-gutter ?= 4px + +$fab-margin ?= 5px + +$table-transition ?= $generic-hover-transition +$table-border-radius ?= $generic-border-radius +$table-box-shadow ?= $shadow-2 + +$table-border-color ?= $separator-color +$table-hover-background ?= rgba(0, 0, 0, .03) +$table-selected-background ?= rgba(0, 0, 0, .06) + +$table-dark-border-color ?= $separator-dark-color +$table-dark-hover-background ?= rgba(255, 255, 255, .07) +$table-dark-selected-background ?= rgba(255, 255, 255, .1) + +$toolbar-min-height ?= 50px +$toolbar-padding ?= 0 12px +$toolbar-inset-size ?= 58px +$toolbar-title-font-size ?= 21px +$toolbar-title-font-weight ?= normal +$toolbar-title-letter-spacing ?= .01em +$toolbar-title-padding ?= 0 12px + +$layout-border ?= 1px solid $separator-color +$layout-shadow ?= 0 0 10px 2px rgba(0,0,0,0.2), 0 0px 10px rgba(0,0,0,0.24) + +$menu-background ?= white +$menu-box-shadow ?= $shadow-2 +$menu-max-width ?= 95vw + +$rating-grade-color ?= $yellow +$rating-shadow ?= 0 1px 3px rgba(0, 0, 0, .12), 0 1px 2px rgba(0, 0, 0, .24) + +$tooltip-color ?= #fafafa +$tooltip-background ?= $grey-7 +$tooltip-padding ?= 6px 10px +$tooltip-border-radius ?= $generic-border-radius +$tooltip-fontsize ?= 10px +$tooltip-mobile-padding ?= 8px 16px +$tooltip-mobile-fontsize ?= 14px + +$option-focus-transition ?= .22s cubic-bezier(0,0,.2,1) + +$input-font-size ?= 14px +$input-text-color ?= rgba(0,0,0,.87) +$input-label-color ?= rgba(0,0,0,.6) +$input-autofill-color ?= inherit + +$img-width ?= 100% +$img-background-repeat ?= no-repeat +$img-loading-font-size ?= 50px +$img-content-position ?= absolute +$img-content-padding ?= 16px +$img-content-color ?= white +$img-content-background ?= rgba(0, 0, 0, .47) diff --git a/example/client/src/layouts/MyLayout.vue b/example/client/src/layouts/MyLayout.vue deleted file mode 100644 index 10ff526..0000000 --- a/example/client/src/layouts/MyLayout.vue +++ /dev/null @@ -1,110 +0,0 @@ - - - - - diff --git a/example/client/src/layouts/default.vue b/example/client/src/layouts/default.vue index e5b3f77..ad316fb 100644 --- a/example/client/src/layouts/default.vue +++ b/example/client/src/layouts/default.vue @@ -4,7 +4,7 @@ - Title + Websocket Client for Four In One UCI Base Example @@ -14,11 +14,7 @@ - - - Title - - + @@ -28,6 +24,7 @@ export default { data () { return { + status: [] } } } diff --git a/example/client/src/pages/Index.vue b/example/client/src/pages/Index.vue index ac083ca..07dae4e 100644 --- a/example/client/src/pages/Index.vue +++ b/example/client/src/pages/Index.vue @@ -1,10 +1,10 @@ diff --git a/example/client/src/pages/Index.vue.org b/example/client/src/pages/Index.vue.org deleted file mode 100644 index 7125cfc..0000000 --- a/example/client/src/pages/Index.vue.org +++ /dev/null @@ -1,14 +0,0 @@ - - - - - diff --git a/example/server.js b/example/server.js deleted file mode 100644 index a4eab28..0000000 --- a/example/server.js +++ /dev/null @@ -1,36 +0,0 @@ -import Socket from '@uci/websocket' - -// ws server to example ws client - -async function packetProcess (packet) { - return new Promise(resolve => { - let res = {} - switch (packet.cmd) { - case 'echo': - res.msg = 'Echoing Back any payload propery' - res.payload = packet.payload - this.push({msg:'pushing echo to to any clients also', res:res}) - break - case 'on': - case 'off': - res.msg = `Command turn ${packet.cmd} was sent for light id: ${packet.id ||'none!'} of brightness: ${packet.brightness || 0}` - res.payload = {switch:packet.cmd} - this.push(res) - break - default: - res.msg = `command ${packet.cmd} was unknown at server echo payload back` - res.payload = {} - } - - resolve(res) - }) -} - -// let test = new Test() -let test = new Socket({ port: 8090, clientTracking: true }) -test.registerPacketProcessor(packetProcess) -;(async () => { - console.log(await test.create()) -})().catch(err => { - console.error('FATAL: UNABLE TO START SYSTEM!\n', err) -}) diff --git a/nodemon.json.off b/nodemon.json.off new file mode 100644 index 0000000..ab901e4 --- /dev/null +++ b/nodemon.json.off @@ -0,0 +1,4 @@ +{ + "ignoreRoot": [".git","examples/ws-fio-client"], + "watch": ["node_modules/@uci/","node_modules/@uci-utils/","src/","index.js","examples/","test/"] +} diff --git a/package.json b/package.json index aa60133..6c2c373 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,14 @@ { "name": "@uci/websocket-client", - "version": "0.1.7", + "version": "0.1.8", "description": "JSON packet browser client over web socket", "main": "src", + "watch": { + "client": "src/*.js" + }, "scripts": { - "example": "cd ./example/client && npm run tc", - "example:server": "node -r esm ./example/server.js" + "client": "cd ./example/client && npm run client", + "client:watch": "npm-watch" }, "author": "David Kebler", "license": "MIT", @@ -28,13 +31,13 @@ }, "homepage": "https://github.com/uCOMmandIt/websocket-client#readme", "devDependencies": { - "@uci/websocket": "^0.3.7", - "esm": "^3.2.25" + "npm-watch": "^0.6.0" }, "dependencies": { "auto-bind": "^2.1.0", - "await-to-js": "^2.1.1", "better-try-catch": "^0.6.2", - "eventemitter3": "^4.0.0" + "delay": "^4.3.0", + "eventemitter3": "^4.0.0", + "ws": "^7.1.2" } } diff --git a/src/WSConsumer.js b/src/WSConsumer.js index 132e87c..85cc3df 100644 --- a/src/WSConsumer.js +++ b/src/WSConsumer.js @@ -4,6 +4,8 @@ import btc from 'better-try-catch' import EventEmitter from 'eventemitter3' import autoBind from 'auto-bind' +import pause from 'delay' + /** * Web Socket Consumer - An in browser consumer/client that can communicate via UCI packets @@ -12,8 +14,6 @@ import autoBind from 'auto-bind' * @extends EventEmitter */ -let count = 1 - class WSConsumer extends EventEmitter { /** * constructor - Description @@ -26,11 +26,15 @@ class WSConsumer extends EventEmitter { this.name = opts.name || 'browser' this.instanceID = new Date().getTime() this.url = url - this.rsLimit = opts.rsLimit || 5 - this.initTimeout = opts.initTimeout || 30000 - this.rsDelay = opts.rsDelay || 5000 // in large production you'd want a more robust delay calculation + this.initTimeout = opts.initTimeout * 1000 || 60000 + this.retryWait = opts.retryWait * 1000 || 5000 this.protocol = opts.protocol // available if needed but not documented - this.started = false + this.opts = opts + this._connected = false + this._authenticated = false + this._conAttempt = 1 + this._aborted = false + this._reconnect = false autoBind(this) } @@ -42,59 +46,123 @@ class WSConsumer extends EventEmitter { * but opted to use https://www.npmjs.com/package/reconnecting-websocket */ - async connect () { - // console.log('--- initial connect to websocket at', this.url) + async connect (opts={}) { + this._connected = false + this._authenticated = false + this._conAttempt = 1 + this.url = opts.url || this.url + this.name = opts.name || this.name + this.initTimeout = opts.initTimeout || this.initTimeout + this.retryWait = opts.retryWait || this.retryWait + return new Promise((resolve, reject) => { + if(!this.url) reject('no url provided!') - let timeout - let connect = con.bind(this) + if(this._authenticated) resolve('socket already online') + this.emit('status',{level:30, msg:'attempting an initial connection', id:this.id, opts:this.opts, ready:false}) + let initTimeout = {} + if (this.initTimeout > 499) { // if not set above 500 ms then infinite tries + initTimeout = setTimeout(() => { + this._aborted = true + this.socket.onopen = null // same as 'connect' for regular socket + this.socket.onerror = null + this.emit('status',{level:30, msg:'initial connection timed out', id:this.id, timeout:this.initTimeout, wait:this.retryWait, opts:this.opts, ready:false}) + reject({ opts: this.opts, msg: `unable to connect initially to socket server in ${this.initTimeout/1000} secs, giving up no more attempts`}) + } + , this.initTimeout) + } - function con () { - // console.log(this.started, this.socket) - if (this.socket) delete this.socket // make sure previous socket is garabage collected - this.socket = new WebSocket(this.url, this.protocol) - // console.log('ready after create', this.socket.readyState, this.socket.onopen, this.socket.onclose) - this.socket.onopen = open.bind(this) + const initialConnectHandler = async () => { + this.emit('status',{level:30, msg:'initial connect handler', _clear:true}) + this.socket.onmessage =initialHandshake.bind(this) + } - timeout = setTimeout(function () { - if (!this.started && count===1) console.log('original connection connect failed - retrying') - console.log(`socket has not ${this.started?'re':''}connected in ${this.rsDelay*count/1000} seconds`) - count += 1 - if (!this.started && this.rsDelay*count > this.initTimeout) { - let err = `unable to make a connection to websocket server at ${this.url} within ${this.initTimeout/1000}s` - console.log(err) - reject({url:this.url, msg:err}) + const initialHandshake = async (event) => { + this.emit('status',{level:30, msg:'initial handshake'}) + let packet = JSON.parse(event.data) + if (packet._handshake) { + clearTimeout(initTimeout) + this._connected = true + this.emit('status',{level:30, msg:'connected to server, sending authentification', id:this.id, opts:this.opts, connected:this._authenticated}) + let authPacket = this._authenticate() || {} + authPacket._authenticate = true + authPacket.consumerName = this.name + let [err,res] = await btc(this._authenticateSend)(authPacket) + if (err) reject(err) + if (!res.authenticated) { + this.emit('status',{level:60, msg:`authentication failed: ${res.reason}`, id:this.id, opts:this.opts, connected:this._authenticated }) + reject('unable to authenticate') } - else connect() - }.bind(this), this.rsDelay) + else { + this._authenticated = res.authenticated + this.emit('status',{level:30, success:true, msg:'authentication succesful', id:this.id, opts:this.opts, connected:this._authenticated }) + this._listen() + this.emit('consumer-connection', {state:'connected', id:this.id}) + if (this.opts.conPacket) (this.send(this.conPacket)) + resolve('initial connection successful') + } + } } - function open () { - this.listen() // this handles messages - // console.log(`socket open to server at : ${this.url}`) - if (!this.started) this.emit('connected') - else this.emit('reconnected') - clearTimeout(timeout) - // this.socket.onerror = error.bind(this) - this.socket.onclose = close.bind(this) - count = 0 - this.started = true - resolve({url:this.url, msg:`socket open to server at : ${this.url}`}) + const initialErrorHandler = async (err) => { + this.socket.onopen = null + this.socket.onerror = null + if (!this._aborted) { + this.emit('status',{level:'error', msg:`error during initial connect, trying again in ${this.retryWait/1000} secs`, err:err, id:this.id, connected:this._authenticated }) + await pause(this.retryWait) + connect() // reconnect on error + } } + const connect = async () => { + let [err] = await btc(this.disconnect)() + if (!err) { + this.socket = new WebSocket(this.url) //, this.protocol) + this.socket.onopen = initialConnectHandler.bind(this) // same as 'connect' for regular socket + this.socket.onerror = initialErrorHandler.bind(this) + } + } // end connect + connect() // get the ball rolling - function close () { - this.socket.onclose = null - console.error('Socket has closed, attempting reconnect') - this.removeAllListeners('push') - this.socket.onmessage = null - this.emit('disconnected') - connect() - } }) // end promise } + async disconnect () { + return new Promise((resolve, reject) => { + + clearTimeout(this.pingTimeout) + this.removeAllListeners('ping') + + if (!this.socket) { resolve ('no socket, nothing to close');return } + if (this.socket.readyState === WebSocket.CLOSED || this.socket.readyState === WebSocket.CLOSING) { + this._connected = false + this._authenticated = false + this.emit('status', {level:'trace', msg:'disconnecting - socket is already closed/closing'}) + resolve('socket already closed') + return + } + this.socket.close() + + const timeout = setTimeout(() => { + clearInterval(wait) + this.emit('status', {level:40, msg:'Unable to disconnect in 5 seconds!'}) + reject('unable to close socket in 5 seconds') + },5000) + + const wait = setInterval(() => { + if (this.socket.readyState == WebSocket.CLOSED) { + clearInterval(wait) + clearTimeout(timeout) + this._connected = false + this._authenticated = false + this.emit('status', {level:40, msg:'Socket been closed/disconnected', connected:this._authenticated}) + resolve('socket is now closed') + } + },500) + }) + } + /** * listen - Description * @@ -102,37 +170,100 @@ class WSConsumer extends EventEmitter { * * @returns {type} Description */ - listen (func) { - this.socket.onmessage = packetHandler.bind(this) + _listen () { - // process 'pushed' packets - this.on('pushed', async function (packet) { + const reconnect = async (reason) => { + let [err] = await btc(this.disconnect)() + if (err) { + this.emit('status',{level:'fatal', msg:'unable to close current connection - reconnection attempts aborted'}) + } else { + this.emit('status',{level:'error', msg:`connection failed because ${reason}. attempting reconnect in ${this.retryWait/1000} secs`}) + this.emit('consumer-connection', {state:'disconnected', id:this.id}) + await pause(this.retryWait) + this.removeListener('pushed',pushedHandler) + this.removeListener('ping',pingHandler) + this.socket = new WebSocket(this.url) //, this.protocol) + this.socket.onopen = connectHandler.bind(this) // same as 'connect' for regular socket + this.socket.onerror = errorHandler.bind(this) + } + } // end reconnect + + const connectHandler = async () => { + this.emit('status',{level:30, msg:'starting reconnect', _clear:true}) + this.socket.onmessage =handshake.bind(this) + } + + const handshake = async (event) => { + this.emit('status',{level:30, msg:'handshake/authenticate'}) + let packet = JSON.parse(event.data) + if (packet._handshake) { + this._connected = true + this.emit('status',{level:30, msg:'connected to server, sending authentification', id:this.id, opts:this.opts, connected:this._authenticated }) + let authPacket = this._authenticate() || {} + authPacket._authenticate = true + authPacket.consumerName = this.name + let [err,res] = await btc(this._authenticateSend)(authPacket) + if (err) this.socket.emit('error','authentication send failed') + if (!res.authenticated) { + this.emit('status',{level:60, msg:`authentication failed: ${res.reason}`, id:this.id, opts:this.opts, connected:this._authenticated}) + reconnect.call(this, 'authentication failed') + } + else { + this._authenticated = res.authenticated + this.emit('status',{level:30, success:true, msg:'authentication succesful - reconnected', id:this.id, opts:this.opts, connected:this._authenticated}) + this._listen() + this.emit('consumer-connection', {state:'reconnected', id:this.id}) + if (this.opts.conPacket) (this.send(this.conPacket)) + } + } + } + + const errorHandler = async () => { // all reconnects go through here + this.emit('status',{level:50, msg:'error with socket connection', _clear:true, connected: false}) + reconnect('emitted connection error') // reconnect on error + } + + function monitorPing () { + this.pingTimeout = setTimeout( () => { + this.removeAllListeners('ping') + this.emit('status',{level:40, msg:'failed to receive ping - websocket offline', connected:false }) + reconnect('ping not received in time') + },this._pingTimeout) + } + + const pingHandler = async (packet) => { + clearTimeout(this.pingTimeout) + this.emit('status',{level:'trace', msg:'received ping - resetting timeout' }) + this._pingTimeout= packet.pingInterval + 1000 + monitorPing.call(this) + } + + const packetHandler = (event) => { + let [err, packet] = btc(JSON.parse)(event.data) + if (err) this.emit('status', {'level':'error', msg: `Incoming message - could not parse JSON: ${event.data}` }) + else { + if (packet._header) { + if (packet._header.id !=='ping') this.emit('status', {'level':'debug', msg: `Incoming message - ${packet._header.id}` }) + this.emit(packet._header.id,packet) + } + } + } + + const pushedHandler = async (packet) => { // TODO do some extra security here for 'evil' pushed packets let res = await this._packetProcess(packet) if (!res) { - // if process was not promise returning like just logged to console - // console.log('warning: consumer process function was not promise returning') + this.emit('status',{level:40, msg:`consumer process function ${packet.cmd} was not promise returning`}) } - }) - - function packetHandler (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}` - } - } - // console.log('in the handler', event.data) - if (func) func(packet) // extra processing if enabled - // this is response to a packet send command listener and is processed below - // will also emit 'pushed' via id which can be listened for in app - this.emit(packet._header.id, packet) } - } + + // set the main message handler and ping handler + + this.on('pushed',pushedHandler) + this.socket.onmessage = packetHandler + this.on('ping',pingHandler) + + } // end listen /** * send - Description @@ -143,10 +274,7 @@ class WSConsumer extends EventEmitter { */ async send (packet) { return new Promise((resolve, reject) => { - if (this.socket.readyState !== 1) - reject( - new Error(`Connection not Ready, CODE:${this.socket.readyState}`) - ) + if (!this._connected) reject('Unable to send not connected') packet._header = { id: Math.random() .toString() @@ -155,16 +283,13 @@ class WSConsumer extends EventEmitter { 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) + if (err) reject(`Could not JSON stringify: ${packet}`) this.socket.send(message) - // listen for when packet comes back with unique header id this.once(packet._header.id, async function (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') + this.emit('status',{level:40, msg:`consumer process function ${packet.cmd} was not promise returning`}) } resolve(res) }) // end reply listener @@ -186,6 +311,26 @@ class WSConsumer extends EventEmitter { async _packetProcess (packet) { return Promise.resolve(packet) } + + // default authentication using a simple token + _authenticate () { + return { token: process.env.UCI_CLIENT_TOKEN || this.token || 'default' } + } + + async _authenticateSend (authPacket={}) { + return new Promise(async (resolve, reject) => { + setTimeout(() => {reject({ error: 'no response from socket in 10sec' })}, 10000) + let [err, data] = await btc(JSON.stringify)(authPacket) + if (err) reject('unable to stringify authorization packet') + this.socket.onmessage = event => { + let [err,packet] = btc(JSON.parse)(event.data) + if (err) reject('unable to parse authorization return from server') + resolve (packet) + } + this.socket.send(data) + }) + } + } // end Consumer Class export default WSConsumer