use anyhow::Result;
use serde::Serialize;
use crate::{
args::Args, parsers::parse_address, progress::Progress, records::get_agent_record,
sign::sign_request, storage::Storage, transport::agent_base_url,
};
use relay_lib::prelude::Address;
#[derive(Serialize)]
struct ClaimInbloxReq {
pub id: String,
}
#[derive(Debug, Clone, clap::Parser)]
#[clap(about = "Claim an inbox for an existing identity")]
pub struct ClaimInboxCmd {
#[arg(value_parser = parse_address)]
pub address: Address,
}
impl ClaimInboxCmd {
pub fn execute(&self, _: Args, storage: &mut Storage) -> Result<()> {
let mut progress = Progress::new(false);
if self.address.inbox().is_none() {
progress.abort("Cannot claim an empty inbox.");
}
let inbox = self.address.inbox().unwrap().clone();
let mut address = self.address.clone();
address.inbox = None;
progress.step(
&format!("Checking existing identity for `{}`", address),
"Checked existing identity",
);
let identity = match storage.root.get_identity(&self.address) {
Some(identity) => {
if identity.inboxes.contains(&inbox) {
progress.abort(&format!("Inbox for address `{}` already exists.", address));
}
identity.clone()
}
None => {
progress.abort(&format!(
"No identity found for address `{}`. Please claim the base identity first using the `claim` command.",
address,
));
}
};
progress.step("Fetching agent keys", "Fetched agent keys");
let agent_record = get_agent_record(self.address.agent()).map_err(|_| {
progress.abort("Failed to fetch agent record");
})?;
progress.step("Requsting inbox claim", "Inbox claimed");
let request = sign_request(
&address.canonical(),
ClaimInbloxReq {
id: inbox.canonical().to_string(),
},
&agent_record,
&identity.signing_key(),
)
.map_err(|_| {
progress.abort("Failed to sign inbox claim request");
})?;
let resp = reqwest::blocking::Client::new()
.post(agent_base_url(address.agent())?.join("/user/claim/inbox")?)
.json(&request)
.send()
.map_err(|_| {
progress.abort("Failed to send inbox claim request");
})?;
if resp.status().as_u16() == 409 {
progress.commit();
progress.nested_section(0, "Inbox already claimed on the Agent");
progress.nested(1, &format!("Inbox added locally: `{}`", address));
storage
.root
.identities
.get_mut(&address)
.unwrap()
.inboxes
.push(inbox.clone());
}
if !resp.status().is_success() {
let status = resp.status();
progress.abort(&format!("Failed to claim inbox. Status: {}", status));
}
progress.step("Storing inbox locally", "Inbox stored locally");
storage
.root
.identities
.get_mut(&address)
.unwrap()
.inboxes
.push(inbox.clone());
progress.commit();
progress.arrow(&format!("Successfully claimed inbox `{}`", self.address));
Ok(())
}
}