github.com/stampzilla/stampzilla-go@v2.0.0-rc9+incompatible/nodes/stampzilla-server/web/src/components/Websocket.js (about) 1 import { Component } from 'react'; 2 import { connect } from 'react-redux'; 3 import ReconnectableWebSocket from 'reconnectingwebsocket'; 4 import Url from 'url'; 5 6 import { subscribe as certificates } from '../ducks/certificates'; 7 import { connected, disconnected, received } from '../ducks/connection'; 8 import { subscribe as connections } from '../ducks/connections'; 9 import { subscribe as devices } from '../ducks/devices'; 10 import { subscribe as nodes } from '../ducks/nodes'; 11 import { subscribe as requests } from '../ducks/requests'; 12 import { subscribe as rules } from '../ducks/rules'; 13 import { subscribe as savedstates } from '../ducks/savedstates'; 14 import { subscribe as schedules } from '../ducks/schedules'; 15 import { update as updateServer } from '../ducks/server'; 16 17 // Placeholder until we have the write func from the websocket 18 let writeSocket = null; 19 const writeFunc = (data) => { 20 if (writeSocket === null) { 21 throw new Error('Not initialized yet'); 22 } 23 writeSocket.send(data); 24 }; 25 export const write = msg => writeFunc(JSON.stringify(msg)); 26 27 class Websocket extends Component { 28 constructor(props) { 29 super(props); 30 31 this.subscriptions = {}; 32 } 33 34 componentDidMount() { 35 this.setupSocket(this.props); 36 } 37 38 componentWillReceiveProps(props) { 39 this.setupSocket(props); 40 } 41 42 componentWillUnmount() { 43 if (typeof this.socket !== 'undefined') { 44 this.socket.close(); 45 } 46 } 47 48 onOpen = () => () => { 49 this.props.dispatch(connected()); 50 51 const url = Url.parse(this.props.url); 52 if (url.protocol === 'wss:') { 53 this.props.dispatch(updateServer({ secure: true })); 54 } 55 56 this.subscribe({ 57 certificates, 58 connections, 59 devices, 60 nodes, 61 requests, 62 rules, 63 savedstates, 64 schedules, 65 }); 66 }; 67 onClose = () => () => { 68 this.props.dispatch(disconnected()); 69 this.subscriptions = {}; 70 }; 71 onMessage = () => (event) => { 72 const { dispatch } = this.props; 73 const parsed = JSON.parse(event.data); 74 75 dispatch(received(parsed)); 76 const subscriptions = this.subscriptions[parsed.type]; 77 if (subscriptions) { 78 subscriptions.forEach(callback => callback(parsed.body)); 79 } 80 switch (parsed.type) { 81 case 'server-info': { 82 dispatch(updateServer(parsed.body)); 83 break; 84 } 85 default: { 86 // Nothing 87 } 88 } 89 }; 90 91 setupSocket(props) { 92 const { url } = props; 93 if (this.socket) { 94 // this is becuase there is a bug in reconnecting websocket causing it to retry forever 95 this.socket.onclose = () => { 96 throw new Error('force close socket'); 97 }; 98 // Close the existing connection 99 this.socket.close(); 100 } 101 102 this.socket = new ReconnectableWebSocket(url, ['gui'], { 103 reconnectInterval: 3000, 104 timeoutInterval: 1000, 105 }); 106 writeSocket = this.socket; 107 // writeFunc = this.socket.send; 108 this.socket.onmessage = this.onMessage(); 109 this.socket.onopen = this.onOpen(); 110 this.socket.onerror = this.onClose(); 111 this.socket.onclose = this.onClose(); 112 } 113 114 subscribe = (ducks) => { 115 const subscriptions = []; 116 Object.keys(ducks).forEach((duck) => { 117 if (!ducks[duck]) { 118 return; 119 } 120 121 const channels = ducks[duck](this.props.dispatch); 122 Object.keys(channels).forEach((channel) => { 123 this.subscriptions[channel] = this.subscriptions[channel] || []; 124 this.subscriptions[channel].push(channels[channel]); 125 subscriptions.push(channel); 126 }); 127 }); 128 129 write({ 130 type: 'subscribe', 131 body: subscriptions, 132 }); 133 }; 134 135 render = () => null; 136 } 137 138 const mapToProps = state => ({ 139 url: state.getIn(['app', 'url']), 140 }); 141 export default connect(mapToProps)(Websocket);