Preparing to move session into an extractor.

This commit is contained in:
Jeff Baskin 2025-04-19 07:57:16 -04:00
parent 9e6d407b69
commit bb70cc65e0
5 changed files with 146 additions and 38 deletions

82
Cargo.lock generated
View File

@ -106,7 +106,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"axum-core", "axum-core 0.4.5",
"bytes", "bytes",
"futures-util", "futures-util",
"http", "http",
@ -154,6 +154,25 @@ dependencies = [
"tracing", "tracing",
] ]
[[package]]
name = "axum-core"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68464cd0412f486726fb3373129ef5d2993f90c34bc2bc1c1e9943b2f4fc7ca6"
dependencies = [
"bytes",
"futures-core",
"http",
"http-body",
"http-body-util",
"mime",
"pin-project-lite",
"rustversion",
"sync_wrapper",
"tower-layer",
"tower-service",
]
[[package]] [[package]]
name = "axum-extra" name = "axum-extra"
version = "0.9.6" version = "0.9.6"
@ -161,7 +180,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c794b30c904f0a1c2fb7740f7df7f7972dfaa14ef6f57cb6178dc63e5dca2f04" checksum = "c794b30c904f0a1c2fb7740f7df7f7972dfaa14ef6f57cb6178dc63e5dca2f04"
dependencies = [ dependencies = [
"axum", "axum",
"axum-core", "axum-core 0.4.5",
"bytes", "bytes",
"cookie", "cookie",
"fastrand", "fastrand",
@ -228,9 +247,9 @@ checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.2.18" version = "1.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "525046617d8376e3db1deffb079e91cef90a89fc3ca5c185bbf8c9ecdd15cd5c" checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362"
dependencies = [ dependencies = [
"shlex", "shlex",
] ]
@ -257,9 +276,9 @@ dependencies = [
[[package]] [[package]]
name = "clap" name = "clap"
version = "4.5.35" version = "4.5.36"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8aa86934b44c19c50f87cc2790e19f54f7a67aedb64101c2e1a2e5ecfb73944" checksum = "2df961d8c8a0d08aa9945718ccf584145eee3f3aa06cddbeac12933781102e04"
dependencies = [ dependencies = [
"clap_builder", "clap_builder",
"clap_derive", "clap_derive",
@ -267,9 +286,9 @@ dependencies = [
[[package]] [[package]]
name = "clap_builder" name = "clap_builder"
version = "4.5.35" version = "4.5.36"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2414dbb2dd0695280da6ea9261e327479e9d37b0630f6b53ba2a11c60c679fd9" checksum = "132dbda40fb6753878316a489d5a1242a8ef2f0d9e47ba01c951ea8aa7d013a5"
dependencies = [ dependencies = [
"anstream", "anstream",
"anstyle", "anstyle",
@ -407,6 +426,17 @@ version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
[[package]]
name = "futures-macro"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "futures-task" name = "futures-task"
version = "0.3.31" version = "0.3.31"
@ -420,9 +450,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
dependencies = [ dependencies = [
"futures-core", "futures-core",
"futures-macro",
"futures-task", "futures-task",
"pin-project-lite", "pin-project-lite",
"pin-utils", "pin-utils",
"slab",
] ]
[[package]] [[package]]
@ -608,9 +640,9 @@ dependencies = [
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.171" version = "0.2.172"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
[[package]] [[package]]
name = "lock_api" name = "lock_api"
@ -677,6 +709,7 @@ dependencies = [
"rand", "rand",
"tokio", "tokio",
"tower", "tower",
"tower-cookies",
"uuid", "uuid",
] ]
@ -785,9 +818,9 @@ dependencies = [
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.94" version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
@ -950,6 +983,15 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "slab"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
dependencies = [
"autocfg",
]
[[package]] [[package]]
name = "smallvec" name = "smallvec"
version = "1.15.0" version = "1.15.0"
@ -1077,6 +1119,22 @@ dependencies = [
"tracing", "tracing",
] ]
[[package]]
name = "tower-cookies"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "151b5a3e3c45df17466454bb74e9ecedecc955269bdedbf4d150dfa393b55a36"
dependencies = [
"axum-core 0.5.2",
"cookie",
"futures-util",
"http",
"parking_lot",
"pin-project-lite",
"tower-layer",
"tower-service",
]
[[package]] [[package]]
name = "tower-layer" name = "tower-layer"
version = "0.3.3" version = "0.3.3"

View File

@ -12,6 +12,7 @@ chrono = { version = "0.4.40", features = ["now"] }
clap = { version = "4.5.1", features = ["derive"] } clap = { version = "4.5.1", features = ["derive"] }
rand = "0.8.5" rand = "0.8.5"
tokio = { version = "1.36.0", features = ["full"] } tokio = { version = "1.36.0", features = ["full"] }
tower-cookies = "0.11.0"
uuid = { version = "1.8.0", features = ["v4"] } uuid = { version = "1.8.0", features = ["v4"] }
[dev-dependencies] [dev-dependencies]

View File

@ -107,7 +107,7 @@ mod replies {
#[derive(Clone)] #[derive(Clone)]
pub struct ClientRegistry { pub struct ClientRegistry {
registry: Arc<Mutex<HashMap<Uuid, Sender<Reply>>>>, registry: Arc<Mutex<HashMap<Uuid, Sender<Message>>>>,
} }
impl ClientRegistry { impl ClientRegistry {
@ -119,7 +119,7 @@ impl ClientRegistry {
fn get_id<'a>( fn get_id<'a>(
gen: &mut impl Iterator<Item = Uuid>, gen: &mut impl Iterator<Item = Uuid>,
data: &HashMap<Uuid, Sender<Reply>>, data: &HashMap<Uuid, Sender<Message>>,
) -> Uuid { ) -> Uuid {
let mut id = gen.next().unwrap(); let mut id = gen.next().unwrap();
while data.contains_key(&id) { while data.contains_key(&id) {
@ -128,7 +128,7 @@ impl ClientRegistry {
id.clone() id.clone()
} }
pub fn add(&mut self, tx: Sender<Reply>) -> Uuid { pub fn add(&mut self, tx: Sender<Message>) -> Uuid {
let mut reg = self.registry.lock().unwrap(); let mut reg = self.registry.lock().unwrap();
let mut gen_id = GenID::new(); let mut gen_id = GenID::new();
let id = ClientRegistry::get_id(&mut gen_id, &reg); let id = ClientRegistry::get_id(&mut gen_id, &reg);
@ -136,7 +136,7 @@ impl ClientRegistry {
id id
} }
fn send(&mut self, id: &Uuid, msg: Reply) { fn send(&mut self, id: &Uuid, msg: Message) {
let mut reg = self.registry.lock().unwrap(); let mut reg = self.registry.lock().unwrap();
let tx = reg.remove(id).unwrap(); let tx = reg.remove(id).unwrap();
tx.send(msg).unwrap(); tx.send(msg).unwrap();
@ -165,15 +165,15 @@ mod clientregistries {
fn send_from_client() { fn send_from_client() {
let mut reg = ClientRegistry::new(); let mut reg = ClientRegistry::new();
let count = 10; let count = 10;
let mut rxs: HashMap<Uuid, Receiver<Reply>> = HashMap::new(); let mut rxs: HashMap<Uuid, Receiver<Message>> = HashMap::new();
for _ in 0..count { for _ in 0..count {
let (tx, rx) = channel::<Reply>(); let (tx, rx) = channel::<Message>();
let id = reg.add(tx); let id = reg.add(tx);
rxs.insert(id, rx); rxs.insert(id, rx);
} }
assert_eq!(rxs.len(), count, "should have been {} receivers", count); assert_eq!(rxs.len(), count, "should have been {} receivers", count);
for (id, rx) in rxs.iter() { for (id, rx) in rxs.iter() {
let msg = create_reply(); let msg = Message::new(MsgType::Document);
reg.send(id, msg); reg.send(id, msg);
rx.recv_timeout(TIMEOUT).unwrap(); rx.recv_timeout(TIMEOUT).unwrap();
} }
@ -184,7 +184,7 @@ mod clientregistries {
#[test] #[test]
fn prevent_duplicates() { fn prevent_duplicates() {
let mut reg = ClientRegistry::new(); let mut reg = ClientRegistry::new();
let (tx, _rx) = channel::<Reply>(); let (tx, _rx) = channel::<Message>();
let existing = reg.add(tx); let existing = reg.add(tx);
let expected = Uuid::new_v4(); let expected = Uuid::new_v4();
let ids = [existing.clone(), expected.clone()]; let ids = [existing.clone(), expected.clone()];
@ -208,12 +208,12 @@ impl ClientLink {
} }
} }
pub fn send(&mut self, req: Request) -> Receiver<Reply> { pub fn send(&mut self, mut req: Message) -> Receiver<Message> {
let (tx, rx) = channel(); let (tx, rx) = channel();
let mut msg: Message = req.into(); //let mut msg: Message = req.into();
let id = self.registry.add(tx); let id = self.registry.add(tx);
msg.add_data("tx_id", id); req.add_data("tx_id", id);
self.tx.send(msg).unwrap(); self.tx.send(req).unwrap();
rx rx
} }
} }
@ -232,7 +232,7 @@ mod clientlinks {
let mut registry = ClientRegistry::new(); let mut registry = ClientRegistry::new();
let mut link = ClientLink::new(tx, registry.clone()); let mut link = ClientLink::new(tx, registry.clone());
let req = Request::new(None); let req = Request::new(None);
let rx_client = link.send(req); let rx_client = link.send(req.into());
let msg = rx.recv_timeout(TIMEOUT).unwrap(); let msg = rx.recv_timeout(TIMEOUT).unwrap();
match msg.get_msg_type() { match msg.get_msg_type() {
MsgType::ClientRequest => {} MsgType::ClientRequest => {}
@ -241,7 +241,7 @@ mod clientlinks {
match msg.get_data("tx_id") { match msg.get_data("tx_id") {
Some(result) => { Some(result) => {
let id = result.to_uuid().unwrap(); let id = result.to_uuid().unwrap();
registry.send(&id, create_reply()); registry.send(&id, msg.reply(MsgType::Document));
rx_client.recv().unwrap(); rx_client.recv().unwrap();
} }
None => unreachable!("should have had a seender id"), None => unreachable!("should have had a seender id"),
@ -319,11 +319,13 @@ impl Client {
fn document(&mut self, msg: Message) { fn document(&mut self, msg: Message) {
let initial_msg = self.return_to.remove(&msg.get_id()).unwrap(); let initial_msg = self.return_to.remove(&msg.get_id()).unwrap();
let tx_id = initial_msg.get_data("tx_id").unwrap().to_uuid().unwrap(); let tx_id = initial_msg.get_data("tx_id").unwrap().to_uuid().unwrap();
/*
let reply = Reply::new( let reply = Reply::new(
initial_msg.get_data("sess_id").unwrap().to_uuid().unwrap(), initial_msg.get_data("sess_id").unwrap().to_uuid().unwrap(),
msg.get_data("doc").unwrap().to_string(), msg.get_data("doc").unwrap().to_string(),
); )s
self.registry.send(&tx_id, reply); */
self.registry.send(&tx_id, initial_msg.reply(MsgType::Document));
} }
} }
@ -335,6 +337,7 @@ mod clients {
static TIMEOUT: Duration = Duration::from_millis(500); static TIMEOUT: Duration = Duration::from_millis(500);
/*
#[test] #[test]
fn start_client() { fn start_client() {
let sess_id1 = Uuid::new_v4(); let sess_id1 = Uuid::new_v4();
@ -348,7 +351,7 @@ mod clients {
); );
let mut link = Client::start(queue.clone()); let mut link = Client::start(queue.clone());
let req = get_root_with_session(&sess_id1); let req = get_root_with_session(&sess_id1);
let reply_rx = link.send(req); let reply_rx = link.send(req.into());
let send1 = rx.recv_timeout(TIMEOUT).unwrap(); let send1 = rx.recv_timeout(TIMEOUT).unwrap();
match send1.get_msg_type() { match send1.get_msg_type() {
MsgType::SessionValidate => {} MsgType::SessionValidate => {}
@ -376,7 +379,8 @@ mod clients {
document.add_data("doc", doc.clone()); document.add_data("doc", doc.clone());
queue.send(document).unwrap(); queue.send(document).unwrap();
let reply = reply_rx.recv_timeout(TIMEOUT).unwrap(); let reply = reply_rx.recv_timeout(TIMEOUT).unwrap();
assert_eq!(reply.get_session(), sess_id2); assert_eq!(reply.get_data("sess_id").unwrap().to_uuid().unwrap(), sess_id2);
assert_eq!(reply.get_content(), doc); assert_eq!(reply.get_data("doc").unwrap().to_string(), doc);
} }
*/
} }

View File

@ -10,8 +10,9 @@ use client::{Client, ClientLink, Reply, Request};
use clock::Clock; use clock::Clock;
use document::Document; use document::Document;
use field::Field; use field::Field;
use queue::Queue; use queue::{Message, MsgType, Queue};
use session::Session; use session::Session;
use uuid::Uuid;
#[derive(Clone)] #[derive(Clone)]
pub struct MoreThanText { pub struct MoreThanText {
@ -29,7 +30,21 @@ impl MoreThanText {
} }
} }
pub fn request<F>(&mut self, session: Option<F>) -> Reply pub fn validate_session<F>(&mut self, session: Option<F>) -> Uuid
where
F: Into<Field>,
{
let mut msg = Message::new(MsgType::SessionValidate);
match session {
Some(id) => msg.add_data("sess_id", id.into()),
None => {},
}
let rx = self.client_link.send(msg);
let reply = rx.recv().unwrap();
reply.get_data("sess_id").unwrap().to_uuid().unwrap()
}
pub fn request<F>(&mut self, session: Option<F>) -> Message
where where
F: Into<Field>, F: Into<Field>,
{ {
@ -38,7 +53,7 @@ impl MoreThanText {
None => None, None => None,
}; };
let req = Request::new(sess); let req = Request::new(sess);
let rx = self.client_link.send(req); let rx = self.client_link.send(req.into());
rx.recv().unwrap() rx.recv().unwrap()
} }
} }

View File

@ -1,8 +1,19 @@
use axum::{extract::State, response::IntoResponse, routing::get, Router}; use axum::{
async_trait,
extract::{Extension, FromRequestParts, State},
http::request::Parts,
response::IntoResponse,
routing::get,
RequestPartsExt,
Router,
};
use axum_extra::extract::cookie::{Cookie, CookieJar}; use axum_extra::extract::cookie::{Cookie, CookieJar};
use clap::Parser; use clap::Parser;
use morethantext::MoreThanText; use morethantext::MoreThanText;
use std::convert::Infallible;
use tokio::{spawn, sync::mpsc::channel}; use tokio::{spawn, sync::mpsc::channel};
use tower_cookies::{CookieManagerLayer, Cookies};
use uuid::Uuid;
const LOCALHOST: &str = "127.0.0.1"; const LOCALHOST: &str = "127.0.0.1";
const SESSION_KEY: &str = "sessionid"; const SESSION_KEY: &str = "sessionid";
@ -33,11 +44,30 @@ async fn main() {
.unwrap(); .unwrap();
} }
struct SessionID;
#[async_trait]
impl<S> FromRequestParts<S> for SessionID
where
S: Send + Sync,
{
type Rejection = Infallible;
async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
let cookies = parts.extract::<Extension<Cookies>>();
Ok(Self {})
}
}
async fn create_app(state: MoreThanText) -> Router { async fn create_app(state: MoreThanText) -> Router {
Router::new().route("/", get(mtt_conn)).with_state(state) Router::new().route("/", get(mtt_conn)).with_state(state)
} }
async fn mtt_conn(jar: CookieJar, state: State<MoreThanText>) -> impl IntoResponse { async fn mtt_conn(
jar: CookieJar,
sess_id: SessionID,
state: State<MoreThanText>,
) -> impl IntoResponse {
let sid = match jar.get(SESSION_KEY) { let sid = match jar.get(SESSION_KEY) {
Some(cookie) => Some(cookie.value().to_string()), Some(cookie) => Some(cookie.value().to_string()),
None => None, None => None,
@ -48,9 +78,9 @@ async fn mtt_conn(jar: CookieJar, state: State<MoreThanText>) -> impl IntoRespon
tx.send(state.clone().request(sess_info)).await.unwrap(); tx.send(state.clone().request(sess_info)).await.unwrap();
}); });
let reply = rx.recv().await.unwrap(); let reply = rx.recv().await.unwrap();
let cookie = Cookie::build((SESSION_KEY, reply.get_session().to_string())); let cookie = Cookie::build((SESSION_KEY, reply.get_data("sess_id").unwrap().to_string()));
let cookies = jar.add(cookie); let cookies = jar.add(cookie);
(cookies, reply.get_content()) (cookies, reply.get_data("dov").unwrap().to_string())
} }
#[cfg(test)] #[cfg(test)]