Add static file server, CSS styles for home
Also fix the livereloading.
This commit is contained in:
parent
758e644173
commit
97c4ae73f0
33
Cargo.lock
generated
33
Cargo.lock
generated
@ -1407,6 +1407,16 @@ version = "0.3.17"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mime_guess"
|
||||||
|
version = "2.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef"
|
||||||
|
dependencies = [
|
||||||
|
"mime",
|
||||||
|
"unicase",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "minimal-lexical"
|
name = "minimal-lexical"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
@ -2477,9 +2487,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.28.0"
|
version = "1.28.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c3c786bf8134e5a3a166db9b29ab8f48134739014a3eca7bc6bfa95d673b136f"
|
checksum = "94d7b1cfd2aa4011f2de74c2c4c63665e27a71006b0a192dcd2710272e73dfa2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"bytes",
|
"bytes",
|
||||||
@ -2570,7 +2580,13 @@ dependencies = [
|
|||||||
"http",
|
"http",
|
||||||
"http-body",
|
"http-body",
|
||||||
"http-range-header",
|
"http-range-header",
|
||||||
|
"httpdate",
|
||||||
|
"mime",
|
||||||
|
"mime_guess",
|
||||||
|
"percent-encoding",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
|
"tokio",
|
||||||
|
"tokio-util",
|
||||||
"tower-layer",
|
"tower-layer",
|
||||||
"tower-service",
|
"tower-service",
|
||||||
"tracing",
|
"tracing",
|
||||||
@ -2584,9 +2600,9 @@ checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tower-livereload"
|
name = "tower-livereload"
|
||||||
version = "0.7.3"
|
version = "0.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b8b316f4712049eb6c939efd3a7e1f7fefd3cbebd00794e82e7774855c8858ea"
|
checksum = "7e90e6da0427c5e111e03c764d49c4e970f5a9f6569fe408e5a1cbe257f48388"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"http",
|
"http",
|
||||||
@ -2688,6 +2704,15 @@ version = "1.16.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
|
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicase"
|
||||||
|
version = "2.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
|
||||||
|
dependencies = [
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-bidi"
|
name = "unicode-bidi"
|
||||||
version = "0.3.13"
|
version = "0.3.13"
|
||||||
|
@ -37,8 +37,8 @@ thiserror = "1"
|
|||||||
tokio = { version = "1", features = ["full"] }
|
tokio = { version = "1", features = ["full"] }
|
||||||
tokio-stream = { version = "0.1", features = ["sync"] }
|
tokio-stream = { version = "0.1", features = ["sync"] }
|
||||||
tower = "0.4"
|
tower = "0.4"
|
||||||
tower-livereload = "0.7"
|
tower-livereload = "0.8"
|
||||||
tower-http = { version = "0.4", features = ["trace"] }
|
tower-http = { version = "0.4", features = ["trace", "fs"] }
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
tracing-appender = "0.2"
|
tracing-appender = "0.2"
|
||||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||||
|
@ -10,7 +10,7 @@ use crate::partials::layout::Layout;
|
|||||||
pub async fn get(State(pool): State<PgPool>, layout: Layout) -> Result<Response> {
|
pub async fn get(State(pool): State<PgPool>, layout: Layout) -> Result<Response> {
|
||||||
let entries = get_entries(&pool, GetEntriesOptions::default()).await?;
|
let entries = get_entries(&pool, GetEntriesOptions::default()).await?;
|
||||||
Ok(layout.render(html! {
|
Ok(layout.render(html! {
|
||||||
ul {
|
ul class="entries" {
|
||||||
@for entry in entries {
|
@for entry in entries {
|
||||||
@let title = entry.title.unwrap_or_else(|| "Untitled".to_string());
|
@let title = entry.title.unwrap_or_else(|| "Untitled".to_string());
|
||||||
@let url = format!("/entry/{}", entry.id);
|
@let url = format!("/entry/{}", entry.id);
|
||||||
|
@ -15,7 +15,8 @@ pub async fn crawl(pool: &PgPool) -> anyhow::Result<()> {
|
|||||||
let client = Client::new();
|
let client = Client::new();
|
||||||
let feeds = get_feeds(pool).await?;
|
let feeds = get_feeds(pool).await?;
|
||||||
for feed in feeds {
|
for feed in feeds {
|
||||||
let _feed_span = info_span!("feed", id = feed.id, url = feed.url.as_str());
|
let feed_span = info_span!("feed", id = feed.id, url = feed.url.as_str());
|
||||||
|
let _feed_span_guard = feed_span.enter();
|
||||||
info!("Fetching feed");
|
info!("Fetching feed");
|
||||||
// TODO: handle these results
|
// TODO: handle these results
|
||||||
let bytes = client.get(feed.url).send().await?.bytes().await?;
|
let bytes = client.get(feed.url).send().await?.bytes().await?;
|
||||||
@ -23,7 +24,8 @@ pub async fn crawl(pool: &PgPool) -> anyhow::Result<()> {
|
|||||||
let parsed_feed = parser::parse(&bytes[..])?;
|
let parsed_feed = parser::parse(&bytes[..])?;
|
||||||
let mut payload = Vec::with_capacity(parsed_feed.entries.len());
|
let mut payload = Vec::with_capacity(parsed_feed.entries.len());
|
||||||
for entry in parsed_feed.entries {
|
for entry in parsed_feed.entries {
|
||||||
let _entry_span = info_span!("entry", id = entry.id, title = entry.title.clone().map(|t| t.content));
|
let entry_span = info_span!("entry", id = entry.id, title = entry.title.clone().map(|t| t.content));
|
||||||
|
let _entry_span_guard = entry_span.enter();
|
||||||
if let Some(link) = entry.links.get(0) {
|
if let Some(link) = entry.links.get(0) {
|
||||||
// if no scraped or feed date is available, fallback to the current time
|
// if no scraped or feed date is available, fallback to the current time
|
||||||
let published_at = entry.published.unwrap_or_else(Utc::now).naive_utc();
|
let published_at = entry.published.unwrap_or_else(Utc::now).naive_utc();
|
||||||
@ -51,7 +53,7 @@ pub async fn crawl(pool: &PgPool) -> anyhow::Result<()> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
let entries = upsert_entries(pool, payload).await?;
|
let entries = upsert_entries(pool, payload).await?;
|
||||||
info!("Created {} entries for feed {}", entries.len(), feed.id);
|
info!("Created {} entries", entries.len());
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
27
src/main.rs
27
src/main.rs
@ -1,4 +1,4 @@
|
|||||||
use std::path::Path;
|
use std::{path::Path, net::SocketAddr};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use axum::{
|
use axum::{
|
||||||
@ -11,7 +11,7 @@ use notify::Watcher;
|
|||||||
use sqlx::postgres::PgPoolOptions;
|
use sqlx::postgres::PgPoolOptions;
|
||||||
use tokio::sync::watch::channel;
|
use tokio::sync::watch::channel;
|
||||||
use tower::ServiceBuilder;
|
use tower::ServiceBuilder;
|
||||||
use tower_http::trace::TraceLayer;
|
use tower_http::{trace::TraceLayer, services::ServeDir};
|
||||||
use tower_livereload::LiveReloadLayer;
|
use tower_livereload::LiveReloadLayer;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
@ -20,6 +20,14 @@ use lib::handlers;
|
|||||||
use lib::log::init_tracing;
|
use lib::log::init_tracing;
|
||||||
use lib::state::AppState;
|
use lib::state::AppState;
|
||||||
|
|
||||||
|
async fn serve(app: Router, addr: SocketAddr) -> Result<()> {
|
||||||
|
debug!("listening on {}", addr);
|
||||||
|
axum::Server::bind(&addr)
|
||||||
|
.serve(app.into_make_service())
|
||||||
|
.await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<()> {
|
async fn main() -> Result<()> {
|
||||||
dotenv().ok();
|
dotenv().ok();
|
||||||
@ -49,6 +57,7 @@ async fn main() -> Result<()> {
|
|||||||
.route("/entry/:id", get(handlers::entry::get))
|
.route("/entry/:id", get(handlers::entry::get))
|
||||||
.route("/log", get(handlers::log::get))
|
.route("/log", get(handlers::log::get))
|
||||||
.route("/log/stream", get(handlers::log::stream))
|
.route("/log/stream", get(handlers::log::stream))
|
||||||
|
.nest_service("/static", ServeDir::new("static"))
|
||||||
.with_state(AppState {
|
.with_state(AppState {
|
||||||
pool,
|
pool,
|
||||||
config,
|
config,
|
||||||
@ -56,22 +65,20 @@ async fn main() -> Result<()> {
|
|||||||
})
|
})
|
||||||
.layer(ServiceBuilder::new().layer(TraceLayer::new_for_http()));
|
.layer(ServiceBuilder::new().layer(TraceLayer::new_for_http()));
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
if cfg!(debug_assertions) {
|
||||||
{
|
debug!("starting livereload");
|
||||||
let livereload = LiveReloadLayer::new();
|
let livereload = LiveReloadLayer::new();
|
||||||
let reloader = livereload.reloader();
|
let reloader = livereload.reloader();
|
||||||
let mut watcher = notify::recommended_watcher(move |_| reloader.reload())?;
|
let mut watcher = notify::recommended_watcher(move |_| reloader.reload())?;
|
||||||
watcher.watch(
|
watcher.watch(
|
||||||
Path::new("target/debug/crawlnicle"),
|
Path::new("static"),
|
||||||
notify::RecursiveMode::Recursive,
|
notify::RecursiveMode::Recursive,
|
||||||
)?;
|
)?;
|
||||||
app = app.layer(livereload);
|
app = app.layer(livereload);
|
||||||
|
serve(app, addr).await?;
|
||||||
|
} else {
|
||||||
|
serve(app, addr).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("listening on {}", addr);
|
|
||||||
axum::Server::bind(&addr)
|
|
||||||
.serve(app.into_make_service())
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ use maud::{html, Markup};
|
|||||||
|
|
||||||
pub fn header(title: &str) -> Markup {
|
pub fn header(title: &str) -> Markup {
|
||||||
html! {
|
html! {
|
||||||
header {
|
header class="header" {
|
||||||
nav {
|
nav {
|
||||||
h1 { a href="/" data-turbo-frame="main" { (title) } }
|
h1 { a href="/" data-turbo-frame="main" { (title) } }
|
||||||
ul {
|
ul {
|
||||||
|
@ -42,6 +42,7 @@ impl Layout {
|
|||||||
script type="module" {
|
script type="module" {
|
||||||
r#"import * as Turbo from 'https://cdn.skypack.dev/@hotwired/turbo';"#
|
r#"import * as Turbo from 'https://cdn.skypack.dev/@hotwired/turbo';"#
|
||||||
}
|
}
|
||||||
|
link rel="stylesheet" href="/static/styles.css";
|
||||||
}
|
}
|
||||||
body {
|
body {
|
||||||
(header(&self.title))
|
(header(&self.title))
|
||||||
|
39
static/styles.css
Normal file
39
static/styles.css
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
/* Header */
|
||||||
|
|
||||||
|
header.header nav {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
header.header nav h1 {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
header.header nav a {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
header.header nav ul {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
header.header nav ul li {
|
||||||
|
margin-left: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Home */
|
||||||
|
|
||||||
|
ul.entries {
|
||||||
|
list-style: none;
|
||||||
|
margin: 24px 8px;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.entries li {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user