Skip to content

Commit cefcb14

Browse files
committed
implement sync RPC calls, move storage api to synced
1 parent 1cac4e1 commit cefcb14

File tree

10 files changed

+283
-96
lines changed

10 files changed

+283
-96
lines changed

src-tauri/Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src-tauri/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ actix-cors = "0.7"
3838
winapi = "0.3"
3939
tauri-plugin-deep-link = "0.1.2"
4040
gumdrop = "0.8.1"
41+
lazy_static = "1.4"
4142

4243
[target.'cfg(target_os = "windows")'.dependencies]
4344
dll-syringe = "0.15"

src-tauri/src/commands.rs

Lines changed: 0 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,5 @@
1-
use std::fs;
2-
use std::path::PathBuf;
3-
4-
use serde_json::{json, Value};
5-
use tauri::State;
6-
71
use crate::{injector, samp};
82

9-
#[derive(Default)]
10-
pub struct AppState {
11-
pub storage_file: PathBuf,
12-
}
13-
14-
fn ensure_storage_file(storage_file: &PathBuf) -> Result<(), String> {
15-
if !storage_file.exists() {
16-
// Create an empty JSON file
17-
fs::write(storage_file, "{}").map_err(|e| e.to_string())?;
18-
}
19-
Ok(())
20-
}
21-
22-
#[tauri::command]
23-
pub fn get_item(state: State<AppState>, key: String) -> Result<Option<String>, String> {
24-
let storage_file = state.storage_file.clone();
25-
ensure_storage_file(&storage_file)?;
26-
27-
let data = fs::read_to_string(&storage_file).map_err(|e| e.to_string())?;
28-
let json_data: Value = serde_json::from_str(&data).map_err(|e| e.to_string())?;
29-
30-
Ok(json_data
31-
.get(&key)
32-
.and_then(|v| v.as_str().map(|s| s.to_string())))
33-
}
34-
35-
#[tauri::command]
36-
pub fn set_item(state: State<AppState>, key: String, value: String) -> Result<(), String> {
37-
let storage_file = state.storage_file.clone();
38-
ensure_storage_file(&storage_file)?;
39-
40-
let data = fs::read_to_string(&storage_file).map_err(|e| e.to_string())?;
41-
let mut json_data: Value = serde_json::from_str(&data).map_err(|e| e.to_string())?;
42-
43-
json_data[key] = json!(value);
44-
45-
fs::write(storage_file, json_data.to_string()).map_err(|e| e.to_string())?;
46-
Ok(())
47-
}
48-
49-
#[tauri::command]
50-
pub fn remove_item(state: State<AppState>, key: String) -> Result<(), String> {
51-
let storage_file = state.storage_file.clone();
52-
ensure_storage_file(&storage_file)?;
53-
54-
let data = fs::read_to_string(&storage_file).map_err(|e| e.to_string())?;
55-
let mut json_data: Value = serde_json::from_str(&data).map_err(|e| e.to_string())?;
56-
57-
json_data.as_object_mut().map(|map| map.remove(&key));
58-
59-
fs::write(storage_file, json_data.to_string()).map_err(|e| e.to_string())?;
60-
Ok(())
61-
}
62-
63-
#[tauri::command]
64-
pub fn get_all_items(state: State<AppState>) -> Result<String, String> {
65-
let storage_file = state.storage_file.clone();
66-
ensure_storage_file(&storage_file)?;
67-
68-
let data = fs::read_to_string(&storage_file).unwrap_or_else(|_| "{}".to_string());
69-
Ok(data)
70-
}
71-
723
#[tauri::command]
734
pub async fn inject(
745
name: &str,

src-tauri/src/main.rs

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,9 @@ mod rpcs;
1010
mod samp;
1111

1212
use std::env;
13-
use std::path::PathBuf;
1413
use std::process::exit;
1514
use std::sync::Mutex;
1615

17-
use commands::AppState;
1816
use gumdrop::Options;
1917
use injector::run_samp;
2018
use log::{error, LevelFilter};
@@ -53,8 +51,11 @@ async fn main() {
5351

5452
#[cfg(windows)]
5553
{
56-
use windows::Win32::System::Console::{AttachConsole, ATTACH_PARENT_PROCESS};
57-
let _ = unsafe { AttachConsole(ATTACH_PARENT_PROCESS) };
54+
#[cfg(not(debug_assertions))]
55+
{
56+
use windows::Win32::System::Console::{AttachConsole, ATTACH_PARENT_PROCESS};
57+
let _ = unsafe { AttachConsole(ATTACH_PARENT_PROCESS) };
58+
}
5859
}
5960

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

110111
#[cfg(windows)]
111112
{
112-
use windows::Win32::System::Console::FreeConsole;
113-
let _ = unsafe { FreeConsole() };
113+
#[cfg(not(debug_assertions))]
114+
{
115+
use windows::Win32::System::Console::FreeConsole;
116+
let _ = unsafe { FreeConsole() };
117+
}
114118
}
115119

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

121125
match tauri::Builder::default()
122-
.manage(AppState {
123-
storage_file: PathBuf::from(format!(
124-
"{}/com.open.mp/storage.json",
125-
dirs_next::data_local_dir().unwrap().to_str().unwrap()
126-
)),
127-
})
128126
.plugin(tauri_plugin_upload::init())
129127
.setup(|app| {
130128
let handle = app.handle();
@@ -160,11 +158,7 @@ Options:
160158
commands::get_gtasa_path_from_samp,
161159
commands::get_nickname_from_samp,
162160
commands::rerun_as_admin,
163-
commands::get_samp_favorite_list,
164-
commands::get_item,
165-
commands::set_item,
166-
commands::remove_item,
167-
commands::get_all_items
161+
commands::get_samp_favorite_list
168162
])
169163
.run(tauri::generate_context!())
170164
{

src-tauri/src/rpcs.rs

Lines changed: 193 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,28 @@
11
use actix_cors::Cors;
22
use actix_web::{web, App, HttpResponse, HttpServer, Responder};
3+
use lazy_static::lazy_static;
34
use md5::compute;
45
use serde::Deserialize;
5-
use serde_json::json;
6+
use serde_json::{json, Value};
67
use sevenz_rust::decompress_file;
78
use std::error::Error;
9+
use std::fs;
810
use std::fs::File;
911
use std::io::Read;
12+
use std::path::PathBuf;
13+
use std::sync::Mutex;
1014
use std::time::Instant;
15+
use tokio::sync::Semaphore;
1116

1217
use crate::query;
1318
use crate::{discord, helpers};
1419

20+
static STORAGE_FILE: Mutex<Option<PathBuf>> = Mutex::new(None);
21+
22+
lazy_static! {
23+
static ref SEMAPHORE: Semaphore = Semaphore::new(1);
24+
}
25+
1526
#[derive(Deserialize)]
1627
struct RpcParams {
1728
params: serde_json::Value,
@@ -50,6 +61,17 @@ struct CopyFilesToGtaSaParams {
5061
gtasa_dir: String,
5162
}
5263

64+
#[derive(Deserialize)]
65+
struct StorageGetOrRemoveItemParams {
66+
key: String,
67+
}
68+
69+
#[derive(Deserialize)]
70+
struct StorageSetItemParams {
71+
key: String,
72+
value: String,
73+
}
74+
5375
async fn request_server_info(ip: &str, port: i32) -> Result<String, String> {
5476
match query::Query::new(ip, port).await {
5577
Ok(q) => {
@@ -148,6 +170,65 @@ fn copy_files_to_gtasa(src: &str, gtasa_dir: &str) -> Result<(), String> {
148170
helpers::copy_files(src, gtasa_dir)
149171
}
150172

173+
fn storage_get_item(key: String) -> Result<Option<String>, String> {
174+
init_storage_file();
175+
let storage_file = STORAGE_FILE.lock().unwrap().to_owned().unwrap();
176+
ensure_storage_file(&storage_file)?;
177+
178+
let data = fs::read_to_string(&storage_file).map_err(|e| e.to_string())?;
179+
let json_data: Value = serde_json::from_str(&data).map_err(|e| e.to_string())?;
180+
181+
Ok(json_data
182+
.get(&key)
183+
.and_then(|v| v.as_str().map(|s| s.to_string())))
184+
}
185+
186+
fn storage_set_item(key: String, value: String) -> Result<(), String> {
187+
init_storage_file();
188+
let storage_file = STORAGE_FILE.lock().unwrap().to_owned().unwrap();
189+
ensure_storage_file(&storage_file)?;
190+
191+
let data = fs::read_to_string(&storage_file).map_err(|e| e.to_string())?;
192+
let mut json_data: Value = serde_json::from_str(&data).map_err(|e| e.to_string())?;
193+
194+
json_data[key] = json!(value);
195+
196+
fs::write(storage_file, json_data.to_string()).map_err(|e| e.to_string())?;
197+
Ok(())
198+
}
199+
200+
fn storage_remove_item(key: String) -> Result<(), String> {
201+
init_storage_file();
202+
let storage_file = STORAGE_FILE.lock().unwrap().to_owned().unwrap();
203+
ensure_storage_file(&storage_file)?;
204+
205+
let data = fs::read_to_string(&storage_file).map_err(|e| e.to_string())?;
206+
let mut json_data: Value = serde_json::from_str(&data).map_err(|e| e.to_string())?;
207+
208+
json_data.as_object_mut().map(|map| map.remove(&key));
209+
210+
fs::write(storage_file, json_data.to_string()).map_err(|e| e.to_string())?;
211+
Ok(())
212+
}
213+
214+
fn storage_get_all_items() -> Result<String, String> {
215+
init_storage_file();
216+
let storage_file = STORAGE_FILE.lock().unwrap().to_owned().unwrap();
217+
ensure_storage_file(&storage_file)?;
218+
219+
let data = fs::read_to_string(&storage_file).unwrap_or_else(|_| "{}".to_string());
220+
Ok(data)
221+
}
222+
223+
fn storage_clear() -> Result<(), String> {
224+
init_storage_file();
225+
let storage_file = STORAGE_FILE.lock().unwrap().to_owned().unwrap();
226+
ensure_storage_file(&storage_file)?;
227+
228+
fs::write(storage_file, "{}").map_err(|e| e.to_string())?;
229+
Ok(())
230+
}
231+
151232
async fn rpc_handler(
152233
path: web::Path<RpcMethod>,
153234
payload: web::Json<RpcParams>,
@@ -252,14 +333,124 @@ async fn rpc_handler(
252333
Ok(HttpResponse::Ok().body(response))
253334
}
254335

336+
async fn sync_rpc_handler(
337+
path: web::Path<RpcMethod>,
338+
payload: web::Json<RpcParams>,
339+
) -> Result<impl Responder, Box<dyn Error>> {
340+
let _permit = SEMAPHORE.acquire().await.unwrap(); // Acquire a permit to ensure only one request is processed at a time
341+
let params_str = serde_json::to_string(&payload.params)?;
342+
343+
/*
344+
method: storage_get_item
345+
*/
346+
if path.method == "storage_get_item" {
347+
let params: StorageGetOrRemoveItemParams = serde_json::from_str(params_str.as_str())?;
348+
let result = storage_get_item(params.key);
349+
if result.is_err() {
350+
return Ok(
351+
HttpResponse::Ok().body(format!("storage_error|sep|{}", result.err().unwrap()))
352+
);
353+
}
354+
355+
return resolve_option_for_http_response(result.unwrap());
356+
}
357+
/*
358+
method: storage_remove_item
359+
*/
360+
else if path.method == "storage_remove_item" {
361+
let params: StorageGetOrRemoveItemParams = serde_json::from_str(params_str.as_str())?;
362+
let result = storage_remove_item(params.key);
363+
if result.is_err() {
364+
return Ok(
365+
HttpResponse::Ok().body(format!("storage_error|sep|{}", result.err().unwrap()))
366+
);
367+
}
368+
369+
return Ok(HttpResponse::Ok().body("{}"));
370+
}
371+
/*
372+
method: storage_set_item
373+
*/
374+
else if path.method == "storage_set_item" {
375+
let params: StorageSetItemParams = serde_json::from_str(params_str.as_str())?;
376+
let result = storage_set_item(params.key, params.value);
377+
if result.is_err() {
378+
return Ok(
379+
HttpResponse::Ok().body(format!("storage_error|sep|{}", result.err().unwrap()))
380+
);
381+
}
382+
383+
return Ok(HttpResponse::Ok().body("{}"));
384+
}
385+
/*
386+
method: storage_get_all_items
387+
*/
388+
else if path.method == "storage_get_all_items" {
389+
let result = storage_get_all_items();
390+
if result.is_err() {
391+
return Ok(
392+
HttpResponse::Ok().body(format!("storage_error|sep|{}", result.err().unwrap()))
393+
);
394+
}
395+
396+
return Ok(HttpResponse::Ok().body(result.unwrap()));
397+
}
398+
/*
399+
method: storage_clear
400+
*/
401+
else if path.method == "storage_clear" {
402+
let result = storage_clear();
403+
if result.is_err() {
404+
return Ok(
405+
HttpResponse::Ok().body(format!("storage_error|sep|{}", result.err().unwrap()))
406+
);
407+
}
408+
409+
return Ok(HttpResponse::Ok().body("{}"));
410+
}
411+
412+
let response = format!(
413+
"Received RPC request: {} with params: {:?}",
414+
path.method, payload.params
415+
);
416+
Ok(HttpResponse::Ok().body(response))
417+
}
418+
255419
pub async fn initialize_rpc() -> Result<(), std::io::Error> {
256420
HttpServer::new(|| {
257421
App::new()
258422
.wrap(Cors::permissive())
423+
.service(web::resource("/sync_rpc/{method}").route(web::post().to(sync_rpc_handler)))
259424
.service(web::resource("/rpc/{method}").route(web::post().to(rpc_handler)))
260425
})
261426
.bind("127.0.0.1:46290")?
262427
.run()
263428
.await
264-
// Ok(())
429+
}
430+
431+
fn resolve_option_for_http_response(
432+
option: Option<String>,
433+
) -> Result<HttpResponse, Box<dyn Error>> {
434+
match option {
435+
Some(res) => Ok(HttpResponse::Ok().body(res)),
436+
None => Ok(HttpResponse::Ok().body("null")),
437+
}
438+
}
439+
440+
fn ensure_storage_file(storage_file: &PathBuf) -> Result<(), String> {
441+
if !storage_file.exists() {
442+
// Create an empty JSON file
443+
fs::write(storage_file, "{}").map_err(|e| e.to_string())?;
444+
}
445+
Ok(())
446+
}
447+
448+
fn init_storage_file() {
449+
let mut storage_file_guard = STORAGE_FILE.lock().unwrap();
450+
if storage_file_guard.is_none() {
451+
*storage_file_guard = Some(PathBuf::from(format!(
452+
"{}/com.open.mp/storage.json",
453+
dirs_next::data_local_dir().unwrap().to_str().unwrap()
454+
)));
455+
}
265456
}

0 commit comments

Comments
 (0)