diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..50043eb --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +server/target/ diff --git a/server/Cargo.lock b/server/Cargo.lock new file mode 100644 index 0000000..b650552 --- /dev/null +++ b/server/Cargo.lock @@ -0,0 +1,184 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "hashbrown" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" + +[[package]] +name = "indexmap" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "proc-macro2" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", + "serde_core", +] + +[[package]] +name = "serde_spanned" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e24345aa0fe688594e73770a5f6d1b216508b4f93484c0026d521acd30134392" +dependencies = [ + "serde_core", +] + +[[package]] +name = "syn" +version = "2.0.110" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "toml" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dc8b1fb61449e27716ec0e1bdf0f6b8f3e8f6b05391e8497b8b6d7804ea6d8" +dependencies = [ + "indexmap", + "serde_core", + "serde_spanned", + "toml_datetime", + "toml_parser", + "toml_writer", + "winnow", +] + +[[package]] +name = "toml_datetime" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_parser" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" +dependencies = [ + "winnow", +] + +[[package]] +name = "toml_writer" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df8b2b54733674ad286d16267dcfc7a71ed5c776e4ac7aa3c3e2561f7c637bf2" + +[[package]] +name = "unicode-ident" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" + +[[package]] +name = "wgu" +version = "0.0.1" +dependencies = [ + "serde", + "serde_json", + "toml", +] + +[[package]] +name = "winnow" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" diff --git a/server/Cargo.toml b/server/Cargo.toml new file mode 100644 index 0000000..9ef1a1f --- /dev/null +++ b/server/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "wgu" +authors = ["sel "] +version = "0.0.1" +edition = "2024" + +[dependencies] +serde = { version = "*", features = ["derive"] } +serde_json = "1.0.145" +toml = "0.9.8" diff --git a/server/src/lib.rs b/server/src/lib.rs new file mode 100644 index 0000000..3130634 --- /dev/null +++ b/server/src/lib.rs @@ -0,0 +1,58 @@ +pub mod modules; +pub mod types; +use crate::modules::{ModuleItem, item_registry}; +use crate::types::{ObjectInstance, ObjectTemplate}; + +use serde_json::{Value, json}; + +impl ObjectInstance { + pub fn validate(obj: &ObjectInstance) -> Result<(), String> { + let modules = item_registry(); + let object_type = &obj.object_type; + + let template: ObjectTemplate = match modules.get(object_type.as_str()) { + Some(ModuleItem::Template(template_str)) => toml::from_str(template_str).unwrap(), + Some(_) => panic!("{} is not a ModuleItem::Template", object_type), + None => return Err(format!("template {} doesn't exist", object_type)) + }; + + match modules.get(format!("{}:func:validator", object_type).as_str()) { + Some(ModuleItem::Validator(validate)) => validate(&obj)?, + Some(_) => panic!("{}:func:validator is not a ModuleItem::Validator", object_type), + None => (), + }; + + for (name, property) in template.input { + for transform in property.transforms { + let destination = transform.split(":").collect::>(); + + let temp_object = ObjectInstance { + object_type: destination[0].to_string(), + input: json!({ + destination[1]: obj.input.get(&name) + }), + ..ObjectInstance::default() + }; + + match modules.get(format!("{}:func:validator", &destination[0]).as_str()) { + Some(ModuleItem::Validator(validate)) => validate(&temp_object)?, + Some(_) => panic!("{}:func:validator is not a ModuleItem::Validator", object_type), + None => () + } + } + } + + Ok(()) + } + + pub fn from_template(object_type: &str, input: Value) -> Result { + let instance = ObjectInstance { + object_type: object_type.to_string(), + input: json!(input), + ..ObjectInstance::default() + }; + + ObjectInstance::validate(&instance)?; + Ok(instance) + } +} diff --git a/server/src/main.rs b/server/src/main.rs new file mode 100644 index 0000000..f07628e --- /dev/null +++ b/server/src/main.rs @@ -0,0 +1,36 @@ +use serde_json::json; +use wgu::types::ObjectInstance; +use wgu::modules::{ModuleItem, item_registry}; + +fn main() -> Result<(), String> { + let modules = item_registry(); + + // change these! + let object_type = "meta/text"; + let input = json!({ + "value": "owo" + }); + let function = "local"; + + // this creates a new object instance + let some_object = ObjectInstance::from_template(object_type, input)?; + + println!("this is an object:"); + println!("{:?}", some_object); + println!(""); + + // this runs a function on it to calculate other properties + let some_object_with_data = match modules.get(format!("{}:func:{}", object_type, function).as_str()) { + Some(ModuleItem::Calculator(calc)) => calc(&some_object)?, + Some(_) => return Err(format!("if you're trying to run a ModuleItem::Function and not a ModuleItem::Calculator, you'll have to add the match arm for that")), + None => { + println!("the ModuleItem `{}:func:{}` doesn't exist. this is not necessarily bad in this example (if you changed `object_type`)", object_type, function); + some_object.clone() // does nothing(?) i hope + } + }; + + println!("this is the same object with data:"); + println!("{:?}", some_object_with_data); + + Ok(()) +} diff --git a/server/src/modules.rs b/server/src/modules.rs new file mode 100644 index 0000000..feae52c --- /dev/null +++ b/server/src/modules.rs @@ -0,0 +1,20 @@ +use crate::ObjectInstance; +use std::collections::HashMap; + +pub mod meta; + +pub enum ModuleItem { + Template(&'static str), + Validator(fn(&ObjectInstance) -> Result<(), String>), + Calculator(fn(&ObjectInstance) -> Result), + Function(fn( + inputs: HashMap<&str, &ObjectInstance>, + params: Option> + ) -> Result, String>) +} + +pub fn item_registry() -> HashMap<&'static str, ModuleItem> { + let mut map = HashMap::new(); + map.extend(meta::registry()); + map +} diff --git a/server/src/modules/meta.rs b/server/src/modules/meta.rs new file mode 100644 index 0000000..31590d1 --- /dev/null +++ b/server/src/modules/meta.rs @@ -0,0 +1,14 @@ +use crate::modules::ModuleItem; +use std::collections::HashMap; + +pub mod dummy; +pub mod text; + +pub fn registry() -> HashMap<&'static str, ModuleItem> { + let mut map = HashMap::new(); + map.insert("meta/dummy", ModuleItem::Template(dummy::TEMPLATE)); + map.insert("meta/text", ModuleItem::Template(text::TEMPLATE)); + map.insert("meta/text:func:validator", ModuleItem::Validator(text::validate)); + map.insert("meta/text:func:local", ModuleItem::Calculator(text::local)); + map +} diff --git a/server/src/modules/meta/dummy.rs b/server/src/modules/meta/dummy.rs new file mode 100644 index 0000000..ad3b8bc --- /dev/null +++ b/server/src/modules/meta/dummy.rs @@ -0,0 +1,5 @@ +pub const TEMPLATE: &str = r#"[input.value] +transforms = ["meta/text:value"] +subobjects = [] +duplicates = false +"#; diff --git a/server/src/modules/meta/text.rs b/server/src/modules/meta/text.rs new file mode 100644 index 0000000..d3270fb --- /dev/null +++ b/server/src/modules/meta/text.rs @@ -0,0 +1,41 @@ +use serde_json::json; +use crate::ObjectInstance; + +pub const TEMPLATE: &str = r#" +[input.value] +transforms = [] +subobjects = [] +conditions = [] +duplicates = false + +[local.length] +transforms = ["meta/number:value"] +subobjects = [] +conditions = [] +duplicates = false +"#; + +pub fn validate(obj: &ObjectInstance) -> Result<(), String> { + let value = obj.input.get("value") + .ok_or("input.value must exist")?; + + let _value = value.as_str() + .ok_or("input.value must be a string")?; + + Ok(()) +} + +pub fn local(obj: &ObjectInstance) -> Result { + let value = obj.input.get("value") + .ok_or("input.value must exist")?; + + let value = value.as_str() + .ok_or("input.value must be a string")?; + + let mut new = obj.clone(); + new.local = json!({ + "length": value.len() + }); + + Ok(new) +} diff --git a/server/src/types.rs b/server/src/types.rs new file mode 100644 index 0000000..2e627e8 --- /dev/null +++ b/server/src/types.rs @@ -0,0 +1,48 @@ +use serde::{Deserialize, Serialize}; +use serde_json::Value; +use std::collections::HashMap; + +#[derive(Serialize, Deserialize, Debug, Default, Clone)] +pub struct ObjectInstance { + pub version: u32, + pub variant: u32, + pub plotted: bool, + pub created: String, + pub edited: String, + pub hashed: String, + pub input_sha256: String, + pub full_sha256: String, + pub object_type: String, + pub logs: Vec, + pub input: Value, + pub local: Value, + pub remote: Value +} + +// part of ObjectInstance +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct Log { + level: String, + variant: String, + timestamp: String, + message: String, +} + +#[derive(Deserialize, Debug, Default)] +#[serde(default)] +pub struct ObjectTemplate { + pub input: HashMap, + pub local: HashMap, + pub remote: HashMap, +} + +// part of ObjectTemplate +#[derive(Deserialize, Debug, Default)] +#[serde(default)] +pub struct TemplateProperty { + pub transforms: Vec, + pub subobjects: Vec, + pub conditions: Vec<[String; 2]>, + pub duplicates: bool +} +