summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock20
-rw-r--r--Cargo.toml2
-rw-r--r--server/respack_http/Cargo.toml12
-rw-r--r--server/respack_http/src/main.rs105
4 files changed, 137 insertions, 2 deletions
diff --git a/Cargo.lock b/Cargo.lock
index ede4719..0c55365 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1301,7 +1301,7 @@ dependencies = [
"log",
"presser",
"thiserror 1.0.69",
- "windows 0.54.0",
+ "windows 0.58.0",
]
[[package]]
@@ -1371,6 +1371,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc"
[[package]]
+name = "hex"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
+
+[[package]]
name = "hexf-parse"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2682,6 +2688,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832"
[[package]]
+name = "respack_http"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "clap 4.5.32",
+ "env_logger",
+ "hex",
+ "log",
+ "weareshared",
+]
+
+[[package]]
name = "rgb"
version = "0.8.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index 722342f..0840b4c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,3 +1,3 @@
[workspace]
-members = ["shared", "server", "client", "import", "cli"]
+members = ["shared", "server", "server/respack_http", "client", "import", "cli"]
resolver = "3"
diff --git a/server/respack_http/Cargo.toml b/server/respack_http/Cargo.toml
new file mode 100644
index 0000000..47f9ccd
--- /dev/null
+++ b/server/respack_http/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "respack_http"
+version = "0.1.0"
+edition = "2024"
+
+[dependencies]
+anyhow = "1.0.97"
+clap = { version = "4.5.32", features = ["derive"] }
+env_logger = "0.11.7"
+log = "0.4.26"
+weareshared = { path = "../../shared" }
+hex = "0.4.3"
diff --git a/server/respack_http/src/main.rs b/server/respack_http/src/main.rs
new file mode 100644
index 0000000..be703bd
--- /dev/null
+++ b/server/respack_http/src/main.rs
@@ -0,0 +1,105 @@
+use anyhow::{Result, anyhow};
+use clap::Parser;
+use log::{error, warn};
+use std::{
+ io::{BufRead, BufReader, BufWriter, Write},
+ marker::PhantomData,
+ net::{IpAddr, SocketAddr, TcpListener, TcpStream},
+ path::PathBuf,
+ sync::Arc,
+ thread::spawn,
+};
+use weareshared::{packets::Resource, store::ResourceStore};
+
+#[derive(Parser, Debug)]
+struct Args {
+ #[arg(short, long, default_value = "::")]
+ bind_addr: IpAddr,
+ #[arg(short, long, default_value = "28556")]
+ port: u16,
+
+ pack: PathBuf,
+}
+
+fn main() -> Result<()> {
+ env_logger::init_from_env("LOG");
+ let args = Args::parse();
+ let listener = TcpListener::bind(SocketAddr::new(args.bind_addr, args.port))?;
+
+ let store = Arc::new(ResourceStore::new_respack_file(&args.pack)?);
+
+ loop {
+ let (conn, _addr) = listener.accept()?;
+ let store = store.clone();
+ spawn(move || {
+ if let Err(e) = handle_conn(conn, store) {
+ warn!("{e}")
+ }
+ });
+ }
+}
+
+fn handle_conn(conn: TcpStream, store: Arc<ResourceStore>) -> Result<()> {
+ let mut conn_read = BufReader::new(conn.try_clone()?);
+ let mut conn_write = BufWriter::new(conn);
+
+ let mut buf = String::new();
+ while !buf.ends_with("\r\n\r\n") {
+ conn_read.read_line(&mut buf)?;
+ }
+
+ let mut lines = buf.lines();
+ let mut status = lines
+ .next()
+ .ok_or(anyhow!("HTTP status line missing"))?
+ .split(" ");
+ let _method = status.next().ok_or(anyhow!("HTTP method missing"))?;
+ let path = status.next().ok_or(anyhow!("HTTP path missing"))?;
+ let _httpver = status.next().ok_or(anyhow!("HTTP version missing"))?;
+
+ let path = path
+ .strip_prefix("/")
+ .ok_or(anyhow!("path does not start on /"))?;
+
+ let (code, ty, data) = handle_request(path, &store);
+
+ write!(conn_write, "HTTP/1.0 {code} OK\r\n")?;
+ write!(conn_write, "content-type: {ty}\r\n")?;
+ write!(conn_write, "server: write! macros\r\n")?;
+ write!(conn_write, "content-length: {}\r\n", data.len())?;
+ write!(conn_write, "\r\n")?;
+ conn_write.write_all(&data)?;
+ conn_write.flush()?;
+
+ Ok(())
+}
+
+fn handle_request(path: &str, store: &ResourceStore) -> (u16, &'static str, Vec<u8>) {
+ if path == "entry" {
+ if let ResourceStore::Respack(pack) = store {
+ let pack = pack.lock().unwrap();
+ if let Some(entry) = pack.entry() {
+ (200, "application/x.weareresource.id", entry.0.to_vec())
+ } else {
+ (404, "text/plain", b"No entry found".to_vec())
+ }
+ } else {
+ unreachable!()
+ }
+ } else if path.len() == 64 {
+ let mut hash = [0; 32];
+ if let Err(_) = hex::decode_to_slice(path, &mut hash) {
+ return (400, "text/plain", b"Invalid hash format".to_vec());
+ }
+ match store.get_raw(Resource(hash, PhantomData)) {
+ Ok(Some(res)) => (200, "application/x.weareresource", res),
+ Ok(None) => (404, "text/plain", b"Not found".to_vec()),
+ Err(e) => {
+ error!("{e}");
+ (500, "text/plain", b"Internal server error".to_vec())
+ }
+ }
+ } else {
+ (400, "text/plain", b"Bad path".to_vec())
+ }
+}