large rewrite to make mize run on every platform

This commit is contained in:
Sebastian Moser
2024-05-18 08:31:38 +02:00
parent 75a6dca3fc
commit a16c2f9221
37 changed files with 624 additions and 970 deletions

597
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -3,30 +3,45 @@ name = "mize"
version = "0.1.1" version = "0.1.1"
edition = "2021" edition = "2021"
[lib]
name = "mize"
path = "src/lib.rs"
[[bin]]
name = "mize"
path = "src/platform/os/main.rs"
required-features = [ "os-binary" ]
[features]
os-binary = [ "clap", "home", "env_logger", "daemonize", "nix" ]
[dependencies] [dependencies]
clap = { version = "4.4.11", features = ["cargo"] } # core dependencies
home = "0.5.9"
serde = { version = "1.0.152", features = ["derive"] }
serde_json = "1.0.91"
axum = { version = "0.6.1", features = ["ws", "headers"] }
axum-extra = { version = "0.4.2", features = ["spa"] }
axum-macros = "0.3.0"
colored = "2.0.0" colored = "2.0.0"
derive_more = "0.99.17" uuid = "1.3.0"
futures-util = "0.3.24" log = "0.4.20"
tokio = { version = "1.21.0", features = ["sync"] }
cbor = "0.4.1"
clap = { version = "4.4.11", features = ["cargo"], optional = true }
home = { version = "0.5.9", optional = true }
env_logger = { version = "0.10.1", optional = true }
daemonize = { version = "0.5.0", optional = true }
nix = { version = "0.27.1", features = ["signal"], optional = true }
axum = { version = "0.6.1", features = ["ws", "headers"], optional = true }
axum-extra = { version = "0.4.2", features = ["spa"], optional = true }
axum-macros = { version = "0.3.0", optional = true }
#tokio-stream = { version = "0.1.9", optional = true }
#derive_more = "0.99.17"
#futures-util = "0.3.24"
#itertools = "0.10.5" #itertools = "0.10.5"
#lazy_static = "1.4.0" #lazy_static = "1.4.0"
#rmp-serde = "1.1.1" #rmp-serde = "1.1.1"
#rmpv = { version = "1.0.0", features = ["serde", "with-serde"] } #rmpv = { version = "1.0.0", features = ["serde", "with-serde"] }
tokio = { version = "1.21.0", features = ["full", "net"] } #toml = "0.5.10"
tokio-stream = "0.1.9"
toml = "0.5.10"
#tower-http = "0.3.5" #tower-http = "0.3.5"
uuid = "1.3.0"
log = "0.4.20"
env_logger = "0.10.1"
daemonize = "0.5.0"
nix = { version = "0.27.1", features = ["signal"] }
serde_cbor = "0.11.2"

60
flake.lock generated
View File

