From 046d3157c24753556f052bf62082c8648b375ca5 Mon Sep 17 00:00:00 2001 From: joe Date: Sat, 20 Dec 2025 14:19:18 -0800 Subject: [PATCH] receive posts from zulip and reply --- Cargo.lock | 10 ++++++++++ Cargo.toml | 1 + src/lib.rs | 19 ++++++++++++++----- src/server.rs | 37 +++++++++++++++++++++++++++---------- 4 files changed, 52 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 64b24f0..50515d1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -221,6 +221,7 @@ dependencies = [ "tracing", "tracing-subscriber", "unicode-segmentation", + "winnow", ] [[package]] @@ -3306,6 +3307,15 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" +[[package]] +name = "winnow" +version = "0.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" +dependencies = [ + "memchr", +] + [[package]] name = "wit-bindgen" version = "0.46.0" diff --git a/Cargo.toml b/Cargo.toml index 82ab152..713156d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ tokio-util = "0.7.17" tracing = "0.1.43" tracing-subscriber = { version = "0.3.22", features = ["env-filter"] } unicode-segmentation = "1.12.0" +winnow = "0.7.14" [dev-dependencies] rand = "0.9.2" diff --git a/src/lib.rs b/src/lib.rs index 956f518..7ff5f67 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,7 +30,8 @@ pub struct BlogdorTheAggregator { cancel: CancellationToken, endpoint: String, channel_id: u32, - email: String, + blogdor_to_zulip_email: String, + zulip_to_blogdor_email: String, zulip_token: String, // sent *to zulip* in POSTs *from us* blogdor_token: String, // sent *from zulip* in POSTs *to us* } @@ -75,7 +76,10 @@ impl BlogdorTheAggregator { .parse() .expect("ZULIP_CHANNEL must be an integer"); let password = std::env::var("ZULIP_TOKEN").expect("ZULIP_TOKEN must be set"); - let email = std::env::var("BLOGDOR_EMAIL").expect("BLOGDOR_EMAIL must be set"); + let b2z_email = + std::env::var("BLOGDOR_TO_ZULIP_EMAIL").expect("BLOGDOR_TO_ZULIP_EMAIL must be set"); + let z2b_email = + std::env::var("ZULIP_TO_BLOGDOR_EMAIL").expect("ZULIP_TO_BLOGDOR_EMAIL must be set"); let token = std::env::var("BLOGDOR_TOKEN").expect("BLOGDOR_TOKEN must be set"); Self { @@ -84,7 +88,8 @@ impl BlogdorTheAggregator { cancel, endpoint, channel_id, - email, + blogdor_to_zulip_email: b2z_email, + zulip_to_blogdor_email: z2b_email, zulip_token: password, blogdor_token: token, } @@ -95,7 +100,11 @@ impl BlogdorTheAggregator { } pub async fn spawn_http(&self) { - let state = ServerState::new(self.db.clone(), &self.email, &self.blogdor_token); + let state = ServerState::new( + self.db.clone(), + &self.zulip_to_blogdor_email, + &self.blogdor_token, + ); server::spawn_server(state, self.cancel.clone()).await; } @@ -161,7 +170,7 @@ impl BlogdorTheAggregator { match self .client .post(&self.endpoint) - .basic_auth(&self.email, Some(&self.zulip_token)) + .basic_auth(&self.blogdor_to_zulip_email, Some(&self.zulip_token)) .body(msg) .header("Content-Type", "application/x-www-form-urlencoded") .send() diff --git a/src/server.rs b/src/server.rs index db1e013..98d807c 100644 --- a/src/server.rs +++ b/src/server.rs @@ -1,4 +1,4 @@ -use std::{net::SocketAddr, sync::Arc}; +use std::{collections::HashMap, net::SocketAddr, sync::Arc}; use axum::{ Router, @@ -11,6 +11,7 @@ use serde::Deserialize; use serde_json::{Map, Value}; use sqlx::SqlitePool; use tokio_util::sync::CancellationToken; +use winnow::Parser; type Payload = Map; @@ -49,28 +50,28 @@ pub(crate) async fn spawn_server( fn make_router(state: ServerState) -> Router { Router::new() - .route("/api/v1/add-feed", post(handle_add_feed)) + .route("/blogdor/manage-feeds", post(handle_manage_feed)) .with_state(state.into()) } -async fn handle_add_feed( +async fn handle_manage_feed( State(state): State>, - Json(request): Json, + Json(request): Json, ) -> impl IntoResponse { - let AddFeedRequest { + let ManageFeedMessage { bot_email, token, message, _rest: _, } = request; + tracing::debug!("email: {bot_email}, token: {token}"); if state.email == bot_email && state.token == token { tracing::debug!("gonna do a thing with {message:?}"); - // things - (StatusCode::IM_A_TEAPOT, "nee-ope") + Json(HashMap::from([("content", "nee-ope")])).into_response() } else { - tracing::debug!("psych"); - (StatusCode::IM_A_TEAPOT, "nee-ope") + tracing::debug!("bad emal/token"); + StatusCode::IM_A_TEAPOT.into_response() } } @@ -101,7 +102,7 @@ async fn graceful_shutdown(cancel: CancellationToken) { } #[derive(Clone, Debug, PartialEq, Eq, Deserialize)] -struct AddFeedRequest { +struct ManageFeedMessage { bot_email: String, token: String, message: ZulipMessage, @@ -118,3 +119,19 @@ struct ZulipMessage { #[serde(flatten)] _rest: Payload, } + +fn parse_command(input: &mut &str) -> String { + // let Ok(s) = ("***@", winnow::token::take_until(1.., "**")) + // .map(|(_, s, _)| s) + // .parse_next(input) + // else { + // return "could not find Blogdor's name".to_string(); + // }; + // if s != "Blogdor Outgoing Bot" { + // return "could not confirm Blogdor's name".to_string(); + // } + + // s.into() + + todo!() +}