Refactor/improve state handling from ws

This commit is contained in:
Drew DeVault 2017-08-21 17:10:52 -05:00
parent 50161bc2a9
commit 13f7d40e92
10 changed files with 148 additions and 10 deletions

View File

@ -27,6 +27,7 @@
"react-dom": "^15.6.1", "react-dom": "^15.6.1",
"react-redux": "^5.0.5", "react-redux": "^5.0.5",
"redux": "^3.7.2", "redux": "^3.7.2",
"redux-thunk": "^2.2.0",
"style-loader": "^0.18.2", "style-loader": "^0.18.2",
"webpack": "^3.1.0", "webpack": "^3.1.0",
"webpack-dev-middleware": "^1.12.0", "webpack-dev-middleware": "^1.12.0",

View File

@ -0,0 +1,18 @@
import ws_send from '../socket';
export const FILTER_SUBSCRIBE = 'FILTER_SUBSCRIBE';
export const FILTER_UNSUBSCRIBE = 'FILTER_UNSUBSCRIBE';
export function filter_subscribe(kind='torrent', criteria=[]) {
return dispatch => {
const serial = ws_send(FILTER_SUBSCRIBE, { criteria, kind });
dispatch({ type: FILTER_SUBSCRIBE, serial });
};
}
export function filter_unsubscribe(serial) {
return dispatch => {
ws_send(FILTER_UNSUBSCRIBE, { serial });
dispatch({ type: FILTER_UNSUBSCRIBE, serial });
};
}

25
src/actions/subscribe.js Normal file
View File

@ -0,0 +1,25 @@
import ws_send from '../socket';
export const SUBSCRIBE = 'SUBSCRIBE';
export const UNSUBSCRIBE = 'UNSUBSCRIBE';
export function subscribe(...ids) {
return dispatch => {
const serial = ws_send(SUBSCRIBE, { ids });
dispatch({
type: SUBSCRIBE,
serial,
ids
});
};
}
export function unsubscribe(...ids) {
return dispatch => {
ws_send(UNSUBSCRIBE, { ids });
dispatch({
type: UNSUBSCRIBE,
ids
});
};
}

View File

@ -4,6 +4,13 @@ import { Provider } from 'react-redux';
import store from './store'; import store from './store';
import scss from '../scss/base.scss'; import scss from '../scss/base.scss';
import { ws_init } from './socket';
import { filter_subscribe } from './actions/filter_subscribe';
ws_init(() => {
store.dispatch(filter_subscribe());
store.dispatch(filter_subscribe('server'));
});
render( render(
<Provider store={store}> <Provider store={store}>

View File

@ -0,0 +1,18 @@
import {
FILTER_SUBSCRIBE,
FILTER_UNSUBSCRIBE
} from '../actions/filter_subscribe';
export default function filter_subscribe(state = [], action) {
switch (action.type) {
case FILTER_SUBSCRIBE: {
const { serial } = action;
return [...state, serial];
}
case FILTER_UNSUBSCRIBE: {
const { serial } = action;
return state.filter(s => s !== serial);
}
}
return state;
}

View File

@ -1,7 +1,11 @@
import { combineReducers } from 'redux'; import { combineReducers } from 'redux';
import subscribe from './subscribe';
import filter_subscribe from './filter_subscribe';
import torrents from './torrents'; import torrents from './torrents';
const root = combineReducers({ const root = combineReducers({
subscribe,
filter_subscribe,
torrents torrents
}); });

15
src/reducers/subscribe.js Normal file
View File

@ -0,0 +1,15 @@
import { SUBSCRIBE, UNSUBSCRIBE } from '../actions/subscribe';
export default function subscribe(state = [], action) {
switch (action.type) {
case SUBSCRIBE: {
const { ids, serial } = action;
return [ ...state, ...ids.map(id => ({ serial, id })) ];
}
case UNSUBSCRIBE: {
const { ids } = action;
return state.filter(sub => ids.indexOf(sub.id) === -1);
}
}
return state;
}

View File

@ -7,7 +7,7 @@ export default function torrents(state = {}, action) {
...state, ...state,
...action.resources ...action.resources
.filter(r => r.type === "torrent") .filter(r => r.type === "torrent")
.reduce((s, r) => s[r.id] = r, {}) .reduce((s, r) => ({ ...s, [r.id]: r }), {})
}; };
} }
return state; return state;

41
src/socket.js Normal file
View File

@ -0,0 +1,41 @@
import { dispatch } from './store';
import { subscribe } from './actions/subscribe';
let ws;
let serial = 0;
let transactions = {};
export default function ws_send(type, body, callback = null) {
const _serial = serial++;
if (callback) {
transactions[_serial] = callback;
}
const msg = JSON.stringify({
type,
serial: _serial,
...body
});
console.log("->", msg);
ws.send(msg);
return _serial;
}
const handlers = {
RESOURCES_EXTANT: msg => dispatch(subscribe(...msg.ids)),
UPDATE_RESOURCES: msg => dispatch(msg)
};
function ws_recv(e) {
const msg = JSON.parse(e.data);
console.log("<-", msg);
const cb = transactions[msg.serial];
cb && cb(msg);
const handler = handlers[msg.type];
handler && handler(msg);
}
export function ws_init(cb) {
ws = new WebSocket("ws://127.0.0.1:8412");
ws.addEventListener("open", cb);
ws.addEventListener("message", ws_recv);
}

View File

@ -1,10 +1,19 @@
import { createStore } from 'redux'; import {
applyMiddleware,
createStore,
compose
} from 'redux';
import thunk from 'redux-thunk';
import reducer from './reducers'; import reducer from './reducers';
const _compose =
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
|| compose;
const store = createStore( const store = createStore(
reducer, reducer,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__() _compose(applyMiddleware(thunk)),
); );
export const dispatch = action => store.dispatch(action);
export default store; export default store;