From 03ca1ff634c853b757cc13c0397bcdadb4546d3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Tue, 20 Oct 2020 12:09:38 +0200 Subject: [PATCH] Make the updates page interactive --- public/updates-script.js | 26 ++++++++++++++++--- src/subcommand/serve.rs | 56 ++++++++++++++++++++++++++++------------ templates/updates.html | 49 +++++++++++++++++++++++++++++------ 3 files changed, 102 insertions(+), 29 deletions(-) diff --git a/public/updates-script.js b/public/updates-script.js index f2f68e920..68830c767 100644 --- a/public/updates-script.js +++ b/public/updates-script.js @@ -1,13 +1,19 @@ $(window).on('load', function () { - let url = 'ws://' + window.location.hostname + ':' + window.location.port + '/updates/ws'; + let wsProtcol = "ws"; + if (window.location.protocol === 'https') { + wsProtcol = 'wss'; + } + + let url = wsProtcol + '://' + window.location.hostname + ':' + window.location.port + '/updates/ws'; var socket = new WebSocket(url); socket.onmessage = function (event) { - console.log(event.data); + let status = JSON.parse(event.data); - if (event.data.endsWith("processed")) { + if (status.type == 'Pending') { const elem = document.createElement('li'); elem.classList.add("document"); + elem.setAttribute("id", 'update-' + status.update_id); const ol = document.createElement('ol'); const field = document.createElement('li'); @@ -19,7 +25,7 @@ $(window).on('load', function () { const content = document.createElement('div'); content.classList.add("content"); - content.innerHTML = event.data; + content.innerHTML = 'Pending ' + status.update_id; field.appendChild(attribute); field.appendChild(content); @@ -29,6 +35,18 @@ $(window).on('load', function () { prependChild(results, elem); } + + if (status.type == "Processing") { + const id = 'update-' + status.update_id; + const content = $(`#${id} .content`); + content.html('Processing ' + status.update_id); + } + + if (status.type == "Processed") { + const id = 'update-' + status.update_id; + const content = $(`#${id} .content`); + content.html('Processed ' + status.update_id); + } } }); diff --git a/src/subcommand/serve.rs b/src/subcommand/serve.rs index 2662cdd56..64c9edf20 100644 --- a/src/subcommand/serve.rs +++ b/src/subcommand/serve.rs @@ -11,7 +11,7 @@ use askama_warp::Template; use futures::{FutureExt, StreamExt}; use futures::stream; use heed::EnvOpenOptions; -use serde::Deserialize; +use serde::{Serialize, Deserialize}; use structopt::StructOpt; use tokio::fs::File as TFile; use tokio::io::AsyncWriteExt; @@ -84,9 +84,19 @@ struct IndexTemplate { #[derive(Template)] #[template(path = "updates.html")] -struct UpdatesTemplate { +struct UpdatesTemplate { db_name: String, - updates: Vec, + db_size: usize, + docs_count: usize, + updates: Vec>, +} + +#[derive(Debug, Clone, Serialize)] +#[serde(tag = "type")] +enum UpdateStatus { + Pending { update_id: u64, meta: M }, + Processing { update_id: u64, meta: M }, + Processed { update_id: u64, meta: M }, } pub fn run(opt: Opt) -> anyhow::Result<()> { @@ -116,10 +126,14 @@ pub fn run(opt: Opt) -> anyhow::Result<()> { let update_store = UpdateStore::open( update_store_options, update_store_path, - move |uid, meta: String, _content| { - let _ = update_status_sender_cloned.send(format!("processing update {}", uid)); + move |update_id, meta: String, _content| { + let processing = UpdateStatus::Processing { update_id, meta: meta.clone() }; + let _ = update_status_sender_cloned.send(processing); + std::thread::sleep(Duration::from_secs(3)); - let _ = update_status_sender_cloned.send(format!("update {} processed", uid)); + + let processed = UpdateStatus::Processed { update_id, meta: meta.clone() }; + let _ = update_status_sender_cloned.send(processed); Ok(meta) })?; @@ -149,19 +163,24 @@ pub fn run(opt: Opt) -> anyhow::Result<()> { let mut updates = update_store.iter_metas(|processed, pending| { let mut updates = Vec::new(); for result in processed { - let (id, _) = result?; - updates.push(format!("update {} processed", id.get())); + let (uid, meta) = result?; + updates.push(UpdateStatus::Processed { update_id: uid.get(), meta }); } for result in pending { - let (id, _) = result?; - updates.push(format!("update {} pending", id.get())); + let (uid, meta) = result?; + updates.push(UpdateStatus::Pending { update_id: uid.get(), meta }); } Ok(updates) }).unwrap(); if header.contains("text/html") { updates.reverse(); - let template = UpdatesTemplate { db_name: db_name.clone(), updates }; + let template = UpdatesTemplate { + db_name: db_name.clone(), + db_size, + docs_count, + updates, + }; Box::new(template) as Box } else { Box::new(warp::reply::json(&updates)) @@ -289,7 +308,7 @@ pub fn run(opt: Opt) -> anyhow::Result<()> { async fn buf_stream( update_store: Arc>, - update_status_sender: broadcast::Sender, + update_status_sender: broadcast::Sender>, mut stream: impl futures::Stream> + Unpin, ) -> Result { @@ -305,9 +324,9 @@ pub fn run(opt: Opt) -> anyhow::Result<()> { let mmap = unsafe { memmap::Mmap::map(&file).unwrap() }; let meta = String::from("I am the metadata"); - let uid = update_store.register_update(&meta, &mmap[..]).unwrap(); - update_status_sender.send(format!("update {} pending", uid)).unwrap(); - eprintln!("Registering update {}", uid); + let update_id = update_store.register_update(&meta, &mmap[..]).unwrap(); + update_status_sender.send(UpdateStatus::Pending { update_id, meta }).unwrap(); + eprintln!("update {} registered", update_id); Ok(warp::reply()) } @@ -331,8 +350,11 @@ pub fn run(opt: Opt) -> anyhow::Result<()> { update_status_receiver .into_stream() .flat_map(|result| { - match result{ - Ok(msg) => stream::iter(Some(Ok(Message::text(msg)))), + match result { + Ok(status) => { + let msg = serde_json::to_string(&status).unwrap(); + stream::iter(Some(Ok(Message::text(msg)))) + }, Err(e) => { eprintln!("channel error: {:?}", e); stream::iter(None) diff --git a/templates/updates.html b/templates/updates.html index ec83af4e0..55c8088c3 100644 --- a/templates/updates.html +++ b/templates/updates.html @@ -11,7 +11,7 @@ -
+
@@ -21,6 +21,27 @@ milli logo in black
+ +
@@ -29,13 +50,25 @@
    {% for update in updates %} -
  1. -
      -
    1. -
      text
      {{ update }}
      -
    2. -
    -
  2. + {% match update %} + {% when UpdateStatus::Pending with { update_id , meta } %} +
  3. +
      +
    1. +
      text
      Pending {{ update_id }}
      +
    2. +
    +
  4. + {% when UpdateStatus::Processed with { update_id , meta } %} +
  5. +
      +
    1. +
      text
      Processed {{ update_id }}
      +
    2. +
    +
  6. + {% else %} + {% endmatch %} {% endfor %}