Skip to content

Commit

Permalink
chore: interactive cli touchups (#947)
Browse files Browse the repository at this point in the history
  • Loading branch information
miraclx authored Nov 7, 2024
1 parent 6be490e commit 2da9658
Show file tree
Hide file tree
Showing 10 changed files with 199 additions and 134 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions crates/node/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ rand.workspace = true
serde_json.workspace = true
tokio = { workspace = true, features = ["io-std", "macros"] }
tracing.workspace = true
url.workspace = true

calimero-context = { path = "../context" }
calimero-blobstore = { path = "../store/blobs" }
Expand Down
28 changes: 14 additions & 14 deletions crates/node/src/interactive_cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,30 +16,30 @@ use clap::{Parser, Subcommand};

use crate::Node;
#[derive(Debug, Parser)]
#[command(multicall = true, bin_name = "{repl}")]
#[non_exhaustive]
pub struct RootCommand {
#[command(subcommand)]
pub action: SubCommands,
pub action: SubCommand,
}

#[derive(Debug, Subcommand)]
#[non_exhaustive]
pub enum SubCommands {
pub enum SubCommand {
#[command(alias = "app")]
Application(applications::ApplicationCommand),
Call(call::CallCommand),
Context(context::ContextCommand),
Identity(identity::IdentityCommand),
Peers(peers::PeersCommand),
Store(store::StoreCommand),
// Store(store::StoreCommand),
State(state::StateCommand),
}

pub async fn handle_line(node: &mut Node, line: String) -> eyre::Result<()> {
// IMPORTANT: Parser needs first string to be binary name
let mut args = vec!["{repl}"];
args.extend(line.split_whitespace());
let mut args = line.split_whitespace().peekable();

if args.len() == 1 {
if args.peek().is_none() {
return Ok(());
}

Expand All @@ -52,13 +52,13 @@ pub async fn handle_line(node: &mut Node, line: String) -> eyre::Result<()> {
};

match command.action {
SubCommands::Application(application) => application.run(node).await?,
SubCommands::Call(call) => call.run(node).await?,
SubCommands::Context(context) => context.run(node).await?,
SubCommands::Identity(identity) => identity.run(node)?,
SubCommands::Peers(peers) => peers.run(node.network_client.clone().into()).await?,
SubCommands::State(state) => state.run(node)?,
SubCommands::Store(store) => store.run(node)?,
SubCommand::Application(application) => application.run(node).await?,
SubCommand::Call(call) => call.run(node).await?,
SubCommand::Context(context) => context.run(node).await?,
SubCommand::Identity(identity) => identity.run(node)?,
SubCommand::Peers(peers) => peers.run(node.network_client.clone().into()).await?,
SubCommand::State(state) => state.run(node)?,
// SubCommand::Store(store) => store.run(node)?,
}

Ok(())
Expand Down
61 changes: 41 additions & 20 deletions crates/node/src/interactive_cli/applications.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
use calimero_primitives::hash::Hash;
use camino::Utf8PathBuf;
use clap::{Parser, Subcommand};
use eyre::Result;
use owo_colors::OwoColorize;
use url::Url;

use crate::Node;

/// Manage applications
#[derive(Debug, Parser)]
pub struct ApplicationCommand {
#[command(subcommand)]
Expand All @@ -13,40 +16,58 @@ pub struct ApplicationCommand {

#[derive(Debug, Subcommand)]
enum ApplicationSubcommand {
/// List installed applications
Ls,
/// Install an application
Install {
#[arg(value_enum)]
type_: InstallType,
resource: String,
metadata: Option<String>,
#[command(subcommand)]
resource: Resource,
},
Ls,
}

#[derive(Debug, clap::ValueEnum, Clone)]
enum InstallType {
Url,
File,
#[derive(Debug, Subcommand)]
enum Resource {
/// Install an application from a URL
Url {
/// The URL to download the application from
url: Url,
/// The hash of the application (bs58 encoded)
hash: Option<Hash>,
/// Metadata to associate with the application
metadata: Option<String>,
},
/// Install an application from a file
File {
/// The file path to the application
path: Utf8PathBuf,
/// Metadata to associate with the application
metadata: Option<String>,
},
}

impl ApplicationCommand {
pub async fn run(self, node: &Node) -> Result<()> {
let ind = ">>".blue();
match self.command {
ApplicationSubcommand::Install {
type_,
resource,
metadata,
} => {
let application_id = match type_ {
InstallType::Url => {
let url = resource.parse()?;
ApplicationSubcommand::Install { resource } => {
let application_id = match resource {
Resource::Url {
url,
hash,
metadata,
} => {
println!("{ind} Downloading application..");
node.ctx_manager
.install_application_from_url(url, vec![], None)
.install_application_from_url(
url,
metadata
.map(|x| x.as_bytes().to_owned())
.unwrap_or_default(),
hash,
)
.await?
}
InstallType::File => {
let path = Utf8PathBuf::from(resource);
Resource::File { path, metadata } => {
if let Ok(application_id) = node
.ctx_manager
.install_application_from_path(
Expand Down
5 changes: 5 additions & 0 deletions crates/node/src/interactive_cli/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,16 @@ use serde_json::Value;

use crate::Node;

/// Call a method on a context
#[derive(Debug, Parser)]
pub struct CallCommand {
/// The context ID to call the method on
context_id: ContextId,
/// The method to call
method: String,
/// The payload to send to the method
payload: Value,
/// The public key of the executor
executor_key: PublicKey,
}

Expand Down
93 changes: 42 additions & 51 deletions crates/node/src/interactive_cli/context.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
use core::mem::replace;
use core::str::FromStr;

use calimero_primitives::application::ApplicationId;
use calimero_primitives::context::{ContextId, ContextInvitationPayload};
use calimero_primitives::hash::Hash;
use calimero_primitives::identity::{PrivateKey, PublicKey};
use calimero_store::key::ContextMeta as ContextMetaKey;
use clap::{Parser, Subcommand};
use eyre::Result;
use owo_colors::OwoColorize;
use serde_json::Value;
use tokio::sync::oneshot;

use crate::Node;

/// Manage contexts
#[derive(Debug, Parser)]
pub struct ContextCommand {
#[command(subcommand)]
Expand All @@ -18,26 +20,43 @@ pub struct ContextCommand {

#[derive(Debug, Subcommand)]
enum Commands {
/// List contexts
Ls,
Join {
private_key: String,
invitation_payload: String,
},
Leave {
context_id: String,
},
/// Create a context
Create {
application_id: String,
context_seed: Option<String>,
params: Option<String>,
/// The application ID to create the context with
application_id: ApplicationId,
/// The initialization parameters for the context
params: Option<Value>,
/// The seed for the context (to derive a deterministic context ID)
#[clap(long = "seed")]
context_seed: Option<Hash>,
},
/// Invite a user to a context
Invite {
context_id: String,
inviter_id: String,
invitee_id: String,
/// The context ID to invite the user to
context_id: ContextId,
/// The ID of the inviter
inviter_id: PublicKey,
/// The ID of the invitee
invitee_id: PublicKey,
},
/// Join a context
Join {
/// The private key of the user
private_key: PrivateKey,
/// The invitation payload from the inviter
invitation_payload: ContextInvitationPayload,
},
/// Leave a context
Leave {
/// The context ID to leave
context_id: ContextId,
},
/// Delete a context
Delete {
context_id: String,
/// The context ID to delete
context_id: ContextId,
},
}

Expand Down Expand Up @@ -76,9 +95,6 @@ impl ContextCommand {
private_key,
invitation_payload,
} => {
let private_key = private_key.parse()?;
let invitation_payload = invitation_payload.parse()?;

let response = node
.ctx_manager
.join_context(private_key, invitation_payload)
Expand All @@ -95,7 +111,6 @@ impl ContextCommand {
}
}
Commands::Leave { context_id } => {
let context_id = context_id.parse()?;
if node.ctx_manager.delete_context(&context_id).await? {
println!("{ind} Successfully deleted context {context_id}");
} else {
Expand All @@ -105,39 +120,20 @@ impl ContextCommand {
}
Commands::Create {
application_id,
params,
context_seed,
mut params,
} => {
let application_id = application_id.parse()?;

let (context_seed, params) = 'infer: {
let Some(context_seed) = context_seed else {
break 'infer (None, None);
};
let context_seed_clone = context_seed.clone();

if let Ok(context_seed) = context_seed.parse::<Hash>() {
break 'infer (Some(context_seed), params);
};

match replace(&mut params, Some(context_seed))
.map(|arg0| FromStr::from_str(&arg0))
{
Some(Ok(context_seed)) => break 'infer (Some(context_seed), params),
None => break 'infer (None, params),
_ => {}
};
println!("{ind} Invalid context seed: {context_seed_clone}");
return Err(eyre::eyre!("Invalid context seed"));
};

let (tx, rx) = oneshot::channel();

node.ctx_manager.create_context(
context_seed.map(Into::into),
application_id,
None,
params.map(|x| x.as_bytes().to_owned()).unwrap_or_default(),
params
.as_ref()
.map(serde_json::to_vec)
.transpose()?
.unwrap_or_default(),
tx,
)?;

Expand All @@ -159,10 +155,6 @@ impl ContextCommand {
inviter_id,
invitee_id,
} => {
let context_id = context_id.parse()?;
let inviter_id = inviter_id.parse()?;
let invitee_id = invitee_id.parse()?;

if let Some(invitation_payload) = node
.ctx_manager
.invite_to_context(context_id, inviter_id, invitee_id)
Expand All @@ -175,7 +167,6 @@ impl ContextCommand {
}
}
Commands::Delete { context_id } => {
let context_id = context_id.parse()?;
let _ = node.ctx_manager.delete_context(&context_id).await?;
println!("{ind} Deleted context {context_id}");
}
Expand Down
8 changes: 7 additions & 1 deletion crates/node/src/interactive_cli/identity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use owo_colors::OwoColorize;

use crate::Node;

/// Manage identities
#[derive(Debug, Parser)]
pub struct IdentityCommand {
#[command(subcommand)]
Expand All @@ -16,7 +17,12 @@ pub struct IdentityCommand {

#[derive(Debug, Subcommand)]
enum IdentitySubcommands {
Ls { context_id: String },
/// List identities in a context
Ls {
/// The context ID to list identities in
context_id: String,
},
/// Create a new identity
New,
}

Expand Down
8 changes: 5 additions & 3 deletions crates/node/src/interactive_cli/peers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ use eyre::Result;
use libp2p::gossipsub::TopicHash;
use owo_colors::OwoColorize;

/// List the peers in the network
#[derive(Copy, Clone, Debug, Parser)]
pub struct PeersCommand {
topic: Option<ContextId>,
/// The context ID to list the peers for
context_id: Option<ContextId>,
}

impl PeersCommand {
Expand All @@ -20,8 +22,8 @@ impl PeersCommand {
network_client.peer_count().await.cyan()
);

if let Some(topic) = self.topic {
let topic = TopicHash::from_raw(topic);
if let Some(context_id) = self.context_id {
let topic = TopicHash::from_raw(context_id);
println!(
"{ind} Peers (Session) for Topic {}: {:#?}",
topic.clone(),
Expand Down
Loading

0 comments on commit 2da9658

Please sign in to comment.