diff --git a/CHANGELOG.md b/CHANGELOG.md index 340f6c1..21c2cb6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), ## [Unreleased] +### Added + +- Support for MessagePack (`.msgpack`) - binary format, great for storing big amount of data + ## [2.0.1] - 2024-05-02 ### Fixed diff --git a/Cargo.lock b/Cargo.lock index b1e6175..7d744b0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -361,6 +361,7 @@ dependencies = [ "rbx_xml", "reqwest", "rmp-serde", + "rmpv", "roblox_install", "self_update", "serde", @@ -2395,9 +2396,9 @@ dependencies = [ [[package]] name = "rmp" -version = "0.8.12" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f9860a6cc38ed1da53456442089b4dfa35e7cedaa326df63017af88385e6b20" +checksum = "228ed7c16fa39782c3b3468e974aec2795e9089153cd08ee2e9aefb3613334c4" dependencies = [ "byteorder", "num-traits", @@ -2415,6 +2416,18 @@ dependencies = [ "serde", ] +[[package]] +name = "rmpv" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58450723cd9ee93273ce44a20b6ec4efe17f8ed2e3631474387bfdecf18bb2a9" +dependencies = [ + "num-traits", + "rmp", + "serde", + "serde_bytes", +] + [[package]] name = "roblox_install" version = "1.0.0" @@ -2593,6 +2606,15 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde_bytes" +version = "0.11.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b8497c313fd43ab992087548117643f6fcd935cbf36f176ffda0aacf9591734" +dependencies = [ + "serde", +] + [[package]] name = "serde_derive" version = "1.0.197" diff --git a/Cargo.toml b/Cargo.toml index ee84abd..0d2abe2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,6 +31,7 @@ clap = { version = "4.4.1", features = ["derive", "cargo"] } serde = { version = "1.0.189", features = ["derive"] } tokio = { version = "1.32.0", features = ["full"] } reqwest = { version = "0.11.23", features = ["blocking", "rustls-tls"] } +rmpv = {version = "1.3.0", features = ["with-serde"] } self_update = { version = "0.39.0", features = [ "compression-zip-deflate", "rustls", diff --git a/src/cli/exec.rs b/src/cli/exec.rs index 9f1a1d3..a5afbf8 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -53,6 +53,7 @@ impl Exec { code: code.to_owned(), focus: self.focus, })?; + let response = Client::default() .post(url) .header(CONTENT_TYPE, "application/msgpack") diff --git a/src/constants.rs b/src/constants.rs index 468f4ae..e0981a6 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -110,6 +110,9 @@ pub fn default_sync_rules() -> &'static Vec { SyncRule::new(Middleware::TomlModule) .with_pattern("*.toml") .with_child_pattern(".src.toml"), + SyncRule::new(Middleware::MsgpackModule) + .with_pattern("*.msgpack") + .with_child_pattern(".src.msgpack"), // Model files, Argon only SyncRule::new(Middleware::JsonModel) .with_pattern("*.model.json") diff --git a/src/middleware/mod.rs b/src/middleware/mod.rs index b4d93a2..60594fe 100644 --- a/src/middleware/mod.rs +++ b/src/middleware/mod.rs @@ -25,6 +25,7 @@ pub mod dir; pub mod json; pub mod json_model; pub mod lua; +pub mod msgpack; pub mod project; pub mod rbxm; pub mod rbxmx; @@ -42,8 +43,10 @@ pub enum Middleware { StringValue, LocalizationTable, + JsonModule, TomlModule, + MsgpackModule, JsonModel, RbxmModel, @@ -68,8 +71,10 @@ impl Middleware { // Middleware::StringValue => txt::read_txt(path, vfs), Middleware::LocalizationTable => csv::read_csv(path, vfs), + // Middleware::JsonModule => json::read_json(path, vfs), Middleware::TomlModule => toml::read_toml(path, vfs), + Middleware::MsgpackModule => msgpack::read_msgpack(path, vfs), // Middleware::JsonModel => json_model::read_json_model(path, vfs), Middleware::RbxmModel => rbxm::read_rbxm(path, vfs), diff --git a/src/middleware/msgpack.rs b/src/middleware/msgpack.rs new file mode 100644 index 0000000..05a70d7 --- /dev/null +++ b/src/middleware/msgpack.rs @@ -0,0 +1,89 @@ +use anyhow::Result; +use rbx_dom_weak::types::Variant; +use rmp_serde::Deserializer; +use rmpv::Value; +use std::{collections::HashMap, path::Path}; + +use crate::{core::snapshot::Snapshot, vfs::Vfs}; + +#[profiling::function] +pub fn read_msgpack(path: &Path, vfs: &Vfs) -> Result { + let msgpack = vfs.read(path)?; + + let mut deserializer = Deserializer::from_read_ref(&msgpack).with_human_readable(); + let msgpack: Value = serde::Deserialize::deserialize(&mut deserializer)?; + + let lua = format!("return {}", msgpack_to_lua(&msgpack)); + + let mut properties = HashMap::new(); + properties.insert(String::from("Source"), Variant::String(lua)); + + Ok(Snapshot::new().with_class("ModuleScript").with_properties(properties)) +} + +fn msgpack_to_lua(value: &Value) -> String { + let mut lua = String::new(); + + match value { + Value::Nil => lua.push_str("nil"), + Value::Boolean(b) => lua.push_str(&b.to_string()), + Value::Integer(i) => lua.push_str(&i.to_string()), + Value::F32(f) => { + if (*f as f64).is_infinite() { + lua.push_str("math.huge") + } else { + lua.push_str(&f.to_string()) + } + } + Value::F64(f) => { + if f.is_infinite() { + lua.push_str("math.huge") + } else { + lua.push_str(&f.to_string()) + } + } + Value::String(s) => lua.push_str(&format!("\"{}\"", &escape_chars(s.as_str().unwrap_or_default()))), + Value::Binary(b) => lua.push_str(&String::from_utf8_lossy(b)), + Value::Array(a) => { + lua.push('{'); + + for v in a { + lua.push_str(&msgpack_to_lua(v)); + lua.push(','); + } + + lua.push('}'); + } + Value::Map(t) => { + lua.push('{'); + + for (k, v) in t { + lua.push_str(&format!("[{}] = ", &msgpack_to_lua(k))); + lua.push_str(&msgpack_to_lua(v)); + lua.push(','); + } + + lua.push('}'); + } + Value::Ext(_, _) => {} + } + + lua +} + +fn escape_chars(string: &str) -> String { + let mut validated = String::new(); + + for char in string.chars() { + match char { + '\n' => validated.push_str("\\n"), + '\t' => validated.push_str("\\t"), + '\r' => validated.push_str("\\r"), + '\\' => validated.push_str("\\\\"), + '"' => validated.push_str("\\\""), + _ => validated.push(char), + } + } + + validated +}