Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

50 changes: 23 additions & 27 deletions src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Self> {
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<Self> {
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<String>,
pub namespace: String,
pub struct Namespace {
pub name: String,
pub caption: Option<String>,
}

impl Project {
pub fn new(id: &str, namespace: &str, name: Option<String>) -> Self {
impl Namespace {
pub fn new(name: &str, caption: Option<String>) -> Self {
Self {
id: id.to_owned(),
namespace: namespace.to_owned(),
name,
name: name.to_owned(),
caption,
}
}
}
Expand Down Expand Up @@ -160,23 +151,28 @@ pub fn load_default_context(dirs: &crate::dirs::Dirs) -> miette::Result<Option<C

pub async fn infer_context(
name: Option<&str>,
project_id: Option<&str>,
namespace: Option<&str>,
api_key: Option<&str>,
dirs: &crate::dirs::Dirs,
) -> miette::Result<Option<Context>> {
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),
_ => load_default_context(dirs),
}
}

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))
}
9 changes: 2 additions & 7 deletions src/init/manual.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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?")
Expand All @@ -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(())
}
14 changes: 7 additions & 7 deletions src/init/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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("<import from cloud>"),
}
Expand All @@ -36,7 +36,7 @@ pub async fn import_context(dirs: &crate::dirs::Dirs) -> miette::Result<Context>
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),
};

Expand Down Expand Up @@ -80,19 +80,19 @@ 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(());
}
}

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");
Expand Down
12 changes: 6 additions & 6 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<String>,
/// Name of the namespace we're working on
#[arg(short, long, global = true, env = "DMTR_NAMESPACE")]
namespace: Option<String>,

/// The api key to use as authentication
#[arg(short, long, global = true, env = "DMTR_API_KEY")]
Expand All @@ -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
Expand All @@ -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,
)
Expand Down
2 changes: 1 addition & 1 deletion src/pages/deploy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
)?;
Expand Down
4 changes: 2 additions & 2 deletions src/ports/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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?;

Expand Down Expand Up @@ -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);

Expand Down
2 changes: 1 addition & 1 deletion src/ports/delete.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions src/ports/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
2 changes: 1 addition & 1 deletion src/ports/show.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
22 changes: 17 additions & 5 deletions src/ports/tunnel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -108,7 +108,7 @@ fn define_socket_path(
ctx: &crate::context::Context,
) -> miette::Result<PathBuf> {
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);
Expand Down Expand Up @@ -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::<serde_json::Value>(&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<String>, cli: &crate::Cli) -> miette::Result<Resource> {
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");
}
Expand Down
8 changes: 5 additions & 3 deletions src/rpc/auth/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}
Expand Down
11 changes: 8 additions & 3 deletions src/rpc/projects/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ pub async fn find(access_token: &str) -> miette::Result<Vec<proto::Project>> {
Ok(records)
}

pub async fn find_by_id(credential: auth::Credential, id: &str) -> miette::Result<proto::Project> {
pub async fn find_by_namespace(
credential: auth::Credential,
namespace: &str,
) -> miette::Result<proto::Project> {
let interceptor = auth::interceptor(credential).await;

let rpc_url = get_base_url();
Expand All @@ -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()?;

Expand Down