File restructure. Working server

This commit is contained in:
Vladimir Borisov 2021-07-13 17:34:59 +03:00
parent 0e19d1b6aa
commit 3d51316c04
No known key found for this signature in database
GPG key ID: F9A584BE4FCB6603
11 changed files with 157300 additions and 123 deletions

37
Cargo.lock generated
View file

@ -134,6 +134,18 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0419348c027fa7be448d2ae7ea0e4e04c2334c31dc4e74ab29f00a2a7ca69204"
[[package]]
name = "native-windows-derive"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8164b076b08fb63f7cb4da207abe8fd94b5c604e17d9f49618807482dbe25507"
dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "native-windows-gui"
version = "1.0.12"
@ -261,6 +273,15 @@ version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d88417318da0eaf0fdcdb51a0ee6c3bed624333bff8f946733049380be67ac1c"
[[package]]
name = "proc-macro-crate"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785"
dependencies = [
"toml",
]
[[package]]
name = "proc-macro2"
version = "1.0.27"
@ -322,11 +343,18 @@ version = "0.3.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
[[package]]
name = "serde"
version = "1.0.126"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03"
[[package]]
name = "stremio-shell-ng"
version = "0.1.0"
dependencies = [
"mpv",
"native-windows-derive",
"native-windows-gui",
"once_cell",
"webview2",
@ -355,6 +383,15 @@ dependencies = [
"unicode-xid",
]
[[package]]
name = "toml"
version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa"
dependencies = [
"serde",
]
[[package]]
name = "unicode-xid"
version = "0.2.2"

157016
server.js Normal file

File diff suppressed because one or more lines are too long

View file

@ -1,9 +1,7 @@
use native_windows_gui::{self as nwg, Window};
use once_cell::unsync::OnceCell;
use std::mem;
use std::rc::Rc;
use webview2::Controller;
use winapi::um::winuser::*;
use native_windows_gui::{self as nwg, NativeUi};
mod stremio_app;
use crate::stremio_app::{stremio_server::StremioServer, StremioApp};
fn main() {
// native-windows-gui has some basic high DPI support with the high-dpi
@ -12,124 +10,14 @@ fn main() {
//
// Use an application manifest to get rid of this deprecated warning.
#[allow(deprecated)]
unsafe { nwg::set_dpi_awareness() };
unsafe {
nwg::set_dpi_awareness()
};
nwg::init().unwrap();
let mut window = Window::default();
Window::builder()
.title("Stremio")
.size((1600, 900))
.build(&mut window)
.unwrap();
let window_handle = window.handle;
let hwnd = window_handle.hwnd().expect("unable to obtain hwnd");
// Initialize mpv
let mut mpv_builder = mpv::MpvHandlerBuilder::new()
.expect("Error while creating MPV builder");
mpv_builder.set_option("wid", hwnd as i64).expect("failed setting wid");
//mpv_builder.set_option("vo", "gpu").expect("unable to set vo");
// win, opengl: works but least performancy, 10-15% CPU
// winvk, vulkan: works as good as d3d11
// d3d11, d1d11: works great
// dxinterop, auto: works, slightly more cpu use than d3d11
// default (auto) seems to be d3d11 (vo/gpu/d3d11)
/*
mpv_builder.set_option("gpu-context", "angle")
.and_then(|_| mpv_builder.set_option("gpu-api", "auto"))
.expect("setting gpu options failed");
*/
mpv_builder.try_hardware_decoding()
.expect("failed setting hwdec");
mpv_builder.set_option("terminal", "yes").expect("failed setting terminal");
mpv_builder.set_option("msg-level", "all=v").expect("failed setting msg-level");
//mpv_builder.set_option("quiet", "yes").expect("failed setting msg-level");
let mut mpv = mpv_builder
.build()
.expect("Error while initializing MPV with opengl");
//let video_path = "/home/ivo/storage/bbb_sunflower_1080p_30fps_normal.mp4";
let video_path = "http://distribution.bbb3d.renderfarming.net/video/mp4/bbb_sunflower_1080p_30fps_normal.mp4";
mpv.command(&["loadfile", video_path])
.expect("Error loading file");
let controller: Rc<OnceCell<Controller>> = Rc::new(OnceCell::new());
let controller_clone = controller.clone();
let result = webview2::Environment::builder().build(move |env| {
env.unwrap()
.create_controller(hwnd, move |c| {
let c = c.unwrap();
if let Ok(c2) = c.get_controller2() {
c2.put_default_background_color(webview2_sys::Color {
r: 255,
g: 255,
b: 255,
a: 0,
})
.unwrap();
} else {
eprintln!("failed to get interface to controller2");
}
unsafe {
let mut rect = mem::zeroed();
GetClientRect(hwnd, &mut rect);
c.put_bounds(rect).unwrap();
}
let webview = c.get_webview().unwrap();
webview.navigate("https://www.boyanpetrov.rip/stremio/index.html").unwrap();
controller_clone.set(c).unwrap();
Ok(())
})
});
if let Err(e) = result {
nwg::modal_fatal_message(
&window_handle,
"Failed to Create WebView2 Environment",
&format!("{}", e),
);
}
let window_handle = window.handle;
// There isn't an OnWindowRestored event for SC_RESTORE in
// native-windows-gui, so we use raw events.
nwg::bind_raw_event_handler(&window_handle, 0xffff + 1, move |_, msg, w, _| {
match (msg, w as usize) {
(WM_SIZE, _) => {
if let Some(controller) = controller.get() {
unsafe {
let mut rect = mem::zeroed();
GetClientRect(window_handle.hwnd().unwrap(), &mut rect);
controller.put_bounds(rect).unwrap();
}
}
}
(WM_MOVE, _) => {
if let Some(controller) = controller.get() {
controller.notify_parent_window_position_changed().unwrap();
}
}
(WM_SYSCOMMAND, SC_MINIMIZE) => {
if let Some(controller) = controller.get() {
controller.put_is_visible(false).unwrap();
}
}
(WM_SYSCOMMAND, SC_RESTORE) => {
if let Some(controller) = controller.get() {
controller.put_is_visible(true).unwrap();
}
}
(WM_CLOSE, _) => nwg::stop_thread_dispatch(),
_ => {}
}
None
})
.unwrap();
let streaming_server = StremioServer::new();
nwg::init().expect("Failed to init Native Windows GUI");
let _app = StremioApp::build_ui(Default::default()).expect("Failed to build UI");
nwg::dispatch_thread_events();
streaming_server.try_kill();
}

8
src/stremio_app/mod.rs Normal file
View file

@ -0,0 +1,8 @@
pub mod stremio_app;
pub use stremio_app::StremioApp;
pub mod stremio_wevbiew;
pub use stremio_wevbiew::WebView;
pub mod stremio_player;
pub use stremio_player::Player;
pub mod stremio_server;
pub use stremio_server::StremioServer;

View file

@ -0,0 +1,22 @@
use native_windows_derive::NwgUi;
use native_windows_gui as nwg;
use crate::stremio_app::stremio_wevbiew::WebView;
use crate::stremio_app::stremio_player::Player;
#[derive(Default, NwgUi)]
pub struct StremioApp {
#[nwg_control(title: "Stremio", flags: "MAIN_WINDOW|VISIBLE")]
#[nwg_events( OnWindowClose: [StremioApp::quit] )]
window: nwg::Window,
#[nwg_partial(parent: window)]
webview: WebView,
#[nwg_partial(parent: window)]
player: Player,
}
impl StremioApp {
fn quit(&self) {
nwg::stop_thread_dispatch();
}
}

View file

@ -0,0 +1,2 @@
pub mod stremio_player;
pub use stremio_player::Player;

View file

@ -0,0 +1,48 @@
use native_windows_gui::{self as nwg, PartialUi};
#[derive(Default)]
pub struct Player {
mpv: Option<mpv::MpvHandler>,
}
impl PartialUi for Player {
fn build_partial<W: Into<nwg::ControlHandle>>(
data: &mut Self,
parent: Option<W>,
) -> Result<(), nwg::NwgError> {
let mut mpv_builder =
mpv::MpvHandlerBuilder::new().expect("Error while creating MPV builder");
mpv_builder
.set_option("wid", parent.unwrap().into().hwnd().unwrap() as i64)
.expect("failed setting wid");
// mpv_builder.set_option("vo", "gpu").expect("unable to set vo");
// win, opengl: works but least performancy, 10-15% CPU
// winvk, vulkan: works as good as d3d11
// d3d11, d1d11: works great
// dxinterop, auto: works, slightly more cpu use than d3d11
// default (auto) seems to be d3d11 (vo/gpu/d3d11)
mpv_builder
.set_option("gpu-context", "angle")
.and_then(|_| mpv_builder.set_option("gpu-api", "auto"))
.expect("setting gpu options failed");
mpv_builder
.try_hardware_decoding()
.expect("failed setting hwdec");
mpv_builder
.set_option("terminal", "yes")
.expect("failed setting terminal");
mpv_builder
.set_option("msg-level", "all=v")
.expect("failed setting msg-level");
//mpv_builder.set_option("quiet", "yes").expect("failed setting msg-level");
data.mpv = mpv_builder.build().ok();
let mpv = data.mpv.as_mut().expect("Failed to create MPV");
// let video_path = "/home/ivo/storage/bbb_sunflower_1080p_30fps_normal.mp4";
let video_path = "http://distribution.bbb3d.renderfarming.net/video/mp4/bbb_sunflower_1080p_30fps_normal.mp4";
mpv.command(&["loadfile", video_path])
.expect("Error loading file");
// mpv.command(&["stop"]).expect("Error stopping");
Ok(())
}
}

View file

@ -0,0 +1,2 @@
pub mod stremio_server;
pub use stremio_server::StremioServer;

View file

@ -0,0 +1,64 @@
use std::process::Command;
use std::thread;
use std::sync::{Arc, Mutex};
use std::time::Duration;
use winapi::um::processthreadsapi::{OpenProcess, TerminateProcess};
use winapi::um::winnt::PROCESS_TERMINATE;
use winapi::um::handleapi::CloseHandle;
pub struct StremioServer {
should_stop: Arc<std::sync::Mutex<u32>>,
handle: Option<thread::JoinHandle<()>>,
}
impl StremioServer {
pub fn new() -> StremioServer {
let server_pid_mutex = Arc::new(Mutex::new(0));
let server_pid_mutex2 = server_pid_mutex.clone();
StremioServer {
should_stop: server_pid_mutex,
handle: Some(thread::spawn(move || loop {
let mut child = Command::new("node")
.arg("server.js")
.spawn()
.expect("Cannot run the server");
{
let mut kill_request = server_pid_mutex2.lock().unwrap();
*kill_request = child.id();
};
let _status = child.wait().expect("Cannot wait for the server");
let kill_request = server_pid_mutex2.lock().unwrap();
if *kill_request == 0 {
dbg!("Exit server guard loop...");
break;
}
thread::sleep(Duration::from_millis(500));
dbg!("Trying to restart the server...");
})),
}
}
pub fn try_kill(mut self) {
dbg!("Trying to kill the server...");
let should_stop = self.should_stop.clone();
let mut tremination_request = should_stop.lock().unwrap();
unsafe {
let handle = OpenProcess(PROCESS_TERMINATE, 0, *tremination_request);
if !handle.is_null() {
TerminateProcess(handle, 101);
CloseHandle(handle);
}
}
*tremination_request = 0;
drop(self.handle.take())
// .map(thread::JoinHandle::join);
}
}
// impl Drop for StremioServer {
// fn drop(&mut self) {
// dbg!("Server dropped!");
// self.try_kill();
// }
// }

View file

@ -0,0 +1,2 @@
pub mod stremio_wevbiew;
pub use stremio_wevbiew::WebView;

View file

@ -0,0 +1,88 @@
// mod stremio_wevbiew {
use native_windows_gui::{self as nwg, PartialUi};
use once_cell::unsync::OnceCell;
use std::mem;
use std::rc::Rc;
use webview2::Controller;
use winapi::um::winuser::*;
#[derive(Default)]
pub struct WebView {
controller: Rc<OnceCell<Controller>>,
}
impl PartialUi for WebView {
fn build_partial<W: Into<nwg::ControlHandle>>(
data: &mut Self,
parent: Option<W>,
) -> Result<(), nwg::NwgError> {
let parent = parent.unwrap().into();
let hwnd = parent.hwnd().unwrap();
let controller_clone = data.controller.clone();
let result = webview2::EnvironmentBuilder::new()
.with_additional_browser_arguments("--disable-gpu")
.build(move |env| {
env.unwrap().create_controller(hwnd, move |c| {
let c = c.unwrap();
if let Ok(c2) = c.get_controller2() {
c2.put_default_background_color(webview2_sys::Color {
r: 255,
g: 255,
b: 255,
a: 0,
})
.unwrap();
} else {
eprintln!("failed to get interface to controller2");
}
unsafe {
let mut rect = mem::zeroed();
GetClientRect(hwnd, &mut rect);
c.put_bounds(rect).unwrap();
}
let webview = c.get_webview().unwrap();
webview.navigate("edge://gpu").unwrap();
webview
.navigate("https://www.boyanpetrov.rip/stremio/index.html")
.unwrap();
// c.put_is_visible(true).expect("Cannot show the WebView");
controller_clone.set(c).unwrap();
Ok(())
})
});
if let Err(e) = result {
nwg::modal_fatal_message(
&parent,
"Failed to Create WebView2 Environment",
&format!("{}", e),
);
}
Ok(())
}
fn process_event<'a>(
&self,
evt: nwg::Event,
_evt_data: &nwg::EventData,
handle: nwg::ControlHandle,
) {
use nwg::Event as E;
match evt {
E::OnResize | E::OnWindowMaximize => {
if let Some(controller) = self.controller.get() {
unsafe {
let mut rect = mem::zeroed();
GetClientRect(handle.hwnd().unwrap(), &mut rect);
controller.put_bounds(rect).unwrap();
controller.put_is_visible(true).unwrap();
}
}
}
E::OnWindowMinimize => {
if let Some(controller) = self.controller.get() {
controller.put_is_visible(false).unwrap();
}
}
_ => {}
}
}
}
// }