From ae9787748ccda1ee5d665a9828e1aefb741f6efe Mon Sep 17 00:00:00 2001
From: Sami Spets <savasp@utu.fi>
Date: Wed, 30 Oct 2019 09:41:29 +0200
Subject: [PATCH] refactoring

---
 components/net/js/src/peer.js                 | 479 ++++++++----------
 web-service/server/npm-debug.log              |  45 ++
 web-service/server/public/js/lib/Peer.js      | 243 ---------
 web-service/server/src/index.js               |   2 +-
 web-service/server/src/peer.js                |  12 +-
 .../server/{ => src}/public/css/index.css     |   0
 .../server/{ => src}/public/index.html        |   5 +-
 .../js/lib => src/public/js}/bundle.js        | 375 ++++++++++----
 .../server/{ => src}/public/js/index.js       |  72 +--
 .../{ => src}/public/js/lib/libde265.min.js   |   0
 .../{ => src}/public/js/lib/msgpack5.min.js   |   0
 11 files changed, 585 insertions(+), 648 deletions(-)
 create mode 100644 web-service/server/npm-debug.log
 delete mode 100644 web-service/server/public/js/lib/Peer.js
 rename web-service/server/{ => src}/public/css/index.css (100%)
 rename web-service/server/{ => src}/public/index.html (72%)
 rename web-service/server/{public/js/lib => src/public/js}/bundle.js (96%)
 rename web-service/server/{ => src}/public/js/index.js (79%)
 rename web-service/server/{ => src}/public/js/lib/libde265.min.js (100%)
 rename web-service/server/{ => src}/public/js/lib/msgpack5.min.js (100%)

diff --git a/components/net/js/src/peer.js b/components/net/js/src/peer.js
index d330f93c3..75ffcff1d 100644
--- a/components/net/js/src/peer.js
+++ b/components/net/js/src/peer.js
@@ -1,280 +1,243 @@
-const net = require('net');
-const ws = require('ws');
-const urijs = require('uri-js');
-const binary = require('bops');
-const browser = require('detect-browser').detect();
-const isbrowser = !browser || browser.name != "node";
+const msgpack = require('msgpack5')()
+  , encode  = msgpack.encode
+  , decode  = msgpack.decode;
 
