Skip to main content

electron_hook/
lib.rs

1#![warn(missing_docs)]
2//! A library for modding Electron apps in-memory, without modifying any program files.
3//!
4//! This library was made for improving the modding experience for Discord, but it can be used for any Electron app.
5//!
6//! # Features
7//!
8//! - `asar`: Enables the ASAR archive builder. (enabled by default)
9//! - `uuid`: Enables the use of random UUIDs for ASAR archive names. (enabled by default)
10//!
11//! # Examples
12//!
13//! electron-hook maps the original `app.asar` to `_app.asar`,
14//! so keep this in mind if you need to call the original file anywhere,
15//! as shown in this example.
16//!
17//! ```rust,no_run
18//! use electron_hook::asar::Asar;
19//! use electron_hook::paths::mod_artifact_dir;
20//!
21//! let mod_dir = mod_artifact_dir("moonlight");
22//!
23//! let _download_url = "https://github.com/moonlight-mod/moonlight/releases/latest/download/dist.tar.gz";
24//! // extract and save `_download_url` into `mod_dir`
25//!
26//! let mod_entrypoint = mod_dir.join("injector.js");
27//!
28//! let template = r#"
29//!     console.log("Mod injected!!!");
30//!     let asar = require("path").resolve(__dirname, "../_app.asar");
31//!     require(process.env.MODLOADER_MOD_ENTRYPOINT).inject(asar);
32//! "#;
33//!
34//! // Create the asar file
35//! let asar = Asar::new()
36//!     .with_id("moonlight")
37//!     .with_template(template)
38//!     .with_mod_entrypoint(mod_entrypoint.to_str().unwrap())
39//!     .create()
40//!     .unwrap();
41//!
42//! electron_hook::launch(
43//!     "/path/to/executable/Discord",
44//!     "/path/to/electron-hook.so",
45//!     asar.to_str().unwrap(),
46//!     vec!["--pass-arguments-here".to_string()],
47//!     true, // Detach the process
48//! );
49//! ```
50
51#[cfg(any(doc, feature = "asar"))]
52pub mod asar;
53pub mod paths;
54
55// For Linux
56#[cfg(target_os = "linux")]
57mod linux;
58
59// For Windows
60// TODO: Re-implement Windows support.
61#[cfg(target_os = "windows")]
62mod windows;
63
64// TODO: For MacOS
65
66/// Launches an Electron executable with the provided information.
67///
68/// `id` on Linux: the path to the executable.
69///
70/// `id` on Windows: the path to the directory containing `Update.exe`.
71///
72/// `library_path`: The path to the electron-hook `.so` or `.dll`
73///
74/// `asar_path`: The path to the ASAR file to inject
75///
76/// `args`: Arguments to pass to the executable
77///
78/// `detach`: It is recommended to set `detach` to true to prevent the process from dying when the parent process is closed.
79#[allow(unused_variables)]
80pub fn launch(
81    executable: &str,
82    library_path: &str,
83    asar_path: &str,
84    args: Vec<String>,
85    detach: bool,
86) -> Result<Option<u32>, String> {
87    #[cfg(target_os = "linux")]
88    {
89        linux::launch(executable, library_path, asar_path, args, detach)
90    }
91
92    #[cfg(target_os = "windows")]
93    {
94        // No need for detach on Windows, as the process already detaches itself.
95        windows::launch(executable, library_path, asar_path, args)
96    }
97}
98
99/// Launches an Electron executable through Flatpak with the provided information.
100///
101/// This is only available on Linux.
102///
103/// TODO: This only supports global packages. Are --user flatpak packages handled differently?
104///
105/// `id`: The ID of the flatpak package.
106///
107/// `library_path`: The path to the electron-hook `.so` or `.dll`
108///
109/// `asar_path`: The path to the ASAR file to inject
110///
111/// `args`: Arguments to pass to the executable
112///
113/// `detach`: It is recommended to set `detach` to true to prevent the process from dying when the parent process is closed.
114#[cfg(any(doc, target_os = "linux"))]
115pub fn launch_flatpak(
116    id: &FlatpakID,
117    library_path: &str,
118    asar_path: &str,
119    args: Vec<String>,
120    detach: bool,
121) -> Result<Option<u32>, String> {
122    linux::launch_flatpak(id, library_path, asar_path, args, detach)
123}
124
125/// The ID of a Flatpak package.
126pub enum FlatpakID {
127    /// A User install of a flatpak package. Will be run with `--user`
128    User(String),
129    /// A System install of a flatpak package. Will be run with `--system`
130    System(String),
131}
132
133impl std::fmt::Display for FlatpakID {
134    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
135        match self {
136            FlatpakID::User(id) => write!(f, "{id}"),
137            FlatpakID::System(id) => write!(f, "{id}"),
138        }
139    }
140}