Skip to content

Commit

Permalink
implement sync RPC calls, move storage api to synced
Browse files Browse the repository at this point in the history
  • Loading branch information
AmyrAhmady committed Aug 12, 2024
1 parent 1cac4e1 commit cefcb14
Show file tree
Hide file tree
Showing 10 changed files with 283 additions and 96 deletions.
1 change: 1 addition & 0 deletions src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ actix-cors = "0.7"
winapi = "0.3"
tauri-plugin-deep-link = "0.1.2"
gumdrop = "0.8.1"
lazy_static = "1.4"

[target.'cfg(target_os = "windows")'.dependencies]
dll-syringe = "0.15"
Expand Down
69 changes: 0 additions & 69 deletions src-tauri/src/commands.rs
Original file line number Diff line number Diff line change
@@ -1,74 +1,5 @@
use std::fs;
use std::path::PathBuf;

use serde_json::{json, Value};
use tauri::State;

use crate::{injector, samp};

#[derive(Default)]
pub struct AppState {
pub storage_file: PathBuf,
}

fn ensure_storage_file(storage_file: &PathBuf) -> Result<(), String> {
if !storage_file.exists() {
// Create an empty JSON file
fs::write(storage_file, "{}").map_err(|e| e.to_string())?;
}
Ok(())
}

#[tauri::command]
pub fn get_item(state: State<AppState>, key: String) -> Result<Option<String>, String> {
let storage_file = state.storage_file.clone();
ensure_storage_file(&storage_file)?;

let data = fs::read_to_string(&storage_file).map_err(|e| e.to_string())?;
let json_data: Value = serde_json::from_str(&data).map_err(|e| e.to_string())?;

Ok(json_data
.get(&key)
.and_then(|v| v.as_str().map(|s| s.to_string())))
}

#[tauri::command]
pub fn set_item(state: State<AppState>, key: String, value: String) -> Result<(), String> {
let storage_file = state.storage_file.clone();
ensure_storage_file(&storage_file)?;

let data = fs::read_to_string(&storage_file).map_err(|e| e.to_string())?;
let mut json_data: Value = serde_json::from_str(&data).map_err(|e| e.to_string())?;

json_data[key] = json!(value);

fs::write(storage_file, json_data.to_string()).map_err(|e| e.to_string())?;
Ok(())
}

#[tauri::command]
pub fn remove_item(state: State<AppState>, key: String) -> Result<(), String> {
let storage_file = state.storage_file.clone();
ensure_storage_file(&storage_file)?;

let data = fs::read_to_string(&storage_file).map_err(|e| e.to_string())?;
let mut json_data: Value = serde_json::from_str(&data).map_err(|e| e.to_string())?;

json_data.as_object_mut().map(|map| map.remove(&key));

fs::write(storage_file, json_data.to_string()).map_err(|e| e.to_string())?;
Ok(())
}

#[tauri::command]
pub fn get_all_items(state: State<AppState>) -> Result<String, String> {
let storage_file = state.storage_file.clone();
ensure_storage_file(&storage_file)?;

let data = fs::read_to_string(&storage_file).unwrap_or_else(|_| "{}".to_string());
Ok(data)
}

