Provide utilities for convenient plotting of channels

Implement a set of utilities (along with basic examples) to
make it so that we can readily make plots of individual channels
from logfiles (or live on the robot).

Change-Id: Ic648c9ccb9dcb73419dc2c8c4c395fdea0536110
diff --git a/aos/network/www/proxy.ts b/aos/network/www/proxy.ts
index 4fbba85..948f8db 100644
--- a/aos/network/www/proxy.ts
+++ b/aos/network/www/proxy.ts
@@ -5,6 +5,7 @@
 
 import ChannelFb = configuration.aos.Channel;
 import Configuration = configuration.aos.Configuration;
+import Schema = configuration.reflection.Schema;
 import MessageHeader = web_proxy.aos.web_proxy.MessageHeader;
 import WebSocketIce = web_proxy.aos.web_proxy.WebSocketIce;
 import WebSocketMessage = web_proxy.aos.web_proxy.WebSocketMessage;
@@ -83,7 +84,7 @@
   private readonly configHandlers = new Set<(config: Configuration) => void>();
 
   private readonly handlerFuncs =
-      new Map<string, (data: Uint8Array, sentTime: number) => void>();
+      new Map<string, ((data: Uint8Array, sentTime: number) => void)[]>();
   private readonly handlers = new Set<Handler>();
 
   private subscribedChannels: ChannelRequest[] = [];
@@ -122,10 +123,27 @@
       handler: (data: Uint8Array, sentTime: number) => void): void {
     const channel = new Channel(name, type);
     const request = new ChannelRequest(channel, method);
-    this.handlerFuncs.set(channel.key(), handler);
+    if (!this.handlerFuncs.has(channel.key())) {
+      this.handlerFuncs.set(channel.key(), []);
+    }
+    this.handlerFuncs.get(channel.key()).push(handler);
     this.subscribeToChannel(request);
   }
 
+  getSchema(typeName: string): Schema {
+    let schema = null;
+    const config = this.getConfig();
+    for (let ii = 0; ii < config.channelsLength(); ++ii) {
+      if (config.channels(ii).type() === typeName) {
+        schema = config.channels(ii).schema();
+      }
+    }
+    if (schema === null) {
+      throw new Error('Unable to find schema for ' + typeName);
+    }
+    return schema;
+  }
+
   subscribeToChannel(channel: ChannelRequest): void {
     this.subscribedChannels.push(channel);
     if (this.configInternal === null) {
@@ -183,8 +201,10 @@
   onDataChannel(ev: RTCDataChannelEvent): void {
     const channel = ev.channel;
     const name = channel.label;
-    const handlerFunc = this.handlerFuncs.get(name);
-    this.handlers.add(new Handler(handlerFunc, channel));
+    const handlers = this.handlerFuncs.get(name);
+    for (const handler of handlers) {
+      this.handlers.add(new Handler(handler, channel));
+    }
   }
 
   onIceCandidate(e: RTCPeerConnectionIceEvent): void {