├── .gitignore ├── Cross.toml ├── .vscode ├── settings.json ├── defsettings.json └── tasks.json ├── uninstall.sh ├── src ├── main.rs ├── utils.rs ├── patch.rs ├── server.rs ├── devices │ ├── mod.rs │ ├── device_generic.rs │ └── device_ally.rs └── steam.rs ├── Cargo.toml ├── LICENSE ├── install.sh ├── .github └── workflows │ └── build.yaml ├── README.md └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | .idea -------------------------------------------------------------------------------- /Cross.toml: -------------------------------------------------------------------------------- 1 | [target.x86_64-unknown-linux-gnu] 2 | pre-build = [ 3 | "dpkg --add-architecture $CROSS_DEB_ARCH", 4 | "apt-get update && apt-get install --assume-yes libssl-dev:$CROSS_DEB_ARCH" 5 | ] -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "deckip" : "192.168.0.22", 3 | "deckport" : "22", 4 | "deckpass" : "gamer", 5 | "deckkey" : "-i ${env:HOME}/.ssh/id_ed25519", 6 | "deckdir" : "/home/gamer", 7 | } -------------------------------------------------------------------------------- /.vscode/defsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "deckip" : "192.168.0.22", 3 | "deckport" : "22", 4 | "deckpass" : "gamer", 5 | "deckkey" : "-i ${env:HOME}/.ssh/id_ed25519", 6 | "deckdir" : "/home/gamer" 7 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "tunnel", 6 | "type": "shell", 7 | "group": "none", 8 | "detail": "SSH tunnel to the device", 9 | "command": "ssh gamer@${config:deckip} -N -f -L 4040:localhost:8080", 10 | "problemMatcher": [] 11 | }, 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /uninstall.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | [ "$UID" -eq 0 ] || exec sudo "$0" "$@" 4 | 5 | echo "Uninstalling Steam Patch..." 6 | 7 | USER_DIR="$(getent passwd $SUDO_USER | cut -d: -f6)" 8 | WORKING_FOLDER="${USER_DIR}/steam-patch" 9 | 10 | # Disable and remove services 11 | sudo systemctl disable --now steam-patch > /dev/null 12 | sudo rm -f "${USER_DIR}/.config/systemd/user/steam-patch.service" 13 | sudo rm -f "/etc/systemd/system/steam-patch.service" 14 | 15 | # Remove temporary folder if it exists from the install process 16 | rm -rf "/tmp/steam-patch" 17 | 18 | # Cleanup services folder 19 | sudo rm -rf "${WORKING_FOLDER}" 20 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use crate::devices::create_device; 2 | 3 | mod devices; 4 | mod patch; 5 | mod server; 6 | mod steam; 7 | mod utils; 8 | 9 | #[tokio::main] 10 | async fn main() { 11 | let mut tasks = vec![]; 12 | 13 | tasks.push(tokio::spawn(server::run())); 14 | 15 | if let Some(device) = create_device() { 16 | println!("Device created"); 17 | if let Some(mapper) = device.get_key_mapper() { 18 | tasks.push(mapper); 19 | } 20 | } 21 | 22 | if let Some(steam) = steam::SteamClient::watch().await { 23 | tasks.push(steam); 24 | } 25 | 26 | let _ = futures::future::join_all(tasks).await; 27 | } 28 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "steam-patch" 3 | version = "0.2.1" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | tokio = { version = "1", features = [ "rt-multi-thread", "macros"] } 8 | serde = { version = "1.0.169", features=["derive"] } 9 | serde_json = { version = "1.0.100" } 10 | tungstenite = "0.20.0" 11 | dirs = "5.0.1" 12 | futures = "0.3.28" 13 | sysinfo = "0.29.4" 14 | regex = "1" 15 | evdev = { version = "0.12.1", features = ["tokio", "serde"]} 16 | hyper = { version = "0.14", features = ["full"] } 17 | inotify = "0.10.1" 18 | 19 | [profile.release] 20 | opt-level = "z" 21 | # debug = true 22 | lto = true # Enable link-time optimization 23 | codegen-units = 1 # Reduce number of codegen units to increase optimizations 24 | panic = 'abort' # Abort on panic 25 | strip = true # Strip symbols from binary* 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Mikhail Kozlov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /src/utils.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::io; 3 | use std::process::{Command, Output}; 4 | use sysinfo::{ProcessExt, SystemExt}; 5 | 6 | #[allow(dead_code)] 7 | pub fn run_command(command: &[&str]) -> io::Result { 8 | let child = Command::new(command[0]) 9 | .args(&command[1..]) 10 | .stdout(std::process::Stdio::piped()) 11 | .spawn()?; 12 | 13 | let output = child.wait_with_output()?; 14 | Ok(output) 15 | } 16 | 17 | #[allow(dead_code)] 18 | pub fn get_username() -> String { 19 | let args: Vec = env::args().collect(); 20 | 21 | if args.len() != 2 { 22 | return String::from("gamer"); 23 | } 24 | 25 | let arg = &args[1]; 26 | 27 | if arg.starts_with("--user=") { 28 | let username = arg.trim_start_matches("--user="); 29 | String::from(username) 30 | } else { 31 | String::from("gamer") 32 | } 33 | } 34 | 35 | #[allow(dead_code)] 36 | fn is_steam_running() -> bool { 37 | let mut sys = sysinfo::System::new_all(); 38 | 39 | // We need to update the system value to get the fresh process list 40 | sys.refresh_all(); 41 | 42 | sys.processes() 43 | .values() 44 | .any(|process| process.name() == "steam") 45 | } 46 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | [ "$UID" -eq 0 ] || exec sudo "$0" "$@" 4 | 5 | echo "Installing Steam Patch release..." 6 | 7 | USER_DIR="$(getent passwd $SUDO_USER | cut -d: -f6)" 8 | WORKING_FOLDER="${USER_DIR}/steam-patch" 9 | 10 | # Create folder structure 11 | mkdir "${WORKING_FOLDER}" 12 | # Enable CEF debugging 13 | touch "${USER_DIR}/.steam/steam/.cef-enable-remote-debugging" 14 | 15 | # Download latest release and install it 16 | RELEASE=$(curl -s 'https://api.github.com/repos/Maclay74/steam-patch/releases' | jq -r "first(.[] | select(.prerelease == "false"))") 17 | VERSION=$(jq -r '.tag_name' <<< ${RELEASE} ) 18 | DOWNLOAD_URL=$(jq -r '.assets[].browser_download_url | select(endswith("steam-patch"))' <<< ${RELEASE}) 19 | 20 | printf "Installing version %s...\n" "${VERSION}" 21 | curl -L $DOWNLOAD_URL --output ${WORKING_FOLDER}/steam-patch 22 | chmod +x ${WORKING_FOLDER}/steam-patch 23 | 24 | systemctl --user stop steam-patch 2> /dev/null 25 | systemctl --user disable steam-patch 2> /dev/null 26 | 27 | systemctl stop steam-patch 2> /dev/null 28 | systemctl disable steam-patch 2> /dev/null 29 | 30 | # Add new service file 31 | cat > "${WORKING_FOLDER}/steam-patch.service" <<- EOM 32 | [Unit] 33 | Description=Steam Patches Loader 34 | Wants=network.target 35 | After=network.target 36 | 37 | [Service] 38 | Type=simple 39 | User=root 40 | ExecStart=${WORKING_FOLDER}/steam-patch --user=${SUDO_USER} 41 | WorkingDirectory=${WORKING_FOLDER} 42 | 43 | [Install] 44 | WantedBy=multi-user.target 45 | EOM 46 | 47 | rm -f "/etc/systemd/system/steam-patch.service" 48 | cp "${WORKING_FOLDER}/steam-patch.service" "/etc/systemd/system/steam-patch.service" 49 | 50 | # Run service 51 | systemctl daemon-reload 52 | systemctl enable steam-patch.service 53 | systemctl start steam-patch.service -------------------------------------------------------------------------------- /src/patch.rs: -------------------------------------------------------------------------------- 1 | use regex::Regex; 2 | 3 | use crate::utils::get_username; 4 | use std::{fs, path::PathBuf}; 5 | 6 | pub struct Patch { 7 | pub text_to_find: String, 8 | pub replacement_text: String, 9 | pub destination: PatchFile, 10 | } 11 | 12 | pub enum PatchFile { 13 | Chunk, 14 | Library, 15 | } 16 | 17 | impl PatchFile { 18 | pub fn get_regex(&self) -> &str { 19 | match self { 20 | PatchFile::Chunk => "^chunk", 21 | PatchFile::Library => "^library", 22 | } 23 | } 24 | } 25 | 26 | impl PatchFile { 27 | pub fn get_file(&self) -> Option { 28 | let username = get_username(); 29 | let steamui_path = dirs::home_dir() 30 | .map(|home| home.join(format!("/home/{}/.local/share/Steam/steamui", username))); 31 | 32 | let steamui_path = match steamui_path { 33 | Some(path) => path, 34 | None => return None, 35 | }; 36 | 37 | if !steamui_path.exists() { 38 | return None; 39 | } 40 | 41 | let regex = Regex::new(self.get_regex()).unwrap(); 42 | let matching_files: Vec<_> = match fs::read_dir(&steamui_path).ok() { 43 | Some(dir) => dir 44 | .filter_map(|entry| { 45 | let entry = entry.ok()?; 46 | let file_name = entry.file_name(); 47 | if regex.is_match(file_name.to_str().unwrap()) { 48 | Some(entry) 49 | } else { 50 | None 51 | } 52 | }) 53 | .collect(), 54 | None => return None, 55 | }; 56 | 57 | if matching_files.is_empty() || matching_files.len() > 1 { 58 | return None; 59 | } 60 | 61 | let first_matching_file = matching_files[0].file_name(); 62 | Some(steamui_path.join(first_matching_file)) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /.github/workflows/build.yaml: -------------------------------------------------------------------------------- 1 | name: Rust Build 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | tags: 7 | - '*' 8 | pull_request: 9 | branches: [ main ] 10 | 11 | env: 12 | CARGO_TERM_COLOR: always 13 | 14 | jobs: 15 | build: 16 | 17 | runs-on: ubuntu-latest 18 | 19 | steps: 20 | - name: 📚 Checkout Code 21 | uses: actions/checkout@v2 22 | 23 | - name: 🛠️ Set Script Permissions 24 | run: | 25 | chmod +x ./install.sh 26 | chmod +x ./uninstall.sh 27 | 28 | - name: 📦 Warm up cache 29 | uses: actions/cache@v3 30 | continue-on-error: false 31 | with: 32 | path: | 33 | ~/.cargo/bin/ 34 | ~/.cargo/registry/index/ 35 | ~/.cargo/registry/cache/ 36 | ~/.cargo/git/db/ 37 | target/ 38 | key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} 39 | restore-keys: ${{ runner.os }}-cargo- 40 | 41 | - name: 🦀 Setup Rust 42 | uses: actions-rs/toolchain@v1 43 | with: 44 | toolchain: stable 45 | target: x86_64-unknown-linux-gnu 46 | override: true 47 | 48 | - name: 🏗️ Build 49 | uses: actions-rs/cargo@v1 50 | with: 51 | command: build 52 | args: --release --target x86_64-unknown-linux-gnu 53 | 54 | - name: ✂️ Strip Debug Symbols 55 | run: strip -s target/x86_64-unknown-linux-gnu/release/steam-patch 56 | 57 | - name: ➡️ Compress executable with UPX 58 | run: | 59 | sudo apt-get install upx 60 | upx --best target/x86_64-unknown-linux-gnu/release/steam-patch 61 | 62 | - name: 📦 Upload build 63 | uses: actions/upload-artifact@v2 64 | with: 65 | name: steam-patch 66 | path: target/x86_64-unknown-linux-gnu/release/steam-patch 67 | 68 | - name: 🚀 Release 69 | if: startsWith(github.ref, 'refs/tags/') 70 | uses: softprops/action-gh-release@v1 71 | env: 72 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 73 | with: 74 | files: | 75 | target/x86_64-unknown-linux-gnu/release/steam-patch 76 | install.sh 77 | uninstall.sh 78 | -------------------------------------------------------------------------------- /src/server.rs: -------------------------------------------------------------------------------- 1 | use hyper::http::HeaderValue; 2 | use hyper::service::{make_service_fn, service_fn}; 3 | use hyper::Request; 4 | use hyper::{body, Body, Method, Response, Server}; 5 | use serde::Deserialize; 6 | use std::convert::Infallible; 7 | 8 | use crate::devices::create_device; 9 | 10 | #[derive(Deserialize)] 11 | pub struct SettingsRequest { 12 | pub per_app: Option, 13 | } 14 | 15 | #[derive(Deserialize)] 16 | pub struct PerAppConfig { 17 | pub tdp_limit: Option, 18 | } 19 | 20 | async fn update_settings(req: Request) -> Result, Infallible> { 21 | // Convert the request body into bytes 22 | let bytes = body::to_bytes(req.into_body()) 23 | .await 24 | .map_err(|_| Response::new(Body::from("Internal server error"))) 25 | .unwrap(); 26 | 27 | // Parse the bytes into a SettingsRequest 28 | let settings_request: SettingsRequest = serde_json::from_slice(&bytes) 29 | .map_err(|_| Response::new(Body::from("Failed to deserialize request body"))) 30 | .unwrap(); 31 | 32 | if let Some(device) = create_device() { 33 | device.update_settings(settings_request); 34 | } 35 | 36 | Ok(Response::new(Body::from("Settings updated"))) 37 | } 38 | 39 | fn set_cors_headers(mut response: Response) -> Response { 40 | let headers = response.headers_mut(); 41 | 42 | headers.insert("Access-Control-Allow-Origin", HeaderValue::from_static("*")); 43 | headers.insert( 44 | "Access-Control-Allow-Methods", 45 | HeaderValue::from_static("GET, POST, PUT, DELETE, OPTIONS"), 46 | ); 47 | headers.insert( 48 | "Access-Control-Allow-Headers", 49 | HeaderValue::from_static("*"), 50 | ); 51 | 52 | response 53 | } 54 | 55 | async fn router(req: Request) -> Result, Infallible> { 56 | let path = req.uri().path(); // Get the path of the request 57 | 58 | let response = match (req.method(), path) { 59 | (&Method::POST, "/update_settings") => update_settings(req).await, 60 | _ => Ok(Response::new(Body::empty())), 61 | }; 62 | 63 | Ok(set_cors_headers(response?)) 64 | } 65 | 66 | pub async fn run() { 67 | let make_svc = make_service_fn(|_conn| async { Ok::<_, Infallible>(service_fn(router)) }); 68 | 69 | let addr = ([127, 0, 0, 1], 1338).into(); 70 | 71 | let server = Server::bind(&addr).serve(make_svc); 72 | 73 | println!("Server started"); 74 | 75 | if let Err(e) = server.await { 76 | eprintln!("Server error: {}", e); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/devices/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod device_ally; 2 | pub mod device_generic; 3 | 4 | use crate::{patch::Patch, server::SettingsRequest}; 5 | use device_ally::DeviceAlly; 6 | use device_generic::DeviceGeneric; 7 | use regex::Regex; 8 | use std::fs; 9 | 10 | pub trait Device { 11 | fn update_settings(&self, request: SettingsRequest); 12 | fn set_tdp(&self, tdp: i8); 13 | fn get_patches(&self) -> Vec; 14 | fn get_key_mapper(&self) -> Option>; 15 | } 16 | 17 | pub fn create_device() -> Option> { 18 | match get_device_name() { 19 | Some(device_name) => { 20 | match device_name.trim() { 21 | // Asus Rog Ally 22 | "AMD Ryzen Z1 Extreme ASUSTeK COMPUTER INC. RC71L" => { 23 | Some(Box::new(DeviceAlly::new())) 24 | } 25 | 26 | // Ayaneo 2 27 | "AMD Ryzen 7 6800U with Radeon Graphics AYANEO AYANEO 2" => { 28 | Some(Box::new(DeviceGeneric::new(28))) 29 | } 30 | 31 | // Ayaneo Geek 32 | "AMD Ryzen 7 6800U with Radeon Graphics AYANEO GEEK" => { 33 | Some(Box::new(DeviceGeneric::new(28))) 34 | } 35 | 36 | // Ayaneo 2S 37 | "AMD Ryzen 7 7840U w/ Radeon 780M Graphics AYANEO AYANEO 2S" => { 38 | Some(Box::new(DeviceGeneric::new(30))) 39 | } 40 | 41 | // Ayaneo Geek 1S 42 | "AMD Ryzen 7 7840U w/ Radeon 780M Graphics AYANEO GEEK 1S" => { 43 | Some(Box::new(DeviceGeneric::new(30))) 44 | } 45 | 46 | // GPD WM2 47 | "AMD Ryzen 7 6800U with Radeon Graphics GPD G1619-04" => { 48 | Some(Box::new(DeviceGeneric::new(28))) 49 | } 50 | 51 | // AOKZOE A1 52 | "AMD Ryzen 7 6800U with Radeon Graphics AOKZOE AOKZOE A1 AR07" => { 53 | Some(Box::new(DeviceGeneric::new(28))) 54 | } 55 | 56 | // Any other device 57 | _ => Some(Box::new(DeviceGeneric::new(25))), 58 | } 59 | } 60 | None => None, 61 | } 62 | } 63 | 64 | fn get_device_name() -> Option { 65 | let cpuinfo = fs::read_to_string("/proc/cpuinfo").expect("Unknown"); 66 | 67 | let model_re = Regex::new(r"model name\s*:\s*(.*)").unwrap(); 68 | let model = model_re.captures_iter(&cpuinfo).next().unwrap()[1] 69 | .trim() 70 | .to_string(); 71 | 72 | let board_vendor = match fs::read_to_string("/sys/devices/virtual/dmi/id/board_vendor") { 73 | Ok(str) => str.trim().to_string(), 74 | Err(_) => return None, 75 | }; 76 | 77 | let board_name = match fs::read_to_string("/sys/devices/virtual/dmi/id/board_name") { 78 | Ok(str) => str.trim().to_string(), 79 | Err(_) => return None, 80 | }; 81 | 82 | Some(format!("{} {} {}", model, board_vendor, board_name)) 83 | } 84 | -------------------------------------------------------------------------------- /src/devices/device_generic.rs: -------------------------------------------------------------------------------- 1 | use super::Device; 2 | use crate::devices::Patch; 3 | use crate::patch::PatchFile; 4 | use crate::server::SettingsRequest; 5 | use crate::utils; 6 | 7 | pub struct DeviceGeneric { 8 | max_tdp: i8, 9 | } 10 | 11 | impl DeviceGeneric { 12 | pub fn new(max_tdp: i8) -> DeviceGeneric { 13 | DeviceGeneric { max_tdp } 14 | } 15 | } 16 | 17 | impl Device for DeviceGeneric { 18 | fn update_settings(&self, request: SettingsRequest) { 19 | if let Some(per_app) = &request.per_app { 20 | // TDP changes 21 | if let Some(tdp) = per_app.tdp_limit { 22 | self.set_tdp(tdp); 23 | } 24 | } 25 | } 26 | 27 | fn set_tdp(&self, tdp: i8) { 28 | // Update TDP 29 | let target_tdp = tdp as i32 * 1000; 30 | let boost_tdp = target_tdp + 2000; 31 | 32 | let command = [ 33 | "ryzenadj", 34 | &format!("--stapm-limit={}", target_tdp), 35 | &format!("--fast-limit={}", boost_tdp), 36 | &format!("--slow-limit={}", target_tdp), 37 | ]; 38 | match utils::run_command(&command) { 39 | Ok(_) => println!("Set TDP successfully!"), 40 | Err(_) => println!("Couldn't set TDP"), 41 | } 42 | } 43 | 44 | fn get_patches(&self) -> Vec { 45 | vec![ 46 | // Max TDP = 28 47 | Patch { 48 | text_to_find: "return[o,t,n,e=>r((()=>g.Get().SetTDPLimit(e)))".to_string(), 49 | replacement_text: format!("return[o,t,{:?},e=>r((()=>g.Get().SetTDPLimit(e)))", self.max_tdp).to_string(), 50 | destination: PatchFile::Chunk, 51 | }, 52 | // Listen to TDP changes 53 | Patch { 54 | text_to_find: "const t=c.Hm.deserializeBinary(e).toObject();Object.keys(t)".to_string(), 55 | replacement_text: "const t=c.Hm.deserializeBinary(e).toObject(); console.log(t); fetch(`http://localhost:1338/update_settings`, { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(t.settings)}); Object.keys(t)".to_string(), 56 | destination: PatchFile::Chunk, 57 | }, 58 | // Replace Xbox menu button with Steam one 59 | Patch { 60 | text_to_find: "/steaminputglyphs/xbox_button_logo.svg".to_string(), 61 | replacement_text: "/steaminputglyphs/sc_button_steam.svg".to_string(), 62 | destination: PatchFile::Chunk, 63 | }, 64 | 65 | // Change resolution to Native (if Default) after installation 66 | Patch { 67 | text_to_find: "DownloadComplete_Title\"),i=Ve(n,t.data.appid());const l=(0,H.Q2)();".to_string(), 68 | replacement_text: "DownloadComplete_Title\"),i=Ve(n,t.data.appid()); SteamClient.Apps.GetResolutionOverrideForApp(t.data.appid()).then(res => res === \"Default\" && SteamClient.Apps.SetAppResolutionOverride(t.data.appid(), \"Native\")); const l=(0,H.Q2)();".to_string(), 69 | destination: PatchFile::Chunk, 70 | }, 71 | ] 72 | } 73 | 74 | fn get_key_mapper(&self) -> Option> { 75 | None 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ⚙️ Steam Patch 2 | Steam Patch is a tool designed to enhance your Steam experience by applying patches to the Steam client. 3 | 4 | ## 📥 Installation 5 | To install Steam Patch, run next command in your terminal 6 | 7 | ```bash 8 | curl -L https://github.com/Maclay74/steam-patch/releases/latest/download/install.sh | sh 9 | ``` 10 | 11 | To uninstall: 12 | ```bash 13 | curl -L https://github.com/Maclay74/steam-patch/releases/latest/download/uninstall.sh | sh 14 | ``` 15 | 16 | This script will add a new service to `systemctl` and apply the necessary patches to your Steam client. The patches will also be automatically applied every time you restart your system. 17 | 18 | ## 📋 Available Patches 19 | 20 | Here is a list of currently available patches that can be applied: 21 | 22 | 1. **TDP Slider Fix for Quick Access Menu**: This patch addresses and resolves the issues with the TDP slider in the Quick Access Menu, ensuring a smoother user experience. 23 | 24 | 2. **Menu Icon Replacement** For a more integrated and consistent look, this patch replaces icon to 25 | 3. **Mapping Device-Specific Buttons for Asus Rog Ally**: This patch adjusts the mapping of the Asus Rog Ally's device-specific buttons for the Main Menu and Quick Access Menu to match the button mapping of the Steam Deck.. 26 | 27 | ## 🎯 Supported Devices 28 | 29 | Below is a list of devices supported by the Steam Patch: 30 | 31 | - **Asus Rog Ally** (30 TDP, changes thermal policy) 32 | - Aya Neo 2, Geek 1S (28 TDP) 33 | - GPD WM2 (28 TDP) 34 | - Any other AMD device (25 TDP) 35 | 36 | ⚠️ **Please note**: From version 0.5 onwards, for **Asus Rog Ally**, it becomes necessary to disable **HandyGCCS**. 37 | This is because the patch now uses a different method to support the Menu and QAM buttons, 38 | and HandyGCCS can interfere with this new approach. Use the following command to disable HandyGCCS: 39 | ``` 40 | sudo systemctl disable handycon 41 | ``` 42 | To enable it back: 43 | ``` 44 | sudo systemctl enable handycon 45 | ``` 46 | 47 | Before adjusting the TDP, please ensure your device can support the new value. 48 | There is a tangible risk of causing damage to your device otherwise. 49 | If you're aware that your device has different limitations, kindly reach out to me via 50 | [Discord](https://discordapp.com/users/maclay74), 51 | [Telegram](https://t.me/mikefinch), or 52 | [email](mailto:mishakozlov74@gmail.com), and I will handle it. 53 | 54 | ## 📝 License 55 | 56 | This project is licensed under the [MIT License](LICENSE). Feel free to use and modify the code according to the terms of the license. 57 | 58 | I've added a new section for supported devices and removed the note about no support of patching after a Steam restart as you requested. 59 | -------------------------------------------------------------------------------- /src/devices/device_ally.rs: -------------------------------------------------------------------------------- 1 | use super::Device; 2 | use crate::devices::device_generic::DeviceGeneric; 3 | use crate::devices::Patch; 4 | use crate::patch::PatchFile; 5 | use crate::server::SettingsRequest; 6 | use crate::steam::SteamClient; 7 | use std::fs; 8 | use std::thread; 9 | use std::time::Duration; 10 | 11 | pub struct DeviceAlly { 12 | device: DeviceGeneric, 13 | } 14 | 15 | impl DeviceAlly { 16 | pub fn new() -> Self { 17 | DeviceAlly { 18 | device: DeviceGeneric::new(30), 19 | } 20 | } 21 | } 22 | 23 | impl Device for DeviceAlly { 24 | fn update_settings(&self, request: SettingsRequest) { 25 | if let Some(per_app) = &request.per_app { 26 | // TDP changes 27 | if let Some(tdp) = per_app.tdp_limit { 28 | self.set_tdp(tdp); 29 | } 30 | } 31 | } 32 | 33 | fn get_patches(&self) -> Vec { 34 | let mut patches = self.device.get_patches(); 35 | patches.push(Patch { 36 | text_to_find: String::from("this.m_rgControllers=new Map,\"undefined\"!=typeof SteamClient&&(this.m_hUnregisterControllerDigitalInput"), 37 | replacement_text: String::from("this.m_rgControllers=new Map; window.HandleSystemKeyEvents = this.HandleSystemKeyEvents; \"undefined\"!=typeof SteamClient&&(this.m_hUnregisterControllerDigitalInput"), 38 | destination: PatchFile::Library, 39 | }); 40 | patches 41 | } 42 | 43 | fn set_tdp(&self, tdp: i8) { 44 | // Update thermal policy 45 | let thermal_policy = match tdp { 46 | val if val < 12 => 2, // silent 47 | val if (12..=25).contains(&val) => 0, // performance 48 | _ => 1, // turbo 49 | }; 50 | 51 | println!("New Policy: {}", thermal_policy); 52 | 53 | let file_path = "/sys/devices/platform/asus-nb-wmi/throttle_thermal_policy"; 54 | let _ = thread::spawn(move || match fs::read_to_string(file_path) { 55 | Ok(content) if content.trim() != thermal_policy.to_string() => { 56 | thread::sleep(Duration::from_millis(50)); 57 | fs::write(file_path, thermal_policy.to_string()) 58 | .expect("Couldn't change thermal policy") 59 | } 60 | _ => {} 61 | }); 62 | 63 | self.device.set_tdp(tdp); 64 | } 65 | 66 | fn get_key_mapper(&self) -> Option> { 67 | tokio::spawn(async move { 68 | let mut steam = SteamClient::new(); 69 | steam.connect().await; 70 | start_mapper(steam); 71 | }); 72 | None 73 | } 74 | } 75 | 76 | pub fn pick_device() -> Option { 77 | let target_vendor_id = 0xb05u16; 78 | let target_product_id = 0x1abeu16; 79 | 80 | let devices = evdev::enumerate(); 81 | for (_, device) in devices { 82 | let input_id = device.input_id(); 83 | 84 | if input_id.vendor() == target_vendor_id && input_id.product() == target_product_id { 85 | if device.supported_keys().map_or(false, |keys| keys.contains(evdev::Key::KEY_PROG1)) { 86 | return Some(device); 87 | } 88 | } 89 | } 90 | 91 | None 92 | } 93 | 94 | pub fn start_mapper(mut steam:SteamClient) -> Option> { 95 | let device = pick_device(); 96 | 97 | match device { 98 | Some(device) => Some(tokio::spawn(async move { 99 | if let Ok(mut events) = device.into_event_stream() { 100 | loop { 101 | match events.next_event().await { 102 | Ok(event) => { 103 | if let evdev::InputEventKind::Key(key) = event.kind() { 104 | // QAM button pressed 105 | if key == evdev::Key::KEY_PROG1 && event.value() == 0 { 106 | println!("Show QAM"); 107 | steam 108 | .execute("window.HandleSystemKeyEvents({eKey: 1})") 109 | .await; 110 | } 111 | 112 | // Main menu button pressed 113 | if key == evdev::Key::KEY_F16 && event.value() == 0 { 114 | println!("Show Menu"); 115 | steam 116 | .execute("window.HandleSystemKeyEvents({eKey: 0})") 117 | .await; 118 | } 119 | } 120 | }, 121 | Err(_) => { 122 | print!("Error reading event stream, retrying in 1 second"); 123 | thread::sleep(Duration::from_secs(1)); 124 | tokio::spawn(async move { 125 | start_mapper(steam) 126 | }); 127 | break 128 | } 129 | }; 130 | } 131 | } 132 | })), 133 | None => { 134 | println!("No Ally-specific found, retrying in 2 seconds"); 135 | thread::sleep(Duration::from_secs(2)); 136 | tokio::spawn(async move { 137 | start_mapper(steam) 138 | }); 139 | None 140 | } 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/steam.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] // Allow non-snake_case identifiers 2 | 3 | use crate::devices::create_device; 4 | use crate::patch::Patch; 5 | use crate::utils::get_username; 6 | use hyper::{Client, Uri}; 7 | use inotify::{Inotify, WatchMask}; 8 | use serde::Deserialize; 9 | use std::collections::HashMap; 10 | use std::fs::{self, File}; 11 | use std::io::{BufRead, BufReader, Error}; 12 | use std::path::PathBuf; 13 | use sysinfo::{ProcessExt, SystemExt}; 14 | use tokio::time::{sleep, Duration}; 15 | use tungstenite::connect; 16 | use tungstenite::stream::MaybeTlsStream; 17 | use tungstenite::{Message, WebSocket}; 18 | 19 | #[derive(Deserialize)] 20 | struct Tab { 21 | title: String, 22 | webSocketDebuggerUrl: String, 23 | } 24 | 25 | pub struct SteamClient { 26 | socket: Option>>, 27 | } 28 | 29 | impl SteamClient { 30 | pub fn patch(&mut self, patches: Vec) -> Result<(), Error> { 31 | let mut opened_files: HashMap = HashMap::new(); 32 | 33 | for patch in patches { 34 | let path_file = patch.destination.get_file().unwrap(); 35 | let path_str = path_file.to_str().unwrap().to_string(); 36 | let content = opened_files 37 | .entry(path_str.clone()) 38 | .or_insert_with(|| fs::read_to_string(&path_file).unwrap()); 39 | let text_to_find = &patch.text_to_find; 40 | let replacement_text = &patch.replacement_text; 41 | *content = content.replace(text_to_find, replacement_text); 42 | } 43 | 44 | for (path, content) in &opened_files { 45 | fs::write(path, content)?; 46 | } 47 | 48 | Ok(()) 49 | } 50 | 51 | pub fn unpatch(&mut self, patches: Vec) -> Result<(), Error> { 52 | let mut opened_files: HashMap = HashMap::new(); 53 | 54 | for patch in patches { 55 | let path_file = patch.destination.get_file().unwrap(); 56 | let path_str = path_file.to_str().unwrap().to_string(); 57 | let content = opened_files 58 | .entry(path_str.clone()) 59 | .or_insert_with(|| fs::read_to_string(&path_file).unwrap()); 60 | let text_to_find = &patch.text_to_find; 61 | let replacement_text = &patch.replacement_text; 62 | *content = content.replace(replacement_text, text_to_find); 63 | } 64 | 65 | for (path, content) in &opened_files { 66 | fs::write(path, content)?; 67 | } 68 | 69 | Ok(()) 70 | } 71 | 72 | async fn send_message(&mut self, message: serde_json::Value) { 73 | let mut retries = 3; 74 | 75 | while retries > 0 { 76 | match self.socket.as_mut() { 77 | Some(socket) => match socket.send(Message::Text(message.to_string())) { 78 | Ok(_) => break, 79 | Err(_) => { 80 | eprintln!("Couldn't send message to Steam, retrying..."); 81 | 82 | self.connect().await; 83 | 84 | retries -= 1; 85 | } 86 | }, 87 | None => { 88 | self.connect().await; 89 | retries -= 1; 90 | } 91 | } 92 | } 93 | } 94 | 95 | pub async fn reboot(&mut self) { 96 | self.send_message(serde_json::json!({ 97 | "id": 1, 98 | "method": "Page.reload", 99 | })) 100 | .await; 101 | } 102 | 103 | pub async fn execute(&mut self, js_code: &str) { 104 | self.send_message(serde_json::json!({ 105 | "id": 1, 106 | "method": "Runtime.evaluate", 107 | "params": { 108 | "expression": js_code, 109 | } 110 | })) 111 | .await; 112 | } 113 | 114 | async fn get_context() -> Option { 115 | println!("Getting Steam..."); 116 | 117 | let client = Client::new(); 118 | let start_time = tokio::time::Instant::now(); 119 | let uri: Uri = "http://localhost:8080/json".parse().unwrap(); 120 | 121 | loop { 122 | if start_time.elapsed() > Duration::from_secs(60) { 123 | println!("Timeout while trying to fetch Steam data!"); 124 | return None; 125 | } 126 | 127 | match client.get(uri.clone()).await { 128 | Ok(response) => { 129 | let bytes = hyper::body::to_bytes(response.into_body()).await.unwrap(); 130 | let tabs: Vec = 131 | serde_json::from_slice(&bytes).unwrap_or_else(|_| Vec::new()); 132 | if let Some(tab) = tabs.into_iter().find(|tab| { 133 | tab.title == "SharedJSContext" && !tab.webSocketDebuggerUrl.is_empty() 134 | }) { 135 | return Some(tab.webSocketDebuggerUrl); 136 | } 137 | } 138 | Err(_) => println!("Couldn't connect to Steam"), 139 | } 140 | 141 | sleep(Duration::from_millis(50)).await; 142 | } 143 | } 144 | 145 | pub fn new() -> SteamClient { 146 | return SteamClient { socket: None }; 147 | } 148 | 149 | pub async fn connect(&mut self) { 150 | if let Some(context) = Self::get_context().await { 151 | self.socket = match connect(context) { 152 | Ok((socket, _)) => Some(socket), 153 | Err(_) => None, 154 | }; 155 | } 156 | } 157 | 158 | pub fn get_log_path() -> Option { 159 | let username = get_username(); 160 | dirs::home_dir().map(|home| { 161 | home.join(format!( 162 | "/home/{}/.local/share/Steam/logs/bootstrap_log.txt", 163 | username 164 | )) 165 | }) 166 | } 167 | 168 | pub async fn watch() -> Option> { 169 | // If Steam client is already running, patch it and restart 170 | if Self::is_running() { 171 | let mut client = Self::new(); 172 | client.connect().await; 173 | 174 | if let Some(device) = create_device() { 175 | match client.patch(device.get_patches()) { 176 | Ok(_) => println!("Steam patched"), 177 | Err(_) => eprintln!("Couldn't patch Steam"), 178 | } 179 | } 180 | 181 | client.reboot().await; 182 | } 183 | 184 | // Watch for changes in log 185 | let mut inotify = Inotify::init().expect("Failed to initialize inotify"); 186 | 187 | if let Some(log_path) = Self::get_log_path() { 188 | inotify.watches().add(log_path, WatchMask::MODIFY).unwrap(); 189 | } 190 | 191 | println!("Watching Steam log..."); 192 | let task = tokio::task::spawn_blocking(move || { 193 | let mut buffer = [0u8; 4096]; 194 | let mut client = Self::new(); 195 | loop { 196 | if let Ok(events) = inotify.read_events_blocking(&mut buffer) { 197 | for _ in events { 198 | let file = File::open(Self::get_log_path().unwrap()).unwrap(); 199 | let reader = BufReader::new(file); 200 | 201 | match reader.lines().last() { 202 | Some(Ok(line)) => { 203 | if line.contains("Verification complete") { 204 | if let Some(device) = create_device() { 205 | match client.patch(device.get_patches()) { 206 | Ok(_) => println!("Steam patched"), 207 | Err(_) => eprintln!("Couldn't patch Steam"), 208 | } 209 | } 210 | } 211 | 212 | if line.contains("Shutdown") { 213 | if let Some(device) = create_device() { 214 | match client.unpatch(device.get_patches()) { 215 | Ok(_) => println!("Steam unpatched"), 216 | Err(_) => eprintln!("Couldn't unpatch Steam"), 217 | } 218 | } 219 | } 220 | } 221 | Some(Err(err)) => println!("Error reading line: {}", err), 222 | None => println!("The file is empty"), 223 | } 224 | } 225 | } 226 | } 227 | }); 228 | 229 | Some(task) 230 | } 231 | 232 | fn is_running() -> bool { 233 | let mut sys = sysinfo::System::new_all(); 234 | 235 | // We need to update the system value to get the fresh process list 236 | sys.refresh_all(); 237 | 238 | sys.processes() 239 | .values() 240 | .any(|process| process.name() == "steam") 241 | } 242 | } 243 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.20.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler" 16 | version = "1.0.2" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 19 | 20 | [[package]] 21 | name = "aho-corasick" 22 | version = "1.0.2" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" 25 | dependencies = [ 26 | "memchr", 27 | ] 28 | 29 | [[package]] 30 | name = "autocfg" 31 | version = "1.1.0" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 34 | 35 | [[package]] 36 | name = "backtrace" 37 | version = "0.3.68" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" 40 | dependencies = [ 41 | "addr2line", 42 | "cc", 43 | "cfg-if", 44 | "libc", 45 | "miniz_oxide", 46 | "object", 47 | "rustc-demangle", 48 | ] 49 | 50 | [[package]] 51 | name = "bitflags" 52 | version = "1.3.2" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 55 | 56 | [[package]] 57 | name = "bitvec" 58 | version = "1.0.1" 59 | source = "registry+https://github.com/rust-lang/crates.io-index" 60 | checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" 61 | dependencies = [ 62 | "funty", 63 | "radium", 64 | "tap", 65 | "wyz", 66 | ] 67 | 68 | [[package]] 69 | name = "block-buffer" 70 | version = "0.10.4" 71 | source = "registry+https://github.com/rust-lang/crates.io-index" 72 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 73 | dependencies = [ 74 | "generic-array", 75 | ] 76 | 77 | [[package]] 78 | name = "byteorder" 79 | version = "1.4.3" 80 | source = "registry+https://github.com/rust-lang/crates.io-index" 81 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 82 | 83 | [[package]] 84 | name = "bytes" 85 | version = "1.4.0" 86 | source = "registry+https://github.com/rust-lang/crates.io-index" 87 | checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" 88 | 89 | [[package]] 90 | name = "cc" 91 | version = "1.0.79" 92 | source = "registry+https://github.com/rust-lang/crates.io-index" 93 | checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" 94 | 95 | [[package]] 96 | name = "cfg-if" 97 | version = "1.0.0" 98 | source = "registry+https://github.com/rust-lang/crates.io-index" 99 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 100 | 101 | [[package]] 102 | name = "core-foundation-sys" 103 | version = "0.8.4" 104 | source = "registry+https://github.com/rust-lang/crates.io-index" 105 | checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" 106 | 107 | [[package]] 108 | name = "cpufeatures" 109 | version = "0.2.9" 110 | source = "registry+https://github.com/rust-lang/crates.io-index" 111 | checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" 112 | dependencies = [ 113 | "libc", 114 | ] 115 | 116 | [[package]] 117 | name = "crossbeam-channel" 118 | version = "0.5.8" 119 | source = "registry+https://github.com/rust-lang/crates.io-index" 120 | checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" 121 | dependencies = [ 122 | "cfg-if", 123 | "crossbeam-utils", 124 | ] 125 | 126 | [[package]] 127 | name = "crossbeam-deque" 128 | version = "0.8.3" 129 | source = "registry+https://github.com/rust-lang/crates.io-index" 130 | checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" 131 | dependencies = [ 132 | "cfg-if", 133 | "crossbeam-epoch", 134 | "crossbeam-utils", 135 | ] 136 | 137 | [[package]] 138 | name = "crossbeam-epoch" 139 | version = "0.9.15" 140 | source = "registry+https://github.com/rust-lang/crates.io-index" 141 | checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" 142 | dependencies = [ 143 | "autocfg", 144 | "cfg-if", 145 | "crossbeam-utils", 146 | "memoffset 0.9.0", 147 | "scopeguard", 148 | ] 149 | 150 | [[package]] 151 | name = "crossbeam-utils" 152 | version = "0.8.16" 153 | source = "registry+https://github.com/rust-lang/crates.io-index" 154 | checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" 155 | dependencies = [ 156 | "cfg-if", 157 | ] 158 | 159 | [[package]] 160 | name = "crypto-common" 161 | version = "0.1.6" 162 | source = "registry+https://github.com/rust-lang/crates.io-index" 163 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 164 | dependencies = [ 165 | "generic-array", 166 | "typenum", 167 | ] 168 | 169 | [[package]] 170 | name = "data-encoding" 171 | version = "2.4.0" 172 | source = "registry+https://github.com/rust-lang/crates.io-index" 173 | checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" 174 | 175 | [[package]] 176 | name = "digest" 177 | version = "0.10.7" 178 | source = "registry+https://github.com/rust-lang/crates.io-index" 179 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 180 | dependencies = [ 181 | "block-buffer", 182 | "crypto-common", 183 | ] 184 | 185 | [[package]] 186 | name = "dirs" 187 | version = "5.0.1" 188 | source = "registry+https://github.com/rust-lang/crates.io-index" 189 | checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" 190 | dependencies = [ 191 | "dirs-sys", 192 | ] 193 | 194 | [[package]] 195 | name = "dirs-sys" 196 | version = "0.4.1" 197 | source = "registry+https://github.com/rust-lang/crates.io-index" 198 | checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" 199 | dependencies = [ 200 | "libc", 201 | "option-ext", 202 | "redox_users", 203 | "windows-sys", 204 | ] 205 | 206 | [[package]] 207 | name = "either" 208 | version = "1.8.1" 209 | source = "registry+https://github.com/rust-lang/crates.io-index" 210 | checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" 211 | 212 | [[package]] 213 | name = "evdev" 214 | version = "0.12.1" 215 | source = "registry+https://github.com/rust-lang/crates.io-index" 216 | checksum = "2bed59fcc8cfd6b190814a509018388462d3b203cf6dd10db5c00087e72a83f3" 217 | dependencies = [ 218 | "bitvec", 219 | "cfg-if", 220 | "futures-core", 221 | "libc", 222 | "nix", 223 | "paste", 224 | "serde", 225 | "thiserror", 226 | "tokio", 227 | ] 228 | 229 | [[package]] 230 | name = "fnv" 231 | version = "1.0.7" 232 | source = "registry+https://github.com/rust-lang/crates.io-index" 233 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 234 | 235 | [[package]] 236 | name = "form_urlencoded" 237 | version = "1.2.0" 238 | source = "registry+https://github.com/rust-lang/crates.io-index" 239 | checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" 240 | dependencies = [ 241 | "percent-encoding", 242 | ] 243 | 244 | [[package]] 245 | name = "funty" 246 | version = "2.0.0" 247 | source = "registry+https://github.com/rust-lang/crates.io-index" 248 | checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" 249 | 250 | [[package]] 251 | name = "futures" 252 | version = "0.3.28" 253 | source = "registry+https://github.com/rust-lang/crates.io-index" 254 | checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" 255 | dependencies = [ 256 | "futures-channel", 257 | "futures-core", 258 | "futures-executor", 259 | "futures-io", 260 | "futures-sink", 261 | "futures-task", 262 | "futures-util", 263 | ] 264 | 265 | [[package]] 266 | name = "futures-channel" 267 | version = "0.3.28" 268 | source = "registry+https://github.com/rust-lang/crates.io-index" 269 | checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" 270 | dependencies = [ 271 | "futures-core", 272 | "futures-sink", 273 | ] 274 | 275 | [[package]] 276 | name = "futures-core" 277 | version = "0.3.28" 278 | source = "registry+https://github.com/rust-lang/crates.io-index" 279 | checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" 280 | 281 | [[package]] 282 | name = "futures-executor" 283 | version = "0.3.28" 284 | source = "registry+https://github.com/rust-lang/crates.io-index" 285 | checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" 286 | dependencies = [ 287 | "futures-core", 288 | "futures-task", 289 | "futures-util", 290 | ] 291 | 292 | [[package]] 293 | name = "futures-io" 294 | version = "0.3.28" 295 | source = "registry+https://github.com/rust-lang/crates.io-index" 296 | checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" 297 | 298 | [[package]] 299 | name = "futures-macro" 300 | version = "0.3.28" 301 | source = "registry+https://github.com/rust-lang/crates.io-index" 302 | checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" 303 | dependencies = [ 304 | "proc-macro2", 305 | "quote", 306 | "syn", 307 | ] 308 | 309 | [[package]] 310 | name = "futures-sink" 311 | version = "0.3.28" 312 | source = "registry+https://github.com/rust-lang/crates.io-index" 313 | checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" 314 | 315 | [[package]] 316 | name = "futures-task" 317 | version = "0.3.28" 318 | source = "registry+https://github.com/rust-lang/crates.io-index" 319 | checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" 320 | 321 | [[package]] 322 | name = "futures-util" 323 | version = "0.3.28" 324 | source = "registry+https://github.com/rust-lang/crates.io-index" 325 | checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" 326 | dependencies = [ 327 | "futures-channel", 328 | "futures-core", 329 | "futures-io", 330 | "futures-macro", 331 | "futures-sink", 332 | "futures-task", 333 | "memchr", 334 | "pin-project-lite", 335 | "pin-utils", 336 | "slab", 337 | ] 338 | 339 | [[package]] 340 | name = "generic-array" 341 | version = "0.14.7" 342 | source = "registry+https://github.com/rust-lang/crates.io-index" 343 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 344 | dependencies = [ 345 | "typenum", 346 | "version_check", 347 | ] 348 | 349 | [[package]] 350 | name = "getrandom" 351 | version = "0.2.10" 352 | source = "registry+https://github.com/rust-lang/crates.io-index" 353 | checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" 354 | dependencies = [ 355 | "cfg-if", 356 | "libc", 357 | "wasi", 358 | ] 359 | 360 | [[package]] 361 | name = "gimli" 362 | version = "0.27.3" 363 | source = "registry+https://github.com/rust-lang/crates.io-index" 364 | checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" 365 | 366 | [[package]] 367 | name = "h2" 368 | version = "0.3.20" 369 | source = "registry+https://github.com/rust-lang/crates.io-index" 370 | checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049" 371 | dependencies = [ 372 | "bytes", 373 | "fnv", 374 | "futures-core", 375 | "futures-sink", 376 | "futures-util", 377 | "http", 378 | "indexmap", 379 | "slab", 380 | "tokio", 381 | "tokio-util", 382 | "tracing", 383 | ] 384 | 385 | [[package]] 386 | name = "hashbrown" 387 | version = "0.12.3" 388 | source = "registry+https://github.com/rust-lang/crates.io-index" 389 | checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" 390 | 391 | [[package]] 392 | name = "hermit-abi" 393 | version = "0.3.2" 394 | source = "registry+https://github.com/rust-lang/crates.io-index" 395 | checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" 396 | 397 | [[package]] 398 | name = "http" 399 | version = "0.2.9" 400 | source = "registry+https://github.com/rust-lang/crates.io-index" 401 | checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" 402 | dependencies = [ 403 | "bytes", 404 | "fnv", 405 | "itoa", 406 | ] 407 | 408 | [[package]] 409 | name = "http-body" 410 | version = "0.4.5" 411 | source = "registry+https://github.com/rust-lang/crates.io-index" 412 | checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" 413 | dependencies = [ 414 | "bytes", 415 | "http", 416 | "pin-project-lite", 417 | ] 418 | 419 | [[package]] 420 | name = "httparse" 421 | version = "1.8.0" 422 | source = "registry+https://github.com/rust-lang/crates.io-index" 423 | checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" 424 | 425 | [[package]] 426 | name = "httpdate" 427 | version = "1.0.2" 428 | source = "registry+https://github.com/rust-lang/crates.io-index" 429 | checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" 430 | 431 | [[package]] 432 | name = "hyper" 433 | version = "0.14.27" 434 | source = "registry+https://github.com/rust-lang/crates.io-index" 435 | checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" 436 | dependencies = [ 437 | "bytes", 438 | "futures-channel", 439 | "futures-core", 440 | "futures-util", 441 | "h2", 442 | "http", 443 | "http-body", 444 | "httparse", 445 | "httpdate", 446 | "itoa", 447 | "pin-project-lite", 448 | "socket2", 449 | "tokio", 450 | "tower-service", 451 | "tracing", 452 | "want", 453 | ] 454 | 455 | [[package]] 456 | name = "idna" 457 | version = "0.4.0" 458 | source = "registry+https://github.com/rust-lang/crates.io-index" 459 | checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" 460 | dependencies = [ 461 | "unicode-bidi", 462 | "unicode-normalization", 463 | ] 464 | 465 | [[package]] 466 | name = "indexmap" 467 | version = "1.9.3" 468 | source = "registry+https://github.com/rust-lang/crates.io-index" 469 | checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" 470 | dependencies = [ 471 | "autocfg", 472 | "hashbrown", 473 | ] 474 | 475 | [[package]] 476 | name = "inotify" 477 | version = "0.10.1" 478 | source = "registry+https://github.com/rust-lang/crates.io-index" 479 | checksum = "ff335215fb898bf09c45833b657233d8c0b699a616d7dd64d0513080da270ab6" 480 | dependencies = [ 481 | "bitflags", 482 | "futures-core", 483 | "inotify-sys", 484 | "libc", 485 | "tokio", 486 | ] 487 | 488 | [[package]] 489 | name = "inotify-sys" 490 | version = "0.1.5" 491 | source = "registry+https://github.com/rust-lang/crates.io-index" 492 | checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" 493 | dependencies = [ 494 | "libc", 495 | ] 496 | 497 | [[package]] 498 | name = "itoa" 499 | version = "1.0.8" 500 | source = "registry+https://github.com/rust-lang/crates.io-index" 501 | checksum = "62b02a5381cc465bd3041d84623d0fa3b66738b52b8e2fc3bab8ad63ab032f4a" 502 | 503 | [[package]] 504 | name = "libc" 505 | version = "0.2.147" 506 | source = "registry+https://github.com/rust-lang/crates.io-index" 507 | checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" 508 | 509 | [[package]] 510 | name = "log" 511 | version = "0.4.19" 512 | source = "registry+https://github.com/rust-lang/crates.io-index" 513 | checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" 514 | 515 | [[package]] 516 | name = "memchr" 517 | version = "2.5.0" 518 | source = "registry+https://github.com/rust-lang/crates.io-index" 519 | checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" 520 | 521 | [[package]] 522 | name = "memoffset" 523 | version = "0.6.5" 524 | source = "registry+https://github.com/rust-lang/crates.io-index" 525 | checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" 526 | dependencies = [ 527 | "autocfg", 528 | ] 529 | 530 | [[package]] 531 | name = "memoffset" 532 | version = "0.9.0" 533 | source = "registry+https://github.com/rust-lang/crates.io-index" 534 | checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" 535 | dependencies = [ 536 | "autocfg", 537 | ] 538 | 539 | [[package]] 540 | name = "miniz_oxide" 541 | version = "0.7.1" 542 | source = "registry+https://github.com/rust-lang/crates.io-index" 543 | checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" 544 | dependencies = [ 545 | "adler", 546 | ] 547 | 548 | [[package]] 549 | name = "mio" 550 | version = "0.8.8" 551 | source = "registry+https://github.com/rust-lang/crates.io-index" 552 | checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" 553 | dependencies = [ 554 | "libc", 555 | "wasi", 556 | "windows-sys", 557 | ] 558 | 559 | [[package]] 560 | name = "nix" 561 | version = "0.23.2" 562 | source = "registry+https://github.com/rust-lang/crates.io-index" 563 | checksum = "8f3790c00a0150112de0f4cd161e3d7fc4b2d8a5542ffc35f099a2562aecb35c" 564 | dependencies = [ 565 | "bitflags", 566 | "cc", 567 | "cfg-if", 568 | "libc", 569 | "memoffset 0.6.5", 570 | ] 571 | 572 | [[package]] 573 | name = "ntapi" 574 | version = "0.4.1" 575 | source = "registry+https://github.com/rust-lang/crates.io-index" 576 | checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4" 577 | dependencies = [ 578 | "winapi", 579 | ] 580 | 581 | [[package]] 582 | name = "num_cpus" 583 | version = "1.16.0" 584 | source = "registry+https://github.com/rust-lang/crates.io-index" 585 | checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" 586 | dependencies = [ 587 | "hermit-abi", 588 | "libc", 589 | ] 590 | 591 | [[package]] 592 | name = "object" 593 | version = "0.31.1" 594 | source = "registry+https://github.com/rust-lang/crates.io-index" 595 | checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" 596 | dependencies = [ 597 | "memchr", 598 | ] 599 | 600 | [[package]] 601 | name = "once_cell" 602 | version = "1.18.0" 603 | source = "registry+https://github.com/rust-lang/crates.io-index" 604 | checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" 605 | 606 | [[package]] 607 | name = "option-ext" 608 | version = "0.2.0" 609 | source = "registry+https://github.com/rust-lang/crates.io-index" 610 | checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" 611 | 612 | [[package]] 613 | name = "paste" 614 | version = "1.0.13" 615 | source = "registry+https://github.com/rust-lang/crates.io-index" 616 | checksum = "b4b27ab7be369122c218afc2079489cdcb4b517c0a3fc386ff11e1fedfcc2b35" 617 | 618 | [[package]] 619 | name = "percent-encoding" 620 | version = "2.3.0" 621 | source = "registry+https://github.com/rust-lang/crates.io-index" 622 | checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" 623 | 624 | [[package]] 625 | name = "pin-project-lite" 626 | version = "0.2.10" 627 | source = "registry+https://github.com/rust-lang/crates.io-index" 628 | checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57" 629 | 630 | [[package]] 631 | name = "pin-utils" 632 | version = "0.1.0" 633 | source = "registry+https://github.com/rust-lang/crates.io-index" 634 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 635 | 636 | [[package]] 637 | name = "ppv-lite86" 638 | version = "0.2.17" 639 | source = "registry+https://github.com/rust-lang/crates.io-index" 640 | checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" 641 | 642 | [[package]] 643 | name = "proc-macro2" 644 | version = "1.0.64" 645 | source = "registry+https://github.com/rust-lang/crates.io-index" 646 | checksum = "78803b62cbf1f46fde80d7c0e803111524b9877184cfe7c3033659490ac7a7da" 647 | dependencies = [ 648 | "unicode-ident", 649 | ] 650 | 651 | [[package]] 652 | name = "quote" 653 | version = "1.0.29" 654 | source = "registry+https://github.com/rust-lang/crates.io-index" 655 | checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105" 656 | dependencies = [ 657 | "proc-macro2", 658 | ] 659 | 660 | [[package]] 661 | name = "radium" 662 | version = "0.7.0" 663 | source = "registry+https://github.com/rust-lang/crates.io-index" 664 | checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" 665 | 666 | [[package]] 667 | name = "rand" 668 | version = "0.8.5" 669 | source = "registry+https://github.com/rust-lang/crates.io-index" 670 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 671 | dependencies = [ 672 | "libc", 673 | "rand_chacha", 674 | "rand_core", 675 | ] 676 | 677 | [[package]] 678 | name = "rand_chacha" 679 | version = "0.3.1" 680 | source = "registry+https://github.com/rust-lang/crates.io-index" 681 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 682 | dependencies = [ 683 | "ppv-lite86", 684 | "rand_core", 685 | ] 686 | 687 | [[package]] 688 | name = "rand_core" 689 | version = "0.6.4" 690 | source = "registry+https://github.com/rust-lang/crates.io-index" 691 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 692 | dependencies = [ 693 | "getrandom", 694 | ] 695 | 696 | [[package]] 697 | name = "rayon" 698 | version = "1.7.0" 699 | source = "registry+https://github.com/rust-lang/crates.io-index" 700 | checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" 701 | dependencies = [ 702 | "either", 703 | "rayon-core", 704 | ] 705 | 706 | [[package]] 707 | name = "rayon-core" 708 | version = "1.11.0" 709 | source = "registry+https://github.com/rust-lang/crates.io-index" 710 | checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" 711 | dependencies = [ 712 | "crossbeam-channel", 713 | "crossbeam-deque", 714 | "crossbeam-utils", 715 | "num_cpus", 716 | ] 717 | 718 | [[package]] 719 | name = "redox_syscall" 720 | version = "0.2.16" 721 | source = "registry+https://github.com/rust-lang/crates.io-index" 722 | checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" 723 | dependencies = [ 724 | "bitflags", 725 | ] 726 | 727 | [[package]] 728 | name = "redox_users" 729 | version = "0.4.3" 730 | source = "registry+https://github.com/rust-lang/crates.io-index" 731 | checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" 732 | dependencies = [ 733 | "getrandom", 734 | "redox_syscall", 735 | "thiserror", 736 | ] 737 | 738 | [[package]] 739 | name = "regex" 740 | version = "1.9.1" 741 | source = "registry+https://github.com/rust-lang/crates.io-index" 742 | checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" 743 | dependencies = [ 744 | "aho-corasick", 745 | "memchr", 746 | "regex-automata", 747 | "regex-syntax", 748 | ] 749 | 750 | [[package]] 751 | name = "regex-automata" 752 | version = "0.3.2" 753 | source = "registry+https://github.com/rust-lang/crates.io-index" 754 | checksum = "83d3daa6976cffb758ec878f108ba0e062a45b2d6ca3a2cca965338855476caf" 755 | dependencies = [ 756 | "aho-corasick", 757 | "memchr", 758 | "regex-syntax", 759 | ] 760 | 761 | [[package]] 762 | name = "regex-syntax" 763 | version = "0.7.3" 764 | source = "registry+https://github.com/rust-lang/crates.io-index" 765 | checksum = "2ab07dc67230e4a4718e70fd5c20055a4334b121f1f9db8fe63ef39ce9b8c846" 766 | 767 | [[package]] 768 | name = "rustc-demangle" 769 | version = "0.1.23" 770 | source = "registry+https://github.com/rust-lang/crates.io-index" 771 | checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" 772 | 773 | [[package]] 774 | name = "ryu" 775 | version = "1.0.14" 776 | source = "registry+https://github.com/rust-lang/crates.io-index" 777 | checksum = "fe232bdf6be8c8de797b22184ee71118d63780ea42ac85b61d1baa6d3b782ae9" 778 | 779 | [[package]] 780 | name = "scopeguard" 781 | version = "1.1.0" 782 | source = "registry+https://github.com/rust-lang/crates.io-index" 783 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 784 | 785 | [[package]] 786 | name = "serde" 787 | version = "1.0.169" 788 | source = "registry+https://github.com/rust-lang/crates.io-index" 789 | checksum = "bd51c3db8f9500d531e6c12dd0fd4ad13d133e9117f5aebac3cdbb8b6d9824b0" 790 | dependencies = [ 791 | "serde_derive", 792 | ] 793 | 794 | [[package]] 795 | name = "serde_derive" 796 | version = "1.0.169" 797 | source = "registry+https://github.com/rust-lang/crates.io-index" 798 | checksum = "27738cfea0d944ab72c3ed01f3d5f23ec4322af8a1431e40ce630e4c01ea74fd" 799 | dependencies = [ 800 | "proc-macro2", 801 | "quote", 802 | "syn", 803 | ] 804 | 805 | [[package]] 806 | name = "serde_json" 807 | version = "1.0.100" 808 | source = "registry+https://github.com/rust-lang/crates.io-index" 809 | checksum = "0f1e14e89be7aa4c4b78bdbdc9eb5bf8517829a600ae8eaa39a6e1d960b5185c" 810 | dependencies = [ 811 | "itoa", 812 | "ryu", 813 | "serde", 814 | ] 815 | 816 | [[package]] 817 | name = "sha1" 818 | version = "0.10.5" 819 | source = "registry+https://github.com/rust-lang/crates.io-index" 820 | checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" 821 | dependencies = [ 822 | "cfg-if", 823 | "cpufeatures", 824 | "digest", 825 | ] 826 | 827 | [[package]] 828 | name = "slab" 829 | version = "0.4.8" 830 | source = "registry+https://github.com/rust-lang/crates.io-index" 831 | checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" 832 | dependencies = [ 833 | "autocfg", 834 | ] 835 | 836 | [[package]] 837 | name = "socket2" 838 | version = "0.4.9" 839 | source = "registry+https://github.com/rust-lang/crates.io-index" 840 | checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" 841 | dependencies = [ 842 | "libc", 843 | "winapi", 844 | ] 845 | 846 | [[package]] 847 | name = "steam-patch" 848 | version = "0.2.1" 849 | dependencies = [ 850 | "dirs", 851 | "evdev", 852 | "futures", 853 | "hyper", 854 | "inotify", 855 | "regex", 856 | "serde", 857 | "serde_json", 858 | "sysinfo", 859 | "tokio", 860 | "tungstenite", 861 | ] 862 | 863 | [[package]] 864 | name = "syn" 865 | version = "2.0.24" 866 | source = "registry+https://github.com/rust-lang/crates.io-index" 867 | checksum = "36ccaf716a23c35ff908f91c971a86a9a71af5998c1d8f10e828d9f55f68ac00" 868 | dependencies = [ 869 | "proc-macro2", 870 | "quote", 871 | "unicode-ident", 872 | ] 873 | 874 | [[package]] 875 | name = "sysinfo" 876 | version = "0.29.4" 877 | source = "registry+https://github.com/rust-lang/crates.io-index" 878 | checksum = "751e810399bba86e9326f5762b7f32ac5a085542df78da6a78d94e07d14d7c11" 879 | dependencies = [ 880 | "cfg-if", 881 | "core-foundation-sys", 882 | "libc", 883 | "ntapi", 884 | "once_cell", 885 | "rayon", 886 | "winapi", 887 | ] 888 | 889 | [[package]] 890 | name = "tap" 891 | version = "1.0.1" 892 | source = "registry+https://github.com/rust-lang/crates.io-index" 893 | checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" 894 | 895 | [[package]] 896 | name = "thiserror" 897 | version = "1.0.43" 898 | source = "registry+https://github.com/rust-lang/crates.io-index" 899 | checksum = "a35fc5b8971143ca348fa6df4f024d4d55264f3468c71ad1c2f365b0a4d58c42" 900 | dependencies = [ 901 | "thiserror-impl", 902 | ] 903 | 904 | [[package]] 905 | name = "thiserror-impl" 906 | version = "1.0.43" 907 | source = "registry+https://github.com/rust-lang/crates.io-index" 908 | checksum = "463fe12d7993d3b327787537ce8dd4dfa058de32fc2b195ef3cde03dc4771e8f" 909 | dependencies = [ 910 | "proc-macro2", 911 | "quote", 912 | "syn", 913 | ] 914 | 915 | [[package]] 916 | name = "tinyvec" 917 | version = "1.6.0" 918 | source = "registry+https://github.com/rust-lang/crates.io-index" 919 | checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" 920 | dependencies = [ 921 | "tinyvec_macros", 922 | ] 923 | 924 | [[package]] 925 | name = "tinyvec_macros" 926 | version = "0.1.1" 927 | source = "registry+https://github.com/rust-lang/crates.io-index" 928 | checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" 929 | 930 | [[package]] 931 | name = "tokio" 932 | version = "1.29.1" 933 | source = "registry+https://github.com/rust-lang/crates.io-index" 934 | checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" 935 | dependencies = [ 936 | "autocfg", 937 | "backtrace", 938 | "bytes", 939 | "libc", 940 | "mio", 941 | "num_cpus", 942 | "pin-project-lite", 943 | "socket2", 944 | "tokio-macros", 945 | "windows-sys", 946 | ] 947 | 948 | [[package]] 949 | name = "tokio-macros" 950 | version = "2.1.0" 951 | source = "registry+https://github.com/rust-lang/crates.io-index" 952 | checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" 953 | dependencies = [ 954 | "proc-macro2", 955 | "quote", 956 | "syn", 957 | ] 958 | 959 | [[package]] 960 | name = "tokio-util" 961 | version = "0.7.8" 962 | source = "registry+https://github.com/rust-lang/crates.io-index" 963 | checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" 964 | dependencies = [ 965 | "bytes", 966 | "futures-core", 967 | "futures-sink", 968 | "pin-project-lite", 969 | "tokio", 970 | "tracing", 971 | ] 972 | 973 | [[package]] 974 | name = "tower-service" 975 | version = "0.3.2" 976 | source = "registry+https://github.com/rust-lang/crates.io-index" 977 | checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" 978 | 979 | [[package]] 980 | name = "tracing" 981 | version = "0.1.37" 982 | source = "registry+https://github.com/rust-lang/crates.io-index" 983 | checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" 984 | dependencies = [ 985 | "cfg-if", 986 | "pin-project-lite", 987 | "tracing-core", 988 | ] 989 | 990 | [[package]] 991 | name = "tracing-core" 992 | version = "0.1.31" 993 | source = "registry+https://github.com/rust-lang/crates.io-index" 994 | checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" 995 | dependencies = [ 996 | "once_cell", 997 | ] 998 | 999 | [[package]] 1000 | name = "try-lock" 1001 | version = "0.2.4" 1002 | source = "registry+https://github.com/rust-lang/crates.io-index" 1003 | checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" 1004 | 1005 | [[package]] 1006 | name = "tungstenite" 1007 | version = "0.20.0" 1008 | source = "registry+https://github.com/rust-lang/crates.io-index" 1009 | checksum = "e862a1c4128df0112ab625f55cd5c934bcb4312ba80b39ae4b4835a3fd58e649" 1010 | dependencies = [ 1011 | "byteorder", 1012 | "bytes", 1013 | "data-encoding", 1014 | "http", 1015 | "httparse", 1016 | "log", 1017 | "rand", 1018 | "sha1", 1019 | "thiserror", 1020 | "url", 1021 | "utf-8", 1022 | ] 1023 | 1024 | [[package]] 1025 | name = "typenum" 1026 | version = "1.16.0" 1027 | source = "registry+https://github.com/rust-lang/crates.io-index" 1028 | checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" 1029 | 1030 | [[package]] 1031 | name = "unicode-bidi" 1032 | version = "0.3.13" 1033 | source = "registry+https://github.com/rust-lang/crates.io-index" 1034 | checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" 1035 | 1036 | [[package]] 1037 | name = "unicode-ident" 1038 | version = "1.0.10" 1039 | source = "registry+https://github.com/rust-lang/crates.io-index" 1040 | checksum = "22049a19f4a68748a168c0fc439f9516686aa045927ff767eca0a85101fb6e73" 1041 | 1042 | [[package]] 1043 | name = "unicode-normalization" 1044 | version = "0.1.22" 1045 | source = "registry+https://github.com/rust-lang/crates.io-index" 1046 | checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" 1047 | dependencies = [ 1048 | "tinyvec", 1049 | ] 1050 | 1051 | [[package]] 1052 | name = "url" 1053 | version = "2.4.0" 1054 | source = "registry+https://github.com/rust-lang/crates.io-index" 1055 | checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" 1056 | dependencies = [ 1057 | "form_urlencoded", 1058 | "idna", 1059 | "percent-encoding", 1060 | ] 1061 | 1062 | [[package]] 1063 | name = "utf-8" 1064 | version = "0.7.6" 1065 | source = "registry+https://github.com/rust-lang/crates.io-index" 1066 | checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" 1067 | 1068 | [[package]] 1069 | name = "version_check" 1070 | version = "0.9.4" 1071 | source = "registry+https://github.com/rust-lang/crates.io-index" 1072 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 1073 | 1074 | [[package]] 1075 | name = "want" 1076 | version = "0.3.1" 1077 | source = "registry+https://github.com/rust-lang/crates.io-index" 1078 | checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" 1079 | dependencies = [ 1080 | "try-lock", 1081 | ] 1082 | 1083 | [[package]] 1084 | name = "wasi" 1085 | version = "0.11.0+wasi-snapshot-preview1" 1086 | source = "registry+https://github.com/rust-lang/crates.io-index" 1087 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 1088 | 1089 | [[package]] 1090 | name = "winapi" 1091 | version = "0.3.9" 1092 | source = "registry+https://github.com/rust-lang/crates.io-index" 1093 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1094 | dependencies = [ 1095 | "winapi-i686-pc-windows-gnu", 1096 | "winapi-x86_64-pc-windows-gnu", 1097 | ] 1098 | 1099 | [[package]] 1100 | name = "winapi-i686-pc-windows-gnu" 1101 | version = "0.4.0" 1102 | source = "registry+https://github.com/rust-lang/crates.io-index" 1103 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1104 | 1105 | [[package]] 1106 | name = "winapi-x86_64-pc-windows-gnu" 1107 | version = "0.4.0" 1108 | source = "registry+https://github.com/rust-lang/crates.io-index" 1109 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1110 | 1111 | [[package]] 1112 | name = "windows-sys" 1113 | version = "0.48.0" 1114 | source = "registry+https://github.com/rust-lang/crates.io-index" 1115 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 1116 | dependencies = [ 1117 | "windows-targets", 1118 | ] 1119 | 1120 | [[package]] 1121 | name = "windows-targets" 1122 | version = "0.48.1" 1123 | source = "registry+https://github.com/rust-lang/crates.io-index" 1124 | checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" 1125 | dependencies = [ 1126 | "windows_aarch64_gnullvm", 1127 | "windows_aarch64_msvc", 1128 | "windows_i686_gnu", 1129 | "windows_i686_msvc", 1130 | "windows_x86_64_gnu", 1131 | "windows_x86_64_gnullvm", 1132 | "windows_x86_64_msvc", 1133 | ] 1134 | 1135 | [[package]] 1136 | name = "windows_aarch64_gnullvm" 1137 | version = "0.48.0" 1138 | source = "registry+https://github.com/rust-lang/crates.io-index" 1139 | checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" 1140 | 1141 | [[package]] 1142 | name = "windows_aarch64_msvc" 1143 | version = "0.48.0" 1144 | source = "registry+https://github.com/rust-lang/crates.io-index" 1145 | checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" 1146 | 1147 | [[package]] 1148 | name = "windows_i686_gnu" 1149 | version = "0.48.0" 1150 | source = "registry+https://github.com/rust-lang/crates.io-index" 1151 | checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" 1152 | 1153 | [[package]] 1154 | name = "windows_i686_msvc" 1155 | version = "0.48.0" 1156 | source = "registry+https://github.com/rust-lang/crates.io-index" 1157 | checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" 1158 | 1159 | [[package]] 1160 | name = "windows_x86_64_gnu" 1161 | version = "0.48.0" 1162 | source = "registry+https://github.com/rust-lang/crates.io-index" 1163 | checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" 1164 | 1165 | [[package]] 1166 | name = "windows_x86_64_gnullvm" 1167 | version = "0.48.0" 1168 | source = "registry+https://github.com/rust-lang/crates.io-index" 1169 | checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" 1170 | 1171 | [[package]] 1172 | name = "windows_x86_64_msvc" 1173 | version = "0.48.0" 1174 | source = "registry+https://github.com/rust-lang/crates.io-index" 1175 | checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" 1176 | 1177 | [[package]] 1178 | name = "wyz" 1179 | version = "0.5.1" 1180 | source = "registry+https://github.com/rust-lang/crates.io-index" 1181 | checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" 1182 | dependencies = [ 1183 | "tap", 1184 | ] 1185 | --------------------------------------------------------------------------------