[web] settings store

This commit is contained in:
Jason
2016-06-16 12:20:32 +08:00
parent 1fc2db85fa
commit 99b2b8633d
9 changed files with 441 additions and 61578 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -2,7 +2,9 @@
"name": "mitmproxy",
"private": true,
"scripts": {
"test": "jest"
"test": "jest",
"build": "gulp prod",
"start": "gulp"
},
"jest": {
"testPathDirs": [

View File

@@ -7,7 +7,6 @@ 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"
class ProxyAppMain extends Component {
@@ -24,17 +23,9 @@ class ProxyAppMain extends Component {
constructor(props, context) {
super(props, context)
this.settingsStore = new SettingsStore()
// Default Settings before fetch
_.extend(this.settingsStore.dict, {})
this.state = { settings: this.settingsStore.dict }
this.focus = this.focus.bind(this)
this.onKeyDown = this.onKeyDown.bind(this)
this.updateLocation = this.updateLocation.bind(this)
this.onSettingsChange = this.onSettingsChange.bind(this)
}
/**
@@ -61,29 +52,11 @@ class ProxyAppMain extends Component {
}
/**
* @todo remove settings store
* @todo connect websocket here
* @todo listen to window's key events
*/
componentDidMount() {
this.focus()
this.settingsStore.addListener("recalculate", this.onSettingsChange)
}
/**
* @todo remove settings store
* @todo disconnect websocket here
* @todo stop listening to window's key events
*/
componentWillUnmount() {
this.settingsStore.removeListener("recalculate", this.onSettingsChange)
}
/**
* @todo move to actions
*/
onSettingsChange() {
this.setState({ settings: this.settingsStore.dict })
}
/**
@@ -143,8 +116,7 @@ class ProxyAppMain extends Component {
}
render() {
const { showEventLog, location, children } = this.props
const { settings } = this.state
const { showEventLog, location, children, settings } = this.props
const query = this.getQuery()
return (
<div id="container" tabIndex="0" onKeyDown={this.onKeyDown}>
@@ -165,6 +137,7 @@ class ProxyAppMain extends Component {
export default connect(
state => ({
showEventLog: state.eventLog.visible
showEventLog: state.eventLog.visible,
settings: state.settings.settings,
})
)(ProxyAppMain)

View File

@@ -3,6 +3,7 @@ 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] === "/") {
@@ -12,6 +13,7 @@ export default function Connection(url, dispatch) {
var ws = new WebSocket(url);
ws.onopen = function () {
dispatch(webSocketActions.connected())
dispatch(settingsActions.fetch())
dispatch(flowActions.fetchFlows())
// workaround to make sure that our state is already available.
.then(() => {
@@ -28,6 +30,8 @@ export default function Connection(url, dispatch) {
return dispatch(eventLogActions.updateLogEntries(message))
case flowActions.UPDATE_FLOWS:
return dispatch(flowActions.updateFlows(message))
case settingsActions.WS_MSG_TYPE:
return dispatch(settingsActions.handleWsMsg(message))
default:
console.warn("unknown message", message)
}
@@ -42,4 +46,4 @@ export default function Connection(url, dispatch) {
dispatch(webSocketActions.disconnected());
};
return ws;
}
}

View File

@@ -2,12 +2,14 @@ import {combineReducers} from 'redux'
import eventLog from './eventLog'
import websocket from './websocket'
import flows from './flows'
import settings from './settings'
import ui from './ui'
const rootReducer = combineReducers({
eventLog,
websocket,
flows,
settings,
ui
})

View File

@@ -0,0 +1,81 @@
import { StoreCmds } from '../actions'
export const WS_MSG_TYPE = 'settings'
export const WS_MSG_CMD_RESET = 'reset'
export const WS_MSG_CMD_UPDATE = 'update'
export const BEGIN_FETCH = 'SETTINGS_BEGIN_FETCH'
export const FETCH_SETTINGS = 'SETTINGS_FETCH_SETTINGS'
export const FETCH_ERROR = 'SETTINGS_FETCH_ERROR'
export const RECV_WS_MSG = 'SETTINGS_RECV_WS_MSG'
const defaultState = { settings: {}, pendings: null, req: null }
function reduceData(data, action) {
switch (action.cmd) {
case WS_MSG_CMD_RESET:
return action.data || {}
case WS_MSG_CMD_UPDATE:
return _.merge({}, data.settings, action.data)
default:
return data
}
}
export default function reduce(state = defaultState, action) {
switch (action.type) {
case BEGIN_FETCH:
return { ...state, pendings: [], req: action.req }
case FETCH_SETTINGS:
const pendings = state.pendings || []
return { ...state, pendings: null, settings: pendings.reduce(reduceData, data) }
case RECV_WS_MSG:
if (state.pendings) {
return { ...state, pendings: state.pendings.concat(action) }
}
return { ...state, settings: reduceData(state.settings, action) }
default:
return state
}
}
export function fetch() {
return dispatch => {
const req = $.getJSON('/' + this.type)
.done(msg => dispatch(reset(msg.data)))
.fail(error => dispatch(handleFetchError(error)));
dispatch({ type: BEGIN_FETCH, req })
return req
}
}
export function handleWsMsg(msg) {
return (dispatch, getState) => {
if (msg.cmd === STORE_CMDS_RESET) {
const req = getState().settings.req
if (req) {
req.abort()
}
return dispatch(reset(msg.data))
}
dispatch({ type: RECV_WS_MSG, cmd: msg.cmd, data: msg.data })
}
}
export function reset(data) {
return { type: FETCH_SETTINGS, data }
}
export function handleFetchError(error) {
console.error(error)
return { type: FETCH_ERROR, error }
}

View File

@@ -93,4 +93,4 @@ _.extend(LiveDictStore.prototype, DictStore.prototype, LiveStoreMixin.prototype)
export function SettingsStore() {
return new LiveDictStore(ActionTypes.SETTINGS_STORE);
}
}