Feed polling
This commit is contained in:
parent
f8b81d8382
commit
5c103507c1
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -2432,6 +2432,7 @@ dependencies = [
|
|||||||
"tokio-stream",
|
"tokio-stream",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
"ubyte",
|
"ubyte",
|
||||||
|
"uuid",
|
||||||
"version_check",
|
"version_check",
|
||||||
"yansi",
|
"yansi",
|
||||||
]
|
]
|
||||||
@ -2513,6 +2514,7 @@ dependencies = [
|
|||||||
"time",
|
"time",
|
||||||
"tokio",
|
"tokio",
|
||||||
"uncased",
|
"uncased",
|
||||||
|
"uuid",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -7,7 +7,7 @@ edition = "2021"
|
|||||||
argon2 = "0.5.3"
|
argon2 = "0.5.3"
|
||||||
atom_syndication = "0.12.6"
|
atom_syndication = "0.12.6"
|
||||||
chrono = { version = "0.4.34", features = ["serde"] }
|
chrono = { version = "0.4.34", features = ["serde"] }
|
||||||
rocket = { version = "0.5.1", features = ["json", "secrets"] }
|
rocket = { version = "0.5.1", features = ["json", "secrets", "uuid"] }
|
||||||
rocket_db_pools = { version = "0.2.0", features = ["sqlx_sqlite"] }
|
rocket_db_pools = { version = "0.2.0", features = ["sqlx_sqlite"] }
|
||||||
rocket_dyn_templates = { version = "0.2.0", features = ["tera"] }
|
rocket_dyn_templates = { version = "0.2.0", features = ["tera"] }
|
||||||
rss = "2.0.11"
|
rss = "2.0.11"
|
||||||
|
31
src/feed_utils.rs
Normal file
31
src/feed_utils.rs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
use feed_rs;
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct FeedError;
|
||||||
|
|
||||||
|
pub async fn fetch_feed(url: &Url) -> Result<feed_rs::model::Feed, FeedError> {
|
||||||
|
// Fetch the feed content
|
||||||
|
let response = reqwest::get(url.as_ref()).await.map_err(|e| {
|
||||||
|
eprintln!("Failed to fetch feed: {}", e);
|
||||||
|
FeedError
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let content = response.text().await.map_err(|e| {
|
||||||
|
eprintln!("Failed to read response body: {}", e);
|
||||||
|
FeedError
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// Parse the feed
|
||||||
|
let feed_data = feed_rs::parser::parse(content.as_bytes()).map_err(|e| {
|
||||||
|
eprintln!("Failed to parse feed content: {}", e);
|
||||||
|
FeedError
|
||||||
|
})?;
|
||||||
|
|
||||||
|
println!("Fetched feed: {}", url.as_ref());
|
||||||
|
for item in &feed_data.entries {
|
||||||
|
println!("{:?}", item);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(feed_data)
|
||||||
|
}
|
31
src/feeds.rs
31
src/feeds.rs
@ -5,6 +5,7 @@ use sqlx::types::JsonValue;
|
|||||||
use url::Url;
|
use url::Url;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
use crate::feed_utils::fetch_feed;
|
||||||
use crate::user::AuthenticatedUser;
|
use crate::user::AuthenticatedUser;
|
||||||
use crate::Db;
|
use crate::Db;
|
||||||
|
|
||||||
@ -43,36 +44,6 @@ pub struct NewFeed {
|
|||||||
pub categorization: Vec<String>,
|
pub categorization: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct FeedError;
|
|
||||||
|
|
||||||
async fn fetch_feed(url: &Url) -> Result<feed_rs::model::Feed, FeedError> {
|
|
||||||
// Fetch the feed content
|
|
||||||
let response = reqwest::get(url.as_ref()).await.map_err(|e| {
|
|
||||||
eprintln!("Failed to fetch feed: {}", e);
|
|
||||||
FeedError
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let content = response.text().await.map_err(|e| {
|
|
||||||
eprintln!("Failed to read response body: {}", e);
|
|
||||||
FeedError
|
|
||||||
})?;
|
|
||||||
|
|
||||||
// Parse the feed
|
|
||||||
let feed_data = feed_rs::parser::parse(content.as_bytes()).map_err(|e| {
|
|
||||||
eprintln!("Failed to parse feed content: {}", e);
|
|
||||||
FeedError
|
|
||||||
})?;
|
|
||||||
|
|
||||||
println!("Fetched feed: {}", url.as_ref());
|
|
||||||
for item in &feed_data.entries {
|
|
||||||
println!("{:?}", item);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(feed_data)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[post("/feeds", data = "<new_feed>")]
|
#[post("/feeds", data = "<new_feed>")]
|
||||||
pub async fn create_feed(
|
pub async fn create_feed(
|
||||||
mut db: Connection<Db>,
|
mut db: Connection<Db>,
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate rocket;
|
extern crate rocket;
|
||||||
|
|
||||||
|
mod feed_utils;
|
||||||
mod feeds;
|
mod feeds;
|
||||||
|
mod poll;
|
||||||
mod user;
|
mod user;
|
||||||
|
|
||||||
use rocket::fs::FileServer;
|
use rocket::fs::FileServer;
|
||||||
@ -64,6 +66,7 @@ fn rocket() -> _ {
|
|||||||
feeds::get_feed,
|
feeds::get_feed,
|
||||||
feeds::list_feeds,
|
feeds::list_feeds,
|
||||||
feeds::delete_feed,
|
feeds::delete_feed,
|
||||||
|
poll::poll_feed,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
.mount("/static", FileServer::from("static"))
|
.mount("/static", FileServer::from("static"))
|
||||||
|
35
src/poll.rs
Normal file
35
src/poll.rs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
use crate::{feed_utils::fetch_feed, Db};
|
||||||
|
use rocket::http::Status;
|
||||||
|
use rocket::serde::uuid::Uuid;
|
||||||
|
use rocket::serde::{json::Json, Serialize};
|
||||||
|
use rocket_db_pools::Connection;
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
#[serde(crate = "rocket::serde")]
|
||||||
|
pub struct FeedPollResponse {
|
||||||
|
count: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[post("/poll/<feed_id>")]
|
||||||
|
pub async fn poll_feed(
|
||||||
|
mut db: Connection<Db>,
|
||||||
|
feed_id: Uuid,
|
||||||
|
) -> Result<Json<FeedPollResponse>, Status> {
|
||||||
|
let feed_id = feed_id.to_string();
|
||||||
|
// Get the feed URL from the database
|
||||||
|
let feed_url = sqlx::query!("SELECT url FROM feeds WHERE feed_id = ?", feed_id)
|
||||||
|
.fetch_optional(&mut **db)
|
||||||
|
.await
|
||||||
|
.map_err(|_| Status::InternalServerError)?
|
||||||
|
.ok_or(Status::NotFound)?
|
||||||
|
.url;
|
||||||
|
|
||||||
|
// Parse the URL
|
||||||
|
let url = url::Url::parse(&feed_url).map_err(|_| Status::InternalServerError)?;
|
||||||
|
|
||||||
|
let feed_data = fetch_feed(&url).await.map_err(|_| Status::BadGateway)?;
|
||||||
|
|
||||||
|
Ok(Json(FeedPollResponse {
|
||||||
|
count: feed_data.entries.len(),
|
||||||
|
}))
|
||||||
|
}
|
@ -33,9 +33,20 @@ function renderFeedItem(feed) {
|
|||||||
const name = document.createElement('span');
|
const name = document.createElement('span');
|
||||||
name.className = 'feed-name';
|
name.className = 'feed-name';
|
||||||
name.textContent = feed.name;
|
name.textContent = feed.name;
|
||||||
name.onclick = () => {
|
name.onclick = async () => {
|
||||||
// TODO: Handle feed click
|
try {
|
||||||
console.log('Feed clicked:', feed);
|
const response = await fetch(`/poll/${feed.feed_id}`, {
|
||||||
|
method: 'POST'
|
||||||
|
});
|
||||||
|
if (response.ok) {
|
||||||
|
const data = await response.json();
|
||||||
|
console.log('Feed poll response:', data);
|
||||||
|
} else {
|
||||||
|
console.error('Failed to poll feed:', response.status);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error polling feed:', error);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const menuButton = document.createElement('button');
|
const menuButton = document.createElement('button');
|
||||||
|
Loading…
Reference in New Issue
Block a user