use std::sync::Arc;
use factorio_rcon::RconClient;
use tokio::sync::Mutex;
use crate::error::SenseiError;
pub type SharedRcon = Arc<Mutex<RconClient>>;
pub async fn execute_lua_json(rcon: &SharedRcon, lua_iife: &str) -> Result<String, SenseiError> {
let command = format!("/silent-command rcon.print(helpers.table_to_json({lua_iife}))");
let response = rcon.lock().await.execute(&command).await?;
if response.contains(r#""error":"no_player""#) {
return Err(SenseiError::NoPlayer);
}
if let Some(msg) = extract_lua_error(&response) {
return Err(SenseiError::LuaError(msg));
}
let trimmed = response.trim_start();
if !trimmed.starts_with('{') && !trimmed.starts_with('[') {
return Err(SenseiError::LuaError(response));
}
Ok(response)
}
fn extract_lua_error(response: &str) -> Option<String> {
let parsed: serde_json::Value = serde_json::from_str(response).ok()?;
let err = parsed.get("error")?.as_str()?;
if err == "no_player" {
return None; }
Some(err.to_string())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_extract_lua_error_with_error() {
let response = r#"{"error":"some lua problem"}"#;
assert_eq!(
extract_lua_error(response),
Some("some lua problem".to_string())
);
}
#[test]
fn test_extract_lua_error_no_player_returns_none() {
let response = r#"{"error":"no_player"}"#;
assert_eq!(extract_lua_error(response), None);
}
#[test]
fn test_extract_lua_error_valid_json() {
let response = r#"{"x":1.5,"y":-3.2}"#;
assert_eq!(extract_lua_error(response), None);
}
#[test]
fn test_extract_lua_error_not_json() {
let response = "not json at all";
assert_eq!(extract_lua_error(response), None);
}
#[test]
fn test_non_json_response_detected() {
let response = "Cannot execute command. Error in assignment...";
let trimmed = response.trim_start();
assert!(!trimmed.starts_with('{') && !trimmed.starts_with('['));
}
#[test]
fn test_json_object_passes_check() {
let response = r#"{"x":1.5,"y":2.0}"#;
let trimmed = response.trim_start();
assert!(trimmed.starts_with('{'));
}
#[test]
fn test_json_array_passes_check() {
let response = r"[1,2,3]";
let trimmed = response.trim_start();
assert!(trimmed.starts_with('['));
}
}