Skip to content

Commit a973e63

Browse files
Initial commit
0 parents  commit a973e63

File tree

8 files changed

+516
-0
lines changed

8 files changed

+516
-0
lines changed

Cargo.toml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[package]
2+
name = "Github-Game-Status"
3+
version = "1.0.0"
4+
edition = "2024"
5+
build = "build.rs"
6+
authors = ["HardCodeDev"]
7+
license = "MIT"
8+
repository = "https://github.com/HardCodeDev777/Github-Game-Status"
9+
10+
[dependencies]
11+
slint = "1.12.1"
12+
serde = { version = "1.0.104", features = ["derive"] }
13+
serde_json = "1.0.140"
14+
sysinfo = "0.36.0"
15+
16+
[build-dependencies]
17+
slint-build = "1.12.1"

build.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
fn main() {
2+
slint_build::compile("ui/mainwindow.slint").unwrap();
3+
}

src/app_data.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
use serde::{Serialize, Deserialize};
2+
3+
pub const SETUP_FILE_NAME: &str = "setupdata.json";
4+
pub const PROCESSES_DATA_FILE_NAME: &str = "processesdata.json";
5+
pub const DEFAULT_STATUS_BATCH_FILE_NAME: &str = "default_status_logic.bat";
6+
pub const STATUS_LOGIC_BATCH_FILE_NAME: &str = "status_logic.bat";
7+
8+
#[derive(Serialize, Deserialize)]
9+
pub struct SetupData {
10+
pub cli_path: String,
11+
pub default_status_text: String,
12+
pub default_status_emoji: String
13+
}
14+
15+
impl SetupData{
16+
pub fn new(cli_path: String, default_status_text: String, default_status_emoji: String) -> Self{
17+
Self {cli_path, default_status_text, default_status_emoji}
18+
}
19+
}
20+
21+
#[derive(Serialize, Deserialize, Clone)]
22+
pub struct ProcessData{
23+
pub game_file_name: String,
24+
pub status_text: String,
25+
pub status_emoji: String
26+
}
27+
28+
impl ProcessData{
29+
pub fn new(game_file_name: String, status_text: String, status_emoji: String) -> Self{
30+
Self {game_file_name, status_text, status_emoji}
31+
}
32+
}

