aboutsummaryrefslogtreecommitdiffstats
path: root/web
diff options
context:
space:
mode:
authorMaximilian Hils <git@maximilianhils.com>2016-06-23 23:38:19 -0700
committerMaximilian Hils <git@maximilianhils.com>2016-06-23 23:38:19 -0700
commit21c3480429108cbbd45f5ae3de7a36d15460cdc3 (patch)
tree43f7df8c382bee7b9e5feb831379541685cfb4c0 /web
parented05d3f858fb6b7c93b2353c947d88b3aefcd1ae (diff)
parent57af1d00ddd16bd36609a8c6dbf61411f5cd504c (diff)
downloadmitmproxy-21c3480429108cbbd45f5ae3de7a36d15460cdc3.tar.gz
mitmproxy-21c3480429108cbbd45f5ae3de7a36d15460cdc3.tar.bz2
mitmproxy-21c3480429108cbbd45f5ae3de7a36d15460cdc3.zip
Merge remote-tracking branch 'jason/websocket'
Diffstat (limited to 'web')
-rw-r--r--web/src/js/app.jsx12
-rw-r--r--web/src/js/components/ProxyApp.jsx58
-rw-r--r--web/src/js/connection.js49
-rw-r--r--web/src/js/ducks/app.js27
-rw-r--r--web/src/js/ducks/websocket.js117
5 files changed, 168 insertions, 95 deletions
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(
<Provider store={store}>
<ReactRouter history={hashHistory}>
diff --git a/web/src/js/components/ProxyApp.jsx b/web/src/js/components/ProxyApp.jsx
index 5d795b57..84564c32 100644
--- a/web/src/js/components/ProxyApp.jsx
+++ b/web/src/js/components/ProxyApp.jsx
@@ -3,6 +3,7 @@ import ReactDOM from 'react-dom'
import _ from 'lodash'
import { connect } from 'react-redux'
+import { init as appInit, destruct as appDestruct } from '../ducks/app'
import Header from './Header'
import EventLog from './EventLog'
import Footer from './Footer'
@@ -26,27 +27,8 @@ class ProxyAppMain extends Component {
this.updateLocation = this.updateLocation.bind(this)
}
- /**
- * @todo move to actions
- */
- updateLocation(pathname, queryUpdate) {
- if (pathname === undefined) {
- pathname = this.props.location.pathname
- }
- const query = this.props.location.query
- for (const key of Object.keys(queryUpdate || {})) {
- query[key] = queryUpdate[key] || undefined
- }
- this.context.router.replace({ pathname, query })
- }
-
- /**
- * @todo pass in with props
- */
- getQuery() {
- // For whatever reason, react-router always returns the same object, which makes comparing
- // the current props with nextProps impossible. As a workaround, we just clone the query object.
- return _.clone(this.props.location.query)
+ componentWillMount() {
+ this.props.appInit()
}
/**
@@ -56,6 +38,10 @@ class ProxyAppMain extends Component {
this.focus()
}
+ componentWillUnmount() {
+ this.props.appDestruct()
+ }
+
/**
* @todo use props
*/
@@ -110,6 +96,29 @@ class ProxyAppMain extends Component {
e.preventDefault()
}
+ /**
+ * @todo move to actions
+ */
+ updateLocation(pathname, queryUpdate) {
+ if (pathname === undefined) {
+ pathname = this.props.location.pathname
+ }
+ const query = this.props.location.query
+ for (const key of Object.keys(queryUpdate || {})) {
+ query[key] = queryUpdate[key] || undefined
+ }
+ this.context.router.replace({ pathname, query })
+ }
+
+ /**
+ * @todo pass in with props
+ */
+ getQuery() {
+ // For whatever reason, react-router always returns the same object, which makes comparing
+ // the current props with nextProps impossible. As a workaround, we just clone the query object.
+ return _.clone(this.props.location.query)
+ }
+
render() {
const { showEventLog, location, children } = this.props
const query = this.getQuery()
@@ -132,5 +141,10 @@ class ProxyAppMain extends Component {
export default connect(
state => ({
showEventLog: state.eventLog.visible,
- })
+ settings: state.settings.settings,
+ }),
+ {
+ appInit,
+ appDestruct,
+ }
)(ProxyAppMain)
diff --git a/web/src/js/connection.js b/web/src/js/connection.js
deleted file mode 100644
index 524a8f6a..00000000
--- a/web/src/js/connection.js
+++ /dev/null
@@ -1,49 +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"
-import * as settingsActions from './ducks/settings'
-
-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(settingsActions.fetchSettings())
- 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))
- case settingsActions.UPDATE_SETTINGS:
- return dispatch(settingsActions.handleWsMsg(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;
-}
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 ebb39cf8..f38124c9 100644
--- a/web/src/js/ducks/websocket.js
+++ b/web/src/js/ducks/websocket.js
@@ -1,30 +1,113 @@
-const CONNECTED = 'WEBSOCKET_CONNECTED'
-const DISCONNECTED = 'WEBSOCKET_DISCONNECTED'
+import { ConnectionActions } from '../actions.js'
+import { AppDispatcher } from '../dispatcher.js'
+import * as eventLogActions from './eventLog'
+import * as flowsActions from './flows'
+import * as settingsActions from './settings'
+export const SYM_SOCKET = Symbol('WEBSOCKET_SYM_SOCKET')
-const defaultState = {
- connected: false,
- /* we may want to have an error message attribute here at some point */
-}
-export default function reducer(state = defaultState, action) {
+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 reduce(state = defaultState, action) {
switch (action.type) {
+
+ case CONNECT:
+ return { ...state, [SYM_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, [SYM_SOCKET]: null, connected: false }
+
default:
return state
}
}
+export function connect() {
+ return dispatch => {
+ const socket = new WebSocket(location.origin.replace('http', 'ws') + '/updates')
+
+ // @todo remove this
+ window.ws = socket
-export function connected() {
- return {type: CONNECTED}
+ 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 (dispatch, getState) => {
+ getState().settings[SYM_SOCKET].close()
+ dispatch({ type: DISCONNECT })
+ }
}
-export function disconnected() {
- return {type: DISCONNECTED}
+
+export function onConnect() {
+ // workaround to make sure that our state is already available.
+ return dispatch => {
+ dispatch({ type: CONNECTED })
+ dispatch(settingsActions.fetchSettings())
+ dispatch(flowsActions.fetchFlows()).then(() => ConnectionActions.open())
+ }
+}
+
+export function onMessage(msg) {
+ return dispatch => {
+ const data = JSON.parse(msg.data)
+
+ AppDispatcher.dispatchServerAction(data)
+
+ switch (data.type) {
+
+ case eventLogActions.UPDATE_LOG:
+ return dispatch(eventLogActions.updateLogEntries(data))
+
+ case flowsActions.UPDATE_FLOWS:
+ return dispatch(flowsActions.updateFlows(data))
+
+ case settingsActions.UPDATE_SETTINGS:
+ return dispatch(settingsActions.updateSettings(message))
+
+ default:
+ console.warn('unknown message', data)
+ }
+
+ dispatch({ type: MESSAGE, msg })
+ }
+}
+
+export function onDisconnect() {
+ return dispatch => {
+ ConnectionActions.close()
+ dispatch(eventLogActions.addLogEntry('WebSocket connection closed.'))
+ dispatch({ 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 })
+ }
}