-class Peer {
-	constructor(uri) {
-		let t = typeof uri;
-		this.handlers_ = {
-			'open': [],
-			'data': [],
-			'error': [],
-			'close': []
-		};
-		this.handshake_ = false;
-		this.lasterr_ = null;
-		this.connected_ = false;
-		this.valid_ = false;
-		this.uuid_ = binary.create(16);
-		if (!isbrowser) {
-			this.buffer_ = new Buffer(0); // Only in nodejs
-		}
-		if (t == "string") {
-			this._fromURI(uri);
-		}
-		else if (t == "object") {
-			this._fromObject(uri);
-		}
-	}
-	error(errno) {
-		this.lasterr_ = errno;
-		this.dispatch('error', [errno]);
-	}
-	isValid() {
-		return this.valid_;
-	}
-    /**
-     * Construct the correct kind of socket connection from a URI.
-     */
-	_fromURI(uri) {
-		let uriobj = urijs.parse(uri);
-		this.uri_ = uri;
-		this.scheme_ = uriobj.scheme;
-		// Could not parse uri so report error
-		if (uriobj.scheme === undefined || uriobj.host === undefined) {
-			this.error(Socket.ERROR_MALFORMEDURI);
-			return;
-		}
-		// Websocket protocol
-		if (this.scheme_ == "ws") {
-			// Detect if in browser or not, choose correct websocket object
-			if (typeof WebSocket == "undefined") {
-				// Nodejs
-				this.socket_ = new ws(uri);
-			}
-			else {
-				// Browser
-				this.socket_ = new WebSocket(uri);
-			}
-			this._initWebsocket();
-			// TCP
-		}
-		else if (this.scheme_ == "tcp") {
-			if (!isbrowser) {
-				this.socket_ = net.connect(uriobj.port, uriobj.host);
-				this._initTCPSocket();
-			}
-			else {
-				this.error(Socket.ERROR_TCPINBROWSER);
-			}
-			// Unrecognised protocol
-		}
-		else {
-			this.error(Socket.ERROR_BADPROTOCOL);
-		}
-	}
-	_fromObject(sock) {
-		this.socket_ = sock;
-		if (typeof WebSocket == "undefined") {
-			if (sock instanceof ws)
-				this.scheme_ = "ws";
-			else if (sock instanceof net.Socket)
-				this.scheme_ = "tcp";
-			else
-				this.scheme_ = null;
-		}
-		else {
-			if (sock instanceof WebSocket)
-				this.scheme_ = "ws";
-			else
-				this.scheme_ = null;
-		}
-		if (this.scheme_ == "ws")
-			this._initWebsocket();
-		else if (this.scheme_ == "tcp")
-			this._initTCPSocket();
-	}
-    /**
-     * Setup correct handlers for a websocket connection.
-     */
-	_initWebsocket() {
-		this.valid_ = true;
-		let dataHandler = (data) => {
-			this.processMessage(data);
-		};
-		if (this.socket_.addEventHandler) {
-			this.socket_.addEventHandler('message', event => {
-				dataHandler(event.data);
-			});
-		}
-		else {
-			this.socket_.on('message', dataHandler);
-		}
-		this.socket_.on('open', () => {
-			//this.connected_ = true;
-			//this.dispatch('open', []);
-		});
-		this.socket_.on('error', (err) => {
-			this.connected_ = false;
-			this.valid_ = false;
-			switch (err.errno) {
-				case 'ENOTFOUND':
-					this.lasterr_ = Socket.ERROR_BADHOST;
-					break;
-				default: this.lasterr_ = err.errno;
-			}
-			this.dispatch('error', [this.lasterr_]);
-		});
-		this.socket_.on('close', () => {
-			this.dispatch('close', []);
-		});
-	}
-	processMessage(buffer) {
-		if (!this.handshake_) {
-			// Check handshake
-			if (!checkMagic(buffer)) {
+const kConnecting = 1;
+const kConnected = 2;
+const kDisconnected = 3;
+
+// Generate a unique id for this webservice
+let my_uuid = new Uint8Array(16);
+my_uuid[0] = 44;
+my_uuid = Buffer.from(my_uuid);
+
+const kMagic = 0x0009340053640912;
+const kVersion = 0;
+
+/**
+ * Wrap a web socket with a MsgPack RCP protocol that works with our C++ version.
+ * @param {websocket} ws Websocket object
+ */
+function Peer(ws) {
+	this.sock = ws;
+	this.status = kConnecting;
+	this.id = null;
+	this.string_id = "";
+	this.bindings = {};
+	this.proxies = {};
+	this.events = {};
+	this.callbacks = {};
+	this.cbid = 0;
+
+	this.uri = "unknown";
+	this.name = "unknown";
+	this.master = false;
+
+	this.sock.on("message", (raw) => {
+		// console.log(raw)
+		let msg = decode(raw);
+		console.log("MSG", msg)
+		if (this.status == kConnecting) {
+			if (msg[1] != "__handshake__") {
+				console.log("Bad handshake");
 				this.close();
-				this.error(Socket.ERROR_BADHANDSHAKE);
-				return 0;
 			}
-			binary.copy(buffer, this.uuid_, 0, 8, 16);
-			let proto_size = binary.readUInt32LE(buffer, 24);
-			this.handshake_ = true;
-			this.connected_ = true;
-			this.dispatch('open', []);
-			return 28 + proto_size;
 		}
-		else {
-			let size = binary.readUInt32LE(buffer, 0);
-			let service = binary.readUInt32LE(buffer, 4);
-			console.log("Message: " + service + "(size=" + size + ")");
-			// Do we have a complete message yet?
-			if (size > 1024 * 1024 * 100) {
-				this.error(Socket.ERROR_LARGEMESSAGE);
-				this.close();
-				return 0;
-			}
-			else if (buffer.length - 4 >= size) {
-				// Yes, so dispatch
-				this.dispatch(service, [size, binary.subarray(buffer, 8)]);
-				return size + 4;
-			}
-			else {
-				return 0;
+		//console.log("MSG", msg);
+		if (msg[0] == 0) {
+			// Notification
+			if (msg.length == 3) {
+				this._dispatchNotification(msg[1], msg[2]);
+			// Call
+			} else {
+				this._dispatchCall(msg[2], msg[1], msg[3]);
 			}
+		} else if (msg[0] == 1) {
+			this._dispatchResponse(msg[1], msg[3]);
 		}
+	});
+
+	this.sock.on("close", () => {
+		this.status = kDisconnected;
+		this._notify("disconnect", this);
+	});
+
+	this.sock.on("error", () => {
+		console.error("Socket error");
+		this.sock.close();
+		this.status = kDisconnected;
+	});
+
+	this.bind("__handshake__", (magic, version, id) => {
+		if (magic == kMagic) {
+			console.log("Handshake received");
+			this.status = kConnected;
+			this.id = id.buffer;
+			this.string_id  = id.toString('hex');
+			this._notify("connect", this);
+		} else {
+			console.log("Magic does not match");
+			this.close();
+		}
+	});
+
+	this.send("__handshake__", kMagic, kVersion, [my_uuid]);
+}
+
+Peer.uuid = my_uuid;
+
+/**
+ * @private
+ */
+Peer.prototype._dispatchNotification = function(name, args) {
+	if (this.bindings.hasOwnProperty(name)) {
+		//console.log("Notification for: ", name);
+		this.bindings[name].apply(this, args);
+	} else {
+		console.log("Missing handler for: ", name);
 	}
-    /**
-     * Setup TCP socket handlers and message buffering mechanism.
-     */
-	_initTCPSocket() {
-		this.valid_ = true;
-		let dataHandler = (data) => {
-			this.buffer_ = Buffer.concat([this.buffer_, data]);
-			while (this.buffer_.length >= 8) {
-				let s = this.processMessage(this.buffer_);
-				if (s == 0)
-					break;
-				this.buffer_ = binary.subarray(this.buffer_, s);
-			}
-		};
-		this.socket_.on('data', dataHandler);
-		this.socket_.on('connect', () => {
-			//this.connected_ = true;
-			//this.dispatch('open', []);
-		});
-		this.socket_.on('error', (err) => {
-			this.connected_ = false;
-			this.valid_ = false;
-			switch (err.errno) {
-				case 'ENOTFOUND':
-					this.error(Socket.ERROR_BADHOST);
-					break;
-				default: this.error(err.errno);
+}
+
+/**
+ * @private
+ */
+Peer.prototype._dispatchCall = function(name, id, args) {
+	if (this.bindings.hasOwnProperty(name)) {
+		//console.log("Call for:", name, id);
+
+		try {
+			let res = this.bindings[name].apply(this, args);
+			this.sock.send(encode([1,id,name,res]));
+		} catch(e) {
+			console.error("Could to dispatch or return call");
+			this.close();
+		}
+	} else if (this.proxies.hasOwnProperty(name)) {
+		//console.log("Proxy for:", name, id);
+		args.unshift((res) => {
+			try {
+				this.sock.send(encode([1,id,name,res]));
+			} catch(e) {
+				this.close();
 			}
 		});
-		this.socket_.on('close', () => {
-			this.dispatch('close', []);
-		});
-	}
-	isConnected() {
-		return this.connected_;
-	}
-    /**
-     * Register event handlers.
-     */
-	on(name, f) {
-		if (typeof name == "string") {
-			if (this.handlers_.hasOwnProperty(name)) {
-				this.handlers_[name].push(f);
-			}
-			else {
-				console.error("Unrecognised handler: ", name);
-			}
-			if (name == "error" && this.lasterr_ != null) {
-				f(this.lasterr_);
-			}
-		}
-		else if (typeof name == "number") {
-			if (this.handlers_[name] === undefined)
-				this.handlers_[name] = [];
-			this.handlers_[name].push(f);
-		}
-		else {
-			console.error("Invalid handler: ", name);
-		}
+		this.proxies[name].apply(this, args);
+	} else {
+		console.log("Missing handler for: ", name);
 	}
-	dispatch(h, args) {
-		if (this.handlers_.hasOwnProperty(h)) {
-			let hs = this.handlers_[h];
-			for (var i = 0; i < hs.length; i++) {
-				hs[i].apply(this, args);
-			}
-			return true;
-		}
-		else {
-			return false;
-		}
+}
+
+/**
+ * @private
+ */
+Peer.prototype._dispatchResponse = function(id, res) {
+	if (this.callbacks.hasOwnProperty(id)) {
+		this.callbacks[id].call(this, res);
+		delete this.callbacks[id];
+	} else {
+		console.log("Missing callback");
 	}
-	close() {
-		if (this.socket_ == null)
-			return;
-		if (this.scheme_ == "ws") {
-			this.socket_.close();
-		}
-		else {
-			this.socket_.destroy();
-		}
-		this.socket_ = null;
+}
+
+/**
+ * Register an RPC handler that will be called from a remote machine. Remotely
+ * passed arguments are provided to the given function as normal arguments, and
+ * if the function returns a value, it will be returned over the network also.
+ * 
+ * @param {string} name The name of the function
+ * @param {function} f A function or lambda to be callable remotely
+ */
+Peer.prototype.bind = function(name, f) {
+	if (this.bindings.hasOwnProperty(name)) {
+		//console.error("Duplicate bind to same procedure");
+		this.bindings[name] = f;
+	} else {
+		this.bindings[name] = f;
 	}
-	_socket() {
-		return this.socket_;
+}
+
+/**
+ * Allow an RPC call to pass through to another machine with minimal local
+ * processing.
+ */
+Peer.prototype.proxy = function(name, f) {
+	if (this.proxies.hasOwnProperty(name)) {
+		//console.error("Duplicate proxy to same procedure");
+		this.proxies[name] = f;
+	} else {
+		this.proxies[name] = f;
 	}
-	getURI() {
-		return this.uri_;
+}
+
+/**
+ * Call a procedure on a remote machine.
+ * 
+ * @param {string} name Name of the procedure
+ * @param {function} cb Callback to receive return value as argument
+ * @param {...} args Any number of arguments to also pass to remote procedure
+ */
+Peer.prototype.rpc = function(name, cb, ...args) {
+	let id = this.cbid++;
+	this.callbacks[id] = cb;
+
+	try {
+		this.sock.send(encode([0, id, name, args]));
+	} catch(e) {
+		this.close();
 	}
-	asyncCall(name, cb /*, ...*/) {
+}
+
+Peer.prototype.sendB = function(name, args) {
+	try {
+		this.sock.send(encode([0, name, args]));
+	} catch(e) {
+		this.close();
 	}
-	send(id /*, ...*/) {
-		//this.socket_.write(
+}
+
+/**
+ * Call a remote procedure but with no return value expected.
+ * 
+ * @param {string} name Name of the procedure
+ * @param {...} args Any number of arguments to also pass to remote procedure
+ */
+Peer.prototype.send = function(name, ...args) {
+	try {
+		this.sock.send(encode([0, name, args]));
+	} catch(e) {
+		this.close();
 	}
 }
 
-Peer.ERROR_BADPROTOCOL = "Bad Protocol";
-Peer.ERROR_BADHOST = "Unknown host";
-Peer.ERROR_BADHANDSHAKE = "Invalid Handshake";
-Peer.ERROR_MALFORMEDURI = "Malformed URI";
-Peer.ERROR_TCPINBROWSER = "TCP invalid in browser";
-Peer.ERROR_LARGEMESSAGE = "Network message too large";
+Peer.prototype.close = function() {
+	this.sock.close();
+	this.status = kDisconnected;
+}
+
+/**
+ * @private
+ */
+Peer.prototype._notify = function(evt, ...args) {
+	if (this.events.hasOwnProperty(evt)) {
+		for (let i=0; i<this.events[evt].length; i++) {
+			let f = this.events[evt][i];
+			f.apply(this, args);
+		}
+	}
+}
 
-function checkMagic(buffer) {
-	if (buffer.length < 8) return false;
-	let lo_magic = binary.readUInt32LE(buffer,0);
-	let hi_magic = binary.readUInt32LE(buffer,4);
-	return (lo_magic == 0x53640912 && hi_magic == 0x10993400)
+/**
+ * Register a callback for socket events. Events include: 'connect',
+ * 'disconnect' and 'error'.
+ * 
+ * @param {string} evt Event name
+ * @param {function} f Callback on event
+ */
+Peer.prototype.on = function(evt, f) {
+	if (!this.events.hasOwnProperty(evt)) {
+		this.events[evt] = [];
+	}
+	this.events[evt].push(f);
 }
 
 module.exports = Peer;
diff --git a/web-service/server/npm-debug.log b/web-service/server/npm-debug.log
new file mode 100644
index 000000000..7381f664f
--- /dev/null
+++ b/web-service/server/npm-debug.log
@@ -0,0 +1,45 @@
+0 info it worked if it ends with ok
+1 verbose cli [ '/usr/bin/node', '/usr/bin/npm', 'start' ]
+2 info using npm@3.5.2
+3 info using node@v8.10.0
+4 verbose run-script [ 'prestart', 'start', 'poststart' ]
+5 info lifecycle @ftl/web-service@0.0.1~prestart: @ftl/web-service@0.0.1
+6 silly lifecycle @ftl/web-service@0.0.1~prestart: no script for prestart, continuing
+7 info lifecycle @ftl/web-service@0.0.1~start: @ftl/web-service@0.0.1
+8 verbose lifecycle @ftl/web-service@0.0.1~start: unsafe-perm in lifecycle true
+9 verbose lifecycle @ftl/web-service@0.0.1~start: PATH: /usr/share/npm/bin/node-gyp-bin:/home/sami/work/ftl/web-service/server/node_modules/.bin:/usr/local/cuda/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
+10 verbose lifecycle @ftl/web-service@0.0.1~start: CWD: /home/sami/work/ftl/web-service/server
+11 silly lifecycle @ftl/web-service@0.0.1~start: Args: [ '-c', 'node src/index.js' ]
+12 silly lifecycle @ftl/web-service@0.0.1~start: Returned: code: 1  signal: null
+13 info lifecycle @ftl/web-service@0.0.1~start: Failed to exec start script
+14 verbose stack Error: @ftl/web-service@0.0.1 start: `node src/index.js`
+14 verbose stack Exit status 1
+14 verbose stack     at EventEmitter.<anonymous> (/usr/share/npm/lib/utils/lifecycle.js:232:16)
+14 verbose stack     at emitTwo (events.js:126:13)
+14 verbose stack     at EventEmitter.emit (events.js:214:7)
+14 verbose stack     at ChildProcess.<anonymous> (/usr/share/npm/lib/utils/spawn.js:24:14)
+14 verbose stack     at emitTwo (events.js:126:13)
+14 verbose stack     at ChildProcess.emit (events.js:214:7)
+14 verbose stack     at maybeClose (internal/child_process.js:925:16)
+14 verbose stack     at Process.ChildProcess._handle.onexit (internal/child_process.js:209:5)
+15 verbose pkgid @ftl/web-service@0.0.1
+16 verbose cwd /home/sami/work/ftl/web-service/server
+17 error Linux 4.15.0-66-generic
+18 error argv "/usr/bin/node" "/usr/bin/npm" "start"
+19 error node v8.10.0
+20 error npm  v3.5.2
+21 error code ELIFECYCLE
+22 error @ftl/web-service@0.0.1 start: `node src/index.js`
+22 error Exit status 1
+23 error Failed at the @ftl/web-service@0.0.1 start script 'node src/index.js'.
+23 error Make sure you have the latest version of node.js and npm installed.
+23 error If you do, this is most likely a problem with the @ftl/web-service package,
+23 error not with npm itself.
+23 error Tell the author that this fails on your system:
+23 error     node src/index.js
+23 error You can get information on how to open an issue for this project with:
+23 error     npm bugs @ftl/web-service
+23 error Or if that isn't available, you can get their info via:
+23 error     npm owner ls @ftl/web-service
+23 error There is likely additional logging output above.
+24 verbose exit [ 1, true ]
diff --git a/web-service/server/public/js/lib/Peer.js b/web-service/server/public/js/lib/Peer.js
deleted file mode 100644
index ff14903ac..000000000
--- a/web-service/server/public/js/lib/Peer.js
+++ /dev/null
@@ -1,243 +0,0 @@
-const msgpack = msgpack5()
-  , encode  = msgpack.encode
-  , decode  = msgpack.decode;
-
-const kConnecting = 1;
-const kConnected = 2;
-const kDisconnected = 3;
-
-// Generate a unique id for this webservice
-// let my_uuid = new Uint8Array(16);
-// my_uuid[0] = 44;
-// my_uuid = Buffer.from(my_uuid);
-
-const kMagic = 0x0009340053640912;
-const kVersion = 0;
-
-/**
- * Wrap a web socket with a MsgPack RCP protocol.
- * @param {websocket} ws Websocket object
- */
-function Peer(ws) {
-	this.sock = ws;
-	this.status = kConnecting;
-	this.id = null;
-	this.string_id = "";
-	this.bindings = {};
-	this.proxies = {};
-	this.events = {};
-	this.callbacks = {};
-	this.cbid = 0;
-
-	this.uri = "unknown";
-	this.name = "unknown";
-	this.master = false;
-
-	console.log(this.sock.send("message"));
-	
-	this.sock.send("message", (raw) => {
-		// console.log(raw)
-		let msg = decode(raw);
-		console.log("MSG", msg)
-		if (this.status == kConnecting) {
-			if (msg[1] != "__handshake__") {
-				console.log("Bad handshake");
-				this.close();
-			}
-		}
-		//console.log("MSG", msg);
-		if (msg[0] == 0) {
-			// Notification
-			if (msg.length == 3) {
-				this._dispatchNotification(msg[1], msg[2]);
-			// Call
-			} else {
-				this._dispatchCall(msg[2], msg[1], msg[3]);
-			}
-		} else if (msg[0] == 1) {
-			this._dispatchResponse(msg[1], msg[3]);
-		}
-	});
-
-	this.sock.on("close", () => {
-		this.status = kDisconnected;
-		this._notify("disconnect", this);
-	});
-
-	this.sock.on("error", () => {
-		console.error("Socket error");
-		this.sock.close();
-		this.status = kDisconnected;
-	});
-
-	this.bind("__handshake__", (magic, version, id) => {
-		if (magic == kMagic) {
-			console.log("Handshake received");
-			this.status = kConnected;
-			this.id = id.buffer;
-			this.string_id  = id.toString('hex');
-			this._notify("connect", this);
-		} else {
-			console.log("Magic does not match");
-			this.close();
-		}
-	});
-
-	this.send("__handshake__", kMagic, kVersion, /*[my_uuid]*/);
-}
-
-// Peer.uuid = my_uuid;
-
-/**
- * @private
- */
-Peer.prototype._dispatchNotification = function(name, args) {
-	if (this.bindings.hasOwnProperty(name)) {
-		//console.log("Notification for: ", name);
-		this.bindings[name].apply(this, args);
-	} else {
-		console.log("Missing handler for: ", name);
-	}
-}
-
-/**
- * @private
- */
-Peer.prototype._dispatchCall = function(name, id, args) {
-	if (this.bindings.hasOwnProperty(name)) {
-		//console.log("Call for:", name, id);
-
-		try {
-			let res = this.bindings[name].apply(this, args);
-			this.sock.send(encode([1,id,name,res]));
-		} catch(e) {
-			console.error("Could to dispatch or return call");
-			this.close();
-		}
-	} else if (this.proxies.hasOwnProperty(name)) {
-		//console.log("Proxy for:", name, id);
-		args.unshift((res) => {
-			try {
-				this.sock.send(encode([1,id,name,res]));
-			} catch(e) {
-				this.close();
-			}
-		});
-		this.proxies[name].apply(this, args);
-	} else {
-		console.log("Missing handler for: ", name);
-	}
-}
-
-/**
- * @private
- */
-Peer.prototype._dispatchResponse = function(id, res) {
-	if (this.callbacks.hasOwnProperty(id)) {
-		this.callbacks[id].call(this, res);
-		delete this.callbacks[id];
-	} else {
-		console.log("Missing callback");
-	}
-}
-
-/**
- * Register an RPC handler that will be called from a remote machine. Remotely
- * passed arguments are provided to the given function as normal arguments, and
- * if the function returns a value, it will be returned over the network also.
- * 
- * @param {string} name The name of the function
- * @param {function} f A function or lambda to be callable remotely
- */
-Peer.prototype.bind = function(name, f) {
-	if (this.bindings.hasOwnProperty(name)) {
-		//console.error("Duplicate bind to same procedure");
-		this.bindings[name] = f;
-	} else {
-		this.bindings[name] = f;
-	}
-}
-
-/**
- * Allow an RPC call to pass through to another machine with minimal local
- * processing.
- */
-Peer.prototype.proxy = function(name, f) {
-	if (this.proxies.hasOwnProperty(name)) {
-		//console.error("Duplicate proxy to same procedure");
-		this.proxies[name] = f;
-	} else {
-		this.proxies[name] = f;
-	}
-}
-
-/**
- * Call a procedure on a remote machine.
- * 
- * @param {string} name Name of the procedure
- * @param {function} cb Callback to receive return value as argument
- * @param {...} args Any number of arguments to also pass to remote procedure
- */
-Peer.prototype.rpc = function(name, cb, ...args) {
-	let id = this.cbid++;
-	this.callbacks[id] = cb;
-
-	try {
-		this.sock.send(encode([0, id, name, args]));
-	} catch(e) {
-		this.close();
-	}
-}
-
-Peer.prototype.sendB = function(name, args) {
-	try {
-		this.sock.send(encode([0, name, args]));
-	} catch(e) {
-		this.close();
-	}
-}
-
-/**
- * Call a remote procedure but with no return value expected.
- * 
- * @param {string} name Name of the procedure
- * @param {...} args Any number of arguments to also pass to remote procedure
- */
-Peer.prototype.send = function(name, ...args) {
-	try {
-		this.sock.send(encode([0, name, args]));
-	} catch(e) {
-		this.close();
-	}
-}
-
-Peer.prototype.close = function() {
-	this.sock.close();
-	this.status = kDisconnected;
-}
-
-/**
- * @private
- */
-Peer.prototype._notify = function(evt, ...args) {
-	if (this.events.hasOwnProperty(evt)) {
-		for (let i=0; i<this.events[evt].length; i++) {
-			let f = this.events[evt][i];
-			f.apply(this, args);
-		}
-	}
-}
-
-/**
- * Register a callback for socket events. Events include: 'connect',
- * 'disconnect' and 'error'.
- * 
- * @param {string} evt Event name
- * @param {function} f Callback on event
- */
-Peer.prototype.on = function(evt, f) {
-	if (!this.events.hasOwnProperty(evt)) {
-		this.events[evt] = [];
-	}
-	this.events[evt].push(f);
-}
\ No newline at end of file
diff --git a/web-service/server/src/index.js b/web-service/server/src/index.js
index f841ae1cb..33e1c8c1e 100644
--- a/web-service/server/src/index.js
+++ b/web-service/server/src/index.js
@@ -453,7 +453,7 @@ app.ws('/', (ws, req) => {
 	});
 
 	// Request from frames from a source
-	p.bind("get_stream", (uri, N, rate, pid, dest) => {
+	p.bind("get_stream", (uri, N, rate, /*pid,*/ dest) => {
 		let peer = uri_data[uri].peer;
 		console.log('PEER', peer);
 		if (peer) {
diff --git a/web-service/server/src/peer.js b/web-service/server/src/peer.js
index 75ffcff1d..cc60d113e 100644
--- a/web-service/server/src/peer.js
+++ b/web-service/server/src/peer.js
@@ -32,9 +32,17 @@ function Peer(ws) {
 	this.uri = "unknown";
 	this.name = "unknown";
 	this.master = false;
-
+	if(this.sock.on == undefined){
+		console.log(this.sock);
+		console.log("piip")
+		this.sock.onopen = (event) => {
+			const obj = [0, '__handshake__']
+			this.sock.send(encode(obj))
+			this.sock.
+		}
+	}
 	this.sock.on("message", (raw) => {
-		// console.log(raw)
+		console.log(raw)
 		let msg = decode(raw);
 		console.log("MSG", msg)
 		if (this.status == kConnecting) {
diff --git a/web-service/server/public/css/index.css b/web-service/server/src/public/css/index.css
similarity index 100%
rename from web-service/server/public/css/index.css
rename to web-service/server/src/public/css/index.css
diff --git a/web-service/server/public/index.html b/web-service/server/src/public/index.html
similarity index 72%
rename from web-service/server/public/index.html
rename to web-service/server/src/public/index.html
index 9d16873a7..08259c821 100644
--- a/web-service/server/public/index.html
+++ b/web-service/server/src/public/index.html
@@ -5,11 +5,10 @@
         <link rel="stylesheet" href="./css/index.css">
         <meta charset="utf-8"/>
     </head>
-    <body onload="checkIfLoggedIn()">
+    <body onload='checkIfLoggedIn();'>
         <div id="container" style="padding-top: 150px; text-align: center"></div>
     </body>
     <script src="./js/lib/libde265.min.js"></script>
     <script src="./js/lib/msgpack5.min.js"></script>
-    <script src="./js/lib/bundle.js"></script>
-    <script src="./js/index.js"></script>
+    <script src="./js/bundle.js"></script>
 </html>
\ No newline at end of file
diff --git a/web-service/server/public/js/lib/bundle.js b/web-service/server/src/public/js/bundle.js
similarity index 96%
rename from web-service/server/public/js/lib/bundle.js
rename to web-service/server/src/public/js/bundle.js
index bf76f475f..42c03acc1 100644
--- a/web-service/server/public/js/lib/bundle.js
+++ b/web-service/server/src/public/js/bundle.js
@@ -383,7 +383,7 @@ BufferList.prototype._match = function(offset, search) {
 
 module.exports = BufferList
 
-},{"readable-stream":18,"safe-buffer":19,"util":38}],2:[function(require,module,exports){
+},{"readable-stream":19,"safe-buffer":20,"util":39}],2:[function(require,module,exports){
 (function (Buffer){
 // Copyright Joyent, Inc. and other Node contributors.
 //
@@ -493,8 +493,8 @@ function objectToString(o) {
   return Object.prototype.toString.call(o);
 }
 
-}).call(this,{"isBuffer":require("../../../../../../../../../../../usr/lib/node_modules/browserify/node_modules/is-buffer/index.js")})
-},{"../../../../../../../../../../../usr/lib/node_modules/browserify/node_modules/is-buffer/index.js":32}],3:[function(require,module,exports){
+}).call(this,{"isBuffer":require("../../../../../../../../../usr/local/lib/node_modules/browserify/node_modules/is-buffer/index.js")})
+},{"../../../../../../../../../usr/local/lib/node_modules/browserify/node_modules/is-buffer/index.js":33}],3:[function(require,module,exports){
 if (typeof Object.create === 'function') {
   // implementation from standard node.js 'util' module
   module.exports = function inherits(ctor, superCtor) {
@@ -613,7 +613,7 @@ function msgpack (options) {
 
 module.exports = msgpack
 
-},{"./lib/decoder":6,"./lib/encoder":7,"./lib/streams":8,"assert":23,"bl":1,"safe-buffer":19}],6:[function(require,module,exports){
+},{"./lib/decoder":6,"./lib/encoder":7,"./lib/streams":8,"assert":24,"bl":1,"safe-buffer":20}],6:[function(require,module,exports){
 'use strict'
 
 var bl = require('bl')
@@ -1051,7 +1051,7 @@ module.exports = function buildDecode (decodingTypes) {
 
 module.exports.IncompleteBufferError = IncompleteBufferError
 
-},{"bl":1,"util":38}],7:[function(require,module,exports){
+},{"bl":1,"util":39}],7:[function(require,module,exports){
 'use strict'
 
 var Buffer = require('safe-buffer').Buffer
@@ -1396,7 +1396,7 @@ function encodeFloat (obj, forceFloat64) {
   return buf
 }
 
-},{"bl":1,"safe-buffer":19}],8:[function(require,module,exports){
+},{"bl":1,"safe-buffer":20}],8:[function(require,module,exports){
 'use strict'
 
 var Transform = require('readable-stream').Transform
@@ -1488,7 +1488,7 @@ Decoder.prototype._transform = function (buf, enc, done) {
 module.exports.decoder = Decoder
 module.exports.encoder = Encoder
 
-},{"bl":1,"inherits":3,"readable-stream":18}],9:[function(require,module,exports){
+},{"bl":1,"inherits":3,"readable-stream":19}],9:[function(require,module,exports){
 (function (process){
 'use strict';
 
@@ -1537,7 +1537,7 @@ function nextTick(fn, arg1, arg2, arg3) {
 
 
 }).call(this,require('_process'))
-},{"_process":34}],10:[function(require,module,exports){
+},{"_process":35}],10:[function(require,module,exports){
 // Copyright Joyent, Inc. and other Node contributors.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a
@@ -2739,7 +2739,7 @@ function indexOf(xs, x) {
   return -1;
 }
 }).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-},{"./_stream_duplex":10,"./internal/streams/BufferList":15,"./internal/streams/destroy":16,"./internal/streams/stream":17,"_process":34,"core-util-is":2,"events":30,"inherits":3,"isarray":4,"process-nextick-args":9,"safe-buffer":19,"string_decoder/":20,"util":28}],13:[function(require,module,exports){
+},{"./_stream_duplex":10,"./internal/streams/BufferList":15,"./internal/streams/destroy":16,"./internal/streams/stream":17,"_process":35,"core-util-is":2,"events":31,"inherits":3,"isarray":4,"process-nextick-args":9,"safe-buffer":20,"string_decoder/":18,"util":29}],13:[function(require,module,exports){
 // Copyright Joyent, Inc. and other Node contributors.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a
@@ -3644,7 +3644,7 @@ Writable.prototype._destroy = function (err, cb) {
   cb(err);
 };
 }).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},require("timers").setImmediate)
-},{"./_stream_duplex":10,"./internal/streams/destroy":16,"./internal/streams/stream":17,"_process":34,"core-util-is":2,"inherits":3,"process-nextick-args":9,"safe-buffer":19,"timers":35,"util-deprecate":21}],15:[function(require,module,exports){
+},{"./_stream_duplex":10,"./internal/streams/destroy":16,"./internal/streams/stream":17,"_process":35,"core-util-is":2,"inherits":3,"process-nextick-args":9,"safe-buffer":20,"timers":36,"util-deprecate":21}],15:[function(require,module,exports){
 'use strict';
 
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
@@ -3724,7 +3724,7 @@ if (util && util.inspect && util.inspect.custom) {
     return this.constructor.name + ' ' + obj;
   };
 }
-},{"safe-buffer":19,"util":28}],16:[function(require,module,exports){
+},{"safe-buffer":20,"util":29}],16:[function(require,module,exports){
 'use strict';
 
 /*<replacement>*/
@@ -3802,80 +3802,7 @@ module.exports = {
 },{"process-nextick-args":9}],17:[function(require,module,exports){
 module.exports = require('events').EventEmitter;
 
-},{"events":30}],18:[function(require,module,exports){
-exports = module.exports = require('./lib/_stream_readable.js');
-exports.Stream = exports;
-exports.Readable = exports;
-exports.Writable = require('./lib/_stream_writable.js');
-exports.Duplex = require('./lib/_stream_duplex.js');
-exports.Transform = require('./lib/_stream_transform.js');
-exports.PassThrough = require('./lib/_stream_passthrough.js');
-
-},{"./lib/_stream_duplex.js":10,"./lib/_stream_passthrough.js":11,"./lib/_stream_readable.js":12,"./lib/_stream_transform.js":13,"./lib/_stream_writable.js":14}],19:[function(require,module,exports){
-/* eslint-disable node/no-deprecated-api */
-var buffer = require('buffer')
-var Buffer = buffer.Buffer
-
-// alternative to using Object.keys for old browsers
-function copyProps (src, dst) {
-  for (var key in src) {
-    dst[key] = src[key]
-  }
-}
-if (Buffer.from && Buffer.alloc && Buffer.allocUnsafe && Buffer.allocUnsafeSlow) {
-  module.exports = buffer
-} else {
-  // Copy properties from require('buffer')
-  copyProps(buffer, exports)
-  exports.Buffer = SafeBuffer
-}
-
-function SafeBuffer (arg, encodingOrOffset, length) {
-  return Buffer(arg, encodingOrOffset, length)
-}
-
-// Copy static methods from Buffer
-copyProps(Buffer, SafeBuffer)
-
-SafeBuffer.from = function (arg, encodingOrOffset, length) {
-  if (typeof arg === 'number') {
-    throw new TypeError('Argument must not be a number')
-  }
-  return Buffer(arg, encodingOrOffset, length)
-}
-
-SafeBuffer.alloc = function (size, fill, encoding) {
-  if (typeof size !== 'number') {
-    throw new TypeError('Argument must be a number')
-  }
-  var buf = Buffer(size)
-  if (fill !== undefined) {
-    if (typeof encoding === 'string') {
-      buf.fill(fill, encoding)
-    } else {
-      buf.fill(fill)
-    }
-  } else {
-    buf.fill(0)
-  }
-  return buf
-}
-
-SafeBuffer.allocUnsafe = function (size) {
-  if (typeof size !== 'number') {
-    throw new TypeError('Argument must be a number')
-  }
-  return Buffer(size)
-}
-
-SafeBuffer.allocUnsafeSlow = function (size) {
-  if (typeof size !== 'number') {
-    throw new TypeError('Argument must be a number')
-  }
-  return buffer.SlowBuffer(size)
-}
-
-},{"buffer":29}],20:[function(require,module,exports){
+},{"events":31}],18:[function(require,module,exports){
 // Copyright Joyent, Inc. and other Node contributors.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a
@@ -4172,7 +4099,80 @@ function simpleWrite(buf) {
 function simpleEnd(buf) {
   return buf && buf.length ? this.write(buf) : '';
 }
-},{"safe-buffer":19}],21:[function(require,module,exports){
+},{"safe-buffer":20}],19:[function(require,module,exports){
+exports = module.exports = require('./lib/_stream_readable.js');
+exports.Stream = exports;
+exports.Readable = exports;
+exports.Writable = require('./lib/_stream_writable.js');
+exports.Duplex = require('./lib/_stream_duplex.js');
+exports.Transform = require('./lib/_stream_transform.js');
+exports.PassThrough = require('./lib/_stream_passthrough.js');
+
+},{"./lib/_stream_duplex.js":10,"./lib/_stream_passthrough.js":11,"./lib/_stream_readable.js":12,"./lib/_stream_transform.js":13,"./lib/_stream_writable.js":14}],20:[function(require,module,exports){
+/* eslint-disable node/no-deprecated-api */
+var buffer = require('buffer')
+var Buffer = buffer.Buffer
+
+// alternative to using Object.keys for old browsers
+function copyProps (src, dst) {
+  for (var key in src) {
+    dst[key] = src[key]
+  }
+}
+if (Buffer.from && Buffer.alloc && Buffer.allocUnsafe && Buffer.allocUnsafeSlow) {
+  module.exports = buffer
+} else {
+  // Copy properties from require('buffer')
+  copyProps(buffer, exports)
+  exports.Buffer = SafeBuffer
+}
+
+function SafeBuffer (arg, encodingOrOffset, length) {
+  return Buffer(arg, encodingOrOffset, length)
+}
+
+// Copy static methods from Buffer
+copyProps(Buffer, SafeBuffer)
+
+SafeBuffer.from = function (arg, encodingOrOffset, length) {
+  if (typeof arg === 'number') {
+    throw new TypeError('Argument must not be a number')
+  }
+  return Buffer(arg, encodingOrOffset, length)
+}
+
+SafeBuffer.alloc = function (size, fill, encoding) {
+  if (typeof size !== 'number') {
+    throw new TypeError('Argument must be a number')
+  }
+  var buf = Buffer(size)
+  if (fill !== undefined) {
+    if (typeof encoding === 'string') {
+      buf.fill(fill, encoding)
+    } else {
+      buf.fill(fill)
+    }
+  } else {
+    buf.fill(0)
+  }
+  return buf
+}
+
+SafeBuffer.allocUnsafe = function (size) {
+  if (typeof size !== 'number') {
+    throw new TypeError('Argument must be a number')
+  }
+  return Buffer(size)
+}
+
+SafeBuffer.allocUnsafeSlow = function (size) {
+  if (typeof size !== 'number') {
+    throw new TypeError('Argument must be a number')
+  }
+  return buffer.SlowBuffer(size)
+}
+
+},{"buffer":30}],21:[function(require,module,exports){
 (function (global){
 
 /**
@@ -4279,9 +4279,17 @@ function Peer(ws) {
 	this.uri = "unknown";
 	this.name = "unknown";
 	this.master = false;
-
+	if(this.sock.on == undefined){
+		console.log(this.sock);
+		console.log("piip")
+		this.sock.onopen = (event) => {
+			const obj = [0, '__handshake__']
+			this.sock.send(encode(obj))
+			this.close();
+		}
+	}
 	this.sock.on("message", (raw) => {
-		// console.log(raw)
+		console.log(raw)
 		let msg = decode(raw);
 		console.log("MSG", msg)
 		if (this.status == kConnecting) {
@@ -4490,7 +4498,162 @@ Peer.prototype.on = function(evt, f) {
 module.exports = Peer;
 
 }).call(this,require("buffer").Buffer)
-},{"buffer":29,"msgpack5":5}],23:[function(require,module,exports){
+},{"buffer":30,"msgpack5":5}],23:[function(require,module,exports){
+const Peer = require('../../peer')
+
+let current_data = {};
+
+
+checkIfLoggedIn = async () => {
+    //     const token = window.localStorage.getItem('token')
+    //     console.log(token)
+    //     if(!token){
+    //         console.log("You need to login")
+    //         renderLogin()
+    //     }else{
+
+    //         //Check if the token is valid
+    //         const response = await fetch('http://localhost:8080/auth/validation', {
+    //             method: 'POST',
+    //             headers: {'Authorization': token}
+    //         })
+    //         console.log('RESPONSE', response)
+            
+    //         //Token is valid, show available streams
+    //         if(response.status === 200){
+    //             console.log("SUCCESS")
+    renderThumbnails()
+    //         }
+    //     }
+}
+
+//Redirects the user to google authentication
+handleLogin = () => {
+    window.location.href="/google";
+}
+
+/**
+ * Returns a list of available streams
+ */
+getAvailableStreams = async () => {
+    const streamsInJson = await fetch('http://localhost:8080/streams');
+    const streams = await streamsInJson.json();
+    console.log('AVAILABLE', streams)
+    return streams;
+}
+
+videoPlayer = () => {
+    const containerDiv = document.getElementById('container')
+    containerDiv.innerHTML = `<h1>Stream ${current_data.uri} is live right here!</h1><br><button onclick="renderThumbnails()">Go back</button><br>
+    <canvas id="ftlab-stream-video" width="0" height="0"></canvas>`;
+    containerDiv.innerHTML += '<br>'
+    containerDiv.innerHTML += ''
+    let decoder = new libde265.Decoder();
+    console.log(decoder)
+}
+
+
+/**
+ * Creates thumbnail (image) for all available streams and adds them to div class='container'
+ */
+renderThumbnails = async () => {
+    const thumbnails = await getAvailableStreams();
+    console.log('THUMBNAILS', thumbnails)
+    const containerDiv = document.getElementById('container')
+    containerDiv.innerHTML = '';
+    console.log(containerDiv)
+    for(var i=0; i<thumbnails.length; i++){
+        const encodedURI = encodeURIComponent(thumbnails[i])
+        current_data.uri = encodedURI
+        console.log("THUMBNAIL[i]", thumbnails[i])
+        try{
+            const someData = await fetch(`http://localhost:8080/stream/rgb?uri=${encodedURI}`)
+            console.log('SOME DATA', someData)
+            if(!someData.ok){
+                throw new Error('Image not found')
+            }
+            const myBlob = await someData.blob();
+            console.log('BLOB', myBlob)
+            const objectURL = URL.createObjectURL(myBlob);
+            // containerDiv.innerHTML += createCard()
+            containerDiv.innerHTML += createCard(objectURL, i+4)
+        }catch(err){
+            console.log("Couldn't create thumbnail");
+            console.log(err) 
+        }
+    }
+}
+
+
+// //FOR LAPTOP
+// const renderThumbnails = async () => {
+//     const containerDiv = document.getElementById('container')
+//     containerDiv.innerHTML = '';
+//     for(var i=0; i<2; i++){
+//             containerDiv.innerHTML += createCard()
+//     }
+// }
+
+/**
+ * Renders button that will redirect to google login
+ */
+renderLogin = () => {
+    const containerDiv = document.getElementById('container');
+        containerDiv.innerHTML = 
+        `<div id='Login'>
+            <h2>Welcome to Future Technology Lab</h2>
+            <h3>Please login!</h3>
+            <a className="button" onClick="handleLogin()">
+                <div>
+                    <span class="svgIcon t-popup-svg">
+                        <svg class="svgIcon-use" width="25" height="37" viewBox="0 0 25 25">
+                            <g fill="none" fill-rule="evenodd">
+                            <path d="M20.66 12.693c0-.603-.054-1.182-.155-1.738H12.5v3.287h4.575a3.91 3.91 0 0 1-1.697 2.566v2.133h2.747c1.608-1.48 2.535-3.65 2.535-6.24z" fill="#4285F4"/>
+                            <path d="M12.5 21c2.295 0 4.22-.76 5.625-2.06l-2.747-2.132c-.76.51-1.734.81-2.878.81-2.214 0-4.088-1.494-4.756-3.503h-2.84v2.202A8.498 8.498 0 0 0 12.5 21z" fill="#34A853"/>
+                            <path d="M7.744 14.115c-.17-.51-.267-1.055-.267-1.615s.097-1.105.267-1.615V8.683h-2.84A8.488 8.488 0 0 0 4 12.5c0 1.372.328 2.67.904 3.817l2.84-2.202z" fill="#FBBC05"/>
+                            <path d="M12.5 7.38c1.248 0 2.368.43 3.25 1.272l2.437-2.438C16.715 4.842 14.79 4 12.5 4a8.497 8.497 0 0 0-7.596 4.683l2.84 2.202c.668-2.01 2.542-3.504 4.756-3.504z" fill="#EA4335"/>
+                            </g>
+                        </svg>
+                    </span>
+                    <span class="button-label">Sign in with Google</span>
+                </div>
+            </a>
+        </div>`
+}
+
+//FOR DESKTOP
+const createCard = (url, viewers) => {
+    return `<div class='ftlab-card-component' >
+                <img src='${url}' class="thumbnail-img" alt="Hups" width="250px"></img>
+                <p>Viewers: ${viewers}</p>
+                <button onclick="videoPlayer()">button</button>
+            </div>`
+}
+
+connectToStream = () => {
+    const ws = new WebSocket('ws://localhost:8080/');
+    current_data.frames = 10;
+    let p = new Peer(ws);
+    p.send('get_stream', (current_data.uri, current_data.frames, 0, /*pid,*/ current_data.uri));
+    console.log("still working")
+
+
+    //setTimeout 1s, ask for the amount of frames user has selected
+}
+
+//FOR LAPTOP
+// const createCard = () => {
+//     return `<div class='ftlab-card-component'>
+//                 <img src='https://via.placeholder.com/250x150' class="thumbnail-img" width="250px" alt="Hups"></img>
+//                 <p>Viewers: yes</p>
+//                 <button onclick="window.location.href='/stream?uri'">button</button>
+//             </div>`
+// }
+
+const cardLogic = () => {
+    const cards = document.getElementsByClassName('ftlab-card-component');
+}
+},{"../../peer":22}],24:[function(require,module,exports){
 (function (global){
 'use strict';
 
@@ -5000,16 +5163,16 @@ var objectKeys = Object.keys || function (obj) {
 };
 
 }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-},{"object-assign":33,"util/":26}],24:[function(require,module,exports){
+},{"object-assign":34,"util/":27}],25:[function(require,module,exports){
 arguments[4][3][0].apply(exports,arguments)
-},{"dup":3}],25:[function(require,module,exports){
+},{"dup":3}],26:[function(require,module,exports){
 module.exports = function isBuffer(arg) {
   return arg && typeof arg === 'object'
     && typeof arg.copy === 'function'
     && typeof arg.fill === 'function'
     && typeof arg.readUInt8 === 'function';
 }
-},{}],26:[function(require,module,exports){
+},{}],27:[function(require,module,exports){
 (function (process,global){
 // Copyright Joyent, Inc. and other Node contributors.
 //
@@ -5599,7 +5762,7 @@ function hasOwnProperty(obj, prop) {
 }
 
 }).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-},{"./support/isBuffer":25,"_process":34,"inherits":24}],27:[function(require,module,exports){
+},{"./support/isBuffer":26,"_process":35,"inherits":25}],28:[function(require,module,exports){
 'use strict'
 
 exports.byteLength = byteLength
@@ -5753,9 +5916,9 @@ function fromByteArray (uint8) {
   return parts.join('')
 }
 
-},{}],28:[function(require,module,exports){
-
 },{}],29:[function(require,module,exports){
+
+},{}],30:[function(require,module,exports){
 (function (Buffer){
 /*!
  * The buffer module from node.js, for the browser.
@@ -7558,7 +7721,7 @@ var hexSliceLookupTable = (function () {
 })()
 
 }).call(this,require("buffer").Buffer)
-},{"base64-js":27,"buffer":29,"ieee754":31}],30:[function(require,module,exports){
+},{"base64-js":28,"buffer":30,"ieee754":32}],31:[function(require,module,exports){
 // Copyright Joyent, Inc. and other Node contributors.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a
@@ -8083,7 +8246,7 @@ function functionBindPolyfill(context) {
   };
 }
 
-},{}],31:[function(require,module,exports){
+},{}],32:[function(require,module,exports){
 exports.read = function (buffer, offset, isLE, mLen, nBytes) {
   var e, m
   var eLen = (nBytes * 8) - mLen - 1
@@ -8169,7 +8332,7 @@ exports.write = function (buffer, value, offset, isLE, mLen, nBytes) {
   buffer[offset + i - d] |= s * 128
 }
 
-},{}],32:[function(require,module,exports){
+},{}],33:[function(require,module,exports){
 /*!
  * Determine if an object is a Buffer
  *
@@ -8192,7 +8355,7 @@ function isSlowBuffer (obj) {
   return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isBuffer(obj.slice(0, 0))
 }
 
-},{}],33:[function(require,module,exports){
+},{}],34:[function(require,module,exports){
 /*
 object-assign
 (c) Sindre Sorhus
@@ -8284,7 +8447,7 @@ module.exports = shouldUseNative() ? Object.assign : function (target, source) {
 	return to;
 };
 
-},{}],34:[function(require,module,exports){
+},{}],35:[function(require,module,exports){
 // shim for using process in browser
 var process = module.exports = {};
 
@@ -8470,7 +8633,7 @@ process.chdir = function (dir) {
 };
 process.umask = function() { return 0; };
 
-},{}],35:[function(require,module,exports){
+},{}],36:[function(require,module,exports){
 (function (setImmediate,clearImmediate){
 var nextTick = require('process/browser.js').nextTick;
 var apply = Function.prototype.apply;
@@ -8549,10 +8712,10 @@ exports.clearImmediate = typeof clearImmediate === "function" ? clearImmediate :
   delete immediateIds[id];
 };
 }).call(this,require("timers").setImmediate,require("timers").clearImmediate)
-},{"process/browser.js":34,"timers":35}],36:[function(require,module,exports){
+},{"process/browser.js":35,"timers":36}],37:[function(require,module,exports){
 arguments[4][3][0].apply(exports,arguments)
-},{"dup":3}],37:[function(require,module,exports){
-arguments[4][25][0].apply(exports,arguments)
-},{"dup":25}],38:[function(require,module,exports){
+},{"dup":3}],38:[function(require,module,exports){
 arguments[4][26][0].apply(exports,arguments)
-},{"./support/isBuffer":37,"_process":34,"dup":26,"inherits":36}]},{},[22]);
+},{"dup":26}],39:[function(require,module,exports){
+arguments[4][27][0].apply(exports,arguments)
+},{"./support/isBuffer":38,"_process":35,"dup":27,"inherits":37}]},{},[23]);
diff --git a/web-service/server/public/js/index.js b/web-service/server/src/public/js/index.js
similarity index 79%
rename from web-service/server/public/js/index.js
rename to web-service/server/src/public/js/index.js
index eb5e54580..e0f453b35 100644
--- a/web-service/server/public/js/index.js
+++ b/web-service/server/src/public/js/index.js
@@ -1,47 +1,47 @@
-
-
-const checkIfLoggedIn = async () => {
-//     const token = window.localStorage.getItem('token')
-//     console.log(token)
-//     if(!token){
-//         console.log("You need to login")
-//         renderLogin()
-//     }else{
-
-//         //Check if the token is valid
-//         const response = await fetch('http://localhost:8080/auth/validation', {
-//             method: 'POST',
-//             headers: {'Authorization': token}
-//         })
-//         console.log('RESPONSE', response)
-        
-//         //Token is valid, show available streams
-//         if(response.status === 200){
-//             console.log("SUCCESS")
-           renderThumbnails()
-//         }
-//     }
- }
+const Peer = require('../../peer')
+
+let current_data = {};
+
+
+checkIfLoggedIn = async () => {
+    //     const token = window.localStorage.getItem('token')
+    //     console.log(token)
+    //     if(!token){
+    //         console.log("You need to login")
+    //         renderLogin()
+    //     }else{
+
+    //         //Check if the token is valid
+    //         const response = await fetch('http://localhost:8080/auth/validation', {
+    //             method: 'POST',
+    //             headers: {'Authorization': token}
+    //         })
+    //         console.log('RESPONSE', response)
+            
+    //         //Token is valid, show available streams
+    //         if(response.status === 200){
+    //             console.log("SUCCESS")
+    renderThumbnails()
+    //         }
+    //     }
+}
 
 //Redirects the user to google authentication
-const handleLogin = () => {
+handleLogin = () => {
     window.location.href="/google";
 }
 
-let current_data = {}; 
-
-
 /**
  * Returns a list of available streams
  */
-const getAvailableStreams = async () => {
+getAvailableStreams = async () => {
     const streamsInJson = await fetch('http://localhost:8080/streams');
     const streams = await streamsInJson.json();
     console.log('AVAILABLE', streams)
     return streams;
 }
 
-const videoPlayer = () => {
+videoPlayer = () => {
     const containerDiv = document.getElementById('container')
     containerDiv.innerHTML = `<h1>Stream ${current_data.uri} is live right here!</h1><br><button onclick="renderThumbnails()">Go back</button><br>
     <canvas id="ftlab-stream-video" width="0" height="0"></canvas>`;
@@ -55,7 +55,7 @@ const videoPlayer = () => {
 /**
  * Creates thumbnail (image) for all available streams and adds them to div class='container'
  */
-const renderThumbnails = async () => {
+renderThumbnails = async () => {
     const thumbnails = await getAvailableStreams();
     console.log('THUMBNAILS', thumbnails)
     const containerDiv = document.getElementById('container')
@@ -96,7 +96,7 @@ const renderThumbnails = async () => {
 /**
  * Renders button that will redirect to google login
  */
-const renderLogin = () => {
+renderLogin = () => {
     const containerDiv = document.getElementById('container');
         containerDiv.innerHTML = 
         `<div id='Login'>
@@ -129,12 +129,14 @@ const createCard = (url, viewers) => {
             </div>`
 }
 
-const connectToStream = () => {
+connectToStream = () => {
     const ws = new WebSocket('ws://localhost:8080/');
+    current_data.frames = 10;
     let p = new Peer(ws);
-    p.send('message', ([0,'__handshake__']));
+    p.send('get_stream', (current_data.uri, current_data.frames, 0, /*pid,*/ current_data.uri));
+    console.log("still working")
+
 
-    current_data.frames = 10;
     //setTimeout 1s, ask for the amount of frames user has selected
 }
 
diff --git a/web-service/server/public/js/lib/libde265.min.js b/web-service/server/src/public/js/lib/libde265.min.js
similarity index 100%
rename from web-service/server/public/js/lib/libde265.min.js
rename to web-service/server/src/public/js/lib/libde265.min.js
diff --git a/web-service/server/public/js/lib/msgpack5.min.js b/web-service/server/src/public/js/lib/msgpack5.min.js
similarity index 100%
rename from web-service/server/public/js/lib/msgpack5.min.js
rename to web-service/server/src/public/js/lib/msgpack5.min.js
-- 
GitLab