Now that we've finished writing our gibbername crate, we'll demonstrate actually using it in a project. We will build gibbername-cli, a trivial wrapper around the library that lets you look up and register names on the command line. Using it willl look something like
$ gibbername-cli lookup tofnal-qujjay-seh
hello world my dudes this is what's bound to the name lol
You can find a complete example in our GitHub repo.
Project setup
Let's start by creating a new binary crate:
$cargonewgibbername-cli$cdgibbername-cli
We add melprot, melstructs, anyhow for error handling,argh for lightweight argument parsing, and futures-lite for bare-bones async support:
$ cargo add melprot melstructs anyhow argh futures-lite Updating crates.io index Adding melprot v0.1.0 to dependencies. Adding melstructs v0.3.2 to dependencies. Adding anyhow v1.0.69 to dependencies. Adding argh v0.1.10 to dependencies. Adding futures-lite 1.12.0 to dependencies.
We also need to add a dependency on Gibbername itself. This will be a "path" dependency to wherever, locally, you put the Gibbername crate:
We write a basic scaffold that parses the arguments with argh:
use argh::FromArgs;use melstructs::{Address, NetID};#[derive(FromArgs, PartialEq, Debug)]/// Look up a name in the Gibbername registry.structCli { #[argh(subcommand)] command:Command,}#[derive(FromArgs, PartialEq, Debug)]#[argh(subcommand)]enumCommand {Lookup(Lookup),Register(Register)}#[derive(FromArgs, PartialEq, Debug)]#[argh(subcommand, name ="lookup")]/// Lookup what is bound to a namestructLookup { #[argh(positional)] name:String,}#[derive(FromArgs, PartialEq, Debug)]#[argh(subcommand, name ="register")]/// Register a namestructRegister { #[argh(option, description ="the Mel address of the gibbername owner")] owner:Address, #[argh(option, description ="the data to be bound to the gibbername")] binding:String, #[argh(option, description ="the name of the wallet sending the transaction")] wallet_name:String,}fnmain() -> anyhow::Result<()> {let args:Cli= argh::from_env();// keep around a clientlet client = melprot::Client::autoconnect(NetID::Mainnet);match args.command.as_ref() {Command::Lookup(lookup) => {todo!() }Command::Register(register) => {todo!() } };Ok(())}
Filling in the functionality
Now that we have a basic scaffold, filling in the functionality is incredibly easy:
use futures_lite::future::block_on;fnmain() -> anyhow::Result<()> {let args:Cli= argh::from_env();// keep around a clientlet client =block_on( melprot::Client::autoconnect(NetID::Testnet) )?;match args.command {Command::Lookup(lookup) => {// we don't need a futures runtime, block_on is finelet gname =block_on(gibbername::lookup(&client, &lookup.name))?;println!("{gname}"); }Command::Register(register) => {// gibbername will prompt the user let name = block_on(gibbername::register(&client, register.owner, ®ister.binding, ®ister.wallet_name))?;
println!("registered {:?}", name); } };Ok(())}
Testing
We now have a complete program! We can test run it with cargo run:
$ cargo run -- register --owner t1cj51xmq3dxn91z8exz3vhbk2wc8g9enh3kzsbmd3zzy6yx1memyg --binding 'hello CLI' --wallet-name my-wallet
Send this command with your wallet: melwallet-cli send -w last --to t1cj51xmq3dxn91z8exz3vhbk2wc8g9enh3kzsbmd3zzy6yx1memyg,0.000001,"(NEWCUSTOM)","68656c6c6f20434c49" --hex-data 6769626265726e616d652d7631
Now we run the melwallet-cli command which will register our gibbername: