feat: update project

This commit is contained in:
2025-07-31 21:59:47 +02:00
parent ba0e1ad1dd
commit 01b1d79d75
7 changed files with 213 additions and 11 deletions

79
Cargo.lock generated
View File

@@ -215,6 +215,9 @@ name = "bitflags"
version = "2.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
dependencies = [
"serde",
]
[[package]]
name = "bollard"
@@ -369,6 +372,27 @@ version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
[[package]]
name = "dirs"
version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e"
dependencies = [
"dirs-sys",
]
[[package]]
name = "dirs-sys"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab"
dependencies = [
"libc",
"option-ext",
"redox_users",
"windows-sys 0.59.0",
]
[[package]]
name = "displaydoc"
version = "0.2.5"
@@ -912,6 +936,16 @@ version = "0.2.174"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
[[package]]
name = "libredox"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3"
dependencies = [
"bitflags",
"libc",
]
[[package]]
name = "litemap"
version = "0.8.0"
@@ -990,12 +1024,14 @@ dependencies = [
"bollard",
"bytes",
"clap",
"dirs",
"futures-util",
"norun-grpc-interface",
"notmad",
"pretty_assertions",
"prost",
"prost-types",
"ron",
"serde",
"tokio",
"tokio-util",
@@ -1003,6 +1039,7 @@ dependencies = [
"tonic",
"tracing",
"tracing-subscriber",
"uuid",
]
[[package]]
@@ -1079,6 +1116,12 @@ version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad"
[[package]]
name = "option-ext"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
[[package]]
name = "overload"
version = "0.1.1"
@@ -1304,6 +1347,17 @@ dependencies = [
"bitflags",
]
[[package]]
name = "redox_users"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac"
dependencies = [
"getrandom 0.2.16",
"libredox",
"thiserror",
]
[[package]]
name = "ref-cast"
version = "1.0.24"
@@ -1368,6 +1422,19 @@ version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "ron"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "beceb6f7bf81c73e73aeef6dd1356d9a1b2b4909e1f0fc3e59b034f9572d7b7f"
dependencies = [
"base64",
"bitflags",
"serde",
"serde_derive",
"unicode-ident",
]
[[package]]
name = "rustc-demangle"
version = "0.1.25"
@@ -1924,6 +1991,18 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "uuid"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d"
dependencies = [
"getrandom 0.3.3",
"js-sys",
"serde",
"wasm-bindgen",
]
[[package]]
name = "valuable"
version = "0.1.1"

View File

@@ -3,42 +3,41 @@
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct PublishRequest {
#[prost(message, optional, tag="1")]
#[prost(message, optional, tag = "1")]
pub project: ::core::option::Option<Project>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
pub struct PublishResponse {
}
pub struct PublishResponse {}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetTopicRequest {
#[prost(string, tag="1")]
#[prost(string, tag = "1")]
pub topic: ::prost::alloc::string::String,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetTopicResponse {
#[prost(message, optional, tag="1")]
#[prost(message, optional, tag = "1")]
pub projects: ::core::option::Option<Projects>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Projects {
#[prost(message, repeated, tag="1")]
#[prost(message, repeated, tag = "1")]
pub projects: ::prost::alloc::vec::Vec<Project>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Project {
#[prost(string, tag="1")]
#[prost(string, tag = "1")]
pub name: ::prost::alloc::string::String,
#[prost(string, tag="2")]
#[prost(string, tag = "2")]
pub image: ::prost::alloc::string::String,
#[prost(string, tag="3")]
#[prost(string, tag = "3")]
pub version: ::prost::alloc::string::String,
#[prost(uint32, optional, tag="4")]
#[prost(uint32, optional, tag = "4")]
pub port: ::core::option::Option<u32>,
}
include!("norun.v1.tonic.rs");
// @@protoc_insertion_point(module)
// @@protoc_insertion_point(module)

View File

@@ -23,6 +23,9 @@ async-trait = "0.1.88"
notmad = "0.7.2"
bollard = "0.19.1"
futures-util = "0.3.31"
dirs = "6.0.0"
uuid = { version = "1.17.0", features = ["serde", "v4"] }
ron = "0.10.1"
[dev-dependencies]
pretty_assertions = "1.4.1"

View File

@@ -7,6 +7,8 @@ mod state;
mod server;
mod services;
mod grpc_client;
mod grpc_server;

View File

@@ -1,5 +1,7 @@
pub mod project_tag;
pub use project_tag::*;
use serde::{Deserialize, Serialize};
use uuid::Uuid;
pub mod port {
#[derive(Clone, Debug, PartialEq)]
@@ -8,3 +10,15 @@ pub mod port {
pub container_port: usize,
}
}
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub struct Project {
pub id: Uuid,
pub spec: ProjectSpec,
}
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub enum ProjectSpec {
Compose {},
Container {},
}

View File

@@ -0,0 +1 @@
pub mod project_registry;

View File

@@ -0,0 +1,104 @@
use std::path::PathBuf;
use anyhow::Context;
use tokio::io::AsyncWriteExt;
use crate::{models::Project, state::ClientState};
pub struct ProjectRegistry {
state_dir: PathBuf,
}
impl ProjectRegistry {
pub async fn get_project(&self, project: &Project) -> anyhow::Result<Option<Project>> {
let project_dir = self.project_file(project)?;
if !project_dir.exists() {
return Ok(None);
}
let project_content = tokio::fs::read_to_string(&project_dir)
.await
.context("failed to read ron file")?;
let project: Project = ron::from_str(&project_content)
.context(format!("failed to read: '{}'", project_dir.display()))?;
Ok(Some(project))
}
pub async fn create_project(&self, project: &Project) -> anyhow::Result<()> {
match self.get_project(project).await {
Ok(_) => anyhow::bail!("project already exists"),
Err(_) => {
// continue
}
}
let project_file_path = self.project_file(project)?;
if let Some(project_file) = project_file_path.parent() {
tokio::fs::create_dir_all(project_file)
.await
.context("create ron project dir")?;
}
let mut project_file = tokio::fs::File::create_new(&project_file_path)
.await
.context("create project file")?;
let project_content = ron::to_string(project)?;
project_file
.write_all(&project_content.as_bytes())
.await
.context("write project file")?;
Ok(())
}
pub async fn update_project(&self, project: &Project) -> anyhow::Result<()> {
let project_file_path = self.project_file(project)?;
if let Some(project_file) = project_file_path.parent() {
tokio::fs::create_dir_all(project_file)
.await
.context("update ron project dir")?;
}
let mut project_file = tokio::fs::File::create_new(&project_file_path)
.await
.context("update project file")?;
let project_content = ron::to_string(project)?;
project_file
.write_all(project_content.as_bytes())
.await
.context("update project file")?;
Ok(())
}
fn project_file(&self, project: &Project) -> anyhow::Result<PathBuf> {
let project_dir = self
.state_dir
.join(project.id.to_string())
.join("project.ron");
Ok(project_dir)
}
}
pub trait ProjectRegistryState {
fn project_registry(&self) -> ProjectRegistry;
}
impl ProjectRegistryState for ClientState {
fn project_registry(&self) -> ProjectRegistry {
ProjectRegistry {
state_dir: dirs::state_dir()
.expect("to be able to find state")
.join("norun")
.join("projects"),
}
}
}