#[tauri::command]
pub async fn inject(
name: &str,
Expand Down
28 changes: 11 additions & 17 deletions src-tauri/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,9 @@ mod rpcs;
mod samp;

use std::env;
use std::path::PathBuf;
use std::process::exit;
use std::sync::Mutex;

use commands::AppState;
use gumdrop::Options;
use injector::run_samp;
use log::{error, LevelFilter};
Expand Down Expand Up @@ -53,8 +51,11 @@ async fn main() {

#[cfg(windows)]
{
use windows::Win32::System::Console::{AttachConsole, ATTACH_PARENT_PROCESS};
let _ = unsafe { AttachConsole(ATTACH_PARENT_PROCESS) };
#[cfg(not(debug_assertions))]
{
use windows::Win32::System::Console::{AttachConsole, ATTACH_PARENT_PROCESS};
let _ = unsafe { AttachConsole(ATTACH_PARENT_PROCESS) };
}
}

let raw_args: Vec<String> = env::args().collect();
Expand Down Expand Up @@ -109,8 +110,11 @@ Options:

#[cfg(windows)]
{
use windows::Win32::System::Console::FreeConsole;
let _ = unsafe { FreeConsole() };
#[cfg(not(debug_assertions))]
{
use windows::Win32::System::Console::FreeConsole;
let _ = unsafe { FreeConsole() };
}
}

std::thread::spawn(move || {
Expand All @@ -119,12 +123,6 @@ Options:
});

match tauri::Builder::default()
.manage(AppState {
storage_file: PathBuf::from(format!(
"{}/com.open.mp/storage.json",
dirs_next::data_local_dir().unwrap().to_str().unwrap()
)),
})
.plugin(tauri_plugin_upload::init())
.setup(|app| {
let handle = app.handle();
Expand Down Expand Up @@ -160,11 +158,7 @@ Options:
commands::get_gtasa_path_from_samp,
commands::get_nickname_from_samp,
commands::rerun_as_admin,
commands::get_samp_favorite_list,
commands::get_item,
commands::set_item,
commands::remove_item,
commands::get_all_items
commands::get_samp_favorite_list
])
.run(tauri::generate_context!())
{
Expand Down
195 changes: 193 additions & 2 deletions src-tauri/src/rpcs.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,28 @@
use actix_cors::Cors;
use actix_web::{web, App, HttpResponse, HttpServer, Responder};
use lazy_static::lazy_static;
use md5::compute;
use serde::Deserialize;
use serde_json::json;
use serde_json::{json, Value};
use sevenz_rust::decompress_file;
use std::error::Error;
use std::fs;
use std::fs::File;
use std::io::Read;
use std::path::PathBuf;
use std::sync::Mutex;
use std::time::Instant;
use tokio::sync::Semaphore;

use crate::query;
use crate::{discord, helpers};

static STORAGE_FILE: Mutex<Option<PathBuf>> = Mutex::new(None);

lazy_static! {
static ref SEMAPHORE: Semaphore = Semaphore::new(1);
}

#[derive(Deserialize)]
struct RpcParams {
params: serde_json::Value,
Expand Down Expand Up @@ -50,6 +61,17 @@ struct CopyFilesToGtaSaParams {
gtasa_dir: String,
}

#[derive(Deserialize)]
struct StorageGetOrRemoveItemParams {
key: String,
}

#[derive(Deserialize)]
struct StorageSetItemParams {
key: String,
value: String,
}

async fn request_server_info(ip: &str, port: i32) -> Result<String, String> {
match query::Query::new(ip, port).await {
Ok(q) => {
Expand Down Expand Up @@ -148,6 +170,65 @@ fn copy_files_to_gtasa(src: &str, gtasa_dir: &str) -> Result<(), String> {
helpers::copy_files(src, gtasa_dir)
}

fn storage_get_item(key: String) -> Result<Option<String>, String> {
init_storage_file();
let storage_file = STORAGE_FILE.lock().unwrap().to_owned().unwrap();
ensure_storage_file(&storage_file)?;

let data = fs::read_to_string(&storage_file).map_err(|e| e.to_string())?;
let json_data: Value = serde_json::from_str(&data).map_err(|e| e.to_string())?;

Ok(json_data
.get(&key)
.and_then(|v| v.as_str().map(|s| s.to_string())))
}

fn storage_set_item(key: String, value: String) -> Result<(), String> {
init_storage_file();
let storage_file = STORAGE_FILE.lock().unwrap().to_owned().unwrap();
ensure_storage_file(&storage_file)?;

let data = fs::read_to_string(&storage_file).map_err(|e| e.to_string())?;
let mut json_data: Value = serde_json::from_str(&data).map_err(|e| e.to_string())?;

json_data[key] = json!(value);

fs::write(storage_file, json_data.to_string()).map_err(|e| e.to_string())?;
Ok(())
}

fn storage_remove_item(key: String) -> Result<(), String> {
init_storage_file();
let storage_file = STORAGE_FILE.lock().unwrap().to_owned().unwrap();
ensure_storage_file(&storage_file)?;

let data = fs::read_to_string(&storage_file).map_err(|e| e.to_string())?;
let mut json_data: Value = serde_json::from_str(&data).map_err(|e| e.to_string())?;

json_data.as_object_mut().map(|map| map.remove(&key));

fs::write(storage_file, json_data.to_string()).map_err(|e| e.to_string())?;
Ok(())
}

fn storage_get_all_items() -> Result<String, String> {
init_storage_file();
let storage_file = STORAGE_FILE.lock().unwrap().to_owned().unwrap();
ensure_storage_file(&storage_file)?;

let data = fs::read_to_string(&storage_file).unwrap_or_else(|_| "{}".to_string());
Ok(data)
}

fn storage_clear() -> Result<(), String> {
init_storage_file();
let storage_file = STORAGE_FILE.lock().unwrap().to_owned().unwrap();
ensure_storage_file(&storage_file)?;

fs::write(storage_file, "{}").map_err(|e| e.to_string())?;
Ok(())
}

async fn rpc_handler(
path: web::Path<RpcMethod>,
payload: web::Json<RpcParams>,
Expand Down Expand Up @@ -252,14 +333,124 @@ async fn rpc_handler(
Ok(HttpResponse::Ok().body(response))
}

async fn sync_rpc_handler(
path: web::Path<RpcMethod>,
payload: web::Json<RpcParams>,
) -> Result<impl Responder, Box<dyn Error>> {
let _permit = SEMAPHORE.acquire().await.unwrap(); // Acquire a permit to ensure only one request is processed at a time
let params_str = serde_json::to_string(&payload.params)?;

/*
method: storage_get_item
*/
if path.method == "storage_get_item" {
let params: StorageGetOrRemoveItemParams = serde_json::from_str(params_str.as_str())?;
let result = storage_get_item(params.key);
if result.is_err() {
return Ok(
HttpResponse::Ok().body(format!("storage_error|sep|{}", result.err().unwrap()))
);
}

return resolve_option_for_http_response(result.unwrap());
}
/*
method: storage_remove_item
*/
else if path.method == "storage_remove_item" {
let params: StorageGetOrRemoveItemParams = serde_json::from_str(params_str.as_str())?;
let result = storage_remove_item(params.key);
if result.is_err() {
return Ok(
HttpResponse::Ok().body(format!("storage_error|sep|{}", result.err().unwrap()))
);
}

return Ok(HttpResponse::Ok().body("{}"));
}
/*
method: storage_set_item
*/
else if path.method == "storage_set_item" {
let params: StorageSetItemParams = serde_json::from_str(params_str.as_str())?;
let result = storage_set_item(params.key, params.value);
if result.is_err() {
return Ok(
HttpResponse::Ok().body(format!("storage_error|sep|{}", result.err().unwrap()))
);
}

return Ok(HttpResponse::Ok().body("{}"));
}
/*
method: storage_get_all_items
*/
else if path.method == "storage_get_all_items" {
let result = storage_get_all_items();
if result.is_err() {
return Ok(
HttpResponse::Ok().body(format!("storage_error|sep|{}", result.err().unwrap()))
);
}

return Ok(HttpResponse::Ok().body(result.unwrap()));
}
/*
method: storage_clear
*/
else if path.method == "storage_clear" {
let result = storage_clear();
if result.is_err() {
return Ok(
HttpResponse::Ok().body(format!("storage_error|sep|{}", result.err().unwrap()))
);
}

return Ok(HttpResponse::Ok().body("{}"));
}

let response = format!(
"Received RPC request: {} with params: {:?}",
path.method, payload.params
);
Ok(HttpResponse::Ok().body(response))
}

pub async fn initialize_rpc() -> Result<(), std::io::Error> {
HttpServer::new(|| {
App::new()
.wrap(Cors::permissive())
.service(web::resource("/sync_rpc/{method}").route(web::post().to(sync_rpc_handler)))
.service(web::resource("/rpc/{method}").route(web::post().to(rpc_handler)))
})
.bind("127.0.0.1:46290")?
.run()
.await
// Ok(())
}

fn resolve_option_for_http_response(
option: Option<String>,
) -> Result<HttpResponse, Box<dyn Error>> {
match option {
Some(res) => Ok(HttpResponse::Ok().body(res)),
None => Ok(HttpResponse::Ok().body("null")),
}
}

fn ensure_storage_file(storage_file: &PathBuf) -> Result<(), String> {
if !storage_file.exists() {
// Create an empty JSON file
fs::write(storage_file, "{}").map_err(|e| e.to_string())?;
}
Ok(())
}

fn init_storage_file() {
let mut storage_file_guard = STORAGE_FILE.lock().unwrap();
if storage_file_guard.is_none() {
*storage_file_guard = Some(PathBuf::from(format!(
"{}/com.open.mp/storage.json",
dirs_next::data_local_dir().unwrap().to_str().unwrap()
)));
}
}
Loading

0 comments on commit cefcb14

Please sign in to comment.