Add gpgui-helper (#326)

This commit is contained in:
Kevin Yue
2024-02-21 07:34:14 -05:00
committed by GitHub
parent 5767c252b7
commit 4be877bf8c
53 changed files with 4351 additions and 51 deletions

View File

@@ -13,6 +13,7 @@ tokio.workspace = true
tokio-util.workspace = true
axum = { workspace = true, features = ["ws"] }
futures.workspace = true
serde.workspace = true
serde_json.workspace = true
env_logger.workspace = true
log.workspace = true

View File

@@ -112,7 +112,7 @@ fn init_logger() -> Arc<Redaction> {
let timestamp = buf.timestamp();
writeln!(
buf,
"[{} {} {}] {}",
"[{} {} {}] {}",
timestamp,
record.level(),
record.module_path().unwrap_or_default(),
@@ -127,10 +127,8 @@ fn init_logger() -> Arc<Redaction> {
async fn launch_gui(envs: Option<HashMap<String, String>>, api_key: Vec<u8>, mut minimized: bool) {
loop {
let api_key_clone = api_key.clone();
let gui_launcher = GuiLauncher::new()
let gui_launcher = GuiLauncher::new(env!("CARGO_PKG_VERSION"), &api_key)
.envs(envs.clone())
.api_key(api_key_clone)
.minimized(minimized);
match gui_launcher.launch().await {

View File

@@ -1,15 +1,23 @@
use std::{borrow::Cow, ops::ControlFlow, sync::Arc};
use std::{borrow::Cow, fs::Permissions, ops::ControlFlow, os::unix::fs::PermissionsExt, path::PathBuf, sync::Arc};
use anyhow::bail;
use axum::{
body::Bytes,
extract::{
ws::{self, CloseFrame, Message, WebSocket},
State, WebSocketUpgrade,
},
http::StatusCode,
response::IntoResponse,
};
use futures::{SinkExt, StreamExt};
use gpapi::service::event::WsEvent;
use gpapi::{
service::{event::WsEvent, request::UpdateGuiRequest},
utils::checksum::verify_checksum,
GP_GUI_BINARY,
};
use log::{info, warn};
use tokio::fs;
use crate::ws_server::WsServerContext;
@@ -25,6 +33,48 @@ pub(crate) async fn auth_data(State(ctx): State<Arc<WsServerContext>>, body: Str
ctx.send_event(WsEvent::AuthData(body)).await;
}
pub async fn update_gui(State(ctx): State<Arc<WsServerContext>>, body: Bytes) -> Result<(), StatusCode> {
let payload = match ctx.decrypt::<UpdateGuiRequest>(body.to_vec()) {
Ok(payload) => payload,
Err(err) => {
warn!("Failed to decrypt update payload: {}", err);
return Err(StatusCode::BAD_REQUEST);
}
};
info!("Update GUI: {:?}", payload);
let UpdateGuiRequest { path, checksum } = payload;
info!("Verifying checksum");
verify_checksum(&path, &checksum).map_err(|err| {
warn!("Failed to verify checksum: {}", err);
StatusCode::BAD_REQUEST
})?;
info!("Installing GUI");
install_gui(&path).await.map_err(|err| {
warn!("Failed to install GUI: {}", err);
StatusCode::INTERNAL_SERVER_ERROR
})?;
Ok(())
}
async fn install_gui(src: &str) -> anyhow::Result<()> {
let path = PathBuf::from(GP_GUI_BINARY);
let Some(dir) = path.parent() else {
bail!("Failed to get parent directory of GUI binary");
};
fs::create_dir_all(dir).await?;
// Copy the file to the final location and make it executable
fs::copy(src, GP_GUI_BINARY).await?;
fs::set_permissions(GP_GUI_BINARY, Permissions::from_mode(0o755)).await?;
Ok(())
}
pub(crate) async fn ws_handler(ws: WebSocketUpgrade, State(ctx): State<Arc<WsServerContext>>) -> impl IntoResponse {
ws.on_upgrade(move |socket| handle_socket(socket, ctx))
}

View File

@@ -12,6 +12,7 @@ pub(crate) fn routes(ctx: Arc<WsServerContext>) -> Router {
.route("/health", get(handlers::health))
.route("/active-gui", post(handlers::active_gui))
.route("/auth-data", post(handlers::auth_data))
.route("/update-gui", post(handlers::update_gui))
.route("/ws", get(handlers::ws_handler))
.with_state(ctx)
}

View File

@@ -6,6 +6,7 @@ use gpapi::{
utils::{crypto::Crypto, lock_file::LockFile, redact::Redaction},
};
use log::{info, warn};
use serde::de::DeserializeOwned;
use tokio::{
net::TcpListener,
sync::{mpsc, watch, RwLock},
@@ -38,6 +39,10 @@ impl WsServerContext {
}
}
pub fn decrypt<T: DeserializeOwned>(&self, encrypted: Vec<u8>) -> anyhow::Result<T> {
self.crypto.decrypt(encrypted)
}
pub async fn send_event(&self, event: WsEvent) {
let connections = self.connections.read().await;