summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortcmal <me@aria.rip>2024-09-08 18:46:43 +0100
committertcmal <me@aria.rip>2024-09-12 16:30:09 +0100
commit9a7042df7f9a7ad0324c4442ae918c2a4a442966 (patch)
tree81324f03df3ddaac9db7d1e01ef5b319bef659ef
parentddc97e9361137fde6f0894ffa729d285159662fa (diff)
Add framework for separate printer control thread
-rw-r--r--Cargo.lock10
-rw-r--r--Cargo.toml3
-rw-r--r--crates/control/Cargo.toml9
-rw-r--r--crates/control/src/lib.rs81
-rw-r--r--crates/web/Cargo.toml1
-rw-r--r--crates/web/src/main.rs20
6 files changed, 116 insertions, 8 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 91e2a64..b1aee2b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -18,9 +18,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
+name = "argonaut-control"
+version = "0.1.0"
+dependencies = [
+ "tokio",
+ "tracing",
+ "tracing-subscriber",
+]
+
+[[package]]
name = "argonaut-web"
version = "0.1.0"
dependencies = [
+ "argonaut-control",
"axum",
"serde",
"tokio",
diff --git a/Cargo.toml b/Cargo.toml
index b90f2bb..e7c3e21 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,7 +1,8 @@
[workspace]
resolver = "2"
members = [
- "crates/web"
+ "crates/control",
+ "crates/web"
]
[workspace.dependencies]
diff --git a/crates/control/Cargo.toml b/crates/control/Cargo.toml
new file mode 100644
index 0000000..6934db5
--- /dev/null
+++ b/crates/control/Cargo.toml
@@ -0,0 +1,9 @@
+[package]
+name = "argonaut-control"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+tokio = { workspace = true }
+tracing = { workspace = true }
+tracing-subscriber = { workspace = true }
diff --git a/crates/control/src/lib.rs b/crates/control/src/lib.rs
new file mode 100644
index 0000000..5691cf2
--- /dev/null
+++ b/crates/control/src/lib.rs
@@ -0,0 +1,81 @@
+//! Printer control related code
+//!
+//! To ensure the volume of web requests doesn't mess with printing, communication with the printer is done
+//! in a separate thread, on its own async executor.
+//!
+//! The main server spawns this thread by creating a [`Handle`] and communicates by sending [messages](crate::Message) over an MPSC channel.
+
+use std::{
+ mem::ManuallyDrop,
+ thread::{self, JoinHandle},
+};
+use tokio::{
+ runtime,
+ sync::mpsc::{self, Receiver, Sender},
+};
+use tracing::info;
+
+/// The maximum number of messages to buffer before 'blocking' new ones
+/// This provides a form of backpressure
+const CHANNEL_CAPACITY: usize = 100;
+
+/// A control message sent from the API to the printer control thread
+pub enum Message {
+ Quit,
+}
+
+/// A handle to the printer control thread, allowing for communication.
+pub struct Handle {
+ cmd_send: Sender<Message>,
+ thread_handle: ManuallyDrop<JoinHandle<()>>,
+}
+
+impl Handle {
+ /// Spawn a printer control thread, returning a handle
+ pub fn spawn() -> Self {
+ let (send, recv) = mpsc::channel(CHANNEL_CAPACITY);
+
+ let state = State { cmd_recv: recv };
+ let thread_handle = thread::spawn(move || {
+ let rt = runtime::Builder::new_current_thread()
+ .build()
+ .expect("error spawning printer control thread");
+
+ rt.block_on(async move { state.entrypoint().await });
+ });
+
+ Self {
+ cmd_send: send,
+ thread_handle: ManuallyDrop::new(thread_handle),
+ }
+ }
+}
+
+impl Drop for Handle {
+ fn drop(&mut self) {
+ let _ = self.cmd_send.blocking_send(Message::Quit);
+ unsafe {
+ info!("waiting for printer thread to exit...");
+ ManuallyDrop::take(&mut self.thread_handle)
+ .join()
+ .expect("error joining printer thread")
+ };
+ }
+}
+
+/// The state held by the printer control thread
+pub struct State {
+ cmd_recv: Receiver<Message>,
+}
+
+impl State {
+ /// The entrypoint of the printer control thread
+ pub async fn entrypoint(mut self) {
+ info!("listening for events");
+ while let Some(msg) = self.cmd_recv.recv().await {
+ match msg {
+ Message::Quit => break,
+ }
+ }
+ }
+}
diff --git a/crates/web/Cargo.toml b/crates/web/Cargo.toml
index 62a3504..2528a0a 100644
--- a/crates/web/Cargo.toml
+++ b/crates/web/Cargo.toml
@@ -4,6 +4,7 @@ version = "0.1.0"
edition = "2021"
[dependencies]
+argonaut-control = { path = "../control" }
axum = "0.7.5"
tracing = { workspace = true }
tracing-subscriber = { workspace = true }
diff --git a/crates/web/src/main.rs b/crates/web/src/main.rs
index f641ce0..d80b232 100644
--- a/crates/web/src/main.rs
+++ b/crates/web/src/main.rs
@@ -1,17 +1,23 @@
-use axum::{
- http::StatusCode,
- routing::{get, post},
- Json, Router,
-};
-use serde::{Deserialize, Serialize};
+use std::sync::Arc;
+
+use axum::{routing::get, Router};
+
+pub use argonaut_control::Handle as PrinterThread;
+use tracing::info;
#[tokio::main(flavor = "current_thread")]
async fn main() {
tracing_subscriber::fmt::init();
- let app = Router::new().route("/", get(root));
+ let printer_thread = PrinterThread::spawn();
+ let printer_thread = Arc::new(printer_thread);
+ let app = Router::new()
+ .route("/", get(root))
+ .with_state(printer_thread);
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
+
+ info!("init completed, listening");
axum::serve(listener, app).await.unwrap();
}