diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/balalib.iml b/.idea/balalib.iml new file mode 100644 index 0000000..cf84ae4 --- /dev/null +++ b/.idea/balalib.iml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/discord.xml b/.idea/discord.xml new file mode 100644 index 0000000..912db82 --- /dev/null +++ b/.idea/discord.xml @@ -0,0 +1,14 @@ + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..e075b7e --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/core.rs b/src/core.rs index e54e445..9b40800 100644 --- a/src/core.rs +++ b/src/core.rs @@ -9,34 +9,7 @@ use std::process::Command; pub fn need_update(lua: &Lua, _: ()) -> LuaResult { let current_version = lua.load("require('balamod_version')").eval::()?; - let client = reqwest::blocking::Client::builder() - .user_agent("balamod_lua") - .build() - .unwrap(); - - match client - .get("https://api.github.com/repos/balamod/balamod_lua/releases") - .send() - { - Ok(response) => match response.text() { - Ok(text) => { - let releases: Vec = serde_json::from_str(&text) - .unwrap_or_else(|_| panic!("Failed to parse json: {}", text)); - let latest_version = releases - .iter() - .find(|release| { - !release["prerelease"].as_bool().unwrap() - && !release["draft"].as_bool().unwrap() - }) - .unwrap()["tag_name"] - .as_str() - .unwrap(); - Ok(current_version != latest_version) - } - Err(_) => Ok(false), - }, - Err(_) => Ok(false), - } + super::updater::need_update(current_version) } fn lua_value_to_json_value(value: &Value) -> JsonValue { @@ -54,16 +27,18 @@ fn lua_value_to_json_value(value: &Value) -> JsonValue { fn table_to_json_value(table: &Table) -> JsonValue { let mut map = serde_json::Map::new(); let table_clone = table.clone(); - for (key, value) in table_clone.pairs::().flatten() { - if let Value::String(k) = key { - map.insert( - k.to_str().unwrap().to_string(), - lua_value_to_json_value(&value), - ); - } else if let Value::Integer(k) = key { - map.insert(k.to_string(), lua_value_to_json_value(&value)); - } else if let Value::Number(k) = key { - map.insert(k.to_string(), lua_value_to_json_value(&value)); + for pair in table_clone.pairs::() { + if let Ok((key, value)) = pair { + if let Value::String(k) = key { + map.insert( + k.to_str().unwrap().to_string(), + lua_value_to_json_value(&value), + ); + } else if let Value::Integer(k) = key { + map.insert(k.to_string(), lua_value_to_json_value(&value)); + } else if let Value::Number(k) = key { + map.insert(k.to_string(), lua_value_to_json_value(&value)); + } } } JsonValue::Object(map) @@ -140,27 +115,6 @@ pub fn is_mod_present(lua: &Lua, mod_info: ModInfo) -> LuaResult { Ok(Path::new(&main_path).exists()) } -#[cfg(target_os = "windows")] -pub fn self_update(cli_ver: &str) -> LuaResult<()> { - let url = format!( - "https://github.com/balamod/balamod/releases/download/{}/balamod-{}-windows.exe", - cli_ver, cli_ver - ); - let client = reqwest::blocking::Client::builder() - .user_agent("balalib") - .build() - .unwrap(); - let mut response = client.get(&url).send().unwrap(); - let mut file = std::fs::File::create("balamod.exe").unwrap(); - std::io::copy(&mut response, &mut file).unwrap(); - restart()? -} - -#[cfg(any(target_os = "macos", target_os = "linux"))] -pub fn self_update(_cli_ver: &str) -> LuaResult<()> { - Ok(()) -} - #[cfg(target_os = "windows")] pub fn restart() -> LuaResult<()> { let exe_path = env::current_exe()?; diff --git a/src/lib.rs b/src/lib.rs index 6ab67c6..495c811 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,14 +1,16 @@ use crate::core::{ - inject, is_mod_present, json_to_lua, lua_to_json, need_update, restart, self_update, - setup_injection, + inject, is_mod_present, json_to_lua, lua_to_json, need_update, restart, setup_injection, }; use mlua::prelude::*; use mlua::Value; use crate::mods::*; +use crate::updater::self_update; mod core; mod mods; +mod tests; +mod updater; mod utils; const VERSION: &str = env!("CARGO_PKG_VERSION"); @@ -21,13 +23,10 @@ fn echo(_: &Lua, name: String) -> LuaResult { fn balalib(lua: &Lua) -> LuaResult { let exports = lua.create_table()?; exports.set("echo", lua.create_function(echo)?)?; - exports.set( - "fetch_mods", - lua.create_function(|lua, ()| fetch_mods(lua, ()))?, - )?; + exports.set("fetch_mods", lua.create_function(|_, ()| fetch_mods())?)?; exports.set( "get_local_mods", - lua.create_function(|lua, ()| get_local_mods(lua, ()))?, + lua.create_function(|lua, ()| get_local_mods(lua))?, )?; exports.set( "need_update", diff --git a/src/mods.rs b/src/mods.rs index de63e53..6d4aa94 100644 --- a/src/mods.rs +++ b/src/mods.rs @@ -4,7 +4,6 @@ use jsonschema::JSONSchema; use mlua::prelude::{LuaError, LuaResult, LuaValue}; use mlua::{FromLua, IntoLua, Lua}; use serde::{Deserialize, Serialize}; -use serde_json::json; #[derive(Debug, Clone)] pub struct ModInfo { @@ -72,7 +71,7 @@ pub fn download_mod(lua: &Lua, mod_info: ModInfo) -> LuaResult<()> { let mod_dir = format!("{}/{}", mods_dir, id); std::fs::create_dir_all(&mod_dir)?; let tar = body.to_vec(); - unpack_tar(&mod_dir, tar.clone()).unwrap_or_else(|_| panic!("Failed to unpack tar: {}", url)); + unpack_tar(&mod_dir, tar.clone()).expect(format!("Failed to unpack tar: {}", url).as_str()); Ok(()) } @@ -83,7 +82,7 @@ pub fn unpack_tar(dir: &str, tar: Vec) -> Result<(), Box LuaResult> { +pub fn fetch_mods() -> LuaResult> { let client = reqwest::blocking::Client::new(); match client .get("https://raw.githubusercontent.com/balamod/balamod/master/new_repos.index") @@ -144,101 +143,10 @@ fn get_mods_from_repo(repo_url: String) -> Result, reqwest::Error> Ok(mod_infos) } -pub fn get_local_mods(lua: &Lua, _: ()) -> LuaResult> { - let schema = json!({ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$defs": { - "version": { - "type": "string", - "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$" - }, - "versionConstraint": { - "type": "string", - "pattern": "^(\\^|>|>=|<|<=)? ?[0-9]+(\\.[0-9]+(\\.[0-9]+)?)?(, ?(>|>=|<|<=)? ?[0-9]+(\\.[0-9]+(\\.[0-9]+)?)?)?$" - }, - "id": { - "type": "string", - "pattern": "[a-z0-9_\\-]+" - }, - "authorName": { - "type": "string", - "pattern": "[A-Za-z0-9]+( <.+@[a-z0-9]+\\.[a-z\\.]{3,}>)?" - } - }, - "type": "object", - "required": [ - "id", - "name", - "version", - "description", - "author", - "load_before", - "load_after" - ], - "properties": { - "id": { - "$ref": "#/$defs/id" - }, - "name": { - "type": "string" - }, - "version": { - "$ref": "#/$defs/version" - }, - "description": { - "type": "array", - "items": { - "type": "string", - "maxLength": 50 - } - }, - "author": { - "oneOf": [ - { - "$ref": "#/$defs/authorName" - }, - { - "type": "array", - "items": { - "$ref": "#/$defs/authorName" - } - } - ] - }, - "load_before": { - "type": "array", - "items": { - "$ref": "#/$defs/version" - } - }, - "load_after": { - "type": "array", - "items": { - "$ref": "#/$defs/version" - } - }, - "min_balamod_version": { - "$ref": "#/$defs/version" - }, - "max_balamod_version": { - "$ref": "#/$defs/version" - }, - "balalib_version": { - "$ref": "#/$defs/versionConstraint" - }, - "dependencies": { - "type": "object", - "patternProperties": { - "^[a-z0-9_\\-]+$": { - "$ref": "#/$defs/versionConstraint" - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false - }); - let compiled_schema = JSONSchema::compile(&schema).expect("A valid schema"); +pub fn get_local_mods(lua: &Lua) -> LuaResult> { + let schema = include_bytes!("schema/manifest.schema.json"); + let schema: serde_json::Value = serde_json::from_slice(schema).expect("Invalid schema"); + let compiled_schema = JSONSchema::compile(&schema).expect("Invalid schema"); let love_dir = get_love_dir(lua)?; let mods_dir = format!("{}/mods", love_dir); @@ -280,8 +188,8 @@ pub fn get_local_mods(lua: &Lua, _: ()) -> LuaResult> { let mut manifest: LocalMod = serde_json::from_str(&manifest).unwrap(); - if let Some(balalib_version) = manifest.clone().balalib_version { - match balalib_version.chars().next().unwrap() { + match manifest.clone().balalib_version { + Some(balalib_version) => match balalib_version.chars().next().unwrap() { '>' => { let balalib_version = balalib_version.split(">").nth(1).unwrap(); if balalib_version <= VERSION { @@ -304,21 +212,28 @@ pub fn get_local_mods(lua: &Lua, _: ()) -> LuaResult> { } } _ => {} - } + }, + None => {} } - if let Some(min_balamod_version) = manifest.clone().min_balamod_version { - if balamod_version < min_balamod_version { - lua.load(format!("require('logging').getLogger('balalib'):error('Balalib version too low: {} for mod {}')", min_balamod_version, manifest.id)).exec()?; - continue; + match manifest.clone().min_balamod_version { + Some(min_balamod_version) => { + if balamod_version < min_balamod_version { + lua.load(format!("require('logging').getLogger('balalib'):error('Balalib version too low: {} for mod {}')", min_balamod_version, manifest.id)).exec()?; + continue; + } } + None => {} } - if let Some(max_balamod_version) = manifest.clone().max_balamod_version { - if balamod_version > max_balamod_version { - lua.load(format!("require('logging').getLogger('balalib'):error('Balalib version too high: {} for mod {}')", max_balamod_version, manifest.id)).exec()?; - continue; + match manifest.clone().max_balamod_version { + Some(max_balamod_version) => { + if balamod_version > max_balamod_version { + lua.load(format!("require('logging').getLogger('balalib'):error('Balalib version too high: {} for mod {}')", max_balamod_version, manifest.id)).exec()?; + continue; + } } + None => {} } let folder_name = mod_dir.split("/").last().unwrap(); diff --git a/src/schema/manifest.schema.json b/src/schema/manifest.schema.json new file mode 100644 index 0000000..577d3c7 --- /dev/null +++ b/src/schema/manifest.schema.json @@ -0,0 +1,93 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$defs": { + "version": { + "type": "string", + "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$" + }, + "versionConstraint": { + "type": "string", + "pattern": "^(\\^|>|>=|<|<=)? ?[0-9]+(\\.[0-9]+(\\.[0-9]+)?)?(, ?(>|>=|<|<=)? ?[0-9]+(\\.[0-9]+(\\.[0-9]+)?)?)?$" + }, + "id": { + "type": "string", + "pattern": "[a-z0-9_\\-]+" + }, + "authorName": { + "type": "string", + "pattern": "[A-Za-z0-9]+( <.+@[a-z0-9]+\\.[a-z\\.]{3,}>)?" + } + }, + "type": "object", + "required": [ + "id", + "name", + "version", + "description", + "author", + "load_before", + "load_after" + ], + "properties": { + "id": { + "$ref": "#/$defs/id" + }, + "name": { + "type": "string" + }, + "version": { + "$ref": "#/$defs/version" + }, + "description": { + "type": "array", + "items": { + "type": "string", + "maxLength": 50 + } + }, + "author": { + "oneOf": [ + { + "$ref": "#/$defs/authorName" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/authorName" + } + } + ] + }, + "load_before": { + "type": "array", + "items": { + "$ref": "#/$defs/version" + } + }, + "load_after": { + "type": "array", + "items": { + "$ref": "#/$defs/version" + } + }, + "min_balamod_version": { + "$ref": "#/$defs/version" + }, + "max_balamod_version": { + "$ref": "#/$defs/version" + }, + "balalib_version": { + "$ref": "#/$defs/versionConstraint" + }, + "dependencies": { + "type": "object", + "patternProperties": { + "^[a-z0-9_\\-]+$": { + "$ref": "#/$defs/versionConstraint" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false +} \ No newline at end of file diff --git a/src/tests.rs b/src/tests.rs new file mode 100644 index 0000000..ab45c75 --- /dev/null +++ b/src/tests.rs @@ -0,0 +1,29 @@ +#[cfg(test)] +mod tests { + use crate::utils::minify_lua; + use std::fs; + + #[test] + fn test_update() { + let version = String::from("v0.1.10"); + assert!(crate::updater::need_update(version).unwrap()); + } + + #[test] + fn test_mods_fetch() { + let mods = crate::mods::fetch_mods().unwrap(); + assert!(mods.len() > 0); + } + + #[test] + fn test_parsing() { + let lua_file = fs::read_to_string("test.lua").unwrap(); + let functions = crate::utils::extract_functions(lua_file.clone()); + assert_eq!(functions.len(), 1); + functions.get("test").unwrap(); + assert_eq!( + minify_lua(lua_file), + r#"function test() print("Hello World!") a = function() print("Hello World!") end a() end test()"# + ); + } +} diff --git a/src/updater.rs b/src/updater.rs new file mode 100644 index 0000000..38d81e4 --- /dev/null +++ b/src/updater.rs @@ -0,0 +1,54 @@ +use crate::core::restart; +use mlua::prelude::LuaResult; + +pub fn need_update(current_version: String) -> LuaResult { + let client = reqwest::blocking::Client::builder() + .user_agent("balamod_lua") + .build() + .unwrap(); + + match client + .get("https://api.github.com/repos/balamod/balamod_lua/releases") + .send() + { + Ok(response) => match response.text() { + Ok(text) => { + let releases: Vec = serde_json::from_str(&text) + .expect(format!("Failed to parse json: {}", text).as_str()); + let latest_version = releases + .iter() + .find(|release| { + !release["prerelease"].as_bool().unwrap() + && !release["draft"].as_bool().unwrap() + }) + .unwrap()["tag_name"] + .as_str() + .unwrap(); + Ok(current_version != latest_version) + } + Err(_) => Ok(false), + }, + Err(_) => Ok(false), + } +} + +#[cfg(target_os = "windows")] +pub fn self_update(cli_ver: &str) -> LuaResult<()> { + let url = format!( + "https://github.com/balamod/balamod/releases/download/{}/balamod-{}-windows.exe", + cli_ver, cli_ver + ); + let client = reqwest::blocking::Client::builder() + .user_agent("balalib") + .build() + .unwrap(); + let mut response = client.get(&url).send().unwrap(); + let mut file = std::fs::File::create("balamod.exe").unwrap(); + std::io::copy(&mut response, &mut file).unwrap(); + restart() +} + +#[cfg(any(target_os = "macos", target_os = "linux"))] +pub fn self_update(_cli_ver: &str) -> LuaResult<()> { + restart() +} diff --git a/test.lua b/test.lua new file mode 100644 index 0000000..882a9e4 --- /dev/null +++ b/test.lua @@ -0,0 +1,9 @@ +function test() + print("Hello World!") + a = function() + print("Hello World!") + end + a() +end + +test() \ No newline at end of file