heavy start on add-feeds endpoint
This commit is contained in:
parent
07ae653d49
commit
ab5f97d05f
4 changed files with 81 additions and 16 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -212,6 +212,7 @@ dependencies = [
|
|||
"rand 0.9.2",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"sqlx",
|
||||
"thiserror 2.0.17",
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ html2md = "0.2.15"
|
|||
justerror = "1.1.0"
|
||||
reqwest = "0.12.24"
|
||||
serde = { version = "1.0.228", features = ["derive"] }
|
||||
serde_json = "1.0.145"
|
||||
serde_urlencoded = "0.7.1"
|
||||
sqlx = { version = "0.8.6", default-features = false, features = ["chrono", "derive", "macros", "migrate", "runtime-tokio", "sqlite", "tls-none"] }
|
||||
thiserror = "2.0.17"
|
||||
|
|
|
|||
12
src/lib.rs
12
src/lib.rs
|
|
@ -2,6 +2,7 @@ use std::time::Duration;
|
|||
|
||||
use feed_rs::parser::parse;
|
||||
use reqwest::StatusCode;
|
||||
use server::ServerState;
|
||||
use sqlx::{
|
||||
SqlitePool,
|
||||
sqlite::{SqliteConnectOptions, SqliteJournalMode, SqlitePoolOptions},
|
||||
|
|
@ -30,7 +31,8 @@ pub struct BlogdorTheAggregator {
|
|||
endpoint: String,
|
||||
channel_id: u32,
|
||||
email: String,
|
||||
password: String,
|
||||
password: String, // sent *to zulip* in POSTs *from us*
|
||||
token: String, // checked against incoming POSTs *from zulip*
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq)]
|
||||
|
|
@ -72,9 +74,9 @@ impl BlogdorTheAggregator {
|
|||
.expect("ZULIP_CHANNEL must be set")
|
||||
.parse()
|
||||
.expect("ZULIP_CHANNEL must be an integer");
|
||||
|
||||
let email = std::env::var("BLOGDOR_EMAIL").expect("BLOGDOR_EMAIL 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 token = std::env::var("BLOGDOR_TOKEN").expect("BLOGDOR_TOKEN must be set");
|
||||
|
||||
Self {
|
||||
db,
|
||||
|
|
@ -84,6 +86,7 @@ impl BlogdorTheAggregator {
|
|||
channel_id,
|
||||
email,
|
||||
password,
|
||||
token,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -92,7 +95,8 @@ impl BlogdorTheAggregator {
|
|||
}
|
||||
|
||||
pub async fn spawn_http(&self) {
|
||||
server::spawn_server(self.db.clone(), self.cancel.clone()).await;
|
||||
let state = ServerState::new(self.db.clone(), &self.email, &self.token);
|
||||
server::spawn_server(state, self.cancel.clone()).await;
|
||||
}
|
||||
|
||||
pub async fn check_feeds(&self) -> Result<Vec<Result<FeedResult, String>>, String> {
|
||||
|
|
|
|||
|
|
@ -1,15 +1,42 @@
|
|||
use std::net::SocketAddr;
|
||||
use std::{net::SocketAddr, sync::Arc};
|
||||
|
||||
use axum::{Router, routing::post};
|
||||
use axum::{
|
||||
Router,
|
||||
extract::{Json, State},
|
||||
http::StatusCode,
|
||||
response::IntoResponse,
|
||||
routing::post,
|
||||
};
|
||||
use serde::Deserialize;
|
||||
use serde_json::{Map, Value};
|
||||
use sqlx::SqlitePool;
|
||||
use tokio_util::sync::CancellationToken;
|
||||
|
||||
type Payload = Map<String, Value>;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ServerState {
|
||||
db: SqlitePool,
|
||||
email: String,
|
||||
token: String,
|
||||
}
|
||||
|
||||
impl ServerState {
|
||||
pub fn new(db: SqlitePool, email: &str, token: &str) -> Self {
|
||||
Self {
|
||||
db,
|
||||
email: email.to_string(),
|
||||
token: token.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn spawn_server(
|
||||
pool: SqlitePool,
|
||||
state: ServerState,
|
||||
cancel: CancellationToken,
|
||||
) -> tokio::task::JoinHandle<()> {
|
||||
tokio::task::spawn(async move {
|
||||
let server = make_router(pool);
|
||||
let server = make_router(state);
|
||||
let addr: SocketAddr = ([127, 0, 0, 1], 3000).into();
|
||||
tracing::debug!("binding to {addr:?}");
|
||||
let listener = tokio::net::TcpListener::bind(&addr).await.unwrap();
|
||||
|
|
@ -20,15 +47,28 @@ pub(crate) async fn spawn_server(
|
|||
})
|
||||
}
|
||||
|
||||
fn make_router(db: SqlitePool) -> Router {
|
||||
fn make_router(state: ServerState) -> Router {
|
||||
Router::new()
|
||||
.route(
|
||||
"/api/v1/add-feed",
|
||||
post(async move || {
|
||||
tracing::debug!("got a post to add a feed");
|
||||
}),
|
||||
)
|
||||
.with_state(db)
|
||||
.route("/api/v1/add-feed", post(handle_add_feed))
|
||||
.with_state(state.into())
|
||||
}
|
||||
|
||||
async fn handle_add_feed(
|
||||
State(state): State<Arc<ServerState>>,
|
||||
Json(request): Json<AddFeedRequest>,
|
||||
) -> impl IntoResponse {
|
||||
let AddFeedRequest {
|
||||
bot_email,
|
||||
token,
|
||||
message,
|
||||
_rest: _,
|
||||
} = request;
|
||||
if state.email == bot_email && state.token == token {
|
||||
tracing::debug!("gonna do a thing with {message:?}");
|
||||
} else {
|
||||
tracing::debug!("psych");
|
||||
}
|
||||
(StatusCode::IM_A_TEAPOT, "nee-ope")
|
||||
}
|
||||
|
||||
async fn graceful_shutdown(cancel: CancellationToken) {
|
||||
|
|
@ -56,3 +96,22 @@ async fn graceful_shutdown(cancel: CancellationToken) {
|
|||
}
|
||||
cancel.cancel();
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
|
||||
struct AddFeedRequest {
|
||||
bot_email: String,
|
||||
token: String,
|
||||
message: ZulipMessage,
|
||||
#[serde(flatten)]
|
||||
_rest: Payload,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
|
||||
struct ZulipMessage {
|
||||
content: String,
|
||||
sender_email: String,
|
||||
sender_id: u32,
|
||||
sender_full_name: String,
|
||||
#[serde(flatten)]
|
||||
_rest: Payload,
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue