[shelves] Routing for rust port

This commit is contained in:
soup 2025-02-02 19:03:58 -05:00
parent db920c87ed
commit fd9322923b
Signed by: soup
SSH key fingerprint: SHA256:GYxje8eQkJ6HZKzVWDdyOUF1TyDiprruGhE0Ym8qYDY
7 changed files with 570 additions and 15 deletions

View file

@ -6,3 +6,5 @@ edition = "2024"
[dependencies]
rusqlite = { version = "*" }
async-channel = { version = "*" }
urlpattern = { version = "*" }
url = { version = "*" }

71
rs/src/containers.rs Normal file
View file

@ -0,0 +1,71 @@
use core::fmt::Debug;
use std::borrow::Borrow;
pub struct VecMap<K, V> {
items: Vec<(K, V)>,
}
impl<K, V> Debug for VecMap<K, V>
where
K: Debug,
V: Debug,
{
fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
fmt.debug_map()
.entries(self.iter().map(|&(ref k, ref v)| (k, v)))
.finish()
}
}
impl<K, V> Default for VecMap<K, V> {
fn default() -> Self {
Self::new()
}
}
impl<K, V> VecMap<K, V> {
pub fn new() -> Self {
Self { items: vec![] }
}
pub fn iter(&self) -> impl Iterator<Item = &(K, V)> {
self.items.iter()
}
}
impl<K, V> VecMap<K, V>
where
K: Eq,
{
pub fn get_mut<Q>(&mut self, k: &Q) -> Option<&mut V>
where
K: Borrow<Q>,
Q: Eq + ?Sized,
{
self.items
.iter_mut()
.find(|(ki, _)| ki.borrow() == k)
.map(|(_, v)| v)
}
pub fn get<Q>(&self, k: &Q) -> Option<&V>
where
K: Borrow<Q>,
Q: Eq + ?Sized,
{
self.items
.iter()
.find(|(ki, _)| ki.borrow() == k)
.map(|(_, v)| v)
}
pub fn insert(&mut self, k: K, mut v: V) -> Option<V> {
if let Some(vi) = self.get_mut(&k) {
core::mem::swap(vi, &mut v);
return Some(v);
}
self.items.push((k, v));
None
}
}

View file

@ -1,3 +1,5 @@
pub mod containers;
pub mod router;
pub mod rusqlite_thread_pool;
pub fn add(left: u64, right: u64) -> u64 {

82
rs/src/router.rs Normal file
View file

@ -0,0 +1,82 @@
use crate::containers::VecMap;
use std::collections::HashMap;
use url::Url;
use urlpattern::{UrlPattern, UrlPatternInit, UrlPatternMatchInput};
pub type PathParams = HashMap<String, Option<String>>;
struct UrlPatternWithInput {
pathname: String,
pattern: UrlPattern,
}
impl PartialEq for UrlPatternWithInput {
fn eq(&self, other: &Self) -> bool {
self.pathname == other.pathname
}
}
impl Eq for UrlPatternWithInput {
}
pub struct Router<T> {
patterns: VecMap<UrlPatternWithInput, VecMap<String, T>>,
}
impl<T> Router<T> {
pub fn new() -> Self {
Self {
patterns: VecMap::new(),
}
}
pub fn register(&mut self, method: String, pathname: String, value: T) {
let upwi = UrlPatternWithInput {
pathname: pathname.clone(),
pattern: UrlPattern::parse(
UrlPatternInit {
pathname: Some(pathname),
..Default::default()
},
Default::default(),
)
.unwrap(),
};
if let Some(methods) = self.patterns.get_mut(&upwi) {
methods.insert(method, value);
} else {
let mut methods = VecMap::new();
methods.insert(method, value);
self.patterns.insert(upwi, methods);
}
}
pub fn get(
&self,
method: &str,
url: &str,
) -> Result<(&T, PathParams), u16> {
let url = match Url::parse(url) {
Ok(u) => u,
Err(_) => match Url::parse(&format!("http://example.com{url}")) {
Ok(u) => u,
Err(_) => return Err(400),
},
};
for (upwi, methods) in self.patterns.iter() {
let pattern = &upwi.pattern;
let result = pattern.exec(UrlPatternMatchInput::Url(url.clone()));
let pathGroups = match result {
Ok(Some(res)) => res.pathname.groups,
_ => continue,
};
if let Some(t) = methods.get(method) {
return Ok((t, pathGroups));
}
return Err(405);
}
Err(404)
}
}

390
shelves/Cargo.lock generated
View file

@ -17,6 +17,15 @@ version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
[[package]]
name = "aho-corasick"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"memchr",
]
[[package]]
name = "async-channel"
version = "2.3.1"
@ -35,6 +44,8 @@ version = "0.0.0"
dependencies = [
"async-channel",
"rusqlite",
"url",
"urlpattern",
]
[[package]]
@ -44,6 +55,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d6fd624c75e18b3b4c6b9caf42b1afe24437daaee904069137d8bab077be8b8"
dependencies = [
"axum-core",
"axum-macros",
"bytes",
"form_urlencoded",
"futures-util",
@ -91,6 +103,17 @@ dependencies = [
"tracing",
]
[[package]]
name = "axum-macros"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "604fde5e028fea851ce1d8570bbdc034bec850d157f7569d10f347d06808c05c"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "backtrace"
version = "0.3.74"
@ -148,6 +171,17 @@ version = "0.8.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
[[package]]
name = "displaydoc"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "event-listener"
version = "5.4.0"
@ -340,6 +374,145 @@ dependencies = [
"tower-service",
]
[[package]]
name = "icu_collections"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526"
dependencies = [
"displaydoc",
"yoke",
"zerofrom",
"zerovec",
]
[[package]]
name = "icu_locid"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637"
dependencies = [
"displaydoc",
"litemap",
"tinystr",
"writeable",
"zerovec",
]
[[package]]
name = "icu_locid_transform"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e"
dependencies = [
"displaydoc",
"icu_locid",
"icu_locid_transform_data",
"icu_provider",
"tinystr",
"zerovec",
]
[[package]]
name = "icu_locid_transform_data"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e"
[[package]]
name = "icu_normalizer"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f"
dependencies = [
"displaydoc",
"icu_collections",
"icu_normalizer_data",
"icu_properties",
"icu_provider",
"smallvec",
"utf16_iter",
"utf8_iter",
"write16",
"zerovec",
]
[[package]]
name = "icu_normalizer_data"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516"
[[package]]
name = "icu_properties"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5"
dependencies = [
"displaydoc",
"icu_collections",
"icu_locid_transform",
"icu_properties_data",
"icu_provider",
"tinystr",
"zerovec",
]
[[package]]
name = "icu_properties_data"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569"
[[package]]
name = "icu_provider"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9"
dependencies = [
"displaydoc",
"icu_locid",
"icu_provider_macros",
"stable_deref_trait",
"tinystr",
"writeable",
"yoke",
"zerofrom",
"zerovec",
]
[[package]]
name = "icu_provider_macros"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "idna"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e"
dependencies = [
"idna_adapter",
"smallvec",
"utf8_iter",
]
[[package]]
name = "idna_adapter"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71"
dependencies = [
"icu_normalizer",
"icu_properties",
]
[[package]]
name = "itoa"
version = "1.0.14"
@ -363,6 +536,12 @@ dependencies = [
"vcpkg",
]
[[package]]
name = "litemap"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104"
[[package]]
name = "log"
version = "0.4.25"
@ -470,6 +649,35 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "regex"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "rusqlite"
version = "0.33.0"
@ -589,6 +797,12 @@ dependencies = [
"windows-sys",
]
[[package]]
name = "stable_deref_trait"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
[[package]]
name = "syn"
version = "2.0.98"
@ -606,6 +820,27 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
[[package]]
name = "synstructure"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tinystr"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f"
dependencies = [
"displaydoc",
"zerovec",
]
[[package]]
name = "tokio"
version = "1.43.0"
@ -680,12 +915,88 @@ dependencies = [
"once_cell",
]
[[package]]
name = "unic-char-property"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221"
dependencies = [
"unic-char-range",
]
[[package]]
name = "unic-char-range"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc"
[[package]]
name = "unic-common"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc"
[[package]]
name = "unic-ucd-ident"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e230a37c0381caa9219d67cf063aa3a375ffed5bf541a452db16e744bdab6987"
dependencies = [
"unic-char-property",
"unic-char-range",
"unic-ucd-version",
]
[[package]]
name = "unic-ucd-version"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4"
dependencies = [
"unic-common",
]
[[package]]
name = "unicode-ident"
version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034"
[[package]]
name = "url"
version = "2.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60"
dependencies = [
"form_urlencoded",
"idna",
"percent-encoding",
]
[[package]]
name = "urlpattern"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70acd30e3aa1450bc2eece896ce2ad0d178e9c079493819301573dae3c37ba6d"
dependencies = [
"regex",
"serde",
"unic-ucd-ident",
"url",
]
[[package]]
name = "utf16_iter"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246"
[[package]]
name = "utf8_iter"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
[[package]]
name = "vcpkg"
version = "0.2.15"
@ -770,3 +1081,82 @@ name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "write16"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936"
[[package]]
name = "writeable"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
[[package]]
name = "yoke"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40"
dependencies = [
"serde",
"stable_deref_trait",
"yoke-derive",
"zerofrom",
]
[[package]]
name = "yoke-derive"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154"
dependencies = [
"proc-macro2",
"quote",
"syn",
"synstructure",
]
[[package]]
name = "zerofrom"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e"
dependencies = [
"zerofrom-derive",
]
[[package]]
name = "zerofrom-derive"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808"
dependencies = [
"proc-macro2",
"quote",
"syn",
"synstructure",
]
[[package]]
name = "zerovec"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079"
dependencies = [
"yoke",
"zerofrom",
"zerovec-derive",
]
[[package]]
name = "zerovec-derive"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
dependencies = [
"proc-macro2",
"quote",
"syn",
]

View file

@ -9,7 +9,7 @@ path = "backend/main.rs"
[dependencies]
tokio = { version = "1.43.0", features = ["rt-multi-thread", "fs", "net"] }
axum = { version = "0.8.1", features = ["http1"] }
axum = { version = "0.8.1", features = ["http1", "macros"] }
http = "1.2.0"
atelier = { path = "../rs" }

View file

@ -1,4 +1,6 @@
use std::net::SocketAddr;
use std::pin::Pin;
use std::sync::Arc;
use axum::handler::HandlerWithoutStateExt;
use axum::response::IntoResponse;
@ -20,17 +22,22 @@ fn init(connection: &mut rusqlite::Connection) -> rusqlite::Result<()> {
type Request = axum::extract::Request;
type Response = axum::response::Response;
type Handler = Box<dyn FnMut(Request) -> Box<dyn Future<Output = Response>>>;
type Handler = Box<
dyn Fn(Request) -> Pin<Box<dyn Future<Output = Response> + Send + 'static>>
+ Send
+ Sync
+ 'static,
>;
type Router = atelier::router::Router<Handler>;
fn make_handler<Fut, F>(f: F) -> Handler
where
Fut: Future<Output = Response>,
F: FnMut(Request) -> Fut + Clone + 'static,
Fut: Future<Output = Response> + Send + 'static,
F: FnMut(Request) -> Fut + Clone + Send + Sync + 'static,
{
Box::new(move |req| {
let mut f = f.clone();
Box::new(async move { f(req).await })
Box::pin(async move { f(req).await })
})
}
@ -43,26 +50,26 @@ fn make_router() -> Router {
macro_rules! r {
($m:expr, $p:expr, $h:expr) => {
router.register($m, $p, make_handler($h))
router.register($m.to_string(), $p.to_string(), make_handler($h))
};
}
r!("get", "/hello", get_hello);
r!("GET", "/hello", get_hello);
router
}
async fn serve(
dbs: Dbs,
router: &Router,
router: Arc<Router>,
req: axum::extract::Request,
) -> axum::response::Response {
let method = req.method().as_str();
let uri = format!("{}", req.uri());
let handler = match router.get(method, uri) {
(Some(h), _) => h,
(None, Some(sc)) => {
let (handler, pathParams) = match router.get(method, &uri) {
Ok(h) => h,
Err(sc) => {
return (http::status::StatusCode::from_u16(sc).unwrap(), "")
.into_response()
},
@ -85,14 +92,15 @@ async fn go() -> Result<()> {
let addr = "127.0.0.1:8333".parse::<SocketAddr>()?;
let listener = TcpListener::bind(addr).await?;
let router = make_router();
let serve = move |req| {
let router = Arc::new(make_router());
let s = move |req: Request| {
let tx = tx.clone();
let router = router.clone();
serve(tx, router, req)
serve(tx, router.clone(), req)
};
axum::serve(listener, serve.into_make_service()).await?;
axum::serve(listener, s.into_make_service()).await?;
Ok(())
}