aboutsummaryrefslogtreecommitdiffstats
path: root/web/src/js/ducks/websocket.js
blob: 268c9e6509204c68be76aafa76c075fa971fffa4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
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 }

export default function reducer(state = defaultState, action) {
    switch (action.type) {

        case CONNECT:
            return { ...state, socket: action.socket }

        case CONNECTED:
            return { ...state, connected: true }

        case DISCONNECT:
            return { ...state, connected: false }

        case DISCONNECTED:
            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)

        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 onError(error) {
    // @todo let event log subscribe WebSocketActions.ERROR
    return dispatch => {
        ConnectionActions.error()
        dispatch(eventLogActions.addLogEntry('WebSocket connection error.'))
        dispatch({ type: ERROR, error })
    }
}