diff --git a/server/src/main.rs b/server/src/main.rs index 4068090..73dd963 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -1,10 +1,12 @@ #[macro_use] extern crate rocket; +mod error; +mod nm; use std::{error::Error, io::Cursor, str::FromStr}; use glog::Flags; -use notmuch::{Notmuch, NotmuchError, ThreadSet}; +use notmuch::{Notmuch, NotmuchError}; use rocket::{ http::{ContentType, Header}, request::Request, @@ -14,6 +16,8 @@ use rocket::{ }; use rocket_cors::{AllowedHeaders, AllowedOrigins}; +use crate::error::ServerError; + #[get("/")] fn hello() -> &'static str { "Hello, world!" @@ -52,8 +56,11 @@ async fn search( } #[get("/show/")] -async fn show(nm: &State, query: &str) -> Result, Debug> { - let res = nm.show(query)?; +async fn show( + nm: &State, + query: &str, +) -> Result>, Debug> { + let res = nm::threadset_to_messages(nm.show(query).map_err(|e| -> ServerError { e.into() })?)?; Ok(Json(res)) } diff --git a/shared/src/lib.rs b/shared/src/lib.rs index 448f98b..3fff691 100644 --- a/shared/src/lib.rs +++ b/shared/src/lib.rs @@ -15,5 +15,21 @@ pub struct ShowResult { messages: Vec, } -#[derive(Serialize, Deserialize, Debug)] -pub enum Message {} +pub type AttachementId = String; + +/// # Number of seconds since the Epoch +pub type UnixTime = isize; + +#[derive(Serialize, Deserialize, Debug, Default)] +pub struct Message { + pub from: String, + pub to: Option, + pub cc: Option, + pub timestamp: UnixTime, // date header as unix time + pub date_relative: String, // user-friendly timestamp + pub tags: Vec, + + // HTML formatted body + pub body: String, + pub attachment: Vec, +} diff --git a/web/src/lib.rs b/web/src/lib.rs index d76c6e5..44c63d4 100644 --- a/web/src/lib.rs +++ b/web/src/lib.rs @@ -8,9 +8,9 @@ use std::{ use itertools::Itertools; use log::{debug, error, info, Level}; -use nm::{show_request, view_thread}; use notmuch::ThreadSet; use seed::{prelude::*, *}; +use serde::Deserialize; use wasm_timer::Instant; const SEARCH_RESULTS_PER_PAGE: usize = 20; @@ -93,7 +93,7 @@ mod urls { enum Context { None, Search(shared::SearchResult), - Thread(ThreadSet), + Thread(Vec), } // `Model` describes our app state. @@ -127,7 +127,7 @@ pub enum Msg { }, SearchResult(fetch::Result), ShowRequest(String), - ShowResult(fetch::Result), + ShowResult(fetch::Result>), NextPage, PreviousPage, } @@ -210,6 +210,19 @@ fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders) { } } +pub async fn show_request(tid: &str) -> fetch::Result> { + let b = Request::new(api::show(tid)) + .method(Method::Get) + .fetch() + .await? + .check_status()? + .bytes() + .await?; + let mut deserializer = serde_json::Deserializer::from_slice(&b); + deserializer.disable_recursion_limit(); + Ok(Vec::::deserialize(&mut deserializer) + .map_err(|_| FetchError::JsonError(fetch::JsonError::Serde(JsValue::NULL)))?) +} async fn search_request( query: &str, page: usize, @@ -496,6 +509,13 @@ fn view_footer(render_time_ms: u128) -> Node { ] } +fn view_thread(messages: &[shared::Message]) -> Node { + div![ + "MESSAGES GO HERE", + ol![messages.iter().map(|msg| li![format!("{:?}", msg)])] + ] +} + fn view_desktop(model: &Model) -> Node { let content = match &model.context { Context::None => div![h1!["Loading"]],