mirror of
https://github.com/SteamDeckHomebrew/decky-loader.git
synced 2026-06-17 00:37:49 +00:00
sys: Added initial code injection logic
This commit is contained in:
+120
@@ -0,0 +1,120 @@
|
||||
use std::fmt::{Debug, Display, Formatter};
|
||||
use hyper::{Client, Uri};
|
||||
use hyper::body::Buf;
|
||||
use serde::{ Serialize, Deserialize };
|
||||
use serde_json;
|
||||
use tungstenite::Message;
|
||||
|
||||
type TokioResult<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
|
||||
|
||||
enum AppError {
|
||||
ContentNotFound
|
||||
}
|
||||
|
||||
impl Debug for AppError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
let message = match self {
|
||||
AppError::ContentNotFound => "Content not found"
|
||||
};
|
||||
|
||||
write!(f, "{}", message)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for AppError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for AppError { }
|
||||
unsafe impl Sync for AppError { }
|
||||
|
||||
impl std::error::Error for AppError { }
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[allow(dead_code)]
|
||||
#[derive(Deserialize)]
|
||||
struct WebContent {
|
||||
description: String,
|
||||
devtoolsFrontendUrl: String,
|
||||
id: String,
|
||||
title: String,
|
||||
r#type: String,
|
||||
url: String,
|
||||
webSocketDebuggerUrl: String
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[allow(dead_code)]
|
||||
#[derive(Serialize)]
|
||||
struct DebuggerCommandParams {
|
||||
expression: String,
|
||||
userGesture: bool
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[allow(dead_code)]
|
||||
#[derive(Serialize)]
|
||||
struct DebuggerCommand {
|
||||
id: u32,
|
||||
method: String,
|
||||
params: DebuggerCommandParams
|
||||
}
|
||||
|
||||
async fn get_web_content(url: Uri) -> TokioResult<Vec<WebContent>> {
|
||||
let client = Client::new();
|
||||
let response = client.get(url).await?;
|
||||
let body = hyper::body::aggregate(response).await?;
|
||||
|
||||
let data = String::from(std::str::from_utf8(body.chunk())?);
|
||||
|
||||
Ok(serde_json::from_str(data.as_str())?)
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> TokioResult<()> {
|
||||
let url = "http://127.0.0.1:8080/json".parse::<hyper::Uri>().unwrap();
|
||||
|
||||
let contents = get_web_content(url).await?;
|
||||
|
||||
println!("Available Content:");
|
||||
for content in &contents {
|
||||
println!(" {}", content.title);
|
||||
}
|
||||
|
||||
let mut quick_access_debug_url: Option<String> = None;
|
||||
for content in &contents {
|
||||
if content.title == "QuickAccess" {
|
||||
quick_access_debug_url = Some(content.webSocketDebuggerUrl.clone());
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(url) = quick_access_debug_url {
|
||||
|
||||
let (mut socket, _) = tungstenite::connect(url)?;
|
||||
|
||||
let command = DebuggerCommand {
|
||||
id: 1,
|
||||
method: String::from("Runtime.evaluate"),
|
||||
params: DebuggerCommandParams {
|
||||
expression: String::from(include_str!("plugin_page.js")),
|
||||
userGesture: true
|
||||
}
|
||||
};
|
||||
|
||||
socket.write_message(Message::Text(serde_json::to_string(&command)?))?;
|
||||
|
||||
let response = socket.read_message()?;
|
||||
|
||||
println!("{}", response);
|
||||
|
||||
socket.close(None)?;
|
||||
|
||||
} else {
|
||||
return Err(AppError::ContentNotFound.into());
|
||||
}
|
||||
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
(function () {
|
||||
const PLUGIN_ICON = `
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-plugin" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd" d="M1 8a7 7 0 1 1 2.898 5.673c-.167-.121-.216-.406-.002-.62l1.8-1.8a3.5 3.5 0 0 0
|
||||
4.572-.328l1.414-1.415a.5.5 0 0 0 0-.707l-.707-.707 1.559-1.563a.5.5 0 1 0-.708-.706l-1.559 1.562-1.414-1.414
|
||||
1.56-1.562a.5.5 0 1 0-.707-.706l-1.56 1.56-.707-.706a.5.5 0 0 0-.707 0L5.318 5.975a3.5 3.5 0 0 0-.328
|
||||
4.571l-1.8 1.8c-.58.58-.62 1.6.121 2.137A8 8 0 1 0 0 8a.5.5 0 0 0 1 0Z"/>
|
||||
</svg>
|
||||
`;
|
||||
|
||||
function inject() {
|
||||
let tabs = document.getElementsByClassName("quickaccessmenu_TabContentColumn_2z5NL Panel Focusable")[0];
|
||||
tabs.children[tabs.children.length - 1].innerHTML = PLUGIN_ICON;
|
||||
|
||||
let pages = document.getElementsByClassName("quickaccessmenu_AllTabContents_2yKG4 quickaccessmenu_Down_3rR0o")[0];
|
||||
let pluginPage = pages.children[pages.children.length - 1];
|
||||
pluginPage.innerHTML = "Hello from Rust!";
|
||||
}
|
||||
|
||||
let injector = setInterval(function () {
|
||||
if (document.hasFocus()) {
|
||||
inject();
|
||||
clearInterval(injector);
|
||||
}
|
||||
}, 100);
|
||||
})();
|
||||
Reference in New Issue
Block a user