receive posts from zulip and reply
This commit is contained in:
parent
13a8f5dc8a
commit
046d3157c2
4 changed files with 52 additions and 15 deletions
10
Cargo.lock
generated
10
Cargo.lock
generated
|
|
@ -221,6 +221,7 @@ dependencies = [
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
"unicode-segmentation",
|
"unicode-segmentation",
|
||||||
|
"winnow",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -3306,6 +3307,15 @@ version = "0.53.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
|
checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winnow"
|
||||||
|
version = "0.7.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wit-bindgen"
|
name = "wit-bindgen"
|
||||||
version = "0.46.0"
|
version = "0.46.0"
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ tokio-util = "0.7.17"
|
||||||
tracing = "0.1.43"
|
tracing = "0.1.43"
|
||||||
tracing-subscriber = { version = "0.3.22", features = ["env-filter"] }
|
tracing-subscriber = { version = "0.3.22", features = ["env-filter"] }
|
||||||
unicode-segmentation = "1.12.0"
|
unicode-segmentation = "1.12.0"
|
||||||
|
winnow = "0.7.14"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
rand = "0.9.2"
|
rand = "0.9.2"
|
||||||
|
|
|
||||||
19
src/lib.rs
19
src/lib.rs
|
|
@ -30,7 +30,8 @@ pub struct BlogdorTheAggregator {
|
||||||
cancel: CancellationToken,
|
cancel: CancellationToken,
|
||||||
endpoint: String,
|
endpoint: String,
|
||||||
channel_id: u32,
|
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*
|
zulip_token: String, // sent *to zulip* in POSTs *from us*
|
||||||
blogdor_token: String, // sent *from zulip* in POSTs *to us*
|
blogdor_token: String, // sent *from zulip* in POSTs *to us*
|
||||||
}
|
}
|
||||||
|
|
@ -75,7 +76,10 @@ impl BlogdorTheAggregator {
|
||||||
.parse()
|
.parse()
|
||||||
.expect("ZULIP_CHANNEL must be an integer");
|
.expect("ZULIP_CHANNEL must be an integer");
|
||||||
let password = std::env::var("ZULIP_TOKEN").expect("ZULIP_TOKEN must be set");
|
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");
|
let token = std::env::var("BLOGDOR_TOKEN").expect("BLOGDOR_TOKEN must be set");
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
|
|
@ -84,7 +88,8 @@ impl BlogdorTheAggregator {
|
||||||
cancel,
|
cancel,
|
||||||
endpoint,
|
endpoint,
|
||||||
channel_id,
|
channel_id,
|
||||||
email,
|
blogdor_to_zulip_email: b2z_email,
|
||||||
|
zulip_to_blogdor_email: z2b_email,
|
||||||
zulip_token: password,
|
zulip_token: password,
|
||||||
blogdor_token: token,
|
blogdor_token: token,
|
||||||
}
|
}
|
||||||
|
|
@ -95,7 +100,11 @@ impl BlogdorTheAggregator {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn spawn_http(&self) {
|
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;
|
server::spawn_server(state, self.cancel.clone()).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -161,7 +170,7 @@ impl BlogdorTheAggregator {
|
||||||
match self
|
match self
|
||||||
.client
|
.client
|
||||||
.post(&self.endpoint)
|
.post(&self.endpoint)
|
||||||
.basic_auth(&self.email, Some(&self.zulip_token))
|
.basic_auth(&self.blogdor_to_zulip_email, Some(&self.zulip_token))
|
||||||
.body(msg)
|
.body(msg)
|
||||||
.header("Content-Type", "application/x-www-form-urlencoded")
|
.header("Content-Type", "application/x-www-form-urlencoded")
|
||||||
.send()
|
.send()
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use std::{net::SocketAddr, sync::Arc};
|
use std::{collections::HashMap, net::SocketAddr, sync::Arc};
|
||||||
|
|
||||||
use axum::{
|
use axum::{
|
||||||
Router,
|
Router,
|
||||||
|
|
@ -11,6 +11,7 @@ use serde::Deserialize;
|
||||||
use serde_json::{Map, Value};
|
use serde_json::{Map, Value};
|
||||||
use sqlx::SqlitePool;
|
use sqlx::SqlitePool;
|
||||||
use tokio_util::sync::CancellationToken;
|
use tokio_util::sync::CancellationToken;
|
||||||
|
use winnow::Parser;
|
||||||
|
|
||||||
type Payload = Map<String, Value>;
|
type Payload = Map<String, Value>;
|
||||||
|
|
||||||
|
|
@ -49,28 +50,28 @@ pub(crate) async fn spawn_server(
|
||||||
|
|
||||||
fn make_router(state: ServerState) -> Router {
|
fn make_router(state: ServerState) -> Router {
|
||||||
Router::new()
|
Router::new()
|
||||||
.route("/api/v1/add-feed", post(handle_add_feed))
|
.route("/blogdor/manage-feeds", post(handle_manage_feed))
|
||||||
.with_state(state.into())
|
.with_state(state.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_add_feed(
|
async fn handle_manage_feed(
|
||||||
State(state): State<Arc<ServerState>>,
|
State(state): State<Arc<ServerState>>,
|
||||||
Json(request): Json<AddFeedRequest>,
|
Json(request): Json<ManageFeedMessage>,
|
||||||
) -> impl IntoResponse {
|
) -> impl IntoResponse {
|
||||||
let AddFeedRequest {
|
let ManageFeedMessage {
|
||||||
bot_email,
|
bot_email,
|
||||||
token,
|
token,
|
||||||
message,
|
message,
|
||||||
_rest: _,
|
_rest: _,
|
||||||
} = request;
|
} = request;
|
||||||
|
tracing::debug!("email: {bot_email}, token: {token}");
|
||||||
if state.email == bot_email && state.token == token {
|
if state.email == bot_email && state.token == token {
|
||||||
tracing::debug!("gonna do a thing with {message:?}");
|
tracing::debug!("gonna do a thing with {message:?}");
|
||||||
// things
|
|
||||||
|
|
||||||
(StatusCode::IM_A_TEAPOT, "nee-ope")
|
Json(HashMap::from([("content", "nee-ope")])).into_response()
|
||||||
} else {
|
} else {
|
||||||
tracing::debug!("psych");
|
tracing::debug!("bad emal/token");
|
||||||
(StatusCode::IM_A_TEAPOT, "nee-ope")
|
StatusCode::IM_A_TEAPOT.into_response()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -101,7 +102,7 @@ async fn graceful_shutdown(cancel: CancellationToken) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
|
||||||
struct AddFeedRequest {
|
struct ManageFeedMessage {
|
||||||
bot_email: String,
|
bot_email: String,
|
||||||
token: String,
|
token: String,
|
||||||
message: ZulipMessage,
|
message: ZulipMessage,
|
||||||
|
|
@ -118,3 +119,19 @@ struct ZulipMessage {
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
_rest: Payload,
|
_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!()
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue