Compare commits

..

1 Commits

Author SHA1 Message Date
0147956b5f chore: Most refactoring except appstate, backuperror, and main workspace
Still needs a massive go-over because there shouldn't be anything referencing tauri in any of the workspaces except the original one

Signed-off-by: quexeky <git@quexeky.dev>
2025-10-09 07:46:17 +11:00
152 changed files with 8525 additions and 2487 deletions

2
.gitignore vendored
View File

@ -30,5 +30,3 @@ src-tauri/perf*
/*.AppImage
/squashfs-root
/target/

View File

@ -1,14 +0,0 @@
[workspace]
members = [
"client",
"database",
"src-tauri",
"process",
"remote",
"utils",
"cloud_saves",
"download_manager",
"games",
]
resolver = "3"

View File

@ -1,47 +0,0 @@
use std::{ffi::OsStr, path::PathBuf, process::{Command, Stdio}, sync::LazyLock};
use log::info;
pub static COMPAT_INFO: LazyLock<Option<CompatInfo>> = LazyLock::new(create_new_compat_info);
pub static UMU_LAUNCHER_EXECUTABLE: LazyLock<Option<PathBuf>> = LazyLock::new(|| {
let x = get_umu_executable();
info!("{:?}", &x);
x
});
#[derive(Clone)]
pub struct CompatInfo {
pub umu_installed: bool,
}
fn create_new_compat_info() -> Option<CompatInfo> {
#[cfg(target_os = "windows")]
return None;
let has_umu_installed = UMU_LAUNCHER_EXECUTABLE.is_some();
Some(CompatInfo {
umu_installed: has_umu_installed,
})
}
const UMU_BASE_LAUNCHER_EXECUTABLE: &str = "umu-run";
const UMU_INSTALL_DIRS: [&str; 4] = ["/app/share", "/use/local/share", "/usr/share", "/opt"];
fn get_umu_executable() -> Option<PathBuf> {
if check_executable_exists(UMU_BASE_LAUNCHER_EXECUTABLE) {
return Some(PathBuf::from(UMU_BASE_LAUNCHER_EXECUTABLE));
}
for dir in UMU_INSTALL_DIRS {
let p = PathBuf::from(dir).join(UMU_BASE_LAUNCHER_EXECUTABLE);
if check_executable_exists(&p) {
return Some(p);
}
}
None
}
fn check_executable_exists<P: AsRef<OsStr>>(exec: P) -> bool {
let has_umu_installed = Command::new(exec).stdout(Stdio::null()).output();
has_umu_installed.is_ok()
}

View File

@ -1,4 +0,0 @@
pub mod autostart;
pub mod user;
pub mod app_status;
pub mod compat;

View File

@ -1,27 +0,0 @@
use std::fmt::Display;
use serde_with::SerializeDisplay;
#[derive(Debug, SerializeDisplay, Clone, Copy)]
pub enum BackupError {
InvalidSystem,
NotFound,
ParseError,
}
impl Display for BackupError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let s = match self {
BackupError::InvalidSystem => "Attempted to generate path for invalid system",
BackupError::NotFound => "Could not generate or find path",
BackupError::ParseError => "Failed to parse path",
};
write!(f, "{}", s)
}
}

View File

@ -1,14 +0,0 @@
#![feature(nonpoison_mutex)]
#![feature(sync_nonpoison)]
use std::sync::{LazyLock, nonpoison::Mutex};
use crate::process_manager::ProcessManager;
pub static PROCESS_MANAGER: LazyLock<Mutex<ProcessManager>> =
LazyLock::new(|| Mutex::new(ProcessManager::new()));
pub mod error;
pub mod format;
pub mod process_handlers;
pub mod process_manager;

2142
src-tauri/Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,137 +1,14 @@
[package]
name = "drop-app"
version = "0.3.3"
description = "The client application for the open-source, self-hosted game distribution platform Drop"
authors = ["Drop OSS"]
edition = "2024"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[target."cfg(any(target_os = \"macos\", windows, target_os = \"linux\"))".dependencies]
tauri-plugin-single-instance = { version = "2.0.0", features = ["deep-link"] }
[lib]
# The `_lib` suffix may seem redundant but it is necessary
# to make the lib name unique and wouldn't conflict with the bin name.
# This seems to be only an issue on Windows, see https://github.com/rust-lang/cargo/issues/8519
name = "drop_app_lib"
crate-type = ["staticlib", "cdylib", "rlib"]
rustflags = ["-C", "target-feature=+aes,+sse2"]
[build-dependencies]
tauri-build = { version = "2.0.0", features = [] }
[dependencies]
tauri-plugin-shell = "2.2.1"
serde_json = "1"
rayon = "1.10.0"
webbrowser = "1.0.2"
url = "2.5.2"
tauri-plugin-deep-link = "2"
log = "0.4.22"
hex = "0.4.3"
tauri-plugin-dialog = "2"
http = "1.1.0"
urlencoding = "2.1.3"
md5 = "0.7.0"
chrono = "0.4.38"
tauri-plugin-os = "2"
boxcar = "0.2.7"
umu-wrapper-lib = "0.1.0"
tauri-plugin-autostart = "2.0.0"
shared_child = "1.0.1"
serde_with = "3.12.0"
slice-deque = "0.3.0"
throttle_my_fn = "0.2.6"
parking_lot = "0.12.3"
atomic-instant-full = "0.1.0"
cacache = "13.1.0"
http-serde = "2.1.1"
reqwest-middleware = "0.4.0"
reqwest-middleware-cache = "0.1.1"
deranged = "=0.4.0"
droplet-rs = "0.7.3"
gethostname = "1.0.1"
zstd = "0.13.3"
tar = "0.4.44"
rand = "0.9.1"
regex = "1.11.1"
tempfile = "3.19.1"
schemars = "0.8.22"
sha1 = "0.10.6"
dirs = "6.0.0"
whoami = "1.6.0"
filetime = "0.2.25"
walkdir = "2.5.0"
known-folders = "1.2.0"
native_model = { version = "0.6.4", features = ["rmp_serde_1_3"], git = "https://github.com/Drop-OSS/native_model.git"}
tauri-plugin-opener = "2.4.0"
bitcode = "0.6.6"
reqwest-websocket = "0.5.0"
futures-lite = "2.6.0"
page_size = "0.6.0"
sysinfo = "0.36.1"
humansize = "2.1.3"
tokio-util = { version = "0.7.16", features = ["io"] }
futures-core = "0.3.31"
bytes = "1.10.1"
# tailscale = { path = "./tailscale" }
# Workspaces
client = { path = "../client" }
database = { path = "../database" }
process = { path = "../process" }
remote = { path = "../remote" }
utils = { path = "../utils" }
[dependencies.dynfmt]
version = "0.1.5"
features = ["curly"]
[dependencies.tauri]
version = "2.7.0"
features = ["protocol-asset", "tray-icon"]
[dependencies.tokio]
version = "1.40.0"
features = ["rt", "tokio-macros", "signal"]
[dependencies.log4rs]
version = "1.3.0"
features = ["console_appender", "file_appender"]
[dependencies.rustix]
version = "0.38.37"
features = ["fs"]
[dependencies.uuid]
version = "1.10.0"
features = ["v4", "fast-rng", "macro-diagnostics"]
[dependencies.rustbreak]
version = "2"
features = ["other_errors"] # You can also use "yaml_enc" or "bin_enc"
[dependencies.reqwest]
version = "0.12.22"
default-features = false
features = [
"json",
"http2",
"blocking",
"rustls-tls",
"native-tls-alpn",
"rustls-tls-native-roots",
"stream",
[workspace]
members = [
"client",
"database",
"src-tauri",
"process",
"remote",
"utils",
"cloud_saves",
"download_manager",
"games",
]
[dependencies.serde]
version = "1"
features = ["derive", "rc"]
[profile.release]
lto = true
codegen-units = 1
panic = 'abort'
resolver = "3"

View File

@ -0,0 +1,3 @@
pub mod autostart;
pub mod user;
pub mod app_status;

View File

@ -11,3 +11,7 @@ pub struct User {
profile_picture_object_id: String,
}
#[derive(Clone)]
pub struct CompatInfo {
umu_installed: bool,
}

View File

@ -11,7 +11,6 @@ regex = "1.11.3"
rustix = "1.1.2"
serde = "1.0.228"
serde_json = "1.0.145"
serde_with = "3.15.0"
tar = "0.4.44"
tempfile = "3.23.0"
uuid = "1.18.1"

View File

@ -0,0 +1,5 @@
pub enum BackupError {
InvalidSystem,
ParseError,
NotFound
}

View File

@ -6,7 +6,7 @@ use database::{borrow_db_checked, borrow_db_mut_checked, ApplicationTransientSta
use log::{debug, error, warn};
use remote::{auth::generate_authorization_header, error::RemoteAccessError, requests::generate_url, utils::DROP_CLIENT_SYNC};
use serde::{Deserialize, Serialize};
use tauri::{AppHandle, Emitter};
use tauri::AppHandle;
use utils::app_emit;
use crate::{downloads::error::LibraryError, state::{GameStatusManager, GameStatusWithTransient}};

View File

@ -8,11 +8,10 @@ chrono = "0.4.42"
client = { version = "0.1.0", path = "../client" }
database = { version = "0.1.0", path = "../database" }
dynfmt = "0.1.5"
games = { version = "0.1.0", path = "../games" }
log = "0.4.28"
page_size = "0.6.0"
serde = "1.0.228"
serde_with = "3.15.0"
shared_child = "1.1.1"
tauri = "2.8.5"
tauri-plugin-opener = "2.5.0"
utils = { version = "0.1.0", path = "../utils" }

View File

@ -12,8 +12,7 @@ pub enum ProcessError {
FormatError(String), // String errors supremacy
InvalidPlatform,
OpenerError(tauri_plugin_opener::Error),
InvalidArguments(String),
FailedLaunch(String),
InvalidArguments(String)
}
impl Display for ProcessError {
@ -27,12 +26,7 @@ impl Display for ProcessError {
ProcessError::InvalidPlatform => "This game cannot be played on the current platform",
ProcessError::FormatError(error) => &format!("Could not format template: {error:?}"),
ProcessError::OpenerError(error) => &format!("Could not open directory: {error:?}"),
ProcessError::InvalidArguments(arguments) => {
&format!("Invalid arguments in command {arguments}")
}
ProcessError::FailedLaunch(game_id) => {
&format!("Drop detected that the game {game_id} may have failed to launch properly")
}
ProcessError::InvalidArguments(arguments) => &format!("Invalid arguments in command {arguments}"),
};
write!(f, "{s}")
}

View File

@ -0,0 +1,4 @@
pub mod process_manager;
pub mod process_handlers;
pub mod format;
pub mod error;

View File

@ -1,6 +1,12 @@
use client::compat::{COMPAT_INFO, UMU_LAUNCHER_EXECUTABLE};
use std::{
ffi::OsStr,
path::PathBuf,
process::{Command, Stdio},
sync::LazyLock,
};
use database::{platform::Platform, Database, DownloadableMetadata, GameVersion};
use log::debug;
use log::{debug, info};
use crate::{error::ProcessError, process_manager::ProcessHandler};
@ -18,11 +24,36 @@ impl ProcessHandler for NativeGameLauncher {
Ok(format!("\"{}\" {}", launch_command, args.join(" ")))
}
fn valid_for_platform(&self, _db: &Database, _target: &Platform) -> bool {
fn valid_for_platform(&self, _db: &Database, _state: &AppState, _target: &Platform) -> bool {
true
}
}
pub static UMU_LAUNCHER_EXECUTABLE: LazyLock<Option<PathBuf>> = LazyLock::new(|| {
let x = get_umu_executable();
info!("{:?}", &x);
x
});
const UMU_BASE_LAUNCHER_EXECUTABLE: &str = "umu-run";
const UMU_INSTALL_DIRS: [&str; 4] = ["/app/share", "/use/local/share", "/usr/share", "/opt"];
fn get_umu_executable() -> Option<PathBuf> {
if check_executable_exists(UMU_BASE_LAUNCHER_EXECUTABLE) {
return Some(PathBuf::from(UMU_BASE_LAUNCHER_EXECUTABLE));
}
for dir in UMU_INSTALL_DIRS {
let p = PathBuf::from(dir).join(UMU_BASE_LAUNCHER_EXECUTABLE);
if check_executable_exists(&p) {
return Some(p);
}
}
None
}
fn check_executable_exists<P: AsRef<OsStr>>(exec: P) -> bool {
let has_umu_installed = Command::new(exec).stdout(Stdio::null()).output();
has_umu_installed.is_ok()
}
pub struct UMULauncher;
impl ProcessHandler for UMULauncher {
fn create_launch_process(
@ -52,8 +83,8 @@ impl ProcessHandler for UMULauncher {
))
}
fn valid_for_platform(&self, _db: &Database, _target: &Platform) -> bool {
let Some(compat_info) = &*COMPAT_INFO else {
fn valid_for_platform(&self, _db: &Database, state: &AppState, _target: &Platform) -> bool {
let Some(ref compat_info) = state.compat_info else {
return false;
};
compat_info.umu_installed
@ -93,7 +124,7 @@ impl ProcessHandler for AsahiMuvmLauncher {
#[allow(unreachable_code)]
#[allow(unused_variables)]
fn valid_for_platform(&self, _db: &Database, _target: &Platform) -> bool {
fn valid_for_platform(&self, _db: &Database, state: &AppState, _target: &Platform) -> bool {
#[cfg(not(target_os = "linux"))]
return false;
@ -105,7 +136,7 @@ impl ProcessHandler for AsahiMuvmLauncher {
return false;
}
let Some(compat_info) = &*COMPAT_INFO else {
let Some(ref compat_info) = state.compat_info else {
return false;
};

View File

@ -1,31 +1,27 @@
use std::{
collections::HashMap,
fs::{OpenOptions, create_dir_all},
io,
io::{self},
path::PathBuf,
process::{Command, ExitStatus},
str::FromStr,
sync::Arc,
sync::{Arc, Mutex},
thread::spawn,
time::{Duration, SystemTime},
};
use database::{
ApplicationTransientStatus, Database, DownloadType, DownloadableMetadata, GameDownloadStatus,
GameVersion, borrow_db_checked, borrow_db_mut_checked, db::DATA_ROOT_DIR, platform::Platform,
};
use database::{borrow_db_checked, borrow_db_mut_checked, db::DATA_ROOT_DIR, platform::Platform, ApplicationTransientStatus, Database, DownloadType, DownloadableMetadata, GameDownloadStatus, GameVersion};
use dynfmt::Format;
use dynfmt::SimpleCurlyFormat;
use games::state::GameStatusManager;
use log::{debug, info, warn};
use serde::{Deserialize, Serialize};
use shared_child::SharedChild;
use tauri::{AppHandle, Emitter, Manager};
use tauri_plugin_opener::OpenerExt;
use utils::lock;
use crate::{error::ProcessError, format::DropFormatArgs, process_handlers::{AsahiMuvmLauncher, NativeGameLauncher, UMULauncher}};
use crate::{
PROCESS_MANAGER,
error::ProcessError,
format::DropFormatArgs,
process_handlers::{AsahiMuvmLauncher, NativeGameLauncher, UMULauncher},
};
pub struct RunningProcess {
handle: Arc<SharedChild>,
@ -37,6 +33,7 @@ pub struct ProcessManager<'a> {
current_platform: Platform,
log_output_dir: PathBuf,
processes: HashMap<String, RunningProcess>,
app_handle: AppHandle,
game_launchers: Vec<(
(Platform, Platform),
&'a (dyn ProcessHandler + Sync + Send + 'static),
@ -44,7 +41,7 @@ pub struct ProcessManager<'a> {
}
impl ProcessManager<'_> {
pub fn new() -> Self {
pub fn new(app_handle: AppHandle) -> Self {
let log_output_dir = DATA_ROOT_DIR.join("logs");
ProcessManager {
@ -57,6 +54,7 @@ impl ProcessManager<'_> {
#[cfg(target_os = "linux")]
current_platform: Platform::Linux,
app_handle,
processes: HashMap::new(),
log_output_dir,
game_launchers: vec![
@ -104,16 +102,21 @@ impl ProcessManager<'_> {
self.log_output_dir.join(game_id)
}
fn on_process_finish(
&mut self,
game_id: String,
result: Result<ExitStatus, std::io::Error>,
) -> Result<(), ProcessError> {
pub fn open_process_logs(&mut self, game_id: String) -> Result<(), ProcessError> {
let dir = self.get_log_dir(game_id);
self.app_handle
.opener()
.open_path(dir.display().to_string(), None::<&str>)
.map_err(ProcessError::OpenerError)?;
Ok(())
}
fn on_process_finish(&mut self, game_id: String, result: Result<ExitStatus, std::io::Error>) {
if !self.processes.contains_key(&game_id) {
warn!(
"process on_finish was called, but game_id is no longer valid. finished with result: {result:?}"
);
return Ok(());
return;
}
debug!("process for {:?} exited with {:?}", &game_id, result);
@ -122,7 +125,7 @@ impl ProcessManager<'_> {
Some(process) => process,
None => {
info!("Attempted to stop process {game_id} which didn't exist");
return Ok(());
return;
}
};
@ -160,8 +163,7 @@ impl ProcessManager<'_> {
&& (elapsed.as_secs() <= 2 || result.map_or(true, |r| !r.success()))
{
warn!("drop detected that the game {game_id} may have failed to launch properly");
return Err(ProcessError::FailedLaunch(game_id));
// let _ = self.app_handle.emit("launch_external_error", &game_id);
let _ = self.app_handle.emit("launch_external_error", &game_id);
}
let version_data = match db_handle.applications.game_versions.get(&game_id) {
@ -172,19 +174,18 @@ impl ProcessManager<'_> {
let status = GameStatusManager::fetch_state(&game_id, &db_handle);
// TODO
// push_game_update(
// &self.app_handle,
// &game_id,
// Some(version_data.clone()),
// status,
// );
Ok(())
push_game_update(
&self.app_handle,
&game_id,
Some(version_data.clone()),
status,
);
}
fn fetch_process_handler(
&self,
db_lock: &Database,
state: &AppState,
target_platform: &Platform,
) -> Result<&(dyn ProcessHandler + Send + Sync), ProcessError> {
Ok(self
@ -194,20 +195,23 @@ impl ProcessManager<'_> {
let (e_current, e_target) = e.0;
e_current == self.current_platform
&& e_target == *target_platform
&& e.1.valid_for_platform(db_lock, target_platform)
&& e.1.valid_for_platform(db_lock, state, target_platform)
})
.ok_or(ProcessError::InvalidPlatform)?
.1)
}
pub fn valid_platform(&self, platform: &Platform) -> bool {
pub fn valid_platform(&self, platform: &Platform, state: &AppState) -> bool {
let db_lock = borrow_db_checked();
let process_handler = self.fetch_process_handler(&db_lock, platform);
let process_handler = self.fetch_process_handler(&db_lock, state, platform);
process_handler.is_ok()
}
/// Must be called through spawn as it is currently blocking
pub fn launch_process(&mut self, game_id: String) -> Result<(), ProcessError> {
pub fn launch_process(
&mut self,
game_id: String,
state: &AppState,
) -> Result<(), ProcessError> {
if self.processes.contains_key(&game_id) {
return Err(ProcessError::AlreadyRunning);
}
@ -289,7 +293,7 @@ impl ProcessManager<'_> {
let target_platform = game_version.platform;
let process_handler = self.fetch_process_handler(&db_lock, &target_platform)?;
let process_handler = self.fetch_process_handler(&db_lock, state, &target_platform)?;
let (launch, args) = match game_status {
GameDownloadStatus::Installed {
@ -363,17 +367,35 @@ impl ProcessManager<'_> {
.transient_statuses
.insert(meta.clone(), ApplicationTransientStatus::Running {});
// TODO
// push_game_update(
// &self.app_handle,
// &meta.id,
// None,
// (None, Some(ApplicationTransientStatus::Running {})),
// );
push_game_update(
&self.app_handle,
&meta.id,
None,
(None, Some(ApplicationTransientStatus::Running {})),
);
let wait_thread_handle = launch_process_handle.clone();
let wait_thread_apphandle = self.app_handle.clone();
let wait_thread_game_id = meta.clone();
spawn(move || {
let result: Result<ExitStatus, std::io::Error> = launch_process_handle.wait();
let app_state = wait_thread_apphandle.state::<Mutex<AppState>>();
let app_state_handle = lock!(app_state);
let mut process_manager_handle = app_state_handle
.process_manager
.lock()
.expect("Failed to lock onto process manager");
process_manager_handle.on_process_finish(wait_thread_game_id.id, result);
// As everything goes out of scope, they should get dropped
// But just to explicit about it
drop(process_manager_handle);
drop(app_state_handle);
});
self.processes.insert(
meta.id,
RunningProcess {
@ -382,12 +404,7 @@ impl ProcessManager<'_> {
manually_killed: false,
},
);
let result: Result<ExitStatus, std::io::Error> = launch_process_handle.wait();
PROCESS_MANAGER
.lock()
.on_process_finish(wait_thread_game_id.id, result)
Ok(())
}
}
@ -401,5 +418,5 @@ pub trait ProcessHandler: Send + 'static {
current_dir: &str,
) -> Result<String, ProcessError>;
fn valid_for_platform(&self, db: &Database, target: &Platform) -> bool;
fn valid_for_platform(&self, db: &Database, state: &AppState, target: &Platform) -> bool;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,137 @@
[package]
name = "drop-app"
version = "0.3.3"
description = "The client application for the open-source, self-hosted game distribution platform Drop"
authors = ["Drop OSS"]
edition = "2024"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[target."cfg(any(target_os = \"macos\", windows, target_os = \"linux\"))".dependencies]
tauri-plugin-single-instance = { version = "2.0.0", features = ["deep-link"] }
[lib]
# The `_lib` suffix may seem redundant but it is necessary
# to make the lib name unique and wouldn't conflict with the bin name.
# This seems to be only an issue on Windows, see https://github.com/rust-lang/cargo/issues/8519
name = "drop_app_lib"
crate-type = ["staticlib", "cdylib", "rlib"]
rustflags = ["-C", "target-feature=+aes,+sse2"]
[build-dependencies]
tauri-build = { version = "2.0.0", features = [] }
[dependencies]
tauri-plugin-shell = "2.2.1"
serde_json = "1"
rayon = "1.10.0"
webbrowser = "1.0.2"
url = "2.5.2"
tauri-plugin-deep-link = "2"
log = "0.4.22"
hex = "0.4.3"
tauri-plugin-dialog = "2"
http = "1.1.0"
urlencoding = "2.1.3"
md5 = "0.7.0"
chrono = "0.4.38"
tauri-plugin-os = "2"
boxcar = "0.2.7"
umu-wrapper-lib = "0.1.0"
tauri-plugin-autostart = "2.0.0"
shared_child = "1.0.1"
serde_with = "3.12.0"
slice-deque = "0.3.0"
throttle_my_fn = "0.2.6"
parking_lot = "0.12.3"
atomic-instant-full = "0.1.0"
cacache = "13.1.0"
http-serde = "2.1.1"
reqwest-middleware = "0.4.0"
reqwest-middleware-cache = "0.1.1"
deranged = "=0.4.0"
droplet-rs = "0.7.3"
gethostname = "1.0.1"
zstd = "0.13.3"
tar = "0.4.44"
rand = "0.9.1"
regex = "1.11.1"
tempfile = "3.19.1"
schemars = "0.8.22"
sha1 = "0.10.6"
dirs = "6.0.0"
whoami = "1.6.0"
filetime = "0.2.25"
walkdir = "2.5.0"
known-folders = "1.2.0"
native_model = { version = "0.6.4", features = ["rmp_serde_1_3"], git = "https://github.com/Drop-OSS/native_model.git"}
tauri-plugin-opener = "2.4.0"
bitcode = "0.6.6"
reqwest-websocket = "0.5.0"
futures-lite = "2.6.0"
page_size = "0.6.0"
sysinfo = "0.36.1"
humansize = "2.1.3"
tokio-util = { version = "0.7.16", features = ["io"] }
futures-core = "0.3.31"
bytes = "1.10.1"
# tailscale = { path = "./tailscale" }
# Workspaces
client = { path = "../client" }
database = { path = "../database" }
process = { path = "../process" }
remote = { path = "../remote" }
utils = { path = "../utils" }
[dependencies.dynfmt]
version = "0.1.5"
features = ["curly"]
[dependencies.tauri]
version = "2.7.0"
features = ["protocol-asset", "tray-icon"]
[dependencies.tokio]
version = "1.40.0"
features = ["rt", "tokio-macros", "signal"]
[dependencies.log4rs]
version = "1.3.0"
features = ["console_appender", "file_appender"]
[dependencies.rustix]
version = "0.38.37"
features = ["fs"]
[dependencies.uuid]
version = "1.10.0"
features = ["v4", "fast-rng", "macro-diagnostics"]
[dependencies.rustbreak]
version = "2"
features = ["other_errors"] # You can also use "yaml_enc" or "bin_enc"
[dependencies.reqwest]
version = "0.12.22"
default-features = false
features = [
"json",
"http2",
"blocking",
"rustls-tls",
"native-tls-alpn",
"rustls-tls-native-roots",
"stream",
]
[dependencies.serde]
version = "1"
features = ["derive", "rc"]
[profile.release]
lto = true
codegen-units = 1
panic = 'abort'

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
{}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 6.0 KiB

View File

Before

Width:  |  Height:  |  Size: 911 B

After

Width:  |  Height:  |  Size: 911 B

View File

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

View File

Before

Width:  |  Height:  |  Size: 803 B

After

Width:  |  Height:  |  Size: 803 B

View File

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Some files were not shown because too many files have changed in this diff Show More