@@ -1,5 +1,46 @@
{ {
"nodes": { "nodes": {
"crane": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1715274763,
"narHash": "sha256-3Iv1PGHJn9sV3HO4FlOVaaztOxa9uGLfOmUWrH7v7+A=",
"owner": "ipetkov",
"repo": "crane",
"rev": "27025ab71bdca30e7ed0a16c88fd74c5970fc7f5",
"type": "github"
},
"original": {
"owner": "ipetkov",
"repo": "crane",
"type": "github"
}
},
"fenix": {
"inputs": {
"nixpkgs": [
"nixpkgs"
],
"rust-analyzer-src": "rust-analyzer-src"
},
"locked": {
"lastModified": 1715063087,
"narHash": "sha256-cktPkcCmJ2sR0V/FaWEuCWmKuGPbwoMltih/EfF0mXg=",
"owner": "nix-community",
"repo": "fenix",
"rev": "f8f16c1f2c83bea4e51e6522d988ec8bfcc8420e",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "fenix",
"type": "github"
}
},
"flake-utils": { "flake-utils": {
"inputs": { "inputs": {
"systems": "systems" "systems": "systems"
@@ -36,10 +77,29 @@
}, },
"root": { "root": {
"inputs": { "inputs": {
"crane": "crane",
"fenix": "fenix",
"flake-utils": "flake-utils", "flake-utils": "flake-utils",
"nixpkgs": "nixpkgs" "nixpkgs": "nixpkgs"
} }
}, },
"rust-analyzer-src": {
"flake": false,
"locked": {
"lastModified": 1714936835,
"narHash": "sha256-M+PpgfRMBfHo8Jb2ou/s3maAZbps0XnuHXQU9Hv9vL0=",
"owner": "rust-lang",
"repo": "rust-analyzer",
"rev": "c4618fe14d39992fbbb85c2d6cad028a232c13d2",
"type": "github"
},
"original": {
"owner": "rust-lang",
"ref": "nightly",
"repo": "rust-analyzer",
"type": "github"
}
},
"systems": { "systems": {
"locked": { "locked": {
"lastModified": 1681028828, "lastModified": 1681028828,

View File

@@ -3,15 +3,61 @@
# nixpkgs 35.11 still contains rust 1.73 # nixpkgs 35.11 still contains rust 1.73
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
fenix = {
url = "github:nix-community/fenix";
inputs.nixpkgs.follows = "nixpkgs";
};
crane = {
url = "github:ipetkov/crane";
inputs.nixpkgs.follows = "nixpkgs";
};
flake-utils.url = "github:numtide/flake-utils"; flake-utils.url = "github:numtide/flake-utils";
}; };
outputs = { flake-utils, nixpkgs, ... }@inputs: flake-utils.lib.eachDefaultSystem (system: let pkgs = nixpkgs.legacyPackages.${system}; in { outputs = { self, flake-utils, nixpkgs, fenix, crane, ... }@inputs: flake-utils.lib.eachDefaultSystem (system:
############################## LET BINDINGS ##############################
#packages.default = let
devShells.default = pkgs.mkShell { pkgs = nixpkgs.legacyPackages.${system};
buildInputs = with pkgs; [ cargo rustc ]; wasmToolchain = fenix.packages.${system}.combine [
fenix.packages.${system}.targets.wasm32-unknown-unknown.stable.toolchain
fenix.packages.${system}.complete.toolchain
];
osToolchain = fenix.packages.${system}.complete.toolchain;
wasmCrane = crane.lib.${system}.overrideToolchain wasmToolchain;
osCrane = crane.lib.${system}.overrideToolchain osToolchain;
in {
############################## PACKAGES ##############################
packages.default = osCrane.buildPackage {
src = "${self}";
}; };
packages = {
wasm = wasmCrane.buildPackage {
src = "${self}";
};
};
############################## DEV SHELLS ##############################
devShells.default = pkgs.mkShell {
buildInputs = with pkgs; [
wasm-pack #pkg-config openssl #cargo rustc
cargo-generate
/*
(fenix.packages.${system}.complete.withComponents [
"cargo"
"clippy"
"rust-src"
"rustc"
"rustfmt"
])
*/
(fenix.packages.${system}.combine [ wasmToolchain osToolchain ])
];
};
}); });
} }

3
run
View File

@@ -1,3 +0,0 @@
#!/bin/bash
cargo run -- --folder=./mize-folder run

View File

@@ -1,4 +0,0 @@
use clap::ArgMatches;
pub async fn call(sub_matches: &ArgMatches) {
}

View File

@@ -1,4 +0,0 @@
use clap::ArgMatches;
pub async fn mount(sub_matches: &ArgMatches) {
}

View File

@@ -1,4 +0,0 @@
use clap::ArgMatches;
pub async fn serve(sub_matches: &ArgMatches) {
}

View File

@@ -1,4 +0,0 @@
use clap::ArgMatches;
pub async fn set(sub_matches: &ArgMatches) {
}

View File

@@ -1,4 +0,0 @@
use clap::ArgMatches;
pub async fn print(sub_matches: &ArgMatches) {
}

View File

@@ -1,18 +1,12 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt::Debug; use std::fmt::Debug;
use std::fmt::Display; use std::fmt::Display;
use std::fmt::format; use std::fmt::format;
use std::string::FromUtf8Error; use std::string::FromUtf8Error;
use toml::Value;
use colored::Colorize;
use std::io; use std::io;
use colored::Colorize;
use log::{trace, debug, info, warn, error}; use log::{trace, debug, info, warn, error};
use serde_json::Value as JsonValue;
use toml;
use crate::instance::Connection;
use crate::proto::MizeMessage; use crate::proto::MizeMessage;
pub type MizeResult<T> = Result<T, MizeError>; pub type MizeResult<T> = Result<T, MizeError>;

13
src/core/id.rs Normal file
View File

@@ -0,0 +1,13 @@
use std::hash::Hash;
#[derive(Hash, Eq, PartialEq)]
pub struct MizeId {
path: Vec<String>
}
impl From<String> for MizeId {
fn from(value: String) -> Self {
MizeId{path: vec![value]}
}
}

View File

@@ -0,0 +1,16 @@
use log::{trace, debug, info, warn, error};
use tokio::sync::mpsc::{Sender, Receiver};
use crate::proto::MizeMessage;
use crate::error::{MizeError, MizeResult, IntoMizeResult};
pub trait Connection {
}
//#[derive(Debug)]
//pub struct Connection {
//tx: Sender<MizeMessage>,
//rx: Receiver<MizeMessage>,
//}

71
src/core/instance/mod.rs Normal file
View File

@@ -0,0 +1,71 @@
use std::collections::HashMap;
use std::fs::create_dir;
use log::{trace, debug, info, warn, error};
use uuid::Uuid;
use std::fs::File;
use colored::Colorize;
use std::path::Path;
use crate::error::{MizeError, MizeResult, IntoMizeResult, MizeResultTrait};
use crate::instance::store::Store;
use crate::instance::connection::Connection;
use crate::id::MizeId;
use crate::instance::subscription::Subscription;
use crate::item::{Item, ItemData};
use crate::memstore::MemStore;
pub mod connection;
pub mod store;
pub mod subscription;
static MSG_CHANNEL_SIZE: usize = 200;
/// The Instance type is the heart of the mize system
pub struct Instance<S: Store> {
// question vec of stores???
// would mean replication logic and such things is handeled by the instance
// i think it would be better thogh to then implement a ReplicatedStore
store: S,
peers: Vec<Box<dyn Connection>>,
subs: HashMap<MizeId, Subscription>
}
/*
pub enum RealmId {
Uuid(Uuid),
Local(Vec<String>),
Tld(Vec<String>),
}
*/
impl<S: Store> Instance<S> {
// new() opens a
pub async fn new() -> MizeResult<Instance<MemStore>> {
trace!("[ {} ] Instance::new()", "CALL".yellow());
let memstore = MemStore::new();
let instance = Instance {store: memstore, peers: Vec::new(), subs: HashMap::new()};
// platform specific init code
// TODO
return Ok(instance);
}
pub fn new_item(self) -> MizeResult<Item<S>> {
let id = self.store.new_id()?;
return Ok(Item {id, instance: self});
}
pub fn get<I: Into<MizeId>>(self, id: I) -> MizeResult<Item<S>> {
return Ok(Item {id: id.into(), instance: self});
}
pub fn set<I: Into<MizeId>, V: Into<ItemData>>(self, id: I, value: V) -> MizeResult<()> {
self.store.set(id.into(), value)
}
}

View File

@@ -0,0 +1,27 @@
use crate::error::MizeResult;
use crate::item::{Item, ItemData};
use crate::id::MizeId;
pub trait Store {
// should have the ability to be multi threaded, if the underlying implementation supports
// multithreaded IO operations
// for now all refs to a store hold a Mutex but this mutex is part of where the MizeStore trait
// is implemented, so that there can be a multithreaded implementation
//fn get(self, id: MizeId) -> MizeResult<Item<Self>> where Self: Sized;
fn set<T: Into<ItemData>>(self, id: MizeId, data: T) -> MizeResult<()>;
// in the future should implement transactions, ....
// funcs to do with links, backlinks
fn get_links(self, item: Item<Self>) -> MizeResult<Vec<MizeId>> where Self: Sized;
fn get_backlinks(self, item: Item<Self>) -> MizeResult<Vec<MizeId>> where Self: Sized;
fn new_id(&self) -> MizeResult<MizeId>;
}
/// references an item that is stored in a store
pub trait StoreRef {
// do we need this or is this basically an item
}

View File

@@ -0,0 +1,3 @@
pub struct Subscription;

View File

@@ -1,14 +1,39 @@
use log::{trace, debug, info, warn, error}; use log::{trace, debug, info, warn, error};
use std::{collections::HashMap, path::PathBuf, io::Cursor, fmt::Display}; use std::{collections::HashMap, path::PathBuf, io::Cursor, fmt::Display};
use serde_cbor::Value as CborValue;
use std::fs::File; use std::fs::File;
use tokio::sync::Mutex; use tokio::sync::Mutex;
use std::rc::Rc; use std::rc::Rc;
use crate::error::{MizeError, MizeResult, IntoMizeResult}; use crate::error::{MizeError, MizeResult, IntoMizeResult};
use crate::itemstore::Itemstore; use crate::instance::Instance;
use crate::instance::store::Store;
use crate::id::MizeId;
use cbor::Cbor as CborValue;
// a item always has to do with a Instance, which takes care of how it is updated
pub struct Item<S: Store + Sized> {
pub id: MizeId,
pub instance: Instance<S>
}
// without an Instance it is not an item, but only the "data of an item"
// and this type for now is just an alias to CborValue
pub type ItemData = CborValue;
impl<S: Store> Item<S> {
pub fn id(self) -> MizeId {
self.id
}
pub fn value_raw(self) -> MizeResult<Vec<u8>> {
// this will call from the instance which gets the value from the store
Ok(Vec::new())
}
}
/*
#[derive(Debug)] #[derive(Debug)]
pub enum Item { pub enum Item {
Cbor(ItemCbor), Cbor(ItemCbor),
@@ -233,4 +258,5 @@ impl Item {
todo!() todo!()
} }
} }
*/

3
src/core/lib.rs Normal file
View File

@@ -0,0 +1,3 @@
#![ allow( warnings ) ]

35
src/core/memstore.rs Normal file
View File

@@ -0,0 +1,35 @@
use std::collections::HashMap;
use cbor::Cbor as CborValue;
use crate::id::MizeId;
use crate::instance::store::Store;
use crate::error::MizeResult;
use crate::item::{Item, ItemData};
pub struct MemStore {
map: HashMap<MizeId, CborValue>,
next_id: u64,
}
impl Store for MemStore {
fn set<T: Into<ItemData>>(mut self, id: MizeId, data: T) -> MizeResult<()> {
self.map.insert(id, data.into());
return Ok(())
}
fn get_links(self, item: Item<Self>) -> MizeResult<Vec<MizeId>> {
Ok(Vec::new())
}
fn get_backlinks(self, item: Item<Self>) -> MizeResult<Vec<MizeId>> {
Ok(Vec::new())
}
fn new_id(&self) -> MizeResult<MizeId> {
let id_string = format!("{}", self.next_id);
return Ok(id_string.into());
}
}
impl MemStore {
pub fn new() -> MemStore {
return MemStore { map: HashMap::new(), next_id: 0 };
}
}

View File

@@ -1,5 +1,4 @@
use serde_cbor::Value as CborValue; use cbor::Cbor as CborValue;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct MizeMessage { pub struct MizeMessage {

0
src/core/types/mod.rs Normal file
View File

View File

@@ -1,192 +0,0 @@
use std::collections::HashMap;
use std::path::PathBuf;
use std::fs::create_dir;
use colored::Colorize;
use log::{trace, debug, info, warn, error};
use serde_json::json;
use tokio::net::{UnixListener, UnixStream};
use uuid::Uuid;
use std::fs::File;
use std::path::Path;
use daemonize::Daemonize;
use nix::unistd::Pid;
use crate::error::{MizeError, MizeResult, IntoMizeResult, MizeResultTrait};
use crate::itemstore::{Itemstore, self};
use crate::item::{Item, MizeId, ItemRef};
pub mod peer;
pub mod connection;
pub use connection::Connection;
static UNIX_SOCKET_CHANNEL_SIZE: usize = 200;
static WEB_SOCKET_CHANNEL_SIZE: usize = 200;
static TCP_SOCKET_CHANNEL_SIZE: usize = 200;
static UPDATE_CHANNEL_SIZE: usize = 200;
/// The Instance type is the heart of the mize system
pub struct Instance {
store: Itemstore,
peers: Vec<Connection>,
realm_instance: Option<(RealmId, Vec<Connection>)>,
}
pub enum RealmId {
Uuid(Uuid),
Local(Vec<String>),
Tld(Vec<String>),
}
impl Instance {
pub async fn new(instance_path: PathBuf) -> MizeResult<Instance> {
trace!("[ {} ] Instance::new()", "CALL".yellow());
trace!("[ {} ] instance_path: {:?}", "ARG".yellow(), instance_path);
// if path does not exist, create it
if instance_path.exists() == false {
debug!("instance path \"{}\" does not exist, so creating it", instance_path.clone().display());
File::create(&instance_path)
.mize_result_msg(format!("Could not create Instance at: {}", &instance_path.display())).critical();
}
// if a daemon is running, return instance with memory store
// with realm_instance at that daemon
let mut instance = match find_running_ademon(instance_path.clone()).await {
Ok(con) => {
Instance {
store: Itemstore::Memory(itemstore::new_memory_store()?),
peers: vec![con],
realm_instance: None,
}
},
// else open the itemstore
Err(err) => {
Instance {
store: Itemstore::Folder(itemstore::new_folder_store(instance_path)?),
peers: vec![],
realm_instance: None,
}
},
};
if !instance.store.has_item(MizeId::main(1)).await? {
instance.store.create_item_from_json(json!({
"item": {
"kind": "instance",
},
"daemon": {
"log": "",
"pid": "",
"item": {
"kind": "instance/daemon",
},
},
}));
};
return Ok(instance);
}
pub async fn start_deamon(mut self) -> MizeResult<()> {
trace!("[ {} ] Instance::start_deamon()", "CALL".yellow());
// daemonize
let stdout = self.get_item(MizeId::main(1).join("daemon").join("log")).await?.value_as_file()?;
let pid_file = self.get_item(MizeId::main(1).join("daemon").join("pid")).await?.value_as_path()?;
let daemonize = Daemonize::new()
.pid_file(pid_file)
//.chown_pid_file(true) // is optional, see `Daemonize` documentation
//.working_directory("/tmp") // for default behaviour.
//.user("nobody")
//.group("daemon") // Group name
//.group(2) // or group id.
//.umask(0o777) // Set umask, `0o027` by default.
.stdout(stdout); // Redirect stdout to `/tmp/daemon.out`.
//.privileged_action(|| "Executed before drop privileges");
daemonize.start().mize_result_msg("Error daemonizing")?;
info!("Succesfuly Daemonized");
// listen on unix socket
let sock_path = self.get_item(MizeId::main(1).join("daemon").join("sock")).await?.value_as_path()?;
let listener = UnixListener::bind(&sock_path)
.mize_result_msg(format!("Could not bind to unix Socket at: {}", sock_path.display())).critical();
loop {
match listener.accept().await {
Ok((unix_sock, _addr)) => {
self.peers.push(Connection::from_unix(unix_sock))
},
Err(e) => { MizeError::new().msg("New Peer failed").msg(format!("{}", e)).log(); },
};
}
}
pub async fn get_daemon_pid(self) -> MizeResult<Pid> {
trace!("[ {} ] Instance::get_daemon_pid()", "CALL".yellow());
todo!()
}
pub async fn daemon_is_running(&self) -> MizeResult<bool> {
trace!("[ {} ] Instance::daemon_is_running()", "CALL".yellow());
let sock_path = self.get_item(MizeId::main(1).join("daemon").join("sock")).await?.value_as_path()?;
match find_running_ademon(sock_path).await {
Ok(_) => Ok(true),
Err(_) => Ok(false),
}
}
// item funcs
pub async fn get_item(&self, id: MizeId) -> MizeResult<Item> {
self.store.get_item(id).await
}
pub async fn set_item(&mut self, item: Item) -> MizeResult<()> {
self.store.set_item(item).await
}
pub async fn create_item(&mut self) -> MizeResult<MizeId> {
self.store.create_item().await
}
//pub fn update_item(self) -> MizeResult<Item> {
//todo!()
//}
//pub fn on_item_update(self) -> MizeResult<Item> {
//todo!()
//}
}
async fn find_running_ademon(path: PathBuf) -> MizeResult<Connection> {
match UnixStream::connect(path).await {
Ok(val) => Ok(Connection::from_unix(val)),
Err(err) => Err(MizeError::new().msg("No Daemon found to connect")),
}
}
fn handle_connection() {
todo!()
}
/*
fn get_instance_type() -> MizeResult<Item> {
let mut types_item = Item::new("types");
// instance
let instance_str = include_str!("../../types/mize/instance/item.json");
let instance = Item::new("type").load_json(instance_str)?;
types_item.set("instance", instance);
return Ok(types_item);
}
*/

View File

@@ -1 +0,0 @@

View File

@@ -1,268 +0,0 @@
use log::{trace, debug, info, warn, error};
use std::fs::{self, File};
use std::path::{PathBuf, Path};
use std::collections::HashMap;
use std::io::{Read, Write};
use colored::Colorize;
use std::rc::Rc;
use crate::item::{Item, MizeId, ItemCbor, ItemRef};
use crate::error::{MizeError, MizeResult, IntoMizeResult};
pub enum Itemstore {
Folder(FolderItemstore),
Memory(MemoryItemstore),
}
pub struct FolderItemstore {
path: PathBuf,
next_id: u64,
}
pub struct MemoryItemstore {
inner: HashMap<MizeId, Item>,
next_id: u64,
}
///////////////////////////////////////////////////////////////////////////////////////////
pub fn new_memory_store() -> MizeResult<MemoryItemstore> {
Ok(MemoryItemstore {
inner: HashMap::new(),
next_id: 100,
})
}
pub fn new_folder_store(path: PathBuf) -> MizeResult<FolderItemstore> {
if path.join("store_open").exists() {
let pid_str = fs::read_to_string(path.join("store_open"))
.mize_result_msg("Could not read the store_open file to check which process has the store opened")?;
let pid = pid_str.parse::<u32>()
.mize_result_msg("Could not Parse the content of the store_open file into a u32")?;
if Path::new("/proc").join(format!("{}", pid)).exists() {
return Err(MizeError::new().msg(
format!("the store at {} is already open by process with pid: {}", path.display(), pid)
));
} else {
warn!("An Instance was not closed properly. (store_open file contained a not running PID)");
std::fs::remove_file(path.join("store_open"))
.mize_result_msg("Could not remove the store_open file")?;
}
}
let mut store_open_file = File::create(path.join("store_open"))
.mize_result_msg("Could not create the store_open file")?;
store_open_file.write_all(format!("{}", std::process::id()).as_bytes())
.mize_result_msg("Could not write my pid to the store_open file")?;
// if no store_next_id exists write it with the default 100
let mut next_id: u64 = 100; // as a default
if !path.join("store_next_id").exists() {
fs::write(path.join("store_next_id"), format!("{}", next_id).as_bytes())
.mize_result_msg("Could not write the default next_id to store_next_id")?;
} else {
let next_id_string = fs::read_to_string(path.join("store_next_id"))
.mize_result_msg("Could not read store_next_id of this store")?;
next_id = next_id_string.parse()
.mize_result_msg("Could not parse contents of store_next_id into u64")?;
}
return Ok(FolderItemstore{ path, next_id});
}
///////////////////////////////////////////////////////////////////////////////////////////
impl FolderItemstore {
pub async fn write_next_id(&self) -> MizeResult<()> {
fs::write(self.path.join("store_next_id"), format!("{}", self.next_id).as_bytes())
.mize_result_msg(format!("Could not write the next_id: \"{}\" to \"{}\"", self.next_id, self.path.join("store_next_id").display()))?;
return Ok(());
}
}
///////////////////////////////////////////////////////////////////////////////////////////
impl MemoryItemstore {
// item funcs
async fn get_item(&self, id: MizeId) -> MizeResult<Item> {
match self.inner.get(&id) {
None => {
Err(MizeError::new().msg(format!("there was no item with id ({}) in this store", id)))
},
Some(item) => {
Ok(Item::Cbor(item.as_cbor()?))
},
}
}
async fn set_item(&mut self, item: Item) -> MizeResult<()> {
self.inner.insert(item.id()?, item)
.ok_or(MizeError::new().msg("Could not set an item in a MemoryStore"))?;
return Ok(());
}
async fn create_item(&mut self) -> MizeResult<MizeId> {
// advance the next_id
self.next_id += 1;
return Ok(MizeId::main(self.next_id))
}
//fn update_item(self) -> MizeResult<I>;
// other funcs
async fn close(&self) -> MizeResult<()> {
return Ok(());
}
async fn next_id(&self) -> u64 {
self.next_id
}
async fn has_item(&self, id: MizeId) -> MizeResult<bool> {
Ok(self.inner.contains_key(&id))
}
}
impl FolderItemstore {
// item funcs
async fn get_item(&self, id: MizeId) -> MizeResult<Item> {
let id_string = format!("{}", id.main);
let mut final_path = self.path.join("store");
if id_string.len() < 2 {
// use path 00 for ids under 10
final_path.push("00")
} else {
// will not panic, because of prior check if string is more than two long
final_path.push(id_string[..2].to_owned());
};
return Ok(Item::Descriptor(ItemRef { path: final_path, id}));
}
async fn set_item(&self, item: Item) -> MizeResult<()> {
item.write_to_path(self.get_path_of_item(&item.id()?)?)
}
async fn create_item(&mut self) -> MizeResult<MizeId> {
// advance the next_id
self.next_id += 1;
match self.write_next_id().await {
// on error revert to old next_id
Ok(_) => {},
Err(err) => {
self.next_id -= 1;
return Err(err);
},
}
return Ok(MizeId::main(self.next_id));
}
//fn update_item(self) -> MizeResult<Item>;
// other funcs
async fn close(&self) -> MizeResult<()> {
if self.path.join("store_open").exists() {
std::fs::remove_file(self.path.join("store_open"))
.mize_result_msg("Could not remove the store_open file")?;
}
return Ok(());
}
async fn next_id(&self) -> u64 {
self.next_id
}
async fn has_item(&self, id: MizeId) -> MizeResult<bool> {
Ok(self.get_path_of_item(&id)?.exists())
}
fn get_path_of_item(&self, id: &MizeId) -> MizeResult<PathBuf> {
// get path of item
let id_string = format!("{}", id.main);
let mut final_path = self.path.join("store");
if id_string.len() < 2 {
// use path 00 for ids under 10
final_path.push("00")
} else {
// will not panic, because of prior check if string is more than two long
final_path.push(id_string[..2].to_owned());
};
return Ok(final_path);
}
}
impl Itemstore {
// item funcs
pub async fn get_item(&self, id: MizeId) -> MizeResult<Item> {
trace!("[ {} ] Itemstore::get_item()", "CALL".yellow());
trace!("[ {} ] id: {}", "ARG".yellow(), id);
match self {
Itemstore::Folder(val) => val.get_item(id).await,
Itemstore::Memory(val) => val.get_item(id).await,
}
}
pub async fn set_item(&mut self, item: Item) -> MizeResult<()> {
trace!("[ {} ] Itemstore::set_item()", "CALL".yellow());
trace!("[ {} ] item: {:?}", "ARG".yellow(), item);
match self {
Itemstore::Folder(val) => val.set_item(item).await,
Itemstore::Memory(val) => val.set_item(item).await,
}
}
pub async fn create_item(&mut self) -> MizeResult<MizeId> {
trace!("[ {} ] Itemstore::create_item()", "CALL".yellow());
match self {
Itemstore::Folder(val) => val.create_item().await,
Itemstore::Memory(val) => val.create_item().await,
}
}
//pub fn update_item(self) -> MizeResult<I>;
// other funcs
pub async fn close(&self) -> MizeResult<()> {
trace!("[ {} ] Itemstore::close()", "CALL".yellow());
match self {
Itemstore::Folder(val) => val.close().await,
Itemstore::Memory(val) => val.close().await,
}
}
pub async fn next_id(&self) -> u64 {
trace!("[ {} ] Itemstore::next_id()", "CALL".yellow());
match self {
Itemstore::Folder(val) => val.next_id().await,
Itemstore::Memory(val) => val.next_id().await,
}
}
pub async fn has_item(&self, id: MizeId) -> MizeResult<bool> {
trace!("[ {} ] Itemstore::has_item()", "CAL".yellow());
trace!("[ {} ] id: {}", "ARG".yellow(), id);
let ret = match self {
Itemstore::Folder(val) => val.has_item(id).await,
Itemstore::Memory(val) => val.has_item(id).await,
};
if let Ok(val) = ret {trace!("[ {} ] Itemstore::has_item(): {}", "RET".yellow(), val)};
return ret;
}
}

View File

@@ -3,14 +3,18 @@
static PROTO_VERSION: u8 = 1; static PROTO_VERSION: u8 = 1;
pub mod core {
pub mod memstore;
pub mod instance;
pub mod item;
pub mod id;
pub mod proto;
pub mod error;
pub mod types;
}
pub use core::*;
// pub mod types;
pub mod error;
mod instance;
mod proto;
mod item;
mod itemstore;

View File

@@ -0,0 +1,4 @@
use clap::ArgMatches;
pub fn call(sub_matches: &ArgMatches) {
}

View File

@@ -6,11 +6,13 @@ use std::fs::File;
use log::{trace, debug, info, warn, error}; use log::{trace, debug, info, warn, error};
use nix::sys::signal::{self, Signal}; use nix::sys::signal::{self, Signal};
use crate::error::{MizeResultTrait, IntoMizeResult, MizeError}; use mize::error::{MizeResultTrait, IntoMizeResult, MizeError};
use crate::instance::Instance; use mize::instance::Instance;
pub async fn daemon(sub_matches: &ArgMatches) { pub fn daemon(sub_matches: &ArgMatches) {
println!("not implemented");
/*
let instance_path = match sub_matches.get_one::<String>("store") { let instance_path = match sub_matches.get_one::<String>("store") {
Some(a) => PathBuf::from(a), Some(a) => PathBuf::from(a),
None => { None => {
@@ -60,4 +62,5 @@ pub async fn daemon(sub_matches: &ArgMatches) {
}; };
}, },
} }
*/
} }

View File

@@ -3,12 +3,12 @@ use std::path::PathBuf;
use clap::ArgMatches; use clap::ArgMatches;
use home::home_dir; use home::home_dir;
use crate::error::{MizeResultTrait, IntoMizeResult, MizeError}; use mize::error::{MizeResultTrait, IntoMizeResult, MizeError};
use crate::instance::Instance; use mize::instance::Instance;
pub async fn get(sub_matches: &ArgMatches) { pub fn get(sub_matches: &ArgMatches) {
let instance_folder_path = match sub_matches.get_one::<String>("store") { let instance_folder_path = match sub_matches.get_one::<String>("store") {
Some(a) => PathBuf::from(a), Some(a) => PathBuf::from(a),
None => { None => {
@@ -18,6 +18,7 @@ pub async fn get(sub_matches: &ArgMatches) {
home_dir home_dir
}, },
}; };
let instance = Instance::new(instance_folder_path); println!("unfinished");
//let instance = Instance::new(instance_folder_path);
} }

View File

@@ -0,0 +1,4 @@
use clap::ArgMatches;
pub fn mount(sub_matches: &ArgMatches) {
}

View File

@@ -0,0 +1,4 @@
use clap::ArgMatches;
pub fn serve(sub_matches: &ArgMatches) {
}

View File

@@ -0,0 +1,4 @@
use clap::ArgMatches;
pub fn set(sub_matches: &ArgMatches) {
}

View File

@@ -0,0 +1,4 @@
use clap::ArgMatches;
pub fn show(sub_matches: &ArgMatches) {
}

View File

View File

@@ -21,34 +21,23 @@ mod cli {
pub mod serve; pub mod serve;
pub mod get; pub mod get;
pub mod set; pub mod set;
pub mod show;
pub mod mount; pub mod mount;
pub mod print;
pub mod call; pub mod call;
pub use daemon::daemon; pub use daemon::daemon;
pub use serve::serve; pub use serve::serve;
pub use get::get; pub use get::get;
pub use set::set; pub use set::set;
pub use show::show;
pub use mount::mount; pub use mount::mount;
pub use print::print;
pub use call::call; pub use call::call;
} }
mod error;
// mod types;
mod instance;
mod item;
mod itemstore;
mod proto;
#[cfg(test)]
mod test;
static APPNAME: &str = "mize"; static APPNAME: &str = "mize";
static DEFAULT_LOG_LEVEL: LevelFilter = LevelFilter::Warn; static DEFAULT_LOG_LEVEL: LevelFilter = LevelFilter::Warn;
#[tokio::main] fn main() {
async fn main() {
// welcome to the mize source code // welcome to the mize source code
// this is the main entry point for platforms with an os (eg: Linux, MacOS, Windows, BSD, ...) // this is the main entry point for platforms with an os (eg: Linux, MacOS, Windows, BSD, ...)
// Also let's try to make the most best documented code ever. (eventually) so it's fun to work on // Also let's try to make the most best documented code ever. (eventually) so it's fun to work on
@@ -64,25 +53,25 @@ async fn main() {
// match command // match command
match cli_matches.subcommand() { match cli_matches.subcommand() {
// mi daemon // mi daemon
Some(("daemon", sub_matches)) => cli::daemon(sub_matches).await, Some(("daemon", sub_matches)) => cli::daemon(sub_matches),
// mi serve // mi serve
Some(("serve", sub_matches)) => cli::serve(sub_matches).await, Some(("serve", sub_matches)) => cli::serve(sub_matches),
// mi mount // mi mount
Some(("mount", sub_matches)) => cli::mount(sub_matches).await, Some(("mount", sub_matches)) => cli::mount(sub_matches),
// mi get // mi get
Some(("get", sub_matches)) => cli::get(sub_matches).await, Some(("get", sub_matches)) => cli::get(sub_matches),
// mi set // mi set
Some(("set", sub_matches)) => cli::set(sub_matches).await, Some(("set", sub_matches)) => cli::set(sub_matches),
// mi sub // mi show
Some(("sub", sub_matches)) => cli::sub(sub_matches).await, Some(("show", sub_matches)) => cli::show(sub_matches),
// mi call // mi call
Some(("call", sub_matches)) => cli::call(sub_matches).await, Some(("call", sub_matches)) => cli::call(sub_matches),
// some unknown command passed // some unknown command passed
Some((cmd, sub_matches)) => error!("The subcommand: {} is not known. use --help to list availavle commands", cmd), Some((cmd, sub_matches)) => error!("The subcommand: {} is not known. use --help to list availavle commands", cmd),
@@ -330,8 +319,8 @@ fn cli_matches() -> clap::ArgMatches {
.arg(Arg::new("id").help("The id or path to set")) .arg(Arg::new("id").help("The id or path to set"))
) )
.subcommand( .subcommand(
Command::new("sub") Command::new("show")
.aliases(["su"]) .aliases(["so"])
.arg(&store_arg) .arg(&store_arg)
.arg(Arg::new("id").help("The id or path to sub to and show")) .arg(Arg::new("id").help("The id or path to sub to and show"))
) )

View File

@@ -1,16 +1,3 @@
use log::{trace, debug, info, warn, error};
use tokio::{sync::mpsc::{Sender, Receiver}, net::UnixStream};
use tokio::net::unix::{OwnedReadHalf, OwnedWriteHalf};
use tokio::io::{self, Interest};
use crate::proto::MizeMessage;
use crate::error::{MizeError, MizeResult, IntoMizeResult};
#[derive(Debug)]
pub struct Connection {
tx: Sender<MizeMessage>,
rx: Receiver<MizeMessage>,
}
impl Connection { impl Connection {
pub fn from_unix(unix_sock: UnixStream) -> Connection { pub fn from_unix(unix_sock: UnixStream) -> Connection {

31
src/test/mod.rs Normal file
View File

@@ -0,0 +1,31 @@
use crate::instance::MizeInstance;
#[test]
fn most_minimal_instance_usage() {
// so I'm actually starting the effort for a better code base here in the tests
// i want to write down how you would use the very important instance type
// and then implement it to make it usable in this way
// how every mize based program to run on an os should create a mize instance
// opens the instance the way the user has configured (with env vars, build args, or config
// files)
// and we just call it "new()" and not "default_system()" so that it is clear that this is the
// method that should be used
let mize = MizeInstance::new();
// then the most important things you do with your mize instance is to get/set stuff
let name: MizeItem = mize.get("1/namespace");
let id = mize.new_item();
mize.set(id.join("name"), "test-item");
// or register update callbacks and update
//mize.on_update("5/name", |delta| println!(delta.new_value()));
//mize.update("5/name", "other-item")
// the goal is that also most things about the MizeInstance itself is controlled by
// get/set/update -ing values at the 0/ paths
}