From 25230a35f74b5b7998c3987b9a2571e280981d3e Mon Sep 17 00:00:00 2001 From: Timothy Warren Date: Wed, 30 May 2018 09:34:33 -0400 Subject: [PATCH] Use a custom pub-sub system to handle receiving web socket responses --- package.json | 13 ++-- scripts/test.js | 2 +- src/App.js | 93 ++++++---------------- src/Routes.js | 2 +- src/index.js | 11 ++- src/reducers/index.js | 2 - src/reducers/receiveReducer.js | 13 ---- src/reducers/sendReducer.js | 13 ---- src/views/HomeView.js | 11 ++- src/wsCache.js | 138 +++++++++++++++++++++++++++++++++ yarn.lock | 22 +----- 11 files changed, 183 insertions(+), 137 deletions(-) delete mode 100644 src/reducers/index.js delete mode 100644 src/reducers/receiveReducer.js delete mode 100644 src/reducers/sendReducer.js create mode 100644 src/wsCache.js diff --git a/package.json b/package.json index caff6a0..c80802e 100644 --- a/package.json +++ b/package.json @@ -7,8 +7,9 @@ "build": { "appId": "net.timshomepage.film-exif", "files": [ - "build/*", - "node_modules/**/*" + "build/**/*", + "node_modules/**/*", + "src/**/*" ] }, "dependencies": { @@ -18,9 +19,8 @@ "inferno": "^5.0.1", "inferno-bootstrap": "^5.0.0", "inferno-dev-utils": "^5.3.0", - "inferno-redux": "^5.0.4", "inferno-router": "^5.0.1", - "redux": "^4.0.0", + "lodash": "^4.17.10", "sqlite3": "^4.0.0", "ws": "^5.1.1" }, @@ -54,7 +54,7 @@ "raf": "^3.4.0" }, "scripts": { - "build": "parcel build index.html --out-dir build --detailed-report", + "build": "parcel build index.html --out-dir build/app --detailed-report", "dist": "yarn run build && build", "electron-start": "node src/electron/wait-inferno", "electron": "electron .", @@ -69,6 +69,9 @@ }, "homepage": "./", "main": "src/electron/index.js", + "mac": { + "category": "public.app-category.photography" + }, "jest": { "collectCoverageFrom": [ "src/**/*.{js,jsx,mjs}" diff --git a/scripts/test.js b/scripts/test.js index cac383a..d3efdc1 100644 --- a/scripts/test.js +++ b/scripts/test.js @@ -11,7 +11,7 @@ require('raf').polyfill(global); // ignoring them. In the future, promise rejections that are not handled will // terminate the Node.js process with a non-zero exit code. process.on('unhandledRejection', err => { - throw err; + throw err; }); const jest = require('jest'); diff --git a/src/App.js b/src/App.js index 4edaf73..d0789a4 100644 --- a/src/App.js +++ b/src/App.js @@ -1,7 +1,6 @@ import * as _ from 'lodash'; import { Component } from 'inferno'; import { BrowserRouter, Link, NavLink } from 'inferno-router'; -import { Loader } from '//components'; import { Container, Nav, @@ -11,72 +10,26 @@ import { } from '//components/Bootstrap'; import { Routes } from '//Routes'; -export class App extends Component { - constructor (props) { - super(props); - - this.state = { - webSocketLoaded: false, - }; - - _.bindAll(this, [ - 'onWebSocketOpen', - 'onWebSocketClose', - ]); - } - - componentDidMount () { - window.clientWS = new WebSocket('ws://localhost:65432/'); - - window.clientWS.addEventListener('open', this.onWebSocketOpen); - window.clientWS.addEventListener('message', console); - window.clientWS.addEventListener('close', this.onWebSocketClose); - - console.info(this.context); - } - - componentWillUnmount () { - if (window.clientWS) { - window.clientWS.close(); - } - } - - onWebSocketOpen () { - this.setState({ - webSocketLoaded: true - }); - - window.clientWS.onmessage = message => { - console.info(JSON.parse(message.data)); - }; - } - - onWebSocketClose () { - console.log('WebSocket closed'); - } - - render () { - return ( - - - - Film Exif - - - - - - ); - } -} +export const App = () => { + return ( + + + + Film Exif + + + + + + ); +}; diff --git a/src/Routes.js b/src/Routes.js index decd684..87b863d 100644 --- a/src/Routes.js +++ b/src/Routes.js @@ -7,7 +7,7 @@ import { OopsView, } from '//views'; -export const Routes = (props) => ( +export const Routes = () => ( diff --git a/src/index.js b/src/index.js index 94afb66..058738f 100644 --- a/src/index.js +++ b/src/index.js @@ -3,11 +3,10 @@ import { Provider } from 'inferno-redux'; import configureStore from './configureStore'; import { App } from './App'; +import WSCache from './wsCache'; -const store = configureStore(); +const WEB_SOCKET = new WebSocket('ws://localhost:65432/'); +window.clientWS = WEB_SOCKET; +window.wsCache = new WSCache(WEB_SOCKET); -render(( - - - -), document.getElementById('app')); +render(, document.getElementById('app')); diff --git a/src/reducers/index.js b/src/reducers/index.js deleted file mode 100644 index 42d0239..0000000 --- a/src/reducers/index.js +++ /dev/null @@ -1,2 +0,0 @@ -export * from '//reducers/receiveReducer'; -export * from '//reducers/sendReducer'; diff --git a/src/reducers/receiveReducer.js b/src/reducers/receiveReducer.js deleted file mode 100644 index fd0009b..0000000 --- a/src/reducers/receiveReducer.js +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Reducer for received websocket messages - * - * @param {object} state - * @param {object} action - * @return {object} newState - */ -export const receiveReducer = (state = {}, action) => { - switch (action.type) { - default: - return state; - } -}; diff --git a/src/reducers/sendReducer.js b/src/reducers/sendReducer.js deleted file mode 100644 index d21b5c8..0000000 --- a/src/reducers/sendReducer.js +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Reducer for websocket-based actions - * - * @param {object} state - * @param {object} action - * @return {object} newState - */ -export const sendReducer = (state = {}, action) => { - switch (action.type) { - default: - return state; - } -}; diff --git a/src/views/HomeView.js b/src/views/HomeView.js index c914ccb..21f85ba 100644 --- a/src/views/HomeView.js +++ b/src/views/HomeView.js @@ -10,7 +10,6 @@ import { ModalHeader, Row, } from '//components/Bootstrap'; -import { JSONMessage } from '//helpers/web-socket'; export class HomeView extends Component { constructor (props) { @@ -40,22 +39,22 @@ export class HomeView extends Component { const newTransfer = { ...e.dataTransfer }; console.info(newTransfer); - window.clientWS.send(JSONMessage('dropped-files', draggedFiles)); + window.wsCache.sendJSON('dropped-files', draggedFiles); } showErrorDialog () { - window.clientWS.send(JSONMessage( + window.wsCache.sendJSON( 'show-error-box', 'Looks like there was a problem. (╥﹏╥) \n (╯°□°)╯︵ ┻━┻' - )); + ); } showOpenDialog () { - window.clientWS.send(JSONMessage('show-open-dialog', {})); + window.wsCache.sendJSON('show-open-dialog'); } showSaveDialog () { - window.clientWS.send(JSONMessage('show-save-dialog', {})); + window.wsCache.sendJSON('show-save-dialog'); } toggleErrorModal () { diff --git a/src/wsCache.js b/src/wsCache.js new file mode 100644 index 0000000..b6fc036 --- /dev/null +++ b/src/wsCache.js @@ -0,0 +1,138 @@ +import * as _ from 'lodash' +import { JSONMessage } from '//helpers/web-socket'; + +export class wsCache { + constructor (ws) { + this.ws = ws + + this.ws.addEventListener('open', this.onWebSocketOpen); + this.ws.addEventListener('message', this.onWebSocketMessage); + this.ws.addEventListener('close', this.onWebSocketClose); + + // Websocket channels + // These hold previous messages if they are needed later + this.slots = { + 'default': [], + } + + // Send messages + this.sent = { + 'default': [], + } + + // Subscribers + this.listeners = { + 'default': [console.info], + } + + _.bindAll(this, [ + 'onWebSocketOpen', + 'onWebSocketClose', + 'onWebSocketMessage', + 'publish', + 'send', + 'sendJSON', + 'subscribe', + ]) + } + + onWebSocketOpen () { + window.wsCache.publish('default', 'Websocket opened'); + } + + onWebSocketClose () { + console.info('WebSocket closed'); + } + + /** + * Callback for receiving a websocket message + * + * @param {mixed} message + */ + onWebSocketMessage (message) { + try { + const messageObject = JSON.parse(message.data); + const [slot, data] = messageObject; + window.wsCache.publish(slot, data); + } catch (e) { + window.wsCache.publish('default', message.data); + } + } + + /* + * Send a recieved websocket message to the appropriate listener(s) + * + * @param {string} slot + * @param {mixed} data + * @return {void} + */ + publish (slot, data) { + if (!this.listeners[slot] || data === undefined) { + return; + } + + this.slots[slot].push(data); + + this.listeners[slot].forEach(listener => { + listener(data) + }); + + console.info(this.slots); + } + + /** + * Send a message to the websocket server + * + * @param {mixed} message + */ + send (message) { + this.sent['default'].push(message); + + return this.ws.send(message); + } + + /** + * Send a JSON-encoded message to the websocket server + * + * @param {string} slot + * @param {mixed} data + */ + sendJSON (slot, data = {}) { + const sentSlots = Object.keys(this.sent); + + if (!sentSlots.includes(slot)) { + this.sent[slot] = []; + } + + this.sent[slot].push(data); + + return this.ws.send(JSONMessage(slot, data)); + } + + /** + * Subscribe to a websocket message type + * + * Returns an object with a `unsubscribe` method + * + * @param {string} slot + * @param {function} cb + */ + subscribe (slot, cb) { + const slots = Object.keys(this.slots); + // Create the slots and listener arrays + if (!slots.includes(slot)) { + this.slots[slot] = []; + this.listeners[slot] = []; + } + + const listenerIndex = this.listeners[slot].push(cb) -1; + + return { + remove: () => { + delete this.listeners[slot][listenerIndex]; + } + } + } +} + +export default wsCache; diff --git a/yarn.lock b/yarn.lock index 897fe61..a2f5b4c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4030,13 +4030,6 @@ inferno-popper@^5.0.0: is-equal-shallow "^0.1.3" popper.js "^1.10.8" -inferno-redux@^5.0.4: - version "5.0.5" - resolved "https://registry.npmjs.org/inferno-redux/-/inferno-redux-5.0.5.tgz#8d7eca55f324fd7d24c86ac7eaac89d7cd7f54ef" - dependencies: - hoist-non-inferno-statics "^1.1.3" - inferno-shared "5.0.5" - inferno-router@^5.0.1: version "5.0.5" resolved "https://registry.npmjs.org/inferno-router/-/inferno-router-5.0.5.tgz#3fb68a63e6fa4c9b27b7b87861b1c3fca67015b9" @@ -5072,7 +5065,7 @@ lodash.uniq@^4.5.0: version "4.5.0" resolved "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" -lodash@^4.13.1, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.0, lodash@^4.3.0: +lodash@^4.13.1, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.0, lodash@^4.3.0: version "4.17.10" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" @@ -5080,7 +5073,7 @@ longest@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" -loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1: +loose-envify@^1.0.0, loose-envify@^1.2.0, loose-envify@^1.3.1: version "1.3.1" resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" dependencies: @@ -6530,13 +6523,6 @@ reduce-function-call@^1.0.1: dependencies: balanced-match "^0.4.2" -redux@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/redux/-/redux-4.0.0.tgz#aa698a92b729315d22b34a0553d7e6533555cc03" - dependencies: - loose-envify "^1.1.0" - symbol-observable "^1.2.0" - regenerate-unicode-properties@^6.0.0: version "6.0.0" resolved "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-6.0.0.tgz#0fc26f9d5142289df4e177dec58f303d2d097c16" @@ -7370,10 +7356,6 @@ symbol-observable@1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.1.tgz#8340fc4702c3122df5d22288f88283f513d3fdd4" -symbol-observable@^1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" - symbol-tree@^3.2.2: version "3.2.2" resolved "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6"