Add queue buffers & simulation support to web proxy
This makes a couple of major changes:
-Directly uses EPoll class for managing Seasocks events.
-Adds buffers of queues to web proxy Subscribers so that we can
transfering data losslessly in log replay.
-Modifies the flatbuffer used for the RTC communications so that
the webpage can specify whether it wants every message or subsampled
messages.
-Adds an option to LogReader to let us run past the end of the logfile.
Note that these changes do mean that, for log replay, the web proxy will
load the *entire* logfile into memory. Future changes can optimize this
to, e.g., only load the required channels into memory.
Change-Id: I74e7608c30baa8b36e05c4ab50e12a54bf75aa4c
diff --git a/aos/network/www/BUILD b/aos/network/www/BUILD
index 8142e24..03e269d 100644
--- a/aos/network/www/BUILD
+++ b/aos/network/www/BUILD
@@ -112,6 +112,7 @@
":reflection_ts",
"//aos:configuration_ts_fbs",
"//aos/network:connect_ts_fbs",
+ "//aos/network:web_proxy_ts_fbs",
"@com_github_google_flatbuffers//ts:flatbuffers_ts",
],
)
@@ -163,3 +164,14 @@
],
target_compatible_with = ["@platforms//os:linux"],
)
+
+filegroup(
+ name = "plotting_sample",
+ srcs = [
+ "graph.html",
+ "graph_main_bundle.min.js",
+ "styles.css",
+ "test_config",
+ ],
+ visibility = ["//visibility:public"],
+)
diff --git a/aos/network/www/config_handler.ts b/aos/network/www/config_handler.ts
index a65d2fa..81f61b4 100644
--- a/aos/network/www/config_handler.ts
+++ b/aos/network/www/config_handler.ts
@@ -1,12 +1,14 @@
import * as configuration from 'org_frc971/aos/configuration_generated';
-import * as connect from 'org_frc971/aos/network/connect_generated';
+import {Connection} from 'org_frc971/aos/network/www/proxy';
import * as flatbuffers_builder from 'org_frc971/external/com_github_google_flatbuffers/ts/builder';
+import * as web_proxy from 'org_frc971/aos/network/web_proxy_generated';
-import {Connection} from './proxy';
import Configuration = configuration.aos.Configuration;
import Channel = configuration.aos.Channel;
-import Connect = connect.aos.message_bridge.Connect;
+import SubscriberRequest = web_proxy.aos.web_proxy.SubscriberRequest;
+import ChannelRequest = web_proxy.aos.web_proxy.ChannelRequest;
+import TransferMethod = web_proxy.aos.web_proxy.TransferMethod;
export class ConfigHandler {
private readonly root_div = document.createElement('div');
@@ -76,15 +78,18 @@
Channel.addName(builder, namefb);
Channel.addType(builder, typefb);
const channelfb = Channel.endChannel(builder);
- channels.push(channelfb);
+ ChannelRequest.startChannelRequest(builder);
+ ChannelRequest.addChannel(builder, channelfb);
+ ChannelRequest.addMethod(builder, TransferMethod.SUBSAMPLE);
+ channels.push(ChannelRequest.endChannelRequest(builder));
}
const channelsfb =
- Connect.createChannelsToTransferVector(builder, channels);
- Connect.startConnect(builder);
- Connect.addChannelsToTransfer(builder, channelsfb);
- const connect = Connect.endConnect(builder);
- builder.finish(connect);
+ SubscriberRequest.createChannelsToTransferVector(builder, channels);
+ SubscriberRequest.startSubscriberRequest(builder);
+ SubscriberRequest.addChannelsToTransfer(builder, channelsfb);
+ const request = SubscriberRequest.endSubscriberRequest(builder);
+ builder.finish(request);
this.connection.sendConnectMessage(builder);
}
diff --git a/aos/network/www/graph_main.ts b/aos/network/www/graph_main.ts
index b2286d1..9135cf4 100644
--- a/aos/network/www/graph_main.ts
+++ b/aos/network/www/graph_main.ts
@@ -9,9 +9,9 @@
// it is already being published by the web proxy process, so the demo requires
// very little setup).
import * as configuration from 'org_frc971/aos/configuration_generated';
-import * as connect from 'org_frc971/aos/network/connect_generated';
import {Line, Plot} from 'org_frc971/aos/network/www/plotter';
import * as proxy from 'org_frc971/aos/network/www/proxy';
+import * as web_proxy from 'org_frc971/aos/network/web_proxy_generated';
import * as reflection from 'org_frc971/aos/network/www/reflection'
import * as flatbuffers_builder from 'org_frc971/external/com_github_google_flatbuffers/ts/builder';
import {ByteBuffer} from 'org_frc971/external/com_github_google_flatbuffers/ts/byte-buffer';
@@ -21,7 +21,9 @@
import Configuration = configuration.aos.Configuration;
import Parser = reflection.Parser;
import Table = reflection.Table;
-import Connect = connect.aos.message_bridge.Connect;
+import SubscriberRequest = web_proxy.aos.web_proxy.SubscriberRequest;
+import ChannelRequest = web_proxy.aos.web_proxy.ChannelRequest;
+import TransferMethod = web_proxy.aos.web_proxy.TransferMethod;
const width = 900;
const height = 400;
@@ -88,6 +90,7 @@
this.averagePoints.push(parser.readScalar(statsTable, "average") * 1000);
+ // TODO: These memory allocations absolutely kill performance.
this.max.setPoints(new Float32Array(this.maxPoints));
this.min.setPoints(new Float32Array(this.minPoints));
this.average.setPoints(new Float32Array(this.averagePoints));
@@ -143,13 +146,16 @@
Channel.addName(builder, nameFb);
Channel.addType(builder, typeFb);
const channelFb = Channel.endChannel(builder);
- channels.push(channelFb);
+ ChannelRequest.startChannelRequest(builder);
+ ChannelRequest.addChannel(builder, channelFb);
+ ChannelRequest.addMethod(builder, TransferMethod.EVERYTHING_WITH_HISTORY);
+ channels.push(ChannelRequest.endChannelRequest(builder));
}
- const channelsFb = Connect.createChannelsToTransferVector(builder, channels);
- Connect.startConnect(builder);
- Connect.addChannelsToTransfer(builder, channelsFb);
- const connect = Connect.endConnect(builder);
+ const channelsFb = SubscriberRequest.createChannelsToTransferVector(builder, channels);
+ SubscriberRequest.startSubscriberRequest(builder);
+ SubscriberRequest.addChannelsToTransfer(builder, channelsFb);
+ const connect = SubscriberRequest.endSubscriberRequest(builder);
builder.finish(connect);
conn.sendConnectMessage(builder);
});
diff --git a/aos/network/www/log_web_proxy_demo.sh b/aos/network/www/log_web_proxy_demo.sh
new file mode 100755
index 0000000..e4e97bb
--- /dev/null
+++ b/aos/network/www/log_web_proxy_demo.sh
@@ -0,0 +1 @@
+./aos/network/log_web_proxy_main --config=aos/network/www/test_config.json --data_dir=aos/network/www $@
diff --git a/aos/network/www/plotter.ts b/aos/network/www/plotter.ts
index c10ff80..d33953c 100644
--- a/aos/network/www/plotter.ts
+++ b/aos/network/www/plotter.ts
@@ -35,8 +35,8 @@
private _drawLine: boolean = true;
private _pointSize: number = 3.0;
private _hasUpdate: boolean = false;
- private _minValues: number[] = [0.0, 0.0];
- private _maxValues: number[] = [0.0, 0.0];
+ private _minValues: number[] = [Infinity, Infinity];
+ private _maxValues: number[] = [-Infinity, -Infinity];
private _color: number[] = [1.0, 0.0, 0.0];
private pointAttribLocation: number;
private colorLocation: WebGLUniformLocation | null;
@@ -121,6 +121,10 @@
const x = this.points[ii];
const y = this.points[ii + 1];
+ if (isNaN(x) || isNaN(y)) {
+ continue;
+ }
+
this._minValues = cwiseOp(this._minValues, [x, y], Math.min);
this._maxValues = cwiseOp(this._maxValues, [x, y], Math.max);
}
@@ -497,6 +501,9 @@
for (let line of this.lines) {
minValues = cwiseOp(minValues, line.minValues(), Math.min);
}
+ if (!isFinite(minValues[0]) || !isFinite(minValues[1])) {
+ return [0, 0];
+ }
return minValues;
}
@@ -505,6 +512,9 @@
for (let line of this.lines) {
maxValues = cwiseOp(maxValues, line.maxValues(), Math.max);
}
+ if (!isFinite(maxValues[0]) || !isFinite(maxValues[1])) {
+ return [0, 0];
+ }
return maxValues;
}
@@ -729,10 +739,12 @@
private lastMousePosition: number[] = [0.0, 0.0];
private autoFollow: boolean = true;
private linkedXAxes: Plot[] = [];
+ private lastTimeMs: number = 0;
constructor(wrapperDiv: HTMLDivElement, width: number, height: number) {
wrapperDiv.appendChild(this.canvas);
wrapperDiv.appendChild(this.textCanvas);
+ this.lastTimeMs = (new Date()).getTime();
this.canvas.width =
width - this.axisLabelBuffer.left - this.axisLabelBuffer.right;
@@ -838,6 +850,9 @@
}
setZoom(scale: number[], offset: number[]) {
+ if (!isFinite(scale[0]) || !isFinite(scale[1])) {
+ throw new Error("Doesn't support non-finite scales due to singularities.");
+ }
const x_pressed = Plot.keysPressed["x"];
const y_pressed = Plot.keysPressed["y"];
const zoom = this.drawer.getZoom();
@@ -875,7 +890,17 @@
}
resetZoom() {
- this.setZoomCorners(this.drawer.minValues(), this.drawer.maxValues());
+ const minValues = this.drawer.minValues();
+ const maxValues = this.drawer.maxValues();
+ if (minValues[0] == maxValues[0]) {
+ minValues[0] -= 1;
+ maxValues[0] += 1;
+ }
+ if (minValues[1] == maxValues[1]) {
+ minValues[1] -= 1;
+ maxValues[1] += 1;
+ }
+ this.setZoomCorners(minValues, maxValues);
this.autoFollow = true;
for (let plot of this.linkedXAxes) {
plot.autoFollow = true;
@@ -892,6 +917,9 @@
draw() {
window.requestAnimationFrame(() => this.draw());
+ const curTime = (new Date()).getTime();
+ const frameRate = 1000.0 / (curTime - this.lastTimeMs);
+ this.lastTimeMs = curTime;
// Clear the overlay.
const textCtx = this.textCanvas.getContext("2d");
diff --git a/aos/network/www/proxy.ts b/aos/network/www/proxy.ts
index 4952a11..5660cef 100644
--- a/aos/network/www/proxy.ts
+++ b/aos/network/www/proxy.ts
@@ -1,4 +1,3 @@
-import {ConfigHandler} from './config_handler';
import * as configuration from 'org_frc971/aos/configuration_generated';
import * as web_proxy from 'org_frc971/aos/network/web_proxy_generated';
import {Builder} from 'org_frc971/external/com_github_google_flatbuffers/ts/builder';