src/core_logic.rs

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
use std::fs::{File, remove_file};
2+
use std::io::Write;
3+
use std::error::Error;
4+
use std::process::Command;
5+
use std::{thread, time};
6+
use std::sync::{Arc, atomic};
7+
use slint::{SharedString, ToSharedString};
8+
use sysinfo::System;
9+
use crate::{app_data::{SetupData, ProcessData, PROCESSES_DATA_FILE_NAME, SETUP_FILE_NAME, STATUS_LOGIC_BATCH_FILE_NAME, DEFAULT_STATUS_BATCH_FILE_NAME}, json_utils::{write_setup_data_to_json, read_setup_data_from_json}};
10+
11+
// Create new SetupData and saves it as JSON
12+
pub fn set_setup(path_to_cli: SharedString, default_status_text: SharedString,
13+
default_status_emoji: SharedString) -> Result<(), Box<dyn Error>> {
14+
// Creates a new SetupData instance from the provided parameters
15+
let setup_data = SetupData::new(path_to_cli.to_string(),
16+
default_status_text.to_string(), default_status_emoji.to_string());
17+
18+
// Write it to JSON
19+
write_setup_data_to_json(SETUP_FILE_NAME, setup_data).expect("Error saving setup in Json in core logic!");
20+
21+
Ok(())
22+
}
23+
24+
// Delete all data files
25+
pub fn delete_all_data() -> Result<(), Box<dyn Error>> {
26+
// Remove batch files
27+
remove_file(STATUS_LOGIC_BATCH_FILE_NAME)?;
28+
remove_file(DEFAULT_STATUS_BATCH_FILE_NAME)?;
29+
30+
// Remove JSON data files
31+
remove_file(SETUP_FILE_NAME)?;
32+
remove_file(PROCESSES_DATA_FILE_NAME)?;
33+
34+
Ok(())
35+
}
36+
37+
// Create a batch file that updates the user status
38+
pub fn make_process_batch(status_text: SharedString, status_emoji: SharedString) -> Result<(), Box<dyn Error>> {
39+
40+
// Create the batch file itself
41+
let mut file = File::create(STATUS_LOGIC_BATCH_FILE_NAME)?;
42+
43+
// Read SetupData from JSON
44+
let readed_setup_data = read_setup_data_from_json(SETUP_FILE_NAME).expect("Error reading setup data from Json in core logic!");
45+
46+
// Get GitHub CLI path from setup data
47+
let cli_path = readed_setup_data.cli_path;
48+
49+
// Batch file command content
50+
let bat_message = String::from(format!(
51+
"@echo off \n cd {} \n gh user-status set --emoji \"{}\" \"{}\"",
52+
cli_path, status_emoji, status_text));
53+
54+
// Write commands to the batch file
55+
file.write_all(bat_message.as_bytes())?;
56+
57+
// Run the batch file using cmd
58+
let status = Command::new("cmd").args(["/C", STATUS_LOGIC_BATCH_FILE_NAME]).status()?;
59+
60+
// Check if the batch file executed successfully
61+
if status.success() {
62+
println!("Process batch ran successfully in core logic");
63+
} else {
64+
println!("Process batch failed to run correctly in core logic");
65+
}
66+
67+
// Delete the batch file after execution
68+
remove_file(STATUS_LOGIC_BATCH_FILE_NAME)?;
69+
70+
Ok(())
71+
}
72+
73+
// Set the default user status if no matching process is found (via batch file)
74+
pub fn set_default_status_batch() -> Result<(), Box<dyn Error>> {
75+
// Create the batch file
76+
let mut file = File::create(DEFAULT_STATUS_BATCH_FILE_NAME)?;
77+
78+
// Read SetupData from JSON
79+
let readed_setup_data = read_setup_data_from_json(SETUP_FILE_NAME).expect("Error reading setup data from Json in core logic!");
80+
81+
// Get required data
82+
let cli_path = readed_setup_data.cli_path;
83+
let default_status_text = readed_setup_data.default_status_text;
84+
let default_status_emoji = readed_setup_data.default_status_emoji;
85+
86+
// Batch file command content
87+
let bat_message = String::from(format!(
88+
"@echo off \n cd {} \n gh user-status set --emoji \"{}\" \"{}\"",
89+
cli_path, default_status_emoji, default_status_text));
90+
91+
// Write commands to the batch file
92+
file.write_all(bat_message.as_bytes())?;
93+
94+
// Run the batch file using cmd
95+
let status = Command::new("cmd").args(["/C", DEFAULT_STATUS_BATCH_FILE_NAME]).status()?;
96+
97+
// Check if the batch file executed successfully
98+
if status.success() {
99+
println!("Default batch ran successfully in core logic");
100+
} else {
101+
println!("Default batch failed to run correctly in core logic");
102+
}
103+
104+
// Delete the batch file after execution
105+
remove_file(DEFAULT_STATUS_BATCH_FILE_NAME)?;
106+
107+
Ok(())
108+
}
109+
110+
// Monitor running processes
111+
#[allow(unused_assignments)]
112+
pub fn monitor_processes(running: Arc<atomic::AtomicBool>, readed_data: Vec<ProcessData>) -> Result<(), Box<dyn Error>> {
113+
// Clone the shared running flag(Rust moment)
114+
let running_clone = running.clone();
115+
let running = running_clone.clone();
116+
117+
// Clone game process data
118+
let readed_data_clone = readed_data.clone();
119+
120+
// Start a new thread
121+
thread::spawn(move || {
122+
// Initialize system information
123+
let mut sys = System::new_all();
124+
125+
// Runs while the flag is set to true
126+
while running.load(atomic::Ordering::Relaxed) {
127+
// Refreshes system information
128+
sys.refresh_all();
129+
130+
// Check if at least one monitored process is running
131+
let matching_process_data = readed_data_clone.iter().find(|data| {
132+
sys.processes().values().any(|p| {
133+
p.exe()
134+
.and_then(|path| path.file_name())
135+
.and_then(|name| name.to_str())
136+
.map(|name| name.to_lowercase() == data.game_file_name.to_lowercase())
137+
.unwrap_or(false)
138+
})
139+
});
140+
141+
// React based on whether a matching process is found
142+
match matching_process_data {
143+
Some(process_data) => {
144+
// Update status according to the running process
145+
make_process_batch(process_data.status_text.to_shared_string(),
146+
process_data.status_emoji.to_shared_string())
147+
.expect("Error creating batch file in core logic!");
148+
},
149+
None => {
150+
// Set default status if no matching process is found
151+
set_default_status_batch().expect("Error setting default status in core logic!");
152+
},
153+
}
154+
155+
// Wait for 10 seconds before the next check
156+
thread::sleep(time::Duration::from_secs(10));
157+
}
158+
});
159+
Ok(())
160+
}

src/json_utils.rs

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
use std::fs::{File, OpenOptions, remove_file};
2+
use std::io::{Read, Write};
3+
use std::path::Path;
4+
use std::error::Error;
5+
use serde_json::{to_string_pretty, from_str};
6+
use slint::SharedString;
7+
use crate::app_data::{SetupData, ProcessData};
8+
9+
// Core function for writing to a JSON file
10+
fn write_to_json_core(path: &str, data: String) -> Result<(), Box<dyn Error>> {
11+
let mut file: File;
12+
13+
// If the file exists
14+
if Path::new(path).exists() {
15+
// Open without overwriting
16+
file = OpenOptions::new().write(true).open(path)?;
17+
} else {
18+
// Create a new file
19+
file = File::create(path)?;
20+
}
21+
// Write all data to it
22+
file.write_all(data.as_bytes())?;
23+
24+
Ok(())
25+
}
26+
27+
// Write SetupData to JSON
28+
pub fn write_setup_data_to_json(path: &str, setup_data: SetupData) -> Result<(), Box<dyn Error>> {
29+
// Serialize SetupData
30+
let serialized_data = to_string_pretty(&setup_data).unwrap();
31+
32+
// If the file already exists
33+
if Path::new(path).exists() {
34+
// Delete it first
35+
remove_file(path)?;
36+
}
37+
38+
// Write to JSON
39+
write_to_json_core(path, serialized_data).expect("Error saving to JSON in core logic!");
40+
41+
Ok(())
42+
}
43+
44+
// Write ProcessData to JSON
45+
#[allow(unused_assignments)]
46+
pub fn write_process_data_to_json(path: &str, game_file_name: SharedString, status_text: SharedString,
47+
status_emoji: SharedString) -> Result<(), Box<dyn Error>> {
48+
// Variable to store the final JSON string
49+
let mut serialized_data = String::new();
50+
51+
// Create new ProcessData from received parameters
52+
let new_process_data = ProcessData::new(game_file_name.to_string(), status_text.to_string(),
53+
status_emoji.to_string());
54+
55+
// Clone it
56+
let new_process_data_clone = new_process_data.clone();
57+
58+
// If the file exists
59+
if Path::new(path).exists() {
60+
// Read Vec<ProcessData> from it
61+
let mut read_vec = read_processes_data_from_json(path)
62+
.expect("Error reading game file names from JSON in core logic!");
63+
64+
// Push new ProcessData
65+
read_vec.push(new_process_data);
66+
67+
// Serialize the vector
68+
serialized_data = to_string_pretty(&read_vec).unwrap();
69+
} else {
70+
// Create a new vector of ProcessData
71+
let mut vec_of_game_process_data = Vec::<ProcessData>::new();
72+
73+
// Add the newly created ProcessData
74+
vec_of_game_process_data.push(new_process_data_clone);
75+
76+
// Serialize the vector
77+
serialized_data = to_string_pretty(&vec_of_game_process_data).unwrap();
78+
}
79+
80+
// Write to JSON
81+
write_to_json_core(path, serialized_data).expect("Error saving to JSON in core logic!");
82+
83+
Ok(())
84+
}
85+
86+
// Reads SetupData from JSON
87+
pub fn read_setup_data_from_json(path: &str) -> Result<SetupData, Box<dyn Error>> {
88+
// Open the file at the given path
89+
let mut file = File::open(path)?;
90+
91+
// String to store JSON data
92+
let mut path_to_cli = String::new();
93+
94+
// Read JSON into the string
95+
file.read_to_string(&mut path_to_cli)?;
96+
97+
// Deserialize into SetupData
98+
let result: SetupData = from_str(&path_to_cli).unwrap();
99+
100+
Ok(result)
101+
}
102+
103+
// Read ProcessData from JSON
104+
pub fn read_processes_data_from_json(path: &str) -> Result<Vec<ProcessData>, Box<dyn Error>> {
105+
// Open the file at the given path
106+
let mut file = File::open(path)?;
107+
108+
// String to store JSON data
109+
let mut process_data_read = String::new();
110+
111+
// Read JSON into the string
112+
file.read_to_string(&mut process_data_read)?;
113+
114+
// Deserialize into Vec<ProcessData>
115+
let result: Vec<ProcessData> = from_str(&process_data_read).unwrap();
116+
117+
Ok(result)
118+
}

src/main.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
mod ui_logic;
2+
mod core_logic;
3+
mod json_utils;
4+
mod app_data;
5+
6+
use std::error::Error;
7+
use ui_logic::make_app;
8+
9+
fn main() -> Result<(), Box<dyn Error>> {
10+
// Run the app
11+
make_app().expect("Error in app work... How is this even happened?");
12+
Ok(())
13+
}

0 commit comments

Comments
 (0)