mirror of
https://github.com/Stremio/stremio-shell-ng.git
synced 2026-03-11 17:15:49 +00:00
Server crash logs and boot availability
This commit is contained in:
parent
bb5387bd98
commit
8e1b72d513
4 changed files with 196 additions and 48 deletions
10
src/main.rs
10
src/main.rs
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@ use crate::stremio_app::{
|
|||
PipeServer,
|
||||
};
|
||||
|
||||
use super::stremio_server::StremioServer;
|
||||
|
||||
#[derive(Default, NwgUi)]
|
||||
pub struct MainWindow {
|
||||
pub command: String,
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
@ -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
|
||||
|
|
@ -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();
|
||||
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();
|
||||
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();
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue