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

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"),
}
}
}