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};
|
use native_windows_gui::{self as nwg, NativeUi};
|
||||||
mod stremio_app;
|
mod stremio_app;
|
||||||
use crate::stremio_app::{
|
use crate::stremio_app::{
|
||||||
constants::{DEV_ENDPOINT, IPC_PATH, STA_ENDPOINT, WEB_ENDPOINT},
|
constants::{DEV_ENDPOINT, IPC_PATH, STA_ENDPOINT, STREMIO_SERVER_DEV_MODE, WEB_ENDPOINT},
|
||||||
stremio_server::StremioServer,
|
|
||||||
MainWindow, PipeClient,
|
MainWindow, PipeClient,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -75,9 +74,10 @@ fn main() {
|
||||||
}
|
}
|
||||||
// END IPC
|
// END IPC
|
||||||
|
|
||||||
if !opt.development {
|
std::env::set_var(
|
||||||
StremioServer::new();
|
STREMIO_SERVER_DEV_MODE,
|
||||||
}
|
if opt.development { "true" } else { "false" },
|
||||||
|
);
|
||||||
|
|
||||||
let webui_url = if opt.development && opt.webui_url == WEB_ENDPOINT {
|
let webui_url = if opt.development && opt.webui_url == WEB_ENDPOINT {
|
||||||
DEV_ENDPOINT.to_string()
|
DEV_ENDPOINT.to_string()
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,8 @@ use crate::stremio_app::{
|
||||||
PipeServer,
|
PipeServer,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use super::stremio_server::StremioServer;
|
||||||
|
|
||||||
#[derive(Default, NwgUi)]
|
#[derive(Default, NwgUi)]
|
||||||
pub struct MainWindow {
|
pub struct MainWindow {
|
||||||
pub command: String,
|
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]) ]
|
#[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,
|
pub tray: SystemTray,
|
||||||
#[nwg_partial(parent: window)]
|
#[nwg_partial(parent: window)]
|
||||||
pub webview: WebView,
|
pub splash_screen: SplashImage,
|
||||||
|
#[nwg_partial(parent: window)]
|
||||||
|
pub server: StremioServer,
|
||||||
#[nwg_partial(parent: window)]
|
#[nwg_partial(parent: window)]
|
||||||
pub player: Player,
|
pub player: Player,
|
||||||
#[nwg_partial(parent: window)]
|
#[nwg_partial(parent: window)]
|
||||||
pub splash_screen: SplashImage,
|
pub webview: WebView,
|
||||||
#[nwg_control]
|
#[nwg_control]
|
||||||
#[nwg_events(OnNotice: [Self::on_toggle_fullscreen_notice] )]
|
#[nwg_events(OnNotice: [Self::on_toggle_fullscreen_notice] )]
|
||||||
pub toggle_fullscreen_notice: nwg::Notice,
|
pub toggle_fullscreen_notice: nwg::Notice,
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,16 @@
|
||||||
pub const APP_NAME: &str = "Stremio";
|
pub const APP_NAME: &str = "Stremio";
|
||||||
pub const IPC_PATH: &str = "//./pipe/com.stremio5.";
|
pub const IPC_PATH: &str = "//./pipe/com.stremio5.";
|
||||||
pub const DEV_ENDPOINT: &str = "http://127.0.0.1:11470";
|
pub const DEV_ENDPOINT: &str = "http://127.0.0.1:11470";
|
||||||
pub const WEB_ENDPOINT: &str = "https://web.stremio.com/";
|
pub const WEB_ENDPOINT: &str = "https://web.stremio.com/";
|
||||||
pub const STA_ENDPOINT: &str = "https://staging.strem.io/";
|
pub const STA_ENDPOINT: &str = "https://staging.strem.io/";
|
||||||
pub const WINDOW_MIN_WIDTH: i32 = 1000;
|
pub const WINDOW_MIN_WIDTH: i32 = 1000;
|
||||||
pub const WINDOW_MIN_HEIGHT: i32 = 600;
|
pub const WINDOW_MIN_HEIGHT: i32 = 600;
|
||||||
pub const UPDATE_INTERVAL: u64 = 12 * 60 * 60;
|
pub const UPDATE_INTERVAL: u64 = 12 * 60 * 60;
|
||||||
pub const UPDATE_ENDPOINT: [&str; 3] = [
|
pub const UPDATE_ENDPOINT: [&str; 3] = [
|
||||||
"https://www.strem.io/updater/check?product=stremio-shell-ng",
|
"https://www.strem.io/updater/check?product=stremio-shell-ng",
|
||||||
"https://www.stremio.com/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",
|
"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::{
|
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::{
|
use winapi::um::{
|
||||||
processthreadsapi::GetCurrentProcess,
|
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 {
|
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 || {
|
thread::spawn(move || {
|
||||||
// Use Win32JobObject to kill the child process when the parent process is killed
|
// 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
|
// 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)
|
.and_then(fs::canonicalize)
|
||||||
.expect("Cannot get the current executable path");
|
.expect("Cannot get the current executable path");
|
||||||
path.pop();
|
path.pop();
|
||||||
loop {
|
let lines = Arc::new(Mutex::new(String::new()));
|
||||||
let runtime_path = path.clone().join(path::Path::new("stremio-runtime"));
|
let runtime_path = path.clone().join(path::Path::new("stremio-runtime"));
|
||||||
let server_path = path.clone().join(path::Path::new("server.js"));
|
let server_path = path.clone().join(path::Path::new("server.js"));
|
||||||
let child = Command::new(runtime_path)
|
let child = Command::new(runtime_path)
|
||||||
.arg(server_path)
|
.arg(server_path)
|
||||||
.creation_flags(CREATE_NO_WINDOW)
|
.creation_flags(CREATE_NO_WINDOW)
|
||||||
.spawn();
|
.stdout(Stdio::piped())
|
||||||
match child {
|
.stderr(Stdio::piped())
|
||||||
Ok(mut child) => {
|
.spawn();
|
||||||
// TODO: store somehow last few lines of the child's stdout/stderr instead of just waiting
|
match child {
|
||||||
child.wait().expect("Cannot wait for the server");
|
Ok(mut child) => {
|
||||||
}
|
let mut stdout = child.stdout.take().unwrap();
|
||||||
Err(err) => {
|
let out_lines = lines.clone();
|
||||||
nwg::error_message(
|
let tx = tx.clone();
|
||||||
"Stremio server",
|
let out_thread = thread::spawn(move || {
|
||||||
format!("Cannot execute stremio-runtime: {}", &err).as_str(),
|
let http_endpoint = String::new();
|
||||||
);
|
loop {
|
||||||
break;
|
let mut buffer = [0; SRV_BUFFER_SIZE];
|
||||||
}
|
let on = stdout.read(&mut buffer[..]).unwrap_or(!0);
|
||||||
};
|
if on > buffer.len() {
|
||||||
// TODO: show error message with the child's stdout/stderr
|
continue;
|
||||||
thread::sleep(Duration::from_millis(500));
|
}
|
||||||
dbg!("Trying to restart the server...");
|
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