use std::{convert::TryFrom, str::FromStr};
use futures::future::Either;
use serde::{Deserialize, Serialize};
use tari_common::exit_codes::{ExitCode, ExitError};
use tari_common_types::{
emoji::EmojiId,
tari_address::TariAddress,
types::{BlockHash, CompressedPublicKey, CompressedSignature, PrivateKey},
};
use tari_comms::{peer_manager::NodeId, types::CommsPublicKey};
use tari_utilities::hex::{Hex, HexError};
use thiserror::Error;
use tokio::{runtime, runtime::Runtime};
pub const LOG_TARGET: &str = "minotari::application";
pub fn setup_runtime() -> Result<Runtime, ExitError> {
let mut builder = runtime::Builder::new_multi_thread();
builder.enable_all().build().map_err(|e| {
let msg = format!("There was an error while building the node runtime. {e}");
ExitError::new(ExitCode::UnknownError, msg)
})
}
pub fn parse_emoji_id_or_public_key(key: &str) -> Option<CommsPublicKey> {
EmojiId::from_str(&key.trim().replace('|', ""))
.map(|emoji_id| CompressedPublicKey::from(&emoji_id))
.or_else(|_| CommsPublicKey::from_hex(key))
.ok()
}
pub fn parse_hash(hash_string: &str) -> Option<BlockHash> {
BlockHash::from_hex(hash_string).ok()
}
pub fn parse_emoji_id_or_public_key_or_node_id(key: &str) -> Option<Either<CommsPublicKey, NodeId>> {
parse_emoji_id_or_public_key(key)
.map(Either::Left)
.or_else(|| NodeId::from_hex(key).ok().map(Either::Right))
}
pub fn either_to_node_id(either: Either<CommsPublicKey, NodeId>) -> NodeId {
match either {
Either::Left(pk) => NodeId::from_public_key(&pk),
Either::Right(n) => n,
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UniPublicKey(pub CompressedPublicKey);
impl FromStr for UniPublicKey {
type Err = UniIdError;
fn from_str(key: &str) -> Result<Self, Self::Err> {
if let Ok(emoji_id) = EmojiId::from_str(&key.trim().replace('|', "")) {
Ok(Self(CompressedPublicKey::from(&emoji_id)))
} else if let Ok(public_key) = CompressedPublicKey::from_hex(key) {
Ok(Self(public_key))
} else {
Err(UniIdError::UnknownIdType)
}
}
}
impl From<UniPublicKey> for CompressedPublicKey {
fn from(id: UniPublicKey) -> Self {
id.0
}
}
#[derive(Debug, Clone)]
pub enum UniNodeId {
PublicKey(CompressedPublicKey),
NodeId(NodeId),
TariAddress(TariAddress),
}
#[derive(Debug, Error)]
pub enum UniIdError {
#[error("unknown id type, expected emoji-id, public-key or node-id")]
UnknownIdType,
#[error("impossible convert a value to the expected type")]
Nonconvertible,
}
impl FromStr for UniNodeId {
type Err = UniIdError;
fn from_str(key: &str) -> Result<Self, Self::Err> {
if let Ok(emoji_id) = EmojiId::from_str(&key.trim().replace('|', "")) {
Ok(Self::PublicKey(CompressedPublicKey::from(&emoji_id)))
} else if let Ok(public_key) = CompressedPublicKey::from_hex(key) {
Ok(Self::PublicKey(public_key))
} else if let Ok(node_id) = NodeId::from_hex(key) {
Ok(Self::NodeId(node_id))
} else if let Ok(tari_address) = TariAddress::from_str(key) {
Ok(Self::TariAddress(tari_address))
} else {
Err(UniIdError::UnknownIdType)
}
}
}
impl TryFrom<UniNodeId> for CompressedPublicKey {
type Error = UniIdError;
fn try_from(id: UniNodeId) -> Result<Self, Self::Error> {
match id {
UniNodeId::PublicKey(public_key) => Ok(public_key),
UniNodeId::TariAddress(tari_address) => Ok(tari_address.public_spend_key().clone()),
UniNodeId::NodeId(_) => Err(UniIdError::Nonconvertible),
}
}
}
#[derive(Debug, Clone)]
pub struct UniSignature(CompressedSignature);
impl FromStr for UniSignature {
type Err = HexError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let data = s.split(',').collect::<Vec<_>>();
let signature = PrivateKey::from_hex(data.first().ok_or(HexError::LengthError {})?)?;
let public_nonce = CompressedPublicKey::from_hex(data.get(1).ok_or(HexError::LengthError {})?)?;
let signature = CompressedSignature::new(public_nonce, signature);
Ok(Self(signature))
}
}
impl From<UniSignature> for CompressedSignature {
fn from(id: UniSignature) -> Self {
id.0
}
}
impl From<UniNodeId> for NodeId {
fn from(id: UniNodeId) -> Self {
match id {
UniNodeId::PublicKey(public_key) => NodeId::from_public_key(&public_key),
UniNodeId::NodeId(node_id) => node_id,
UniNodeId::TariAddress(tari_address) => NodeId::from_public_key(tari_address.public_spend_key()),
}
}
}