From f5f661ab3cd0940550966234825c9ffe5a2a4ed3 Mon Sep 17 00:00:00 2001 From: Jon Drews Date: Sun, 27 Feb 2022 20:53:59 -0500 Subject: [PATCH] use reconnecting-websocket to ensure websocket reconnects upon disconnects --- web/package-lock.json | 44 +++++++++------- web/package.json | 1 + web/src/LogViewer.js | 118 +++++++++++++++++++++++++++--------------- 3 files changed, 101 insertions(+), 62 deletions(-) diff --git a/web/package-lock.json b/web/package-lock.json index 20f014d..0dd6351 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -2858,9 +2858,9 @@ "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=" }, "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" }, "ansi-styles": { "version": "3.2.1", @@ -6618,9 +6618,9 @@ } }, "follow-redirects": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz", - "integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==" + "version": "1.14.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", + "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==" }, "for-in": { "version": "1.0.2", @@ -10127,8 +10127,7 @@ }, "nanoid": { "version": "3.1.23", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz", - "integrity": "sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw==" + "resolved": "" }, "nanomatch": { "version": "1.2.13", @@ -12560,6 +12559,11 @@ "picomatch": "^2.2.1" } }, + "reconnecting-websocket": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/reconnecting-websocket/-/reconnecting-websocket-4.4.0.tgz", + "integrity": "sha512-D2E33ceRPga0NvTDhJmphEgJ7FUYF0v4lr1ki0csq06OdlxKfugGzN0dSkxM/NfqCxYELK4KcaTOUOjTV6Dcng==" + }, "recursive-readdir": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz", @@ -12734,9 +12738,9 @@ } }, "nth-check": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.0.tgz", - "integrity": "sha512-i4sc/Kj8htBrAiH1viZ0TgU8Y5XqCaV/FziYK6TBczxmeKm3AEFWqqF3195yKudrarqy7Zu80Ra5dobFjn9X/Q==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", + "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", "requires": { "boolbase": "^1.0.0" } @@ -14174,9 +14178,9 @@ "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==" }, "tar": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.0.tgz", - "integrity": "sha512-DUCttfhsnLCjwoDoFcI+B2iJgYa93vBnDUATYEeRx6sntCTdN01VnqsIuTlALXla/LWooNg0yEGeB+Y8WdFxGA==", + "version": "6.1.11", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", + "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", "requires": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", @@ -14388,9 +14392,9 @@ "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=" }, "tmpl": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", - "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=" + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==" }, "to-arraybuffer": { "version": "1.0.1", @@ -14756,9 +14760,9 @@ } }, "url-parse": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.1.tgz", - "integrity": "sha512-HOfCOUJt7iSYzEx/UqgtwKRMC6EU91NFhsCHMv9oM03VJcVo2Qrp8T8kI9D7amFf1cu+/3CEhgb3rF9zL7k85Q==", + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", "requires": { "querystringify": "^2.1.1", "requires-port": "^1.0.0" diff --git a/web/package.json b/web/package.json index b503d6b..4f2e8b0 100644 --- a/web/package.json +++ b/web/package.json @@ -11,6 +11,7 @@ "react-dom": "^17.0.1", "react-scripts": "4.0.3", "react-virtualized": "9.21.1", + "reconnecting-websocket": "^4.4.0", "web-vitals": "^1.1.2", "websocket": "^1.0.34" }, diff --git a/web/src/LogViewer.js b/web/src/LogViewer.js index 0c77980..4277194 100644 --- a/web/src/LogViewer.js +++ b/web/src/LogViewer.js @@ -1,33 +1,42 @@ import React from 'react'; import './LogViewer.css'; -import { List, AutoSizer } from 'react-virtualized'; +import { + List, + AutoSizer, + CellMeasurer, + CellMeasurerCache +} from 'react-virtualized'; import "react-virtualized/styles.css"; -import { w3cwebsocket as W3CWebSocket } from "websocket"; +import ReconnectingWebSocket from 'reconnecting-websocket'; const url = 'ws://localhost:8081/ws'; -const client = new W3CWebSocket(url); +const rws = new ReconnectingWebSocket(url); + const minRowHeight = 23; export default class LogViewer extends React.Component { constructor (props) { super(props) - this.listRef = React.createRef(); + // this.listRef = React.createRef(); + + //TODO: Handle different line sizes with CellMeasurer + // https://github.com/bvaughn/react-virtualized/blob/master/docs/CellMeasurer.md this.state = { - list: [], + lines: [], scrollToIndex: 0, atBottom: false, } - } - componentDidMount() { - client.onopen = () => { - console.log('WebSocket Client Connected'); - }; - client.onmessage = (message) => { - console.log(message); - this._updateFeed(message); - }; + this.cache = new CellMeasurerCache({ + fixedWidth: true, + defaultHeight: 23, + keyMapper: rowIndex => this.state.lines[rowIndex].id + }); + + // this.connect = this.connect.bind(this); + + } handleScroll = (e) => { @@ -37,13 +46,13 @@ export default class LogViewer extends React.Component { if (nearBottom) { this.setState({ atBottom: true }) console.log("bottom!") - const list = [ ...this.state.list ]; - const scrollToIndex = list.length; + const lines = [ ...this.state.lines ]; + const scrollToIndex = lines.length; this.setState({ scrollToIndex: scrollToIndex }); - if (this.listRef.current) { - this.listRef.current.scrollToRow(scrollToIndex) + if (this.listRef) { + this.listRef.scrollToRow(scrollToIndex) } } else { this.setState({ atBottom: false}) @@ -51,49 +60,60 @@ export default class LogViewer extends React.Component { } } - _updateFeed (message) { - const list = [ ...this.state.list ]; + _updateFeed (message) { + const lines = [ ...this.state.lines ]; - list.push(message.data); + lines.push(message.data); - const scrollToIndex = list.length; + const scrollToIndex = lines.length; this.setState({ - list: list, + lines: lines, scrollToIndex: scrollToIndex }); if (this.state.atBottom) { - this.listRef.current.scrollToRow(scrollToIndex) + this.listRef.scrollToRow(scrollToIndex) } + //TODO: figure this out + // this.listRef.recomputeRowHeights(scrollToIndex); + } - rowRenderer = ({ index, isScrolling, key, style }) => ( -
- {this.state.list[index]} -
+ rowRenderer = ({ index, isScrolling, key, style, ...rest }) => ( + +
+ {this.state.lines[index]} +
+
+ ); + // setListRef = r => (this.listRef = r); + render() { return (
- {({width, height}) => ( + {({height}) => ( {this.listRef = list}} onScroll={this.handleScroll} height={height} - rowCount={this.state.list.length} - rowHeight={minRowHeight} + rowCount={this.state.lines.length} + deferredMeasurementCache={this.cache} + rowHeight={this.cache.rowHeight} // autoHeight={true} scrollToIndex={this.state.scrollToIndex} rowRenderer={this.rowRenderer} @@ -111,4 +131,18 @@ export default class LogViewer extends React.Component {
); } + + connect() { + rws.onopen = () => { + console.log('WebSocket Connected'); + }; + rws.onmessage = (message) => { + console.log(message); + this._updateFeed(message); + }; + } + + componentDidMount() { + this.connect(); + } } \ No newline at end of file