Account manager
This commit is contained in:
+57
-8
@@ -2,21 +2,27 @@ use std::sync::Arc;
|
|||||||
|
|
||||||
use tokio::{sync::Mutex, task::JoinHandle};
|
use tokio::{sync::Mutex, task::JoinHandle};
|
||||||
|
|
||||||
use crate::{store::config::Config, terminal::TerminalServer};
|
use crate::{
|
||||||
|
store::{accounts::AccountList, config::Config},
|
||||||
|
terminal::TerminalServer,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Engine {
|
pub struct Engine {
|
||||||
pub terminal_server: Arc<TerminalServer>,
|
pub terminal_server: Arc<TerminalServer>,
|
||||||
pub config: Arc<Mutex<Config>>,
|
pub config: Arc<Mutex<Config>>,
|
||||||
|
pub accounts: Arc<Mutex<AccountList>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Engine {
|
impl Engine {
|
||||||
pub async fn new() -> tokio::io::Result<Arc<Self>> {
|
pub async fn new() -> tokio::io::Result<Arc<Self>> {
|
||||||
let config = Arc::new(Mutex::new(Config::new().await?));
|
let config = Arc::new(Mutex::new(Config::new().await?));
|
||||||
|
let accounts = Arc::new(Mutex::new(AccountList::new().await?));
|
||||||
|
|
||||||
Ok(Arc::new_cyclic(|engine| Self {
|
Ok(Arc::new_cyclic(|engine| Self {
|
||||||
terminal_server: TerminalServer::new(engine.clone()),
|
terminal_server: TerminalServer::new(engine.clone()),
|
||||||
config,
|
config,
|
||||||
|
accounts,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,15 +84,15 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn invalid_command_usage(&self, name: &str) -> tokio::io::Result<()> {
|
||||||
|
self.terminal_server.error(name, "Invalid usage").await
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn execute_command(&self, command: &str, args: Vec<&str>) -> tokio::io::Result<()> {
|
pub async fn execute_command(&self, command: &str, args: Vec<&str>) -> tokio::io::Result<()> {
|
||||||
match command {
|
match command {
|
||||||
"config" => {
|
"config" | "cfg" => {
|
||||||
const MESSAGE: &str = "Invalid command arguments, usage: config <reload>";
|
|
||||||
|
|
||||||
if args.len() != 1 {
|
if args.len() != 1 {
|
||||||
self.terminal_server.error("config", MESSAGE).await?;
|
return self.invalid_command_usage("config").await;
|
||||||
|
|
||||||
return Ok(());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
match args[0] {
|
match args[0] {
|
||||||
@@ -95,7 +101,50 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
self.terminal_server.error("config", MESSAGE).await?;
|
self.terminal_server
|
||||||
|
.error("config", "Invalid usage")
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"account" | "acc" => {
|
||||||
|
if args.len() == 0 {
|
||||||
|
return self.invalid_command_usage("account man").await;
|
||||||
|
}
|
||||||
|
|
||||||
|
match args[0] {
|
||||||
|
"reload" => {
|
||||||
|
*self.accounts.lock().await = AccountList::new().await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
"list" | "ls" => {
|
||||||
|
self.terminal_server
|
||||||
|
.info("account man", "ACCOUNT LIST")
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let accounts = self.accounts.lock().await;
|
||||||
|
|
||||||
|
for (name, acc) in &accounts.accounts {
|
||||||
|
self.terminal_server
|
||||||
|
.info(
|
||||||
|
"account man",
|
||||||
|
&if name == &accounts.active {
|
||||||
|
format!(
|
||||||
|
"{} (active) -> {}",
|
||||||
|
name,
|
||||||
|
acc.get_truncated_address()
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
format!("{} -> {}", name, acc.get_truncated_address())
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {
|
||||||
|
return self.invalid_command_usage("account man").await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,56 @@
|
|||||||
use std::collections::HashMap;
|
use std::{collections::HashMap, str::FromStr};
|
||||||
|
|
||||||
use hypersdk::U160;
|
use hypersdk::{U160, hypercore::PrivateKeySigner};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct PrivateKey(pub PrivateKeySigner, pub String);
|
||||||
|
|
||||||
|
impl FromStr for PrivateKey {
|
||||||
|
type Err = <PrivateKeySigner as FromStr>::Err;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
Ok(Self(s.parse()?, s.to_string()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for PrivateKey {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
self.1.fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> serde::Deserialize<'de> for PrivateKey {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let s = String::deserialize(deserializer)?;
|
||||||
|
s.parse().map_err(serde::de::Error::custom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl serde::Serialize for PrivateKey {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: serde::Serializer,
|
||||||
|
{
|
||||||
|
serializer.serialize_str(&self.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
||||||
pub struct Account {
|
pub struct Account {
|
||||||
pub address: U160,
|
pub address: U160,
|
||||||
pub private_key: String,
|
pub private_key: PrivateKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Default, serde::Serialize, serde::Deserialize)]
|
||||||
pub struct AccountList(pub HashMap<String, Account>);
|
pub struct AccountList {
|
||||||
|
pub active: String,
|
||||||
|
|
||||||
|
#[serde(flatten)]
|
||||||
|
pub accounts: HashMap<String, Account>,
|
||||||
|
}
|
||||||
|
|
||||||
impl AccountList {
|
impl AccountList {
|
||||||
pub async fn new() -> tokio::io::Result<Self> {
|
pub async fn new() -> tokio::io::Result<Self> {
|
||||||
@@ -39,3 +80,26 @@ impl AccountList {
|
|||||||
.map_err(|v| tokio::io::Error::new(std::io::ErrorKind::Other, v.to_string()))
|
.map_err(|v| tokio::io::Error::new(std::io::ErrorKind::Other, v.to_string()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Account {
|
||||||
|
pub fn get_truncated_address(&self) -> String {
|
||||||
|
let s = format!("{:x}", self.address);
|
||||||
|
|
||||||
|
if s.len() <= 6 {
|
||||||
|
return format!("INVALID");
|
||||||
|
}
|
||||||
|
|
||||||
|
let first: String = s.chars().take(4).collect();
|
||||||
|
|
||||||
|
let last: String = s
|
||||||
|
.chars()
|
||||||
|
.rev()
|
||||||
|
.take(4)
|
||||||
|
.collect::<Vec<char>>()
|
||||||
|
.into_iter()
|
||||||
|
.rev()
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
format!("{}..{}", first, last)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user