···11+[package]
22+name = "subs"
33+version = "0.1.0"
44+edition = "2024"
55+66+[dependencies]
77+maud = { version = "0.27", features = ["poem"] }
88+poem = { version = "3", features = ["static-files", "chrono", "cookie"] }
99+1010+rusqlite = { version = "0.37", features = ["chrono", "bundled"] }
1111+rusqlite_migration = "2.3"
1212+1313+serde = "1"
1414+serde_json = "1"
1515+1616+tokio = { version = "1", features = ["macros", "rt-multi-thread", "process"] }
1717+1818+log = "0.4.28"
1919+env_logger = "0.11.8"
2020+rustypipe = { version = "0.11", features = ["rustls-tls-webpki-roots"], default-features = false}
+34
src/db.rs
···11+use rusqlite::Connection;
22+use rusqlite_migration::{M, Migrations};
33+44+// Define migrations
55+const MIGRATIONS_SLICE: &[M<'_>] = &[
66+ M::up(
77+ "CREATE TABLE subscription(
88+ channel_id TEXT NOT NULL UNIQUE,
99+ name TEXT NOT NULL,
1010+ creation_datetime TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
1111+ );",
1212+ ),
1313+1414+];
1515+1616+const MIGRATIONS: Migrations<'_> = Migrations::from_slice(MIGRATIONS_SLICE);
1717+1818+#[expect(
1919+ clippy::expect_used,
2020+ reason = "If we fail to get DB, we might as well panic."
2121+)]
2222+pub fn connect() -> Connection {
2323+ let mut conn = Connection::open("./db.db3").expect("Failed to open database file");
2424+2525+ // Apply some PRAGMA, often better to do it outside of migrations
2626+ conn.pragma_update_and_check(None, "journal_mode", "WAL", |_| Ok(()))
2727+ .expect("Failed to set WAL journal mode");
2828+2929+ MIGRATIONS
3030+ .to_latest(&mut conn)
3131+ .expect("Failed to run database migrations");
3232+3333+ conn
3434+}
+33
src/main.rs
···11+use poem::{EndpointExt as _, Route, Server, endpoint::StaticFileEndpoint, get, listener::TcpListener, web::Data};
22+use rusqlite::Connection;
33+use std::{env, sync::{Arc, Mutex}};
44+55+mod db;
66+mod routes;
77+88+// type WrappedConnection = Arc<Mutex<Connection>>;
99+// type W = WrappedConnection;
1010+// type D<T> = Data<T>;
1111+type Db<'a> = Data<&'a Arc<Mutex<Connection>>>;
1212+1313+#[tokio::main]
1414+async fn main() -> Result<(), std::io::Error> {
1515+ env_logger::init();
1616+1717+ let conn = Arc::new(Mutex::new(db::connect()));
1818+1919+ let app = Route::new()
2020+ .at("/", poem::get(routes::index::get).post(routes::index::post))
2121+2222+ .at("/style.css", StaticFileEndpoint::new("./style.css").no_cache(true))
2323+ //.with(CookieJarManager::new())
2424+ .data(conn.clone());
2525+2626+ let port = env::var("PORT").unwrap_or("3000".to_owned());
2727+2828+ println!("Listening on https://localhost:{port}");
2929+ Server::new(TcpListener::bind(format!("0.0.0.0:{port}")))
3030+ .name("hello-world")
3131+ .run(app)
3232+ .await
3333+}