From 16a28eca258e07d45c7e2a8ee95368d4eb077d4d Mon Sep 17 00:00:00 2001 From: Jason Date: Wed, 15 Jun 2016 01:18:10 +0800 Subject: [web] websocket --- web/src/js/app.jsx | 12 ++--- web/src/js/components/ProxyApp.jsx | 28 ++++++---- web/src/js/connection.js | 45 ----------------- web/src/js/ducks/websocket.js | 101 ++++++++++++++++++++++++++++++++----- 4 files changed, 110 insertions(+), 76 deletions(-) delete mode 100644 web/src/js/connection.js (limited to 'web/src/js') diff --git a/web/src/js/app.jsx b/web/src/js/app.jsx index 8fa52a00..643bb8b7 100644 --- a/web/src/js/app.jsx +++ b/web/src/js/app.jsx @@ -1,16 +1,15 @@ -import React from "react" +import React from 'react' import { render } from 'react-dom' import { applyMiddleware, createStore } from 'redux' import { Provider } from 'react-redux' import createLogger from 'redux-logger' import thunkMiddleware from 'redux-thunk' -import { Route, Router as ReactRouter, hashHistory, Redirect } from "react-router" +import { Route, Router as ReactRouter, hashHistory, Redirect } from 'react-router' -import Connection from "./connection" -import ProxyApp from "./components/ProxyApp" +import ProxyApp from './components/ProxyApp' import MainView from './components/MainView' import rootReducer from './ducks/index' -import { addLogEntry } from "./ducks/eventLog" +import { addLogEntry } from './ducks/eventLog' // logger must be last const store = createStore( @@ -18,14 +17,13 @@ const store = createStore( applyMiddleware(thunkMiddleware, createLogger()) ) +// @todo move to ProxyApp window.addEventListener('error', msg => { store.dispatch(addLogEntry(msg)) }) // @todo remove this document.addEventListener('DOMContentLoaded', () => { - window.ws = new Connection("/updates", store.dispatch) - render( diff --git a/web/src/js/components/ProxyApp.jsx b/web/src/js/components/ProxyApp.jsx index 81272268..2aedba7c 100644 --- a/web/src/js/components/ProxyApp.jsx +++ b/web/src/js/components/ProxyApp.jsx @@ -1,14 +1,15 @@ -import React, { Component, PropTypes } from "react" -import ReactDOM from "react-dom" -import _ from "lodash" +import React, { Component, PropTypes } from 'react' +import ReactDOM from 'react-dom' +import _ from 'lodash' import { connect } from 'react-redux' -import { Splitter } from "./common.js" -import Header from "./Header" -import EventLog from "./EventLog" -import Footer from "./Footer" -import { SettingsStore } from "../store/store.js" -import { Key } from "../utils.js" +import { Splitter } from './common.js' +import { connect as wsConnect } from '../ducks/websocket' +import Header from './Header' +import EventLog from './EventLog' +import Footer from './Footer' +import { SettingsStore } from '../store/store.js' +import { Key } from '../utils.js' class ProxyAppMain extends Component { @@ -37,6 +38,10 @@ class ProxyAppMain extends Component { this.onSettingsChange = this.onSettingsChange.bind(this) } + componentWillMount() { + this.props.wsConnect() + } + /** * @todo move to actions */ @@ -166,5 +171,8 @@ class ProxyAppMain extends Component { export default connect( state => ({ showEventLog: state.eventLog.visible - }) + }), + { + wsConnect, + } )(ProxyAppMain) diff --git a/web/src/js/connection.js b/web/src/js/connection.js deleted file mode 100644 index 5961909e..00000000 --- a/web/src/js/connection.js +++ /dev/null @@ -1,45 +0,0 @@ -import {ConnectionActions} from "./actions.js"; -import {AppDispatcher} from "./dispatcher.js"; -import * as webSocketActions from "./ducks/websocket" -import * as eventLogActions from "./ducks/eventLog" -import * as flowActions from "./ducks/flows" - -export default function Connection(url, dispatch) { - if (url[0] === "/") { - url = location.origin.replace("http", "ws") + url; - } - - var ws = new WebSocket(url); - ws.onopen = function () { - dispatch(webSocketActions.connected()) - dispatch(flowActions.fetchFlows()) - // workaround to make sure that our state is already available. - .then(() => { - console.log("flows are loaded now") - ConnectionActions.open() - }) - dispatch(eventLogActions.fetchLogEntries()) - }; - ws.onmessage = function (m) { - var message = JSON.parse(m.data); - AppDispatcher.dispatchServerAction(message); - switch (message.type) { - case eventLogActions.UPDATE_LOG: - return dispatch(eventLogActions.updateLogEntries(message)) - case flowActions.UPDATE_FLOWS: - return dispatch(flowActions.updateFlows(message)) - default: - console.warn("unknown message", message) - } - }; - ws.onerror = function () { - ConnectionActions.error(); - dispatch(eventLogActions.addLogEntry("WebSocket connection error.")); - }; - ws.onclose = function () { - ConnectionActions.close(); - dispatch(eventLogActions.addLogEntry("WebSocket connection closed.")); - dispatch(webSocketActions.disconnected()); - }; - return ws; -} \ No newline at end of file diff --git a/web/src/js/ducks/websocket.js b/web/src/js/ducks/websocket.js index ebb39cf8..268c9e65 100644 --- a/web/src/js/ducks/websocket.js +++ b/web/src/js/ducks/websocket.js @@ -1,30 +1,103 @@ +import { ConnectionActions } from '../actions.js' +import { AppDispatcher } from '../dispatcher.js' +import * as eventLogActions from './eventLog' +import * as flowActions from './flows' + +const CONNECT = 'WEBSOCKET_CONNECT' const CONNECTED = 'WEBSOCKET_CONNECTED' +const DISCONNECT = 'WEBSOCKET_DISCONNECT' const DISCONNECTED = 'WEBSOCKET_DISCONNECTED' +const ERROR = 'WEBSOCKET_ERROR' +const MESSAGE = 'WEBSOCKET_MESSAGE' +/* we may want to have an error message attribute here at some point */ +const defaultState = { connected: false, socket: null } -const defaultState = { - connected: false, - /* we may want to have an error message attribute here at some point */ -} export default function reducer(state = defaultState, action) { switch (action.type) { + + case CONNECT: + return { ...state, socket: action.socket } + case CONNECTED: - return { - connected: true - } + return { ...state, connected: true } + + case DISCONNECT: + return { ...state, connected: false } + case DISCONNECTED: - return { - connected: false - } + return { ...state, socket: null } + default: return state } } +export function connect() { + return dispatch => { + const socket = new WebSocket(location.origin.replace('http', 'ws') + '/updates') + + // @todo remove this + window.ws = socket + + socket.addEventListener('open', () => dispatch(onConnect())) + socket.addEventListener('close', () => dispatch(onDisconnect())) + socket.addEventListener('message', msg => dispatch(onMessage(msg))) + socket.addEventListener('error', error => dispatch(onError(error))) + + dispatch({ type: CONNECT, socket }) + + return socket + } +} + +export function disconnect() { + return { type: DISCONNECT } +} + +export function onConnect() { + // workaround to make sure that our state is already available. + return dispatch => { + dispatch({ type: CONNECTED }) + dispatch(flowActions.fetchFlows()).then(() => ConnectionActions.open()) + } +} + +export function onDisconnect() { + return dispatch => { + ConnectionActions.close() + dispatch(eventLogActions.addLogEntry('WebSocket connection closed.')) + dispatch({ type: DISCONNECTED }) + } +} + +export function onMessage(msg) { + return dispatch => { + const data = JSON.parse(msg.data) + + AppDispatcher.dispatchServerAction(data) -export function connected() { - return {type: CONNECTED} + switch (data.type) { + + case eventLogActions.UPDATE_LOG: + return dispatch(eventLogActions.updateLogEntries(data)) + + case flowActions.UPDATE_FLOWS: + return dispatch(flowActions.updateFlows(data)) + + default: + console.warn('unknown message', data) + } + + dispatch({ type: MESSAGE, msg }) + } } -export function disconnected() { - return {type: DISCONNECTED} + +export function onError(error) { + // @todo let event log subscribe WebSocketActions.ERROR + return dispatch => { + ConnectionActions.error() + dispatch(eventLogActions.addLogEntry('WebSocket connection error.')) + dispatch({ type: ERROR, error }) + } } -- cgit v1.2.3 From 6c0511b06fdc359ec4c48879f803c80d7fbeb34c Mon Sep 17 00:00:00 2001 From: Jason Date: Sat, 18 Jun 2016 14:11:42 +0800 Subject: [web] add app ducks --- web/src/js/components/ProxyApp.jsx | 8 +++++--- web/src/js/ducks/app.js | 27 +++++++++++++++++++++++++++ web/src/js/ducks/websocket.js | 19 +++++++++++-------- 3 files changed, 43 insertions(+), 11 deletions(-) create mode 100644 web/src/js/ducks/app.js (limited to 'web/src/js') diff --git a/web/src/js/components/ProxyApp.jsx b/web/src/js/components/ProxyApp.jsx index b5d59b76..11c321e7 100644 --- a/web/src/js/components/ProxyApp.jsx +++ b/web/src/js/components/ProxyApp.jsx @@ -3,7 +3,7 @@ import ReactDOM from 'react-dom' import _ from 'lodash' import { connect } from 'react-redux' -import { connect as wsConnect } from '../ducks/websocket' +import { init as appInit, destruct as appDestruct } from '../ducks/app' import Header from './Header' import EventLog from './EventLog' import Footer from './Footer' @@ -37,7 +37,7 @@ class ProxyAppMain extends Component { } componentWillMount() { - this.props.wsConnect() + this.props.appInit() } /** @@ -79,6 +79,7 @@ class ProxyAppMain extends Component { * @todo stop listening to window's key events */ componentWillUnmount() { + this.props.appDestruct() this.settingsStore.removeListener('recalculate', this.onSettingsChange) } @@ -168,6 +169,7 @@ export default connect( showEventLog: state.eventLog.visible }), { - wsConnect, + appInit, + appDestruct, } )(ProxyAppMain) diff --git a/web/src/js/ducks/app.js b/web/src/js/ducks/app.js new file mode 100644 index 00000000..f1dcb490 --- /dev/null +++ b/web/src/js/ducks/app.js @@ -0,0 +1,27 @@ +import { connect as wsConnect, disconnect as wsDisconnect } from './websocket' + +export const INIT = 'APP_INIT' + +const defaultState = {} + +export function reduce(state = defaultState, action) { + switch (action.type) { + + default: + return state + } +} + +export function init() { + return dispatch => { + dispatch(wsConnect()) + dispatch({ type: INIT }) + } +} + +export function destruct() { + return dispatch => { + dispatch(wsDisconnect()) + dispatch({ type: DESTRUCT }) + } +} diff --git a/web/src/js/ducks/websocket.js b/web/src/js/ducks/websocket.js index 268c9e65..0d0556ad 100644 --- a/web/src/js/ducks/websocket.js +++ b/web/src/js/ducks/websocket.js @@ -3,17 +3,17 @@ import { AppDispatcher } from '../dispatcher.js' import * as eventLogActions from './eventLog' import * as flowActions from './flows' -const CONNECT = 'WEBSOCKET_CONNECT' -const CONNECTED = 'WEBSOCKET_CONNECTED' -const DISCONNECT = 'WEBSOCKET_DISCONNECT' -const DISCONNECTED = 'WEBSOCKET_DISCONNECTED' -const ERROR = 'WEBSOCKET_ERROR' -const MESSAGE = 'WEBSOCKET_MESSAGE' +export const CONNECT = 'WEBSOCKET_CONNECT' +export const CONNECTED = 'WEBSOCKET_CONNECTED' +export const DISCONNECT = 'WEBSOCKET_DISCONNECT' +export const DISCONNECTED = 'WEBSOCKET_DISCONNECTED' +export const ERROR = 'WEBSOCKET_ERROR' +export const MESSAGE = 'WEBSOCKET_MESSAGE' /* we may want to have an error message attribute here at some point */ const defaultState = { connected: false, socket: null } -export default function reducer(state = defaultState, action) { +export default function reduce(state = defaultState, action) { switch (action.type) { case CONNECT: @@ -52,7 +52,10 @@ export function connect() { } export function disconnect() { - return { type: DISCONNECT } + return (dispatch, getState) => { + getState().settings.socket.close() + dispatch({ type: DISCONNECT }) + } } export function onConnect() { -- cgit v1.2.3 From 9a7415a58d299edb4c7219a2bc01d139f050d754 Mon Sep 17 00:00:00 2001 From: Jason Date: Wed, 22 Jun 2016 00:51:45 +0800 Subject: [web] store ws object in symbol property --- web/src/js/ducks/websocket.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'web/src/js') diff --git a/web/src/js/ducks/websocket.js b/web/src/js/ducks/websocket.js index 766f7236..2d4e2b39 100644 --- a/web/src/js/ducks/websocket.js +++ b/web/src/js/ducks/websocket.js @@ -4,6 +4,8 @@ import * as eventLogActions from './eventLog' import * as flowsActions from './flows' import * as settingsActions from './settings' +export const SYM_SOCKET = Symbol('WEBSOCKET_SYM_SOCKET') + export const CONNECT = 'WEBSOCKET_CONNECT' export const CONNECTED = 'WEBSOCKET_CONNECTED' export const DISCONNECT = 'WEBSOCKET_DISCONNECT' @@ -18,7 +20,7 @@ export default function reduce(state = defaultState, action) { switch (action.type) { case CONNECT: - return { ...state, socket: action.socket } + return { ...state, [SYM_SOCKET]: action.socket } case CONNECTED: return { ...state, connected: true } @@ -27,7 +29,7 @@ export default function reduce(state = defaultState, action) { return { ...state, connected: false } case DISCONNECTED: - return { ...state, socket: null } + return { ...state, [SYM_SOCKET]: null } default: return state @@ -54,7 +56,7 @@ export function connect() { export function disconnect() { return (dispatch, getState) => { - getState().settings.socket.close() + getState().settings[SYM_SOCKET].close() dispatch({ type: DISCONNECT }) } } -- cgit v1.2.3 From 57af1d00ddd16bd36609a8c6dbf61411f5cd504c Mon Sep 17 00:00:00 2001 From: Jason Date: Wed, 22 Jun 2016 11:29:21 +0800 Subject: [web] set connected to false when DISCONNECTED --- web/src/js/ducks/websocket.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'web/src/js') diff --git a/web/src/js/ducks/websocket.js b/web/src/js/ducks/websocket.js index 2d4e2b39..f38124c9 100644 --- a/web/src/js/ducks/websocket.js +++ b/web/src/js/ducks/websocket.js @@ -29,7 +29,7 @@ export default function reduce(state = defaultState, action) { return { ...state, connected: false } case DISCONNECTED: - return { ...state, [SYM_SOCKET]: null } + return { ...state, [SYM_SOCKET]: null, connected: false } default: return state -- cgit v1.2.3