2025-08-08 16:51:26 +00:00
|
|
|
use std::{net::SocketAddr, path::Path, sync::Arc};
|
2025-07-04 22:15:52 +00:00
|
|
|
|
2025-07-04 00:00:11 +00:00
|
|
|
use axum::{
|
2025-08-03 20:46:03 +00:00
|
|
|
Json, Router,
|
2025-08-08 16:51:26 +00:00
|
|
|
extract::{ConnectInfo, DefaultBodyLimit, Request},
|
2025-07-04 00:00:11 +00:00
|
|
|
routing::{get, post},
|
|
|
|
|
};
|
2025-08-08 16:51:26 +00:00
|
|
|
use axum_server::tls_rustls::RustlsConfig;
|
|
|
|
|
use hyper::body::Incoming;
|
|
|
|
|
use hyper_util::rt::{TokioExecutor, TokioIo};
|
|
|
|
|
use tokio::{
|
|
|
|
|
net::TcpListener,
|
|
|
|
|
sync::{Mutex, mpsc},
|
|
|
|
|
};
|
|
|
|
|
use tokio_rustls::{
|
|
|
|
|
TlsAcceptor,
|
|
|
|
|
rustls::{
|
|
|
|
|
ServerConfig,
|
|
|
|
|
pki_types::{CertificateDer, PrivateKeyDer, pem::PemObject},
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
use tower::MakeService;
|
2025-07-04 00:00:11 +00:00
|
|
|
use tower_http::limit::RequestBodyLimitLayer;
|
2025-08-08 16:51:26 +00:00
|
|
|
use tower_service::Service;
|
2025-07-04 00:00:11 +00:00
|
|
|
|
|
|
|
|
use crate::{
|
2025-08-06 21:09:37 +00:00
|
|
|
JocalService,
|
2025-07-06 20:56:21 +00:00
|
|
|
discovery::register_device,
|
2025-08-03 20:46:03 +00:00
|
|
|
transfer::{prepare_upload, receive_upload},
|
2025-07-04 00:00:11 +00:00
|
|
|
};
|
|
|
|
|
|
2025-08-06 21:09:37 +00:00
|
|
|
impl JocalService {
|
2025-08-03 20:46:03 +00:00
|
|
|
pub async fn start_http_server(&self, stop_rx: mpsc::Receiver<()>) -> crate::error::Result<()> {
|
|
|
|
|
let app = self.create_router();
|
2025-07-08 22:46:31 +00:00
|
|
|
// TODO: make addr config
|
2025-08-07 22:36:25 +00:00
|
|
|
let addr = SocketAddr::from(([0, 0, 0, 0], self.config.device.port));
|
2025-08-08 16:51:26 +00:00
|
|
|
let (key, cert) = self.config.ssl();
|
2025-07-04 00:00:11 +00:00
|
|
|
|
2025-08-08 16:51:26 +00:00
|
|
|
let ssl_config = rustls_server_config(key, cert);
|
|
|
|
|
|
|
|
|
|
// let stop = Arc::new(Mutex::new(stop_rx));
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
loop {
|
|
|
|
|
let tower_service = app.clone();
|
|
|
|
|
let tls_acceptor = acceptor.clone();
|
|
|
|
|
let stop = stop.clone();
|
|
|
|
|
let mut stop = stop.lock().await;
|
|
|
|
|
|
|
|
|
|
tokio::select! {
|
|
|
|
|
// Wait for new tcp connection
|
|
|
|
|
Ok((cnx, addr)) = listener.accept() => {
|
|
|
|
|
tokio::spawn(async move {
|
|
|
|
|
// Wait for tls handshake to happen
|
|
|
|
|
let Ok(stream) = tls_acceptor.accept(cnx).await else {
|
|
|
|
|
log::error!("error during tls handshake connection from {}", addr);
|
|
|
|
|
return;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Hyper has its own `AsyncRead` and `AsyncWrite` traits and doesn't use tokio.
|
|
|
|
|
// `TokioIo` converts between them.
|
|
|
|
|
let stream = TokioIo::new(stream);
|
|
|
|
|
|
|
|
|
|
// Hyper also has its own `Service` trait and doesn't use tower. We can use
|
|
|
|
|
// `hyper::service::service_fn` to create a hyper `Service` that calls our app
|
|
|
|
|
// through `tower::Service::call`.
|
|
|
|
|
let hyper_service =
|
|
|
|
|
hyper::service::service_fn(move |request: Request<Incoming>| {
|
|
|
|
|
// We have to clone `tower_service` because hyper's `Service` uses `&self`
|
|
|
|
|
// whereas tower's `Service` requires `&mut self`.
|
|
|
|
|
//
|
|
|
|
|
// We don't need to call `poll_ready` since `Router` is always ready.
|
|
|
|
|
tower_service.clone().call(request)
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
let ret = hyper_util::server::conn::auto::Builder::new(TokioExecutor::new())
|
|
|
|
|
.serve_connection_with_upgrades(stream, hyper_service)
|
|
|
|
|
.await;
|
|
|
|
|
|
|
|
|
|
if let Err(err) = ret {
|
|
|
|
|
log::error!("error serving connection from {}: {}", addr, err);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
_ = stop.recv() => {
|
|
|
|
|
log::info!("stopping http server");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
axum_server::bind_rustls(addr, ssl_config)
|
|
|
|
|
.serve(app.into_make_service_with_connect_info::<SocketAddr>())
|
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
|
|
// axum::serve(
|
|
|
|
|
// listener,
|
|
|
|
|
// app.into_make_service_with_connect_info::<SocketAddr>(),
|
|
|
|
|
// )
|
|
|
|
|
// .with_graceful_shutdown(shutdown(stop_rx))
|
|
|
|
|
// .await?;
|
|
|
|
|
|
2025-07-04 00:00:11 +00:00
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-03 20:46:03 +00:00
|
|
|
fn create_router(&self) -> Router {
|
2025-07-04 00:00:11 +00:00
|
|
|
let device = self.device.clone();
|
|
|
|
|
Router::new()
|
|
|
|
|
.route("/api/localsend/v2/register", post(register_device))
|
|
|
|
|
.route(
|
|
|
|
|
"/api/localsend/v2/info",
|
2025-07-08 16:59:03 +00:00
|
|
|
get(move || async move { Json(device) }),
|
2025-07-04 00:00:11 +00:00
|
|
|
)
|
2025-08-03 20:46:03 +00:00
|
|
|
.route("/api/localsend/v2/prepare-upload", post(prepare_upload))
|
|
|
|
|
.route("/api/localsend/v2/upload", post(receive_upload))
|
2025-07-04 00:00:11 +00:00
|
|
|
.layer(DefaultBodyLimit::disable())
|
|
|
|
|
.layer(RequestBodyLimitLayer::new(1024 * 1024 * 1024))
|
2025-07-06 20:56:21 +00:00
|
|
|
.with_state(self.clone())
|
2025-07-04 00:00:11 +00:00
|
|
|
}
|
|
|
|
|
}
|
2025-07-06 23:02:11 +00:00
|
|
|
|
|
|
|
|
async fn shutdown(mut rx: mpsc::Receiver<()>) {
|
|
|
|
|
rx.recv().await.unwrap_or_default()
|
|
|
|
|
}
|
2025-08-08 16:51:26 +00:00
|
|
|
|
|
|
|
|
fn rustls_server_config(key: impl AsRef<Path>, cert: impl AsRef<Path>) -> RustlsConfig {
|
|
|
|
|
let key = match PrivateKeyDer::from_pem_file(&key) {
|
|
|
|
|
Ok(k) => k,
|
|
|
|
|
Err(e) => {
|
|
|
|
|
let path = key.as_ref().display();
|
|
|
|
|
log::error!("could not open {path} for reading; got {e:?}");
|
|
|
|
|
panic!()
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let certs = CertificateDer::pem_file_iter(cert)
|
|
|
|
|
.unwrap()
|
|
|
|
|
.map(|cert| cert.unwrap())
|
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
|
|
let mut config = ServerConfig::builder()
|
|
|
|
|
.with_no_client_auth()
|
|
|
|
|
.with_single_cert(certs, key)
|
|
|
|
|
.expect("bad certificate/key");
|
|
|
|
|
|
|
|
|
|
config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()];
|
|
|
|
|
|
|
|
|
|
RustlsConfig::from_config(config.into())
|
|
|
|
|
}
|