github.com/tuotoo/go-ethereum@v1.7.4-0.20171121184211-049797d40a24/dashboard/assets/components/Dashboard.jsx (about)

     1  // Copyright 2017 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  import React, {Component} from 'react';
    18  import PropTypes from 'prop-types';
    19  import {withStyles} from 'material-ui/styles';
    20  
    21  import SideBar from './SideBar.jsx';
    22  import Header from './Header.jsx';
    23  import Main from "./Main.jsx";
    24  import {isNullOrUndefined, LIMIT, TAGS, DATA_KEYS,} from "./Common.jsx";
    25  
    26  // Styles for the Dashboard component.
    27  const styles = theme => ({
    28      appFrame: {
    29          position:   'relative',
    30          display:    'flex',
    31          width:      '100%',
    32          height:     '100%',
    33          background: theme.palette.background.default,
    34      },
    35  });
    36  
    37  // Dashboard is the main component, which renders the whole page, makes connection with the server and listens for messages.
    38  // When there is an incoming message, updates the page's content correspondingly.
    39  class Dashboard extends Component {
    40      constructor(props) {
    41          super(props);
    42          this.state = {
    43              active:       TAGS.home.id, // active menu
    44              sideBar:      true, // true if the sidebar is opened
    45              memory:       [],
    46              traffic:      [],
    47              logs:         [],
    48              shouldUpdate: {},
    49          };
    50      }
    51  
    52      // componentDidMount initiates the establishment of the first websocket connection after the component is rendered.
    53      componentDidMount() {
    54          this.reconnect();
    55      }
    56  
    57      // reconnect establishes a websocket connection with the server, listens for incoming messages
    58      // and tries to reconnect on connection loss.
    59      reconnect = () => {
    60          const server = new WebSocket(((window.location.protocol === "https:") ? "wss://" : "ws://") + window.location.host + "/api");
    61  
    62          server.onmessage = event => {
    63              const msg = JSON.parse(event.data);
    64              if (isNullOrUndefined(msg)) {
    65                  return;
    66              }
    67              this.update(msg);
    68          };
    69  
    70          server.onclose = () => {
    71              setTimeout(this.reconnect, 3000);
    72          };
    73      };
    74  
    75      // update analyzes the incoming message, and updates the charts' content correspondingly.
    76      update = msg => {
    77          console.log(msg);
    78          this.setState(prevState => {
    79              let newState = [];
    80              newState.shouldUpdate = {};
    81              const insert = (key, values, limit) => {
    82                  newState[key] = [...prevState[key], ...values];
    83                  while (newState[key].length > limit) {
    84                      newState[key].shift();
    85                  }
    86                  newState.shouldUpdate[key] = true;
    87              };
    88              // (Re)initialize the state with the past data.
    89              if (!isNullOrUndefined(msg.history)) {
    90                  const memory = DATA_KEYS.memory;
    91                  const traffic = DATA_KEYS.traffic;
    92                  newState[memory] = [];
    93                  newState[traffic] = [];
    94                  if (!isNullOrUndefined(msg.history.memorySamples)) {
    95                      newState[memory] = msg.history.memorySamples.map(elem => isNullOrUndefined(elem.value) ? 0 : elem.value);
    96                      while (newState[memory].length > LIMIT.memory) {
    97                          newState[memory].shift();
    98                      }
    99                      newState.shouldUpdate[memory] = true;
   100                  }
   101                  if (!isNullOrUndefined(msg.history.trafficSamples)) {
   102                      newState[traffic] = msg.history.trafficSamples.map(elem => isNullOrUndefined(elem.value) ? 0 : elem.value);
   103                      while (newState[traffic].length > LIMIT.traffic) {
   104                          newState[traffic].shift();
   105                      }
   106                      newState.shouldUpdate[traffic] = true;
   107                  }
   108              }
   109              // Insert the new data samples.
   110              if (!isNullOrUndefined(msg.memory)) {
   111                  insert(DATA_KEYS.memory, [isNullOrUndefined(msg.memory.value) ? 0 : msg.memory.value], LIMIT.memory);
   112              }
   113              if (!isNullOrUndefined(msg.traffic)) {
   114                  insert(DATA_KEYS.traffic, [isNullOrUndefined(msg.traffic.value) ? 0 : msg.traffic.value], LIMIT.traffic);
   115              }
   116              if (!isNullOrUndefined(msg.log)) {
   117                  insert(DATA_KEYS.logs, [msg.log], LIMIT.log);
   118              }
   119  
   120              return newState;
   121          });
   122      };
   123  
   124      // The change of the active label on the SideBar component will trigger a new render in the Main component.
   125      changeContent = active => {
   126          this.setState(prevState => prevState.active !== active ? {active: active} : {});
   127      };
   128  
   129      openSideBar = () => {
   130          this.setState({sideBar: true});
   131      };
   132  
   133      closeSideBar = () => {
   134          this.setState({sideBar: false});
   135      };
   136  
   137      render() {
   138          // The classes property is injected by withStyles().
   139          const {classes} = this.props;
   140  
   141          return (
   142              <div className={classes.appFrame}>
   143                  <Header
   144                      opened={this.state.sideBar}
   145                      open={this.openSideBar}
   146                  />
   147                  <SideBar
   148                      opened={this.state.sideBar}
   149                      close={this.closeSideBar}
   150                      changeContent={this.changeContent}
   151                  />
   152                  <Main
   153                      opened={this.state.sideBar}
   154                      active={this.state.active}
   155                      memory={this.state.memory}
   156                      traffic={this.state.traffic}
   157                      logs={this.state.logs}
   158                      shouldUpdate={this.state.shouldUpdate}
   159                  />
   160              </div>
   161          );
   162      }
   163  }
   164  
   165  Dashboard.propTypes = {
   166      classes: PropTypes.object.isRequired,
   167  };
   168  
   169  export default withStyles(styles)(Dashboard);