mirror of
https://github.com/Xevion/dynamic-preauth.git
synced 2025-12-15 02:11:39 -06:00
- Add bacon.toml for Rust development watching with keybindings - Update Justfile to use bacon for dev watching - Configure frontend to build to ./public for backend serving - Improve Justfile organization with comments and better task separation - Add dev-backend and dev-frontend tasks for separate workflows - Minor formatting fix in backend/src/state.rs
123 lines
3.3 KiB
Rust
123 lines
3.3 KiB
Rust
use std::collections::HashMap;
|
|
use std::path::{Path, PathBuf};
|
|
use std::sync::LazyLock;
|
|
|
|
use salvo::{http::cookie::Cookie, Response};
|
|
use tokio::sync::Mutex;
|
|
|
|
use crate::errors::{AppError, Result};
|
|
use crate::models::{BuildLogs, Executable, ExecutableJson, Session};
|
|
|
|
pub static STORE: LazyLock<Mutex<State>> = LazyLock::new(|| Mutex::new(State::new()));
|
|
|
|
#[derive(Default)]
|
|
pub struct State {
|
|
pub sessions: HashMap<u32, Session>,
|
|
pub executables: HashMap<String, Executable>,
|
|
pub build_logs: Option<BuildLogs>,
|
|
pub build_log_url: Option<String>,
|
|
}
|
|
|
|
impl State {
|
|
pub fn new() -> Self {
|
|
Self {
|
|
sessions: HashMap::new(),
|
|
executables: HashMap::new(),
|
|
build_logs: None,
|
|
build_log_url: None,
|
|
}
|
|
}
|
|
|
|
pub fn add_executable(&mut self, exe_type: &str, exe_path: &str) -> Result<()> {
|
|
let path = Path::new(exe_path);
|
|
|
|
let data = std::fs::read(path).map_err(|_| AppError::ExecutableNotFound {
|
|
path: PathBuf::from(exe_path),
|
|
})?;
|
|
|
|
let pattern = "a".repeat(1024);
|
|
let name = path
|
|
.file_stem()
|
|
.and_then(|s| s.to_str())
|
|
.unwrap_or_default()
|
|
.to_string();
|
|
|
|
let key_start = Executable::search_pattern(&data, pattern.as_bytes(), 0)
|
|
.ok_or_else(|| AppError::KeyPatternNotFound { name: name.clone() })?;
|
|
let key_end = key_start + pattern.len();
|
|
|
|
let extension = path
|
|
.extension()
|
|
.and_then(|s| s.to_str())
|
|
.unwrap_or_default()
|
|
.to_string();
|
|
|
|
let exe = Executable {
|
|
data,
|
|
filename: path
|
|
.file_name()
|
|
.and_then(|s| s.to_str())
|
|
.unwrap_or_default()
|
|
.to_string(),
|
|
name,
|
|
extension,
|
|
key_start,
|
|
key_end,
|
|
};
|
|
|
|
self.executables.insert(exe_type.to_string(), exe);
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn new_session(&mut self, res: &mut Response) -> u32 {
|
|
let id: u32 = rand::random();
|
|
|
|
let now = chrono::Utc::now();
|
|
self.sessions.insert(
|
|
id,
|
|
Session {
|
|
id,
|
|
downloads: Vec::new(),
|
|
last_seen: now,
|
|
last_request: now,
|
|
first_seen: now,
|
|
tx: None,
|
|
},
|
|
);
|
|
|
|
tracing::info!("New session created: {}", id);
|
|
|
|
res.add_cookie(
|
|
Cookie::build(("Session", id.to_string()))
|
|
.http_only(true)
|
|
.partitioned(true)
|
|
.secure(cfg!(debug_assertions) == false)
|
|
.path("/")
|
|
// Use SameSite=None only in development
|
|
.same_site(if cfg!(debug_assertions) {
|
|
salvo::http::cookie::SameSite::None
|
|
} else {
|
|
salvo::http::cookie::SameSite::Strict
|
|
})
|
|
.permanent()
|
|
.build(),
|
|
);
|
|
|
|
id
|
|
}
|
|
|
|
pub fn executable_json(&self) -> Vec<ExecutableJson> {
|
|
let mut executables = Vec::new();
|
|
|
|
for (key, exe) in &self.executables {
|
|
executables.push(ExecutableJson {
|
|
id: key.to_string(),
|
|
size: exe.data.len(),
|
|
filename: exe.filename.clone(),
|
|
});
|
|
}
|
|
|
|
executables
|
|
}
|
|
}
|