diff --git a/Cargo.lock b/Cargo.lock index 2e0245f..89eb5c1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -114,6 +114,21 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +[[package]] +name = "crossbeam-queue" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" + [[package]] name = "encoding_rs" version = "0.8.34" @@ -382,6 +397,7 @@ dependencies = [ "reqwest", "rquickjs", "tokio", + "tub", ] [[package]] @@ -446,6 +462,16 @@ version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + [[package]] name = "log" version = "0.4.21" @@ -571,6 +597,29 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "parking_lot" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.5", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -633,6 +682,15 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "redox_syscall" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" +dependencies = [ + "bitflags 2.5.0", +] + [[package]] name = "regex" version = "1.10.4" @@ -782,6 +840,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + [[package]] name = "security-framework" version = "2.10.0" @@ -848,6 +912,15 @@ dependencies = [ "serde", ] +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + [[package]] name = "slab" version = "0.4.9" @@ -949,7 +1022,9 @@ dependencies = [ "libc", "mio", "num_cpus", + "parking_lot", "pin-project-lite", + "signal-hook-registry", "socket2", "tokio-macros", "windows-sys 0.48.0", @@ -1044,6 +1119,16 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "tub" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bca43faba247bc76eb1d6c1b8b561e4a1c5bdd427cc3d7a007faabea75c683a" +dependencies = [ + "crossbeam-queue", + "tokio", +] + [[package]] name = "unicode-bidi" version = "0.3.15" diff --git a/Cargo.toml b/Cargo.toml index ba335d5..20f7085 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ edition = "2021" [dependencies] regex = "1.10.4" rquickjs = {version = "0.6.0", features=["futures"]} -tokio = {version = "1.37.0", features=["net", "macros", "rt-multi-thread", "io-std", "io-util"]} +tokio = { version = "1.37.0", features = ["full", "net", "macros", "rt-multi-thread", "io-std", "io-util"] } reqwest = "0.12.4" lazy-regex = "3.1.0" +tub = "0.3.7" diff --git a/src/jobs.rs b/src/jobs.rs index 0aa797f..e6e6517 100644 --- a/src/jobs.rs +++ b/src/jobs.rs @@ -1,7 +1,10 @@ -use std::sync::Arc; -use tokio::sync::Mutex; +use regex::Regex; +use rquickjs::{AsyncContext, AsyncRuntime}; +use std::{num::NonZeroUsize, ops::Deref, sync::Arc, thread::available_parallelism}; +use tokio::{runtime::Handle, sync::Mutex, task::block_in_place}; +use tub::Pool; -use crate::consts::{REGEX_PLAYER_ID, TEST_YOUTUBE_VIDEO}; +use crate::consts::{NSIG_FUNCTION_ARRAY, REGEX_PLAYER_ID, TEST_YOUTUBE_VIDEO}; pub enum JobOpcode { ForceUpdate, @@ -20,21 +23,89 @@ impl From for JobOpcode { } pub struct PlayerInfo { - nsig_function_bytecode: Vec, + nsig_function_code: Vec, player_id: u32, } + +pub struct JavascriptInterpreter { + js_runtime: AsyncRuntimeWrapper, + nsig_context: AsyncContextWrapper, + nsig_function_name: String, + player_id: u32, +} + +// This is to get Rust to shut up, since the types are aliases for non-null pointers +struct AsyncRuntimeWrapper(AsyncRuntime); +struct AsyncContextWrapper(AsyncContext); + +unsafe impl Send for AsyncRuntimeWrapper {} +unsafe impl Send for AsyncContextWrapper {} +unsafe impl Sync for AsyncRuntimeWrapper {} +unsafe impl Sync for AsyncContextWrapper {} +impl Deref for AsyncRuntimeWrapper { + type Target = AsyncRuntime; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl Deref for AsyncContextWrapper { + type Target = AsyncContext; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl JavascriptInterpreter { + pub fn new() -> JavascriptInterpreter { + let js_runtime = AsyncRuntime::new().unwrap(); + // not ideal, but this is only done at startup + let nsig_context = block_in_place(|| { + Handle::current() + .block_on(AsyncContext::full(&js_runtime)) + .unwrap() + }); + JavascriptInterpreter { + js_runtime: AsyncRuntimeWrapper(js_runtime), + nsig_context: AsyncContextWrapper(nsig_context), + nsig_function_name: Default::default(), + player_id: 0, + } + } +} + pub struct GlobalState { player_info: Mutex, + js_runtime_pool: Mutex>>, + all_runtimes: Mutex>>, } impl GlobalState { pub fn new() -> GlobalState { - return GlobalState { + let number_of_runtimes = available_parallelism() + .unwrap_or(NonZeroUsize::new(1).unwrap()) + .get(); + let mut runtime_vector: Vec> = + Vec::with_capacity(number_of_runtimes); + runtime_vector + .iter_mut() + .for_each(|a| *a = Arc::new(JavascriptInterpreter::new())); + + // Make a clone of the vector, this will clone all the values inside (Arc) + let mut runtime_vector2: Vec> = + Vec::with_capacity(number_of_runtimes); + runtime_vector2.clone_from(&runtime_vector); + let runtime_pool: Pool> = Pool::from_vec(runtime_vector2); + GlobalState { player_info: Mutex::new(PlayerInfo { - nsig_function_bytecode: Default::default(), + nsig_function_code: Default::default(), player_id: Default::default(), }), - }; + js_runtime_pool: Mutex::new(runtime_pool), + all_runtimes: Mutex::new(runtime_vector), + } } } pub async fn process_fetch_update(state: Arc) { @@ -47,7 +118,7 @@ pub async fn process_fetch_update(state: Arc) { } }; - let player_id_str = match REGEX_PLAYER_ID.captures(&response).unwrap().get(0) { + let player_id_str = match REGEX_PLAYER_ID.captures(&response).unwrap().get(1) { Some(result) => result.as_str(), None => return, }; @@ -56,6 +127,7 @@ pub async fn process_fetch_update(state: Arc) { let current_player_info = global_state.player_info.lock().await; let current_player_id = current_player_info.player_id; + // release the mutex for other tasks drop(current_player_info); if player_id == current_player_id { @@ -75,5 +147,22 @@ pub async fn process_fetch_update(state: Arc) { return; } }; + + let nsig_function_array = NSIG_FUNCTION_ARRAY.captures(&player_javascript).unwrap(); + let nsig_array_name = nsig_function_array.get(1).unwrap().as_str(); + let nsig_array_value = usize::from_str_radix(nsig_function_array.get(2).unwrap().as_str(), 10); + + let mut nsig_array_context_regex: String = String::new(); + nsig_array_context_regex += "var "; + nsig_array_context_regex += nsig_array_name; + nsig_array_context_regex += "\\s*=\\s*\\[(.+?)][;,]"; + + let nsig_array_context = match Regex::new(&nsig_array_context_regex) { + Ok(x) => x, + Err(x) => { + println!("Error: nsig regex compilation failed: {}", x); + return; + } + }; } -pub async fn process_decrypt_n_signature(state: Arc, sig: String) {} +pub async fn process_decrypt_n_signature(_state: Arc, _sig: String) {}