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