refactor: move events into controller files
CI / format (push) Has been cancelled
CI / test (push) Has been cancelled
CI / packaging (push) Has been cancelled

This commit is contained in:
Tien Do Nam
2026-07-13 03:28:54 +02:00
parent bd42deb22c
commit 2ed3a712b2
7 changed files with 139 additions and 144 deletions
+87 -2
View File
@@ -5,20 +5,105 @@ use crate::http::dto_v2::{
use crate::http::server::collect_to_json::CollectToJson;
use crate::http::server::controller::check_pin;
use crate::http::server::error::AppError;
use crate::http::server::event::{PrepareUploadDecisionV2, ServerEventV2, SessionEndReasonV2};
use crate::http::server::query::parse_query;
use crate::http::server::response::{empty_body, BoxedBody, JsonResponse};
use crate::http::server::session::{FileStatusV2, SessionFileV2, SessionStateV2, UploadSessionV2};
use crate::http::server::{AppState, RequestClientInfo, V2State};
use crate::model::transfer::FileDto;
use bytes::Bytes;
use http_body_util::BodyExt;
use hyper::body::Incoming;
use hyper::{Request, Response, StatusCode};
use std::collections::HashMap;
use std::collections::{HashMap, HashSet};
use std::net::IpAddr;
use std::sync::Arc;
use tokio::sync::{mpsc, oneshot};
use uuid::Uuid;
/// Events emitted by the v2 HTTP server that must be handled by the application.
#[derive(Debug)]
pub enum ServerEventV2 {
/// A device registered itself via `POST /api/localsend/v2/register`.
Register {
/// The IP address of the remote device.
ip: IpAddr,
/// The device information sent by the remote device.
info: RegisterDtoV2,
},
/// A sender requests to upload files via `POST /api/localsend/v2/prepare-upload`.
///
/// The application must answer on `decision_tx`.
/// Dropping `decision_tx` results in a 500 response.
PrepareUpload {
/// The IP address of the sender.
ip: IpAddr,
/// The device information of the sender.
info: RegisterDtoV2,
/// The offered files, mapped by file ID.
files: HashMap<String, FileDto>,
/// Channel to send the decision (accept all, a subset, or decline).
decision_tx: oneshot::Sender<PrepareUploadDecisionV2>,
},
/// An accepted file is being uploaded via `POST /api/localsend/v2/upload`.
///
/// Binary chunks arrive on `binary_rx` until the channel is closed.
/// The application should compare the number of received bytes with `file.size`
/// and report the result on `result_tx` which determines the HTTP response
/// (200 on `Ok`, 500 on `Err` or when `result_tx` is dropped).
FileUpload {
/// The session ID of the upload session.
session_id: String,
/// The ID of the file being uploaded.
file_id: String,
/// The metadata of the file being uploaded.
file: FileDto,
/// Channel receiving the binary chunks of the file.
binary_rx: mpsc::Receiver<Bytes>,
/// Channel to report whether the file was processed successfully.
result_tx: oneshot::Sender<Result<(), String>>,
},
/// An upload session ended.
SessionEnd {
/// The session ID of the ended session.
session_id: String,
/// Why the session ended.
reason: SessionEndReasonV2,
},
}
/// The application's decision for a prepare-upload request.
#[derive(Debug)]
pub enum PrepareUploadDecisionV2 {
/// Accept the given file IDs (a subset of the offered files).
/// An empty set responds with 204 (no file transfer needed).
Accept(HashSet<String>),
/// Decline the request (403).
Decline,
}
/// Why an upload session ended.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum SessionEndReasonV2 {
/// All accepted files reached a final state (finished or failed).
Finished,
/// The sender cancelled the session via `POST /api/localsend/v2/cancel`.
Cancelled,
}
/// Channel capacity for file upload chunks (provides backpressure).
const UPLOAD_CHANNEL_CAPACITY: usize = 16;
+45 -1
View File
@@ -3,7 +3,6 @@ use crate::http::dto_v2::{
};
use crate::http::server::controller::check_pin;
use crate::http::server::error::AppError;
use crate::http::server::event::WebSendEvent;
use crate::http::server::query::parse_query;
use crate::http::server::response::{full_body, BoxedBody, JsonResponse};
use crate::http::server::{AppState, RequestClientInfo};
@@ -23,6 +22,51 @@ use tokio::sync::{mpsc, oneshot, Mutex};
use tokio_stream::wrappers::ReceiverStream;
use tokio_stream::StreamExt;
/// Events emitted by the web send (download API) endpoints that must be handled
/// by the application. Web send can be enabled independently of the v2 endpoints.
#[derive(Debug)]
pub enum WebSendEvent {
/// A web client requests to download the shared files
/// via `POST /api/localsend/v2/prepare-download`.
///
/// The application must answer on `decision_tx`.
/// Dropping `decision_tx` results in a 500 response.
PrepareDownload {
/// The IP address of the web client.
ip: IpAddr,
/// The ID of the download session that is created when accepted.
session_id: String,
/// The `User-Agent` header of the web client.
user_agent: Option<String>,
/// Channel to send the decision (`true` to accept, `false` to decline).
decision_tx: oneshot::Sender<bool>,
},
/// An accepted web client downloads a file via `GET /api/localsend/v2/download`.
///
/// The application must respond on `content_tx` with a channel receiving
/// the binary chunks of the file. The response body advertises `file.size`
/// bytes, so the application should send exactly that many bytes before
/// closing the channel (closing it earlier aborts the download).
/// Dropping `content_tx` results in a 500 response.
FileDownload {
/// The ID of the download session.
session_id: String,
/// The ID of the file being downloaded.
file_id: String,
/// The metadata of the file being downloaded.
file: FileDto,
/// Channel to provide the receiver on which the file content arrives.
content_tx: oneshot::Sender<mpsc::Receiver<Bytes>>,
},
}
const INDEX_HTML: &str = include_str!("../../../../assets/web/index.html");
const MAIN_JS: &str = include_str!("../../../../assets/web/main.js");
const ERROR_403_HTML: &str = include_str!("../../../../assets/web/error-403.html");
-135
View File
@@ -1,135 +0,0 @@
use crate::http::dto_v2::RegisterDtoV2;
use crate::model::transfer::FileDto;
use bytes::Bytes;
use std::collections::{HashMap, HashSet};
use std::net::IpAddr;
use tokio::sync::{mpsc, oneshot};
/// Events emitted by the v2 HTTP server that must be handled by the application.
#[derive(Debug)]
pub enum ServerEventV2 {
/// A device registered itself via `POST /api/localsend/v2/register`.
Register {
/// The IP address of the remote device.
ip: IpAddr,
/// The device information sent by the remote device.
info: RegisterDtoV2,
},
/// A sender requests to upload files via `POST /api/localsend/v2/prepare-upload`.
///
/// The application must answer on `decision_tx`.
/// Dropping `decision_tx` results in a 500 response.
PrepareUpload {
/// The IP address of the sender.
ip: IpAddr,
/// The device information of the sender.
info: RegisterDtoV2,
/// The offered files, mapped by file ID.
files: HashMap<String, FileDto>,
/// Channel to send the decision (accept all, a subset, or decline).
decision_tx: oneshot::Sender<PrepareUploadDecisionV2>,
},
/// An accepted file is being uploaded via `POST /api/localsend/v2/upload`.
///
/// Binary chunks arrive on `binary_rx` until the channel is closed.
/// The application should compare the number of received bytes with `file.size`
/// and report the result on `result_tx` which determines the HTTP response
/// (200 on `Ok`, 500 on `Err` or when `result_tx` is dropped).
FileUpload {
/// The session ID of the upload session.
session_id: String,
/// The ID of the file being uploaded.
file_id: String,
/// The metadata of the file being uploaded.
file: FileDto,
/// Channel receiving the binary chunks of the file.
binary_rx: mpsc::Receiver<Bytes>,
/// Channel to report whether the file was processed successfully.
result_tx: oneshot::Sender<Result<(), String>>,
},
/// An upload session ended.
SessionEnd {
/// The session ID of the ended session.
session_id: String,
/// Why the session ended.
reason: SessionEndReasonV2,
},
}
/// Events emitted by the web send (download API) endpoints that must be handled
/// by the application. Web send can be enabled independently of the v2 endpoints.
#[derive(Debug)]
pub enum WebSendEvent {
/// A web client requests to download the shared files
/// via `POST /api/localsend/v2/prepare-download`.
///
/// The application must answer on `decision_tx`.
/// Dropping `decision_tx` results in a 500 response.
PrepareDownload {
/// The IP address of the web client.
ip: IpAddr,
/// The ID of the download session that is created when accepted.
session_id: String,
/// The `User-Agent` header of the web client.
user_agent: Option<String>,
/// Channel to send the decision (`true` to accept, `false` to decline).
decision_tx: oneshot::Sender<bool>,
},
/// An accepted web client downloads a file via `GET /api/localsend/v2/download`.
///
/// The application must respond on `content_tx` with a channel receiving
/// the binary chunks of the file. The response body advertises `file.size`
/// bytes, so the application should send exactly that many bytes before
/// closing the channel (closing it earlier aborts the download).
/// Dropping `content_tx` results in a 500 response.
FileDownload {
/// The ID of the download session.
session_id: String,
/// The ID of the file being downloaded.
file_id: String,
/// The metadata of the file being downloaded.
file: FileDto,
/// Channel to provide the receiver on which the file content arrives.
content_tx: oneshot::Sender<mpsc::Receiver<Bytes>>,
},
}
/// The application's decision for a prepare-upload request.
#[derive(Debug)]
pub enum PrepareUploadDecisionV2 {
/// Accept the given file IDs (a subset of the offered files).
/// An empty set responds with 204 (no file transfer needed).
Accept(HashSet<String>),
/// Decline the request (403).
Decline,
}
/// Why an upload session ended.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum SessionEndReasonV2 {
/// All accepted files reached a final state (finished or failed).
Finished,
/// The sender cancelled the session via `POST /api/localsend/v2/cancel`.
Cancelled,
}
+4 -3
View File
@@ -2,18 +2,19 @@ mod client_cert_verifier;
mod collect_to_json;
mod controller;
mod error;
pub mod event;
mod query;
mod response;
mod session;
pub use crate::http::server::controller::web::{WebSendConfig, WebSendI18n};
pub use crate::http::server::controller::v2::{
PrepareUploadDecisionV2, ServerEventV2, SessionEndReasonV2,
};
pub use crate::http::server::controller::web::{WebSendConfig, WebSendEvent, WebSendI18n};
use crate::crypto::cert::public_key_from_cert_der;
use crate::http::server::client_cert_verifier::CustomClientCertVerifier;
use crate::http::server::controller::web::WebPageState;
use crate::http::server::error::AppError;
use crate::http::server::event::ServerEventV2;
use crate::http::server::response::BoxedBody;
use crate::http::server::session::SessionStateV2;
use crate::http::state::ClientInfo;
+1 -1
View File
@@ -7,7 +7,7 @@ mod webrtc;
use crate::crypto::token;
use crate::http::client::LsHttpClientV3;
use crate::http::dto::{PrepareUploadRequestDto, ProtocolType, RegisterDto};
use crate::http::server::event::{PrepareUploadDecisionV2, ServerEventV2};
use crate::http::server::{PrepareUploadDecisionV2, ServerEventV2};
use crate::http::server::{ServerConfigV2, TlsConfig};
use crate::model::discovery::DeviceType;
use crate::webrtc::signaling::{ClientInfo, WsServerMessage};
+1 -1
View File
@@ -3,7 +3,7 @@
use localsend::http::client::{ClientError, LsHttpClientV2};
use localsend::http::dto::ProtocolType;
use localsend::http::dto_v2::{PrepareUploadRequestDtoV2, ProtocolTypeV2, RegisterDtoV2};
use localsend::http::server::event::{PrepareUploadDecisionV2, ServerEventV2, SessionEndReasonV2};
use localsend::http::server::{PrepareUploadDecisionV2, ServerEventV2, SessionEndReasonV2};
use localsend::http::server::{start_with_port, ServerConfigV2};
use localsend::http::state::ClientInfo;
use localsend::model::transfer::FileDto;
+1 -1
View File
@@ -3,7 +3,7 @@
use bytes::Bytes;
use localsend::http::client::{ClientError, LsHttpClientV2};
use localsend::http::dto::ProtocolType;
use localsend::http::server::event::{ServerEventV2, WebSendEvent};
use localsend::http::server::{ServerEventV2, WebSendEvent};
use localsend::http::server::{start_with_port, ServerConfigV2, WebSendConfig, WebSendI18n};
use localsend::http::state::ClientInfo;
use localsend::model::transfer::FileDto;