Skip to content

Commit

Permalink
Server crash logs and boot availability
Browse files Browse the repository at this point in the history
  • Loading branch information
core1024 committed Jan 21, 2025
1 parent bb5387b commit 8e1b72d
Show file tree
Hide file tree
Showing 4 changed files with 196 additions and 48 deletions.
10 changes: 5 additions & 5 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ use clap::Parser;
use native_windows_gui::{self as nwg, NativeUi};
mod stremio_app;
use crate::stremio_app::{
constants::{DEV_ENDPOINT, IPC_PATH, STA_ENDPOINT, WEB_ENDPOINT},
stremio_server::StremioServer,
constants::{DEV_ENDPOINT, IPC_PATH, STA_ENDPOINT, STREMIO_SERVER_DEV_MODE, WEB_ENDPOINT},
MainWindow, PipeClient,
};

Expand Down Expand Up @@ -75,9 +74,10 @@ fn main() {
}
// END IPC

if !opt.development {
StremioServer::new();
}
std::env::set_var(
STREMIO_SERVER_DEV_MODE,
if opt.development { "true" } else { "false" },
);

let webui_url = if opt.development && opt.webui_url == WEB_ENDPOINT {
DEV_ENDPOINT.to_string()
Expand Down
8 changes: 6 additions & 2 deletions src/stremio_app/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ use crate::stremio_app::{
PipeServer,
};

use super::stremio_server::StremioServer;

#[derive(Default, NwgUi)]
pub struct MainWindow {
pub command: String,
Expand All @@ -50,11 +52,13 @@ pub struct MainWindow {
#[nwg_events((tray, MousePressLeftUp): [Self::on_show], (tray_exit, OnMenuItemSelected): [nwg::stop_thread_dispatch()], (tray_show_hide, OnMenuItemSelected): [Self::on_show_hide], (tray_topmost, OnMenuItemSelected): [Self::on_toggle_topmost]) ]
pub tray: SystemTray,
#[nwg_partial(parent: window)]
pub webview: WebView,
pub splash_screen: SplashImage,
#[nwg_partial(parent: window)]
pub server: StremioServer,
#[nwg_partial(parent: window)]
pub player: Player,
#[nwg_partial(parent: window)]
pub splash_screen: SplashImage,
pub webview: WebView,
#[nwg_control]
#[nwg_events(OnNotice: [Self::on_toggle_fullscreen_notice] )]
pub toggle_fullscreen_notice: nwg::Notice,
Expand Down
29 changes: 16 additions & 13 deletions src/stremio_app/constants.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
pub const APP_NAME: &str = "Stremio";
pub const IPC_PATH: &str = "//./pipe/com.stremio5.";
pub const DEV_ENDPOINT: &str = "http://127.0.0.1:11470";
pub const WEB_ENDPOINT: &str = "https://web.stremio.com/";
pub const STA_ENDPOINT: &str = "https://staging.strem.io/";
pub const WINDOW_MIN_WIDTH: i32 = 1000;
pub const WINDOW_MIN_HEIGHT: i32 = 600;
pub const UPDATE_INTERVAL: u64 = 12 * 60 * 60;
pub const UPDATE_ENDPOINT: [&str; 3] = [
"https://www.strem.io/updater/check?product=stremio-shell-ng",
"https://www.stremio.com/updater/check?product=stremio-shell-ng",
"https://www.stremio.net/updater/check?product=stremio-shell-ng",
];
pub const APP_NAME: &str = "Stremio";
pub const IPC_PATH: &str = "//./pipe/com.stremio5.";
pub const DEV_ENDPOINT: &str = "http://127.0.0.1:11470";
pub const WEB_ENDPOINT: &str = "https://web.stremio.com/";
pub const STA_ENDPOINT: &str = "https://staging.strem.io/";
pub const WINDOW_MIN_WIDTH: i32 = 1000;
pub const WINDOW_MIN_HEIGHT: i32 = 600;
pub const UPDATE_INTERVAL: u64 = 12 * 60 * 60;
pub const UPDATE_ENDPOINT: [&str; 3] = [
"https://www.strem.io/updater/check?product=stremio-shell-ng",
"https://www.stremio.com/updater/check?product=stremio-shell-ng",
"https://www.stremio.net/updater/check?product=stremio-shell-ng",
];
pub const STREMIO_SERVER_DEV_MODE: &str = "STREMIO_SERVER_DEV_MODE";
pub const SRV_BUFFER_SIZE: usize = 1024;
pub const SRV_LOG_SIZE: usize = 20;
197 changes: 169 additions & 28 deletions src/stremio_app/stremio_server/server.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
use native_windows_gui as nwg;
use crate::stremio_app::constants::{SRV_BUFFER_SIZE, SRV_LOG_SIZE, STREMIO_SERVER_DEV_MODE};
use native_windows_gui::{self as nwg, PartialUi};
use std::io::Write;
use std::{
env, fs, os::windows::process::CommandExt, path, process::Command, thread, time::Duration,
env, fs,
io::Read,
ops::Deref,
os::windows::process::CommandExt,
path,
process::{Command, Stdio},
sync::{Arc, Mutex},
thread,
};
use winapi::um::{
processthreadsapi::GetCurrentProcess,
Expand All @@ -12,10 +21,23 @@ use winapi::um::{
},
};

pub struct StremioServer {}
#[derive(Default)]
pub struct StremioServer {
development: bool,
parent: nwg::ControlHandle,
crash_notice: nwg::Notice,
logs: Arc<Mutex<String>>,
}

impl StremioServer {
pub fn new() -> StremioServer {
pub fn start(&self) {
if self.development {
return;
}
let (tx, rx) = flume::unbounded();
let logs = self.logs.clone();
let sender = self.crash_notice.sender();

thread::spawn(move || {
// Use Win32JobObject to kill the child process when the parent process is killed
// With the JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK and JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE flags
Expand Down Expand Up @@ -45,31 +67,150 @@ impl StremioServer {
.and_then(fs::canonicalize)
.expect("Cannot get the current executable path");
path.pop();
loop {
let runtime_path = path.clone().join(path::Path::new("stremio-runtime"));
let server_path = path.clone().join(path::Path::new("server.js"));
let child = Command::new(runtime_path)
.arg(server_path)
.creation_flags(CREATE_NO_WINDOW)
.spawn();
match child {
Ok(mut child) => {
// TODO: store somehow last few lines of the child's stdout/stderr instead of just waiting
child.wait().expect("Cannot wait for the server");
}
Err(err) => {
nwg::error_message(
"Stremio server",
format!("Cannot execute stremio-runtime: {}", &err).as_str(),
);
break;
}
};
// TODO: show error message with the child's stdout/stderr
thread::sleep(Duration::from_millis(500));
dbg!("Trying to restart the server...");
let lines = Arc::new(Mutex::new(String::new()));
let runtime_path = path.clone().join(path::Path::new("stremio-runtime"));
let server_path = path.clone().join(path::Path::new("server.js"));
let child = Command::new(runtime_path)
.arg(server_path)
.creation_flags(CREATE_NO_WINDOW)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn();
match child {
Ok(mut child) => {
let mut stdout = child.stdout.take().unwrap();
let out_lines = lines.clone();
let tx = tx.clone();
let out_thread = thread::spawn(move || {
let http_endpoint = String::new();
loop {
let mut buffer = [0; SRV_BUFFER_SIZE];
let on = stdout.read(&mut buffer[..]).unwrap_or(!0);
if on > buffer.len() {
continue;
}
std::io::stdout().write(&buffer).ok();

Check failure on line 92 in src/stremio_app/stremio_server/server.rs

View workflow job for this annotation

GitHub Actions / test

written amount is not handled

Check failure on line 92 in src/stremio_app/stremio_server/server.rs

View workflow job for this annotation

GitHub Actions / test

written amount is not handled
let string_data = String::from_utf8_lossy(&buffer[..on]);
{
let lines = &mut *out_lines.lock().unwrap();
*lines += string_data.deref();
if http_endpoint.is_empty() {
if let Some(http_endpoint) = string_data
.lines()
.find(|line| line.starts_with("EngineFS server started at"))
{
let http_endpoint =
http_endpoint.split_whitespace().last().unwrap();
println!("HTTP endpoint: {}", http_endpoint);
let endpoint = http_endpoint.to_string();
tx.send(endpoint.clone()).ok();
}
}
*lines = lines
.lines()
.rev()
.take(SRV_LOG_SIZE)
.collect::<Vec<&str>>()
.into_iter()
.rev()
.collect::<Vec<&str>>()
.join("\n");
};
if on == 0 {
// Server terminated
break;
}
}
});

let mut stderr = child.stderr.take().unwrap();
let err_lines = lines.clone();
let err_thread = thread::spawn(move || {
let mut buffer = [0; SRV_BUFFER_SIZE];
loop {
let en = stderr.read(&mut buffer[..]).unwrap_or(!0);
if en > buffer.len() {
continue;
}
std::io::stderr().write(&buffer).ok();

Check failure on line 135 in src/stremio_app/stremio_server/server.rs

View workflow job for this annotation

GitHub Actions / test

written amount is not handled

Check failure on line 135 in src/stremio_app/stremio_server/server.rs

View workflow job for this annotation

GitHub Actions / test

written amount is not handled
let string_data = String::from_utf8_lossy(&buffer[..en]);
// eprint!("{:?}", &buffer);
{
let lines = &mut *err_lines.lock().unwrap();
*lines += string_data.deref();
*lines = lines
.lines()
.rev()
.take(SRV_LOG_SIZE)
.collect::<Vec<&str>>()
.into_iter()
.rev()
.collect::<Vec<&str>>()
.join("\n");
};
if en == 0 {
// Server terminated
break;
}
}
});
out_thread.join().ok();
err_thread.join().ok();
}
Err(err) => {
nwg::error_message(
"Stremio server",
format!("Cannot execute stremio-runtime: {}", &err).as_str(),
);
}
};

{
let mut logs = logs.lock().unwrap();
*logs = lines.lock().unwrap().deref().to_string();
}
println!("Server terminated.");
sender.notice();
});
StremioServer {}

// Wait for the server to start
rx.recv().unwrap();
}
}

impl PartialUi for StremioServer {
fn build_partial<W: Into<nwg::ControlHandle>>(
data: &mut Self,
parent: Option<W>,
) -> Result<(), nwg::NwgError> {
if std::env::var(STREMIO_SERVER_DEV_MODE).unwrap_or("false".to_string()) == "true" {
data.development = true;
}

data.parent = parent.unwrap().into().clone();

Check failure on line 190 in src/stremio_app/stremio_server/server.rs

View workflow job for this annotation

GitHub Actions / test

using `clone` on type `ControlHandle` which implements the `Copy` trait

Check failure on line 190 in src/stremio_app/stremio_server/server.rs

View workflow job for this annotation

GitHub Actions / test

using `clone` on type `ControlHandle` which implements the `Copy` trait

nwg::Notice::builder()
.parent(data.parent)
.build(&mut data.crash_notice)
.ok();
data.start();
println!("Stremio server started");
Ok(())
}
fn process_event<'a>(
&self,
evt: nwg::Event,
_evt_data: &nwg::EventData,
handle: nwg::ControlHandle,
) {
use nwg::Event as E;
if evt == E::OnNotice && handle == self.crash_notice.handle {
nwg::modal_error_message(
self.parent,
"Stremio server crash log",
self.logs.lock().unwrap().deref(),
);
self.start();
}
}
}

0 comments on commit 8e1b72d

Please sign in to comment.