diff --git a/exp2/src/serve.rs b/exp2/src/serve.rs index 49aae84..cad434e 100644 --- a/exp2/src/serve.rs +++ b/exp2/src/serve.rs @@ -133,7 +133,7 @@ async fn handle_socket( ))) .await { - eprintln!("Error sending bootstrap reference: {:?}", e); + println!("Error sending bootstrap reference: {:?}", e); continue; } } @@ -143,11 +143,11 @@ async fn handle_socket( .send(Message::Item(ServerMsg::Reference((**reference).clone()))) .await { - eprintln!("Error sending reference: {:?}", e); + println!("Error sending reference: {:?}", e); continue; } } else { - eprintln!("Reference not found: {}", path); + println!("Reference not found: {}", path); } } Message::Item(ClientMsg::GetObject(address)) => { @@ -156,21 +156,21 @@ async fn handle_socket( .send(Message::Item(ServerMsg::Object(object.content.clone()))) .await { - eprintln!("Error sending object: {:?}", e); + println!("Error sending object: {:?}", e); continue; } } else { - eprintln!("Object not found: {}", address); + println!("Object not found: {}", address); } } Message::Ping(items) => { - eprintln!("unhandled ping msg: {:?}", items); + println!("unhandled ping msg: {:?}", items); } Message::Pong(items) => { - eprintln!("unhandled pong msg: {:?}", items); + println!("unhandled pong msg: {:?}", items); } Message::Close(_close_frame) => { - eprintln!("closing websocket connection at client request"); + println!("closing websocket connection at client request"); break; } } @@ -206,7 +206,7 @@ pub fn endpoints( pub async fn serve() { // run our app with hyper, listening globally on port 3000 let (root_ref, refs, objects) = random_references_and_objects(); - println!("Server starting on http://127.0.0.1:3000"); + println!("Server ui starting on http://127.0.0.1:3000/ui/"); println!("WebSocket endpoint available at ws://127.0.0.1:3000/api/v1/ws"); let listener = tokio::net::TcpListener::bind("127.0.0.1:3000") .await diff --git a/exp2/static/client.js b/exp2/static/client.js index 82de876..58b257a 100644 --- a/exp2/static/client.js +++ b/exp2/static/client.js @@ -8,12 +8,44 @@ export { bootstrap }; * @property {string} content_address */ -async function load_bootstrap() { - let response = await fetch("/api/v1/ref/all/username"); - if (!response.ok) { - throw new Error("Network response was not ok: " + response.statusText); - } - return await response.json(); +/** + * @typedef {Object} ServerMsg + * @property {Reference?} Reference + * @property {string?} Object + */ + +/** + * @param {WebSocket} socket + * @returns {Promise} + */ +async function load_bootstrap(socket) { + // Wait for the connection to be established + const data = await send_socket_msg(socket, + JSON.stringify("Bootstrap")); + + return data; +} + +/** + * @param {WebSocket} socket + * @param {string} msg + * @returns {Promise} + */ +async function send_socket_msg(socket, msg) { + // Send a request for all references + socket.send(msg); + + // Wait for the response + /** @type {Promise} */ + const stream = await new Promise((resolve, reject) => { + socket.onmessage = (event) => { + resolve(event.data.text()); + }; + socket.onerror = (_error) => reject(new Error("WebSocket error occurred")); + }); + let data = await stream; + + return JSON.parse(data); } /** @@ -72,7 +104,7 @@ function storeObject(store, reference, root_path) { * @returns {Promise>} An array of references */ function load_reference_paths(refStore, reference) { - return new Promise(async (resolve, reject) => { + return new Promise(async (resolve, _reject) => { let references = []; references.push(reference); if (reference.dependents) { @@ -87,23 +119,24 @@ function load_reference_paths(refStore, reference) { } /** + * @param {WebSocket} socket * @param {IDBDatabase} db * @param {string} storeName * @param {Array} references */ -async function load_objects_and_store(db, references, storeName) { +async function load_objects_and_store(socket, db, references, storeName) { let objects = [] for (var ref of references) { /** @type {Response} */ if (ref.dependents && ref.dependents.length != 0) { continue; // not a leaf object } - let response = await fetch("/api/v1/object/" + ref.content_address); - if (!response.ok) { - throw new Error("Network response was not ok: " + response.statusText); + + let data = await send_socket_msg(socket, JSON.stringify({ "GetObject": ref.content_address })); + if (!data.Object) { + throw { error: "Not an object" }; } - const object = await response.text(); - objects.push({ id: ref.content_address, content: object }); + objects.push({ id: ref.content_address, content: data.Object }); } const objectTrxAndStore = await getStoreAndTransaction(db, storeName); for (var obj of objects) { @@ -133,7 +166,16 @@ async function bootstrap() { const objectStoreName = "objects"; const databaseName = "MerkleStore"; const start = new Date().getTime(); - const root = await load_bootstrap(); + const socket = new WebSocket(`ws://${window.location.host}/api/v1/ws`); + await new Promise((resolve, reject) => { + socket.onopen = () => resolve(); + socket.onerror = (error) => reject(new Error("WebSocket connection failed" + error)); + }); + + const data = await load_bootstrap(socket); + if (!data.Reference) { + throw { error: "Not a Reference" }; + } const db = await openDatabase(databaseName, [refStoreName, objectStoreName]); const refTrxAndStore = await getStoreAndTransaction(db, refStoreName); @@ -143,12 +185,12 @@ async function bootstrap() { refTrxAndStore.trx.onerror = (event) => reject(event.target.error); }); - const refs = await load_reference_paths(refTrxAndStore.store, root); + const refs = await load_reference_paths(refTrxAndStore.store, data.Reference); // Wait for the transaction to complete await transactionComplete; - await load_objects_and_store(db, refs, objectStoreName); + await load_objects_and_store(socket, db, refs, objectStoreName); const end = new Date().getTime(); return end - start;