mirror of
https://github.com/nimbold/Firelink.git
synced 2026-09-10 09:45:44 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| df0e63b39d |
@@ -23,21 +23,25 @@ const stabilityMsValue = Number.parseInt(argValue('--stability-ms') || '5000', 1
|
||||
const stabilityMs = Number.isFinite(stabilityMsValue) && stabilityMsValue >= 0
|
||||
? Math.min(stabilityMsValue, MAX_STABILITY_MS)
|
||||
: 5000;
|
||||
const childEnv = {
|
||||
...process.env,
|
||||
FIRELINK_SMOKE_TEST: '1',
|
||||
FIRELINK_DISABLE_ARIA2_POLLER: '1',
|
||||
WEBKIT_DISABLE_COMPOSITING_MODE: '1',
|
||||
GDK_BACKEND: 'x11',
|
||||
};
|
||||
if (process.argv.includes('--disable-aria2-poller')) {
|
||||
childEnv.FIRELINK_DISABLE_ARIA2_POLLER = '1';
|
||||
}
|
||||
const READY_PORT_TIMEOUT_MS = 500;
|
||||
const child = spawn(executable, [], {
|
||||
cwd: process.env.RUNNER_TEMP || process.env.TMPDIR || process.cwd(),
|
||||
detached: process.platform !== 'win32',
|
||||
env: {
|
||||
...process.env,
|
||||
FIRELINK_SMOKE_TEST: '1',
|
||||
WEBKIT_DISABLE_COMPOSITING_MODE: '1',
|
||||
GDK_BACKEND: 'x11',
|
||||
},
|
||||
env: childEnv,
|
||||
stdio: ['ignore', 'pipe', 'pipe'],
|
||||
});
|
||||
|
||||
let stderr = '';
|
||||
let stdout = '';
|
||||
let spawnError = null;
|
||||
let readyPort = null;
|
||||
let childExit = null;
|
||||
@@ -56,9 +60,7 @@ child.on('exit', (code, signal) => {
|
||||
child.stderr.on('data', data => {
|
||||
stderr += data.toString();
|
||||
});
|
||||
child.stdout.on('data', data => {
|
||||
stdout += data.toString();
|
||||
});
|
||||
child.stdout.on('data', () => {});
|
||||
|
||||
function sleep(ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
@@ -190,45 +192,6 @@ if ($visible.Count -gt 0) {
|
||||
}
|
||||
}
|
||||
|
||||
function windowsCrashDiagnostics() {
|
||||
if (process.platform !== 'win32') {
|
||||
return '';
|
||||
}
|
||||
|
||||
const script = `
|
||||
$start = (Get-Date).AddMinutes(-15)
|
||||
$events = @(Get-WinEvent -FilterHashtable @{ LogName = 'Application'; StartTime = $start } -ErrorAction SilentlyContinue |
|
||||
Where-Object {
|
||||
$_.ProviderName -in @('Application Error', 'Windows Error Reporting') -and
|
||||
$_.Message -match '(?i)firelink'
|
||||
} |
|
||||
Select-Object -First 8)
|
||||
foreach ($event in $events) {
|
||||
Write-Output ("EVENT " + $event.TimeCreated.ToString('o') + " " + $event.ProviderName + " ID=" + $event.Id)
|
||||
Write-Output $event.Message
|
||||
}
|
||||
`;
|
||||
|
||||
try {
|
||||
return execFileSync('powershell', ['-NoProfile', '-NonInteractive', '-Command', script], {
|
||||
encoding: 'utf8',
|
||||
stdio: ['ignore', 'pipe', 'pipe'],
|
||||
windowsHide: true,
|
||||
}).trim();
|
||||
} catch {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
function startupDiagnostics() {
|
||||
const sections = [];
|
||||
if (stdout.trim()) sections.push(`Firelink stdout:\n${stdout.slice(-6000)}`);
|
||||
if (stderr.trim()) sections.push(`Firelink stderr:\n${stderr.slice(-6000)}`);
|
||||
const crashEvents = windowsCrashDiagnostics();
|
||||
if (crashEvents) sections.push(`Windows application events:\n${crashEvents.slice(-12000)}`);
|
||||
return sections.join('\n\n');
|
||||
}
|
||||
|
||||
function waitForChildExit(timeoutMs) {
|
||||
if (childExit) {
|
||||
return Promise.resolve(true);
|
||||
@@ -438,8 +401,6 @@ try {
|
||||
console.log(`Packaged Firelink smoke passed on 127.0.0.1:${readyPort} with ${stabilityMs}ms stability`);
|
||||
} catch (error) {
|
||||
console.error(error instanceof Error ? error.message : String(error));
|
||||
const diagnostics = startupDiagnostics();
|
||||
if (diagnostics) console.error(`\nStartup diagnostics:\n${diagnostics}`);
|
||||
process.exitCode = 1;
|
||||
} finally {
|
||||
if (!await terminateChild()) {
|
||||
|
||||
+3
-47
@@ -3662,22 +3662,6 @@ struct MainWindowRestoreState {
|
||||
startup_complete: AtomicBool,
|
||||
}
|
||||
|
||||
fn startup_trace(marker: &str) {
|
||||
if std::env::var_os("FIRELINK_SMOKE_TEST").is_some() {
|
||||
eprintln!("[firelink-startup] {marker}");
|
||||
}
|
||||
}
|
||||
|
||||
static STARTUP_WINDOW_EVENT_COUNT: std::sync::atomic::AtomicUsize =
|
||||
std::sync::atomic::AtomicUsize::new(0);
|
||||
|
||||
fn startup_trace_window_event(label: &str) {
|
||||
let count = STARTUP_WINDOW_EVENT_COUNT.fetch_add(1, Ordering::Relaxed);
|
||||
if count < 64 {
|
||||
startup_trace(label);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
const MAIN_WINDOW_MINIMIZE_MENU_ID: &str = "main_window_minimize";
|
||||
|
||||
@@ -18275,12 +18259,10 @@ pub fn run() {
|
||||
.plugin(tauri_plugin_deep_link::init())
|
||||
.manage(Aria2DaemonGuard::new())
|
||||
.setup(move |app| {
|
||||
startup_trace("setup:begin");
|
||||
let storage_layout = crate::storage::StorageLayout::resolve(
|
||||
app.handle(),
|
||||
setup_storage_mode.clone(),
|
||||
)?;
|
||||
startup_trace("setup:storage");
|
||||
let main_window_config = app
|
||||
.config()
|
||||
.app
|
||||
@@ -18298,7 +18280,6 @@ pub fn run() {
|
||||
main_window_builder =
|
||||
main_window_builder.data_directory(storage_layout.webview_dir().to_path_buf());
|
||||
}
|
||||
startup_trace("setup:window-builder");
|
||||
|
||||
let mut sys = sysinfo::System::new_all();
|
||||
sys.refresh_all();
|
||||
@@ -18312,7 +18293,6 @@ pub fn run() {
|
||||
log::info!("==========================");
|
||||
build_main_tray(app.handle())
|
||||
.map_err(|error| format!("failed to create tray menu: {error}"))?;
|
||||
startup_trace("setup:tray");
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
use tauri::menu::{MenuItem, WINDOW_SUBMENU_ID};
|
||||
@@ -18365,7 +18345,6 @@ pub fn run() {
|
||||
// malformed or interrupted transaction cannot reach a missing
|
||||
// Tauri state entry at startup.
|
||||
app.manage(database);
|
||||
startup_trace("setup:database");
|
||||
if let Err(error) = recover_torrent_move_journals(
|
||||
app.handle(),
|
||||
&*app.state::<crate::db::DbState>(),
|
||||
@@ -18379,7 +18358,6 @@ pub fn run() {
|
||||
) {
|
||||
log::warn!("Download replacement recovery did not complete: {error}");
|
||||
}
|
||||
startup_trace("setup:recovery");
|
||||
// Establish Firelink-owned Aria2 routing-table paths after the
|
||||
// existing data-root initializer has created the selected storage
|
||||
// directory, but before the daemon launcher is scheduled. A
|
||||
@@ -18441,7 +18419,6 @@ pub fn run() {
|
||||
log::warn!("could not identify retained torrent metadata: {error}");
|
||||
}
|
||||
}
|
||||
startup_trace("setup:torrent-cache");
|
||||
let initial_pairing_token = {
|
||||
// Generate a temporary session token for the extension server on startup.
|
||||
// The frontend will hydrate the real token via IPC once it mounts,
|
||||
@@ -18538,12 +18515,10 @@ pub fn run() {
|
||||
scheduler_settings: Arc::clone(&scheduler_settings),
|
||||
queue_manager,
|
||||
});
|
||||
startup_trace("setup:app-state");
|
||||
|
||||
if let Err(error) = power_manager.activate() {
|
||||
log::error!("power: failed to activate backend power management: {error}");
|
||||
}
|
||||
startup_trace("setup:power");
|
||||
|
||||
// Build the window only after all command state is registered. This
|
||||
// prevents the frontend from racing startup and invoking IPC before
|
||||
@@ -18589,9 +18564,7 @@ pub fn run() {
|
||||
main_window_builder
|
||||
.build()
|
||||
.map_err(|error| format!("failed to create main window: {error}"))?;
|
||||
startup_trace("setup:window-built");
|
||||
restore_pending_main_window(app.handle());
|
||||
startup_trace("setup:pending-window-restored");
|
||||
|
||||
#[cfg(any(target_os = "windows", target_os = "linux"))]
|
||||
dispatch_opened_torrent_paths(
|
||||
@@ -18612,9 +18585,7 @@ pub fn run() {
|
||||
Ok(None) => {}
|
||||
Err(error) => eprintln!("Failed to read startup deep link: {error}"),
|
||||
}
|
||||
startup_trace("setup:deep-link");
|
||||
crate::scheduler::spawn_scheduler(app.handle().clone(), scheduler_settings);
|
||||
startup_trace("setup:scheduler");
|
||||
|
||||
let global_speed_limit = persisted_settings
|
||||
.as_ref()
|
||||
@@ -18657,12 +18628,10 @@ pub fn run() {
|
||||
let aria2_secret_clone = aria2_secret.clone();
|
||||
let app_handle_bg = app.handle().clone();
|
||||
tauri::async_runtime::spawn(async move {
|
||||
startup_trace("aria2-task:begin");
|
||||
|
||||
let mut ws_port = 6800;
|
||||
match resolve_bundled_binary_path(&app_handle_bg, "aria2c") {
|
||||
Ok(binary_path) => {
|
||||
startup_trace("aria2-task:binary");
|
||||
let mut success = false;
|
||||
let mut attempted_rpc_port = false;
|
||||
let mut startup_failure = None;
|
||||
@@ -18756,7 +18725,6 @@ pub fn run() {
|
||||
|
||||
match cmd.spawn() {
|
||||
Ok(mut child) => {
|
||||
startup_trace("aria2-task:spawned");
|
||||
// Give it a moment to fail if port is in use
|
||||
tokio::time::sleep(std::time::Duration::from_millis(200)).await;
|
||||
if let Ok(Some(status)) = child.try_wait() {
|
||||
@@ -18846,7 +18814,6 @@ pub fn run() {
|
||||
attempt_port,
|
||||
async_dns_supported
|
||||
);
|
||||
startup_trace("aria2-task:ready");
|
||||
ready = true;
|
||||
break;
|
||||
}
|
||||
@@ -18899,10 +18866,8 @@ pub fn run() {
|
||||
ws_retries = 0;
|
||||
}
|
||||
tokio::time::sleep(std::time::Duration::from_secs(2)).await;
|
||||
startup_trace("aria2-task:websocket-attempt");
|
||||
let ws_url = format!("ws://127.0.0.1:{}/jsonrpc", ws_port);
|
||||
if let Ok((ws_stream, _)) = tokio_tungstenite::connect_async(&ws_url).await {
|
||||
startup_trace("aria2-task:websocket-connected");
|
||||
ws_retries = 0; // reset on success
|
||||
if let Ok(mut startup_error) = app_handle_bg
|
||||
.state::<Aria2DaemonGuard>()
|
||||
@@ -18916,7 +18881,6 @@ pub fn run() {
|
||||
}
|
||||
}
|
||||
reconcile_aria2_downloads(&app_handle_bg).await;
|
||||
startup_trace("aria2-task:reconciled");
|
||||
use futures_util::StreamExt;
|
||||
let (_, mut read) = ws_stream.split();
|
||||
while let Some(msg) = read.next().await {
|
||||
@@ -19043,7 +19007,9 @@ pub fn run() {
|
||||
let poll_secret = aria2_secret.clone();
|
||||
let poll_mgr = Arc::clone(&queue_manager_poll);
|
||||
tauri::async_runtime::spawn(async move {
|
||||
startup_trace("poller:begin");
|
||||
if std::env::var_os("FIRELINK_DISABLE_ARIA2_POLLER").is_some() {
|
||||
return;
|
||||
}
|
||||
let mut interval = tokio::time::interval(std::time::Duration::from_millis(1000));
|
||||
let mut observations: HashMap<String, Aria2ConnectionObservation> = HashMap::new();
|
||||
let mut missing_gid_recovery_at: HashMap<String, Instant> = HashMap::new();
|
||||
@@ -19055,7 +19021,6 @@ pub fn run() {
|
||||
let mut relocation_checks = HashSet::new();
|
||||
loop {
|
||||
interval.tick().await;
|
||||
startup_trace("poller:tick");
|
||||
// Terminal cleanup removes a download's GID mapping. Do
|
||||
// not retain one observation per historical download for
|
||||
// the lifetime of the poller.
|
||||
@@ -19103,11 +19068,9 @@ pub fn run() {
|
||||
.unwrap_or_else(|| "none".to_string()),
|
||||
active_poll_started.elapsed().as_millis()
|
||||
);
|
||||
startup_trace("poller:rpc-failed");
|
||||
continue;
|
||||
}
|
||||
};
|
||||
startup_trace("poller:rpc-ok");
|
||||
if let Some(active_arr) = active_list.as_array() {
|
||||
let mut seen_ids = HashSet::new();
|
||||
let mut seen_gids = HashSet::new();
|
||||
@@ -19787,7 +19750,6 @@ pub fn run() {
|
||||
|
||||
let ext_app_handle = app.handle().clone();
|
||||
tauri::async_runtime::spawn(async move {
|
||||
startup_trace("extension-task:begin");
|
||||
while let Err(error) = extension_server::start_server(
|
||||
ext_app_handle.clone(),
|
||||
server_pairing_token.clone(),
|
||||
@@ -19800,7 +19762,6 @@ pub fn run() {
|
||||
tokio::time::sleep(std::time::Duration::from_secs(10)).await;
|
||||
}
|
||||
});
|
||||
startup_trace("setup:tasks-started");
|
||||
Ok(())
|
||||
})
|
||||
.plugin(
|
||||
@@ -19847,9 +19808,6 @@ pub fn run() {
|
||||
.plugin(tauri_plugin_notification::init())
|
||||
.plugin(tauri_plugin_clipboard_manager::init())
|
||||
.on_window_event(|window, event| {
|
||||
if window.label() == "main" {
|
||||
startup_trace_window_event("window-event:main");
|
||||
}
|
||||
if properties_window::is_properties_window_label(window.label()) {
|
||||
let resize = match event {
|
||||
tauri::WindowEvent::Resized(size) => {
|
||||
@@ -19942,13 +19900,11 @@ pub fn run() {
|
||||
.expect("error while building tauri application")
|
||||
.run(|app_handle, event| match event {
|
||||
tauri::RunEvent::Ready => {
|
||||
startup_trace("run-event:ready-begin");
|
||||
mark_main_window_startup_complete(app_handle);
|
||||
#[cfg(target_os = "windows")]
|
||||
reveal_main_window(app_handle);
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
restore_pending_main_window(app_handle);
|
||||
startup_trace("run-event:ready-end");
|
||||
}
|
||||
#[cfg(target_os = "macos")]
|
||||
tauri::RunEvent::Opened { urls } => {
|
||||
|
||||
Reference in New Issue
Block a user