working app manager

This commit is contained in:
2025-07-18 04:34:52 -05:00
parent ecb2d2daaf
commit 1170d5e30e
3 changed files with 190 additions and 6 deletions
+146
View File
@@ -0,0 +1,146 @@
use std::path::PathBuf;
use std::process::Command;
use serde::{Deserialize, Serialize};
use std::env;
use std::fs;
#[derive(Clone, Serialize, Deserialize)]
pub struct App {
pub repo: String,
pub branch: String,
pub install_command: String,
pub run_command: String,
pub enabled: Option<bool>,
}
pub fn remove_app(apps: &mut Vec<App>, index: usize) {
if let Some(app) = apps.get(index) {
let home = env::var("HOME").expect("Failed to get HOME environment variable");
let apps_dir = PathBuf::from(home).join("sentryx/apps");
let repo_name = app
.repo
.trim_end_matches(".git")
.rsplit('/')
.next()
.expect("Failed to extract repo name");
fs::remove_dir_all(&apps_dir.join(repo_name)).expect("Failed to remove app directory");
println!("Removed app: {}", app.repo);
} else {
println!("App not found: {}", index);
}
apps.remove(index);
save_apps(apps);
}
pub fn install_app(apps: &mut Vec<App>, app: App) {
let a2 = app.clone();
// Get home directory and create ~/sentryx/apps if needed
let home = env::var("HOME").expect("Failed to get HOME environment variable");
let apps_dir = PathBuf::from(home).join("sentryx/apps");
if !apps_dir.exists() {
fs::create_dir_all(&apps_dir).expect("Failed to create apps directory");
}
// Change to apps directory
env::set_current_dir(&apps_dir).expect("Failed to change to apps directory");
println!("Installing app from repo: {}", app.repo);
println!("Branch: {}", app.branch);
println!("Install command: {}", app.install_command);
println!("Run command: {}", app.run_command);
// Clone the repo
println!("Cloning repo");
Command::new("git")
.arg("clone")
.arg("-b")
.arg(&app.branch)
.arg(&app.repo)
.status()
.expect("Failed to clone repository");
// Extract repo name from URL (e.g., "https://github.com/user/myapp.git" -> "myapp")
let repo_name = app
.repo
.trim_end_matches(".git")
.rsplit('/')
.next()
.expect("Failed to extract repo name");
// Change to cloned repo directory
env::set_current_dir(&repo_name).expect("Failed to change to cloned repo directory");
// You are now inside the cloned repo
println!("Changed directory to {:?}", env::current_dir().unwrap());
apps.push(a2.clone());
save_apps(&apps);
Command::new("bash")
.arg("-c")
.arg(app.install_command)
.status()
.expect("Failed to execute Bash command");
run_app(a2);
}
pub fn run_app(app: App) {
// Change to the app directory
let home = env::var("HOME").expect("Failed to get HOME environment variable");
let app_dir = PathBuf::from(home)
.join("sentryx/apps")
.join(app.repo.trim_end_matches(".git").split('/').last().unwrap());
env::set_current_dir(&app_dir).expect("Failed to change to app directory");
// Run the app
Command::new("bash")
.arg("-c")
.arg(app.run_command)
.status()
.expect("Failed to execute run command");
}
pub fn run_apps() -> Vec<App> {
// Change to the app directory
let home = env::var("HOME").expect("Failed to get HOME environment variable");
let apps_dir = PathBuf::from(home).join("sentryx/apps");
if !apps_dir.exists() {
fs::create_dir_all(&apps_dir).expect("Failed to create apps directory");
fs::write(apps_dir.join("apps.json"), "[]").expect("Failed to create apps.json");
}
let apps_json = serde_json::from_str::<Vec<App>>(
&fs::read_to_string(apps_dir.join("apps.json")).expect("Failed to read apps.json"),
)
.expect("Failed to parse apps.json");
for app in apps_json.clone() {
if app.enabled.unwrap_or(true) {
println!("Running app: {}", app.repo);
std::thread::spawn(|| {
run_app(app);
});
} else {
println!("Skipping disabled app: {}", app.repo);
}
}
apps_json
}
pub fn save_apps(apps: &[App]) {
let home = env::var("HOME").expect("Failed to get HOME environment variable");
let apps_dir = PathBuf::from(home).join("sentryx/apps");
fs::write(
apps_dir.join("apps.json"),
serde_json::to_string(apps).expect("Failed to serialize apps"),
)
.expect("Failed to write apps.json");
}
+32 -4
View File
@@ -1,11 +1,13 @@
pub mod app_manager;
pub mod server_config;
use std::net::TcpListener;
use std::sync::Arc;
use std::thread::spawn;
use std::{net::TcpListener, sync::Mutex};
use sysinfo::{Disks, Networks, System};
use tungstenite::accept;
use crate::app_manager::{install_app, App};
use crate::server_config::ServerStats;
fn get_system_info(sys: &mut System, networks: &Networks, disks: &Disks) -> ServerStats {
let cpus = sys.cpus();
@@ -36,19 +38,26 @@ fn get_system_info(sys: &mut System, networks: &Networks, disks: &Disks) -> Serv
}
fn main() {
let apps = app_manager::run_apps();
let server = TcpListener::bind("127.0.0.1:5273").unwrap();
for stream in server.incoming() {
let mut apps = apps.clone();
spawn(move || {
let mut websocket = accept(stream.unwrap()).unwrap();
let websocket = Arc::new(Mutex::new(accept(stream.unwrap()).unwrap()));
let reader_socket = Arc::clone(&websocket);
let config = Arc::new(server_config::ServerConfig::new());
{
let master_key = websocket.read().unwrap();
let master_key = reader_socket.lock().unwrap().read().unwrap();
if !master_key.is_text()
|| master_key.to_text().unwrap() != config.master_key.clone()
{
websocket
.lock()
.unwrap()
.send(tungstenite::Message::text("!Invalid master key"))
.unwrap();
@@ -56,15 +65,32 @@ fn main() {
}
websocket
.lock()
.unwrap()
.send(tungstenite::Message::text("Success"))
.unwrap();
}
std::thread::spawn(move || loop {
let app: App = serde_json::from_str(
&reader_socket
.lock()
.unwrap()
.read()
.unwrap()
.to_text()
.unwrap(),
)
.unwrap();
install_app(&mut apps, app);
});
let mut sys = System::new_all();
let mut networks = Networks::new();
let mut disks = Disks::new();
while websocket.can_write() {
while websocket.lock().unwrap().can_write() {
sys.refresh_all();
std::thread::sleep(std::time::Duration::from_millis(200));
sys.refresh_all();
@@ -72,6 +98,8 @@ fn main() {
disks.refresh(true);
websocket
.lock()
.unwrap()
.send(tungstenite::Message::text(
serde_json::to_string(&get_system_info(&mut sys, &networks, &disks))
.unwrap(),
+12 -2
View File
@@ -1,4 +1,14 @@
const ws = new WebSocket('ws://localhost:5273');
const ws = new WebSocket("ws://localhost:5273");
ws.onmessage = (msg) => console.log("Received:", msg.data);
ws.onopen = () => ws.send("my-key");
ws.onopen = () => {
ws.send("my-key");
ws.send(
JSON.stringify({
repo: "[email protected]:osui-rs/osui.git",
branch: "master",
install_command: "",
run_command: "cargo run",
})
);
};