From 70c12fa76fe4f31f63d2e829ea21b4de602dd219 Mon Sep 17 00:00:00 2001 From: paulobressan Date: Thu, 7 Nov 2024 21:42:24 -0300 Subject: [PATCH] feat: implemented support to old demeter config --- Cargo.lock | 2 +- src/context.rs | 50 +++++++++++++++++++---------------------- src/init/manual.rs | 9 ++------ src/init/mod.rs | 14 ++++++------ src/main.rs | 12 +++++----- src/pages/deploy.rs | 2 +- src/ports/create.rs | 4 ++-- src/ports/delete.rs | 2 +- src/ports/list.rs | 4 ++-- src/ports/show.rs | 2 +- src/ports/tunnel.rs | 22 +++++++++++++----- src/rpc/auth/mod.rs | 8 ++++--- src/rpc/projects/mod.rs | 11 ++++++--- 13 files changed, 76 insertions(+), 66 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0e2c421..41d5cc0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -555,7 +555,7 @@ dependencies = [ [[package]] name = "dmtrctl" -version = "1.4.1" +version = "2.0.0" dependencies = [ "base64 0.22.1", "clap", diff --git a/src/context.rs b/src/context.rs index 596a6f7..e712852 100644 --- a/src/context.rs +++ b/src/context.rs @@ -13,38 +13,29 @@ pub struct Config { #[derive(Serialize, Deserialize, Clone, Debug)] pub struct Context { - pub project: Project, + pub namespace: Namespace, pub auth: Auth, } impl Context { - pub async fn ephemeral(id: &str, api_key: &str) -> miette::Result { - let project = rpc::projects::find_by_id( - rpc::auth::Credential::Secret((id.into(), api_key.into())), - id, - ) - .await?; - - let project = crate::context::Project::new(id, &project.namespace, Some(project.name)); + pub async fn ephemeral(namespace: &str, api_key: &str) -> miette::Result { + let namespace = crate::context::Namespace::new(namespace, None); let auth = crate::context::Auth::api_key(api_key); - Ok(Self { project, auth }) + Ok(Self { namespace, auth }) } } #[derive(Serialize, Deserialize, Clone, Debug)] -pub struct Project { - pub id: String, - pub name: Option, - pub namespace: String, +pub struct Namespace { + pub name: String, + pub caption: Option, } - -impl Project { - pub fn new(id: &str, namespace: &str, name: Option) -> Self { +impl Namespace { + pub fn new(name: &str, caption: Option) -> Self { Self { - id: id.to_owned(), - namespace: namespace.to_owned(), - name, + name: name.to_owned(), + caption, } } } @@ -160,12 +151,12 @@ pub fn load_default_context(dirs: &crate::dirs::Dirs) -> miette::Result, - project_id: Option<&str>, + namespace: Option<&str>, api_key: Option<&str>, dirs: &crate::dirs::Dirs, ) -> miette::Result> { - match (name, project_id, api_key) { - (None, Some(id), Some(ak)) => Ok(Some(Context::ephemeral(id, ak).await?)), + match (name, namespace, api_key) { + (None, Some(namespace), Some(ak)) => Ok(Some(Context::ephemeral(namespace, ak).await?)), (None, None, Some(_)) => Err(miette::miette!("missing project id value")), (None, Some(_), None) => Err(miette::miette!("missing api key value")), (Some(context), _, _) => load_context_by_name(context, dirs), @@ -173,10 +164,15 @@ pub async fn infer_context( } } -pub fn extract_context_data(cli: &crate::Cli) -> (String, String, String) { +pub async fn extract_context_data(cli: &crate::Cli) -> miette::Result<(String, String, String)> { let api_key = cli.context.as_ref().unwrap().auth.token.clone(); - let namespace = cli.context.as_ref().unwrap().project.namespace.clone(); - let id = cli.context.as_ref().unwrap().project.id.clone(); + let namespace = cli.context.as_ref().unwrap().namespace.name.clone(); + + let project = rpc::projects::find_by_namespace( + rpc::auth::Credential::Secret((namespace.clone(), api_key.clone())), + &namespace, + ) + .await?; - (api_key, id, namespace) + Ok((api_key, project.id, namespace)) } diff --git a/src/init/manual.rs b/src/init/manual.rs index 5fe68d3..b57b1e8 100644 --- a/src/init/manual.rs +++ b/src/init/manual.rs @@ -4,7 +4,7 @@ use crate::context::Context; pub async fn run(context: &Context, dirs: &crate::dirs::Dirs) -> miette::Result<()> { println!("Setting up context for:\n"); - println!(" Project: {}", context.project.namespace); + println!(" Project: {}", context.namespace.name); println!(" API key: {}\n", context.auth.token); let is_default = inquire::Confirm::new("use as default context?") @@ -14,12 +14,7 @@ pub async fn run(context: &Context, dirs: &crate::dirs::Dirs) -> miette::Result< .prompt() .into_diagnostic()?; - crate::context::overwrite_context( - &context.project.namespace, - context.clone(), - is_default, - dirs, - )?; + crate::context::overwrite_context(&context.namespace.name, context.clone(), is_default, dirs)?; Ok(()) } diff --git a/src/init/mod.rs b/src/init/mod.rs index 71585aa..54b6479 100644 --- a/src/init/mod.rs +++ b/src/init/mod.rs @@ -19,9 +19,9 @@ enum ContextOption<'a> { impl<'a> Display for ContextOption<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - ContextOption::Existing(x) => match &x.project.name { - Some(name) => write!(f, "{} ({})", x.project.namespace, name), - _ => write!(f, "{}", x.project.namespace), + ContextOption::Existing(x) => match &x.namespace.caption { + Some(name) => write!(f, "{} ({})", x.namespace.name, name), + _ => write!(f, "{}", x.namespace.name), }, ContextOption::ImportProject => f.write_str(""), } @@ -36,7 +36,7 @@ pub async fn import_context(dirs: &crate::dirs::Dirs) -> miette::Result let api_key = apikey::define_api_key(&access_token, &project.id).await?; let ctx = crate::context::Context { - project: crate::context::Project::new(&project.id, &project.namespace, Some(project.name)), + namespace: crate::context::Namespace::new(&project.namespace, Some(project.name)), auth: crate::context::Auth::api_key(&api_key), }; @@ -80,7 +80,7 @@ pub async fn run(_args: Args, cli: &crate::Cli) -> miette::Result<()> { let config = load_config(&cli.dirs)?; if let Some(context) = cli.context.as_ref() { - if !config.contexts.contains_key(&context.project.namespace) { + if !config.contexts.contains_key(&context.namespace.name) { manual::run(context, &cli.dirs).await?; return Ok(()); } @@ -88,11 +88,11 @@ pub async fn run(_args: Args, cli: &crate::Cli) -> miette::Result<()> { let ctx = define_context(&cli.dirs).await?; - crate::context::set_default_context(&ctx.project.namespace, &cli.dirs)?; + crate::context::set_default_context(&ctx.namespace.name, &cli.dirs)?; println!( "You CLI is now configured to use context {}", - ctx.project.namespace + ctx.namespace.name ); println!("Check out the ports sub-command to start operating"); diff --git a/src/main.rs b/src/main.rs index 2c58595..af11633 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,9 +20,9 @@ pub struct Args { #[command(subcommand)] command: Commands, - /// Project ID uuid - #[arg(short, long, global = true, env = "DMTR_PROJECT_ID")] - project_id: Option, + /// Name of the namespace we're working on + #[arg(short, long, global = true, env = "DMTR_NAMESPACE")] + namespace: Option, /// The api key to use as authentication #[arg(short, long, global = true, env = "DMTR_API_KEY")] @@ -47,10 +47,10 @@ pub struct Args { #[derive(Subcommand)] pub enum Commands { - /// initialize your Demeter project + /// Initialize your Demeter project Init(init::Args), - /// interact with Demeter Pages + /// Interact with Demeter Pages Pages(pages::Args), /// Ports-specific commands @@ -75,7 +75,7 @@ async fn main() -> miette::Result<()> { let context = context::infer_context( args.context.as_deref(), - args.project_id.as_deref(), + args.namespace.as_deref(), args.api_key.as_deref(), &dirs, ) diff --git a/src/pages/deploy.rs b/src/pages/deploy.rs index 00ba1e3..85bba39 100644 --- a/src/pages/deploy.rs +++ b/src/pages/deploy.rs @@ -45,7 +45,7 @@ pub async fn run(args: Args, cli: &crate::Cli) -> miette::Result<()> { let source = args.source.unwrap_or_else(|| Path::new("./dist").into()); let name = define_image_name( - &ctx.project.namespace, + &ctx.namespace.name, args.channel.as_deref(), args.commit_hash.as_deref(), )?; diff --git a/src/ports/create.rs b/src/ports/create.rs index fa30895..1564846 100644 --- a/src/ports/create.rs +++ b/src/ports/create.rs @@ -7,7 +7,7 @@ use crate::{context::extract_context_data, rpc}; pub struct Args {} pub async fn run(_args: Args, cli: &crate::Cli) -> miette::Result<()> { - let (api_key, id, _) = extract_context_data(cli); + let (api_key, project_id, _) = extract_context_data(cli).await?; let metadata = rpc::metadata::find().await?; @@ -54,7 +54,7 @@ pub async fn run(_args: Args, cli: &crate::Cli) -> miette::Result<()> { } let spec = resource_option_selected.spec.to_string(); - let result = rpc::resources::create(&api_key, &id, &kind_selected, &spec).await?; + let result = rpc::resources::create(&api_key, &project_id, &kind_selected, &spec).await?; println!("Port {}({}) created", result.kind, result.id); diff --git a/src/ports/delete.rs b/src/ports/delete.rs index 7d8ab45..dc79e75 100644 --- a/src/ports/delete.rs +++ b/src/ports/delete.rs @@ -27,7 +27,7 @@ pub async fn run(args: Args, cli: &crate::Cli) -> miette::Result<()> { return Ok(()); } - let (api_key, project_id, _) = extract_context_data(cli); + let (api_key, project_id, _) = extract_context_data(cli).await?; rpc::resources::delete(&api_key, &project_id, &args.id) .await diff --git a/src/ports/list.rs b/src/ports/list.rs index 183681d..20fac9a 100644 --- a/src/ports/list.rs +++ b/src/ports/list.rs @@ -16,8 +16,8 @@ pub async fn run(cli: &crate::Cli) -> miette::Result<()> { .as_ref() .ok_or(miette::miette!("can't list ports without a context"))?; - let (api_key, id, _) = extract_context_data(cli); - let response = rpc::resources::find(&api_key, &id).await?; + let (api_key, project_id, _) = extract_context_data(cli).await?; + let response = rpc::resources::find(&api_key, &project_id).await?; if response.is_empty() { println!("No ports found"); diff --git a/src/ports/show.rs b/src/ports/show.rs index 8513c97..35c2abe 100644 --- a/src/ports/show.rs +++ b/src/ports/show.rs @@ -16,7 +16,7 @@ pub async fn run(args: Args, cli: &crate::Cli) -> miette::Result<()> { .as_ref() .ok_or(miette::miette!("can't list ports without a context"))?; - let (api_key, project_id, _) = extract_context_data(cli); + let (api_key, project_id, _) = extract_context_data(cli).await?; let resouces = rpc::resources::find_by_id(&api_key, &project_id, &args.id).await?; if resouces.is_empty() { diff --git a/src/ports/tunnel.rs b/src/ports/tunnel.rs index aedd47d..50d0355 100644 --- a/src/ports/tunnel.rs +++ b/src/ports/tunnel.rs @@ -11,7 +11,7 @@ use tokio::{ io::{AsyncRead, AsyncWrite}, net::{TcpStream, UnixStream}, }; -use tracing::{debug, info, warn}; +use tracing::{debug, error, info, warn}; #[derive(Parser)] pub struct Args { @@ -108,7 +108,7 @@ fn define_socket_path( ctx: &crate::context::Context, ) -> miette::Result { let default = dirs - .ensure_tmp_dir(&ctx.project.namespace)? + .ensure_tmp_dir(&ctx.namespace.name)? .join(format!("{name}.socket")); let path = explicit.to_owned().unwrap_or(default); @@ -152,13 +152,25 @@ struct NodeOption(Resource); impl std::fmt::Display for NodeOption { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}/{} ({})", self.0.kind, self.0.id, self.0.spec) + let network = match serde_json::from_str::(&self.0.spec) { + Ok(spec) => match spec.get("network") { + Some(v) => v.as_str().unwrap().to_string(), + None => "unknown".to_string(), + }, + Err(err) => { + error!(?err); + "unknown".to_string() + } + }; + + write!(f, "{}: {} - {}", self.0.kind, self.0.name, network) } } async fn define_port(port_name: Option, cli: &crate::Cli) -> miette::Result { - let (api_key, id, _) = extract_context_data(cli); - let response = rpc::resources::find(&api_key, &id).await?; + let (api_key, project_id, _) = extract_context_data(cli).await?; + + let response = rpc::resources::find(&api_key, &project_id).await?; if response.is_empty() { bail!("you don't have any cardano-node ports, run dmtrctl ports create"); } diff --git a/src/rpc/auth/mod.rs b/src/rpc/auth/mod.rs index 1545192..28e65d4 100644 --- a/src/rpc/auth/mod.rs +++ b/src/rpc/auth/mod.rs @@ -19,9 +19,11 @@ pub async fn interceptor(credential: Credential) -> impl Interceptor { MetadataValue::try_from(&format!("Bearer {}", token)).unwrap(), ); } - Credential::Secret((project_id, secret)) => { - req.metadata_mut() - .insert("project-id", MetadataValue::try_from(project_id).unwrap()); + Credential::Secret((project_namespace, secret)) => { + req.metadata_mut().insert( + "project-namespace", + MetadataValue::try_from(project_namespace).unwrap(), + ); req.metadata_mut() .insert("dmtr-api-key", MetadataValue::try_from(secret).unwrap()); } diff --git a/src/rpc/projects/mod.rs b/src/rpc/projects/mod.rs index 2e091ec..37a5cbd 100644 --- a/src/rpc/projects/mod.rs +++ b/src/rpc/projects/mod.rs @@ -33,7 +33,10 @@ pub async fn find(access_token: &str) -> miette::Result> { Ok(records) } -pub async fn find_by_id(credential: auth::Credential, id: &str) -> miette::Result { +pub async fn find_by_namespace( + credential: auth::Credential, + namespace: &str, +) -> miette::Result { let interceptor = auth::interceptor(credential).await; let rpc_url = get_base_url(); @@ -45,10 +48,12 @@ pub async fn find_by_id(credential: auth::Credential, id: &str) -> miette::Resul let mut client = proto::project_service_client::ProjectServiceClient::with_interceptor(channel, interceptor); - let request = tonic::Request::new(proto::FetchProjectByIdRequest { id: id.into() }); + let request = tonic::Request::new(proto::FetchProjectByNamespaceRequest { + namespace: namespace.into(), + }); let response = client - .fetch_project_by_id(request) + .fetch_project_by_namespace(request) .await .into_diagnostic()?;