From b21a76385f874d97ca62061fcb28ccda045967e3 Mon Sep 17 00:00:00 2001 From: Erin Nova Date: Wed, 1 Jun 2022 16:50:49 -0400 Subject: [PATCH] Add basic post feed & ability to make posts --- src/main.rs | 100 ++++++++++++++++++++++++++++++++++++++++- static/feed/index.html | 79 ++++++++++++++++++++++++++++++++ 2 files changed, 177 insertions(+), 2 deletions(-) create mode 100644 static/feed/index.html diff --git a/src/main.rs b/src/main.rs index f407b3b..0b85bf6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,12 @@ #[macro_use] extern crate rocket; use std::sync::Mutex; +// This trait is required when dealing with streams. +use async_std::stream::StreamExt; use golgi::{ api::get_subset::{SubsetQuery, SubsetQueryOptions}, - messages::SsbMessageContent, + messages::{SsbMessageContent, SsbMessageContentType, SsbMessageValue}, GolgiError, Sbot, }; use rocket::form::Form; @@ -12,6 +14,11 @@ use rocket::fs::FileServer; use rocket::serde::{json::Json, Serialize}; use rocket::State; +#[derive(FromForm)] +struct Message<'r> { + r#message_text: &'r str, +} + #[derive(FromForm)] struct ProfileUpdate<'r> { r#username: &'r str, @@ -26,11 +33,97 @@ struct Whoami { pubkey: String, } +#[derive(Serialize)] +#[serde(crate = "rocket::serde")] +struct Feed { + posts: Vec, +} + +#[derive(Serialize)] +#[serde(crate = "rocket::serde")] +struct Post { + author: String, + timestamp: f64, + hash: String, +} + #[get("/")] fn index() -> &'static str { "Hello, world!" } +#[get("/posts")] +async fn get_posts() -> Json { + // Initialize SSB data + let mut sbot_client = Sbot::init(None, None).await.unwrap(); + let ssb_id = sbot_client.whoami().await.unwrap(); + + let history_stream = sbot_client.create_history_stream(ssb_id).await.unwrap(); + + // Iterate through the elements in the stream and use `map` to convert + // each `SsbMessageValue` element into a tuple of + // `(String, SsbMessageContentType)`. This is an example of stream + // conversion. + let type_stream = history_stream.map(|msg| match msg { + Ok(val) => { + let message_type = val.get_message_type()?; + let structure = Post { + author: val.author, + timestamp: val.timestamp, + hash: val.hash, + }; + let tuple: (Post, SsbMessageContentType) = (structure, message_type); + Ok(tuple) + } + Err(err) => Err(err), + }); + + // Pin the stream to the stack to allow polling of the `future`. + futures::pin_mut!(type_stream); + + println!("looping through type stream"); + + let mut posts: Vec = Vec::new(); + // Iterate through each element in the stream and match on the `Result`. + // In this case, each element has type + // `Result<(String, SsbMessageContentType), GolgiError>`. + while let Some(res) = type_stream.next().await { + match res { + Ok(value) => { + if value.1 == SsbMessageContentType::Post { + println!( + "author: {}, timestamp: {}, signature: {}", + value.0.author, value.0.timestamp, value.0.hash + ); + posts.push(value.0); + } else { + println!("{:?}", value.1); + } + } + Err(err) => { + println!("err: {:?}", err); + } + } + } + + Json(Feed { posts }) +} + +#[post("/post", data = "")] +async fn new_post(message: Form>) -> Option { + // Initialize SSB data + let mut sbot_client = Sbot::init(None, None).await.unwrap(); + + // We can also match on the returned `Result`, rather than using the `?` operator. + match sbot_client.publish_post(message.message_text).await { + Ok(post_ref) => Some(post_ref), + Err(e) => { + eprintln!("failed to publish post: {}", e); + return None; + } + } +} + #[post("/update", data = "")] async fn profile_update(profileupdate: Form>) -> String { // Initialize SSB data @@ -80,7 +173,10 @@ async fn whoami() -> Json { #[rocket::main] async fn main() { let result = rocket::build() - .mount("/api", routes![index, whoami, profile_update]) + .mount( + "/api", + routes![index, whoami, profile_update, get_posts, new_post], + ) .mount("/", FileServer::from("static/")) .launch() .await; diff --git a/static/feed/index.html b/static/feed/index.html new file mode 100644 index 0000000..1b9e75e --- /dev/null +++ b/static/feed/index.html @@ -0,0 +1,79 @@ + + + + + + + + WebButt + + + + +

Feed

+
+
+ +
+ +
+
+ +
+
+ +
+
+ + + + + + + +