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);