bless
This commit is contained in:
parent
61d71006f7
commit
f9ae2949e4
1542
cli-renderer/Cargo.lock
generated
Normal file
1542
cli-renderer/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
12
cli-renderer/Cargo.toml
Normal file
12
cli-renderer/Cargo.toml
Normal file
@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "cli-renderer"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
crossterm = "0.29.0"
|
||||
ratatui = "0.29.0"
|
||||
ws = "0.9.2"
|
||||
vlogger = { path = "../lib/logger-rs" }
|
||||
clap = { version = "4.5.47", features = ["derive"] }
|
||||
textwrap = "0.16.2"
|
||||
@ -9,6 +9,8 @@ pub enum RenderLayoutKind {
|
||||
CliHorizontal,
|
||||
#[value(name = "vertical", aliases = ["v"])]
|
||||
CliVertical,
|
||||
|
||||
CliOutputSplit,
|
||||
}
|
||||
|
||||
const CLI_INPUT_PREFIX: &str = "> ";
|
||||
@ -88,6 +90,14 @@ impl RenderLayout {
|
||||
),
|
||||
],
|
||||
},
|
||||
RenderLayoutKind::CliOutputSplit => {
|
||||
let layout = Layout::default()
|
||||
.constraints([Constraint::Percentage(70), Constraint::Percentage(30)]);
|
||||
RenderLayout {
|
||||
layout,
|
||||
panes: vec![]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
cli-renderer/src/lib.rs
Normal file
11
cli-renderer/src/lib.rs
Normal file
@ -0,0 +1,11 @@
|
||||
pub mod renderer;
|
||||
pub use renderer::*;
|
||||
|
||||
pub mod command;
|
||||
pub use command::*;
|
||||
|
||||
pub mod layout;
|
||||
pub use layout::*;
|
||||
|
||||
pub mod pane;
|
||||
pub use pane::*;
|
||||
@ -25,11 +25,8 @@ pub enum RenderBuffer {
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum RenderTarget {
|
||||
All,
|
||||
|
||||
CliInput,
|
||||
|
||||
CliOutput,
|
||||
|
||||
PopUp
|
||||
}
|
||||
|
||||
@ -4,7 +4,6 @@ use crossterm::event::KeyCode;
|
||||
use ratatui::{Frame, buffer::Buffer, layout::Rect, widgets::Widget};
|
||||
use vlogger::*;
|
||||
|
||||
use crate::log;
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@ -19,6 +18,7 @@ pub struct Renderer {
|
||||
exit: bool,
|
||||
layout: RenderLayout,
|
||||
mode: InputMode,
|
||||
area: Rect,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
@ -29,11 +29,12 @@ impl Renderer {
|
||||
exit: false,
|
||||
layout: RenderLayout::generate(layout),
|
||||
mode: InputMode::Input,
|
||||
area: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn log(&mut self, msg: String) {
|
||||
self.buffer.push_str(&msg)
|
||||
self.apply(RenderCommand::StringToPaneFocused{str: msg})
|
||||
}
|
||||
|
||||
pub fn draw(&mut self, frame: &mut Frame) {
|
||||
@ -65,8 +66,12 @@ impl Renderer {
|
||||
self.layout.panes.iter_mut().find(|p| p.focused == true)
|
||||
}
|
||||
|
||||
pub fn rects(&self, area: Rect) -> std::rc::Rc<[Rect]> {
|
||||
self.layout.rects(area)
|
||||
pub fn rects(&self) -> std::rc::Rc<[Rect]> {
|
||||
self.layout.rects(self.area)
|
||||
}
|
||||
|
||||
pub fn set_area(&mut self, area: Rect) {
|
||||
self.area = area;
|
||||
}
|
||||
|
||||
pub fn handle_mouse_click_left(&mut self, x: u16, y: u16, rects: std::rc::Rc<[Rect]>) {
|
||||
@ -128,7 +133,6 @@ impl Renderer {
|
||||
RenderTarget::PopUp => {
|
||||
match &mut pane.buffer {
|
||||
RenderBuffer::Select(content, idx) => {
|
||||
log(msg!(DEBUG, "idx before: {idx}"));
|
||||
match key {
|
||||
KeyCode::Up => { *idx = idx.saturating_sub(1) }
|
||||
KeyCode::Down => {
|
||||
@ -138,7 +142,6 @@ impl Renderer {
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
log(msg!(DEBUG, "idx after: {idx}"))
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@ -219,8 +222,8 @@ impl Renderer {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn apply(&mut self, mes: RenderCommand, area: Rect) {
|
||||
let rects = self.layout.rects(area);
|
||||
pub fn apply(&mut self, mes: RenderCommand) {
|
||||
let rects = self.rects();
|
||||
match mes {
|
||||
RenderCommand::MouseClickLeft(x, y) => self.handle_mouse_click_left(x, y, rects),
|
||||
RenderCommand::MouseScrollUp => self.handle_scroll_up(),
|
||||
666
node/Cargo.lock
generated
666
node/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -29,3 +29,5 @@ bincode = { version = "2.0.1", features = ["derive", "serde"] }
|
||||
futures = "0.3.31"
|
||||
secp256k1 = { version = "0.31.1", features = ["hashes", "rand", "recovery", "serde"] }
|
||||
ring = "0.17.14"
|
||||
shared = { path = "../shared", features = ["node"] }
|
||||
cli-renderer = { path = "../cli-renderer" }
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
use std::net::SocketAddr;
|
||||
|
||||
use crate::core;
|
||||
use crate::renderer::RenderLayoutKind;
|
||||
use shared::core;
|
||||
use cli_renderer::RenderLayoutKind;
|
||||
use clap::{Parser, Subcommand};
|
||||
|
||||
use clap::*;
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
use crate::args::*;
|
||||
use crate::core::ChainData;
|
||||
use shared::core::ChainData;
|
||||
use crate::executor::ExecutorCommand;
|
||||
use crate::node::*;
|
||||
use crate::renderer::RenderCommand;
|
||||
use cli_renderer::RenderCommand;
|
||||
use clap::Parser;
|
||||
|
||||
pub fn handle_peer_command(cmd: CliPeerCommand) -> NodeCommand {
|
||||
|
||||
@ -1,51 +0,0 @@
|
||||
use sha2::{Sha256, Digest};
|
||||
use secp256k1::rand;
|
||||
use secp256k1::{Secp256k1, PublicKey, SecretKey};
|
||||
|
||||
pub type Address = String;
|
||||
|
||||
#[derive(Debug, bincode::Decode, bincode::Encode)]
|
||||
pub struct Account {
|
||||
address: Address,
|
||||
balance: u64,
|
||||
nonce: u64,
|
||||
}
|
||||
|
||||
impl Account {
|
||||
pub fn public_key_to_address(public_key: &PublicKey) -> Address {
|
||||
let pk_ser = public_key.serialize();
|
||||
let hash = Sha256::digest(&pk_ser);
|
||||
hex::encode(&hash[..20])
|
||||
}
|
||||
|
||||
pub fn nonce(&self) -> u64 {
|
||||
self.nonce
|
||||
}
|
||||
|
||||
pub fn balance(&self) -> u64 {
|
||||
self.balance
|
||||
}
|
||||
|
||||
pub fn address(&self) -> &Address {
|
||||
&self.address
|
||||
}
|
||||
|
||||
pub fn new() -> Self {
|
||||
let secp = Secp256k1::new();
|
||||
let (secret_key, public_key) = secp.generate_keypair(&mut rand::rng());
|
||||
let addr = Self::public_key_to_address(&public_key);
|
||||
|
||||
println!("{:?}", secret_key);
|
||||
|
||||
Self {
|
||||
address: addr,
|
||||
balance: 0,
|
||||
nonce: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_acc_new() {
|
||||
Account::new();
|
||||
}
|
||||
@ -2,14 +2,15 @@ use bincode::{self, config::Configuration};
|
||||
use sled::{self, Batch};
|
||||
use std::sync::Arc;
|
||||
use vlogger::*;
|
||||
use shared::core::{self, Block, ChainData, Hasher, Address};
|
||||
|
||||
use crate::{
|
||||
core::{self, Block, ChainData, Hasher, Address, Account},
|
||||
db::error::DatabaseError,
|
||||
error::print_error_chain,
|
||||
log,
|
||||
};
|
||||
|
||||
use shared::core::print_error_chain;
|
||||
|
||||
static BINCODE_CONFIG: Configuration = bincode::config::standard();
|
||||
|
||||
const DB_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/database");
|
||||
@ -21,7 +22,6 @@ const CHAIN_DATA_PREFIX: &str = "chain_data";
|
||||
const DATA_TO_BLOCK_PREFIX: &str = "data_to_block";
|
||||
const METADATA_PREFIX: &str = "metadata";
|
||||
const BALANCE_PREFIX: &str = "balance";
|
||||
const ACCOUNT_PREFIX: &str = "account";
|
||||
|
||||
const MEMPOOL_PREFIX: &str = "mempool";
|
||||
|
||||
@ -112,7 +112,7 @@ impl ChainDb {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert_account(&self, acc: &Account) -> Result<(), DatabaseError> {
|
||||
fn insert_account(&self, acc: &Account) -> Result<(), DatabaseError> {
|
||||
let mut batch = Batch::default();
|
||||
if let Some(_) = self.get_account(acc.address())? {
|
||||
return Err(DatabaseError::AccountExists(acc.address().to_string()));
|
||||
|
||||
@ -1,35 +1,6 @@
|
||||
use crate::log;
|
||||
use thiserror::Error;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Error, Debug)]
|
||||
pub enum TxError {
|
||||
#[error("from field is empty")]
|
||||
FromEmpty,
|
||||
#[error("to field is empty")]
|
||||
ToEmpty,
|
||||
#[error("insuffitient fonds")]
|
||||
FromInsuffitientFonds,
|
||||
#[error("0 value transaction")]
|
||||
ValueEmpty,
|
||||
#[error("account {0} not found in database")]
|
||||
UnknownAccount(String),
|
||||
}
|
||||
|
||||
pub fn print_error_chain(err: &anyhow::Error) {
|
||||
let mut err_string = String::from(format!("Error: {}\n", err));
|
||||
|
||||
let mut source = err.source();
|
||||
let mut level = 1;
|
||||
|
||||
while let Some(err) = source {
|
||||
err_string.push_str(format!(" {}: {}\n", level, err).as_str());
|
||||
source = err.source();
|
||||
level += 1;
|
||||
}
|
||||
log(err_string)
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum SystemError<T>
|
||||
where
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use crate::node::NodeCommand;
|
||||
use crate::renderer::RenderCommand;
|
||||
use cli_renderer::RenderCommand;
|
||||
use crate::watcher::WatcherCommand;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
||||
@ -2,9 +2,10 @@ use crate::{
|
||||
bus::{publish_system_event, publish_watcher_event, subscribe_system_event, SystemEvent},
|
||||
log,
|
||||
node::NodeCommand,
|
||||
renderer::RenderTarget,
|
||||
watcher::WatcherCommand,
|
||||
};
|
||||
|
||||
use cli_renderer::pane::RenderTarget;
|
||||
use thiserror::Error;
|
||||
use tokio::{select, sync::mpsc};
|
||||
use vlogger::*;
|
||||
|
||||
@ -4,6 +4,9 @@ pub mod node {
|
||||
|
||||
pub mod error;
|
||||
pub use error::*;
|
||||
|
||||
pub mod blockchain;
|
||||
pub use blockchain::*;
|
||||
}
|
||||
|
||||
pub mod cli;
|
||||
@ -12,26 +15,6 @@ pub mod args;
|
||||
|
||||
pub mod error;
|
||||
|
||||
pub mod core {
|
||||
pub mod block;
|
||||
pub use block::*;
|
||||
|
||||
pub mod blockchain;
|
||||
pub use blockchain::*;
|
||||
|
||||
pub mod tx;
|
||||
pub use tx::*;
|
||||
|
||||
pub mod data;
|
||||
pub use data::*;
|
||||
|
||||
pub mod hasher;
|
||||
pub use hasher::*;
|
||||
|
||||
pub mod account;
|
||||
pub use account::*;
|
||||
}
|
||||
|
||||
pub mod db {
|
||||
pub mod database;
|
||||
pub mod error;
|
||||
@ -61,20 +44,6 @@ pub mod executor {
|
||||
pub use command::*;
|
||||
}
|
||||
|
||||
pub mod renderer {
|
||||
pub mod renderer;
|
||||
pub use renderer::*;
|
||||
|
||||
pub mod pane;
|
||||
pub use pane::*;
|
||||
|
||||
pub mod layout;
|
||||
pub use layout::*;
|
||||
|
||||
pub mod command;
|
||||
pub use command::*;
|
||||
}
|
||||
|
||||
pub mod watcher {
|
||||
pub mod builder;
|
||||
pub mod watcher;
|
||||
@ -99,7 +68,7 @@ pub mod protocol {
|
||||
|
||||
pub mod seeds_constants;
|
||||
|
||||
use crate::renderer::{RenderCommand, RenderTarget};
|
||||
use cli_renderer::{RenderCommand, RenderTarget};
|
||||
|
||||
pub fn log(msg: String) {
|
||||
crate::bus::publish_watcher_event(watcher::WatcherCommand::Render(RenderCommand::StringToPaneId {
|
||||
|
||||
@ -3,15 +3,21 @@ use std::time::UNIX_EPOCH;
|
||||
|
||||
use thiserror::*;
|
||||
|
||||
use crate::core;
|
||||
use crate::core::ChainData;
|
||||
use shared::core;
|
||||
use shared::core::ChainData;
|
||||
use crate::db;
|
||||
use crate::db::DatabaseError;
|
||||
use crate::db::database;
|
||||
use crate::error::TxError;
|
||||
use crate::log;
|
||||
|
||||
use super::hasher::Hasher;
|
||||
use shared::core::Hasher;
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub struct Blockchain {
|
||||
id: String,
|
||||
mempool: Vec<ChainData>,
|
||||
db: database::ChainDb,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Error, Debug)]
|
||||
@ -23,7 +29,7 @@ pub enum BlockchainError {
|
||||
InvalidAccountCreation,
|
||||
|
||||
#[error("Transactional error")]
|
||||
Tx(#[from] TxError),
|
||||
Tx(#[from] shared::core::TxError),
|
||||
|
||||
#[error("Validation Error")]
|
||||
Validation(#[from] ValidationError),
|
||||
@ -47,14 +53,6 @@ pub enum ValidationError {
|
||||
InvalidBlockJson(#[from] serde_json::Error),
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub struct Blockchain {
|
||||
id: String,
|
||||
mempool: Vec<ChainData>,
|
||||
db: database::ChainDb,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl Blockchain {
|
||||
fn hash_transaction_pool(&self) -> Vec<String> {
|
||||
@ -1,12 +1,13 @@
|
||||
use crate::bus::{publish_system_event, publish_watcher_event, subscribe_system_event, SystemEvent};
|
||||
use crate::core::{self, Blockchain, BlockchainError, ChainData, ValidationError};
|
||||
use crate::error::print_error_chain;
|
||||
use shared::core::{self, ChainData};
|
||||
use shared::core::print_error_chain;
|
||||
use crate::executor::ExecutorCommand;
|
||||
use crate::log;
|
||||
use crate::protocol::ProtocolMessage;
|
||||
use crate::protocol::{Connector, ConnectorCommand};
|
||||
use crate::seeds_constants::SEED_NODES;
|
||||
use crate::watcher::{WatcherCommand, WatcherMode};
|
||||
use super::{ Blockchain, BlockchainError, ValidationError };
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::net::SocketAddr;
|
||||
@ -202,7 +203,7 @@ impl Node {
|
||||
}
|
||||
ProtocolMessage::BootstrapResponse { blocks } => {
|
||||
log(msg!(DEBUG, "Received BootstrapResponse from seed"));
|
||||
self.chain = core::Blockchain::build(blocks).unwrap();
|
||||
self.chain = Blockchain::build(blocks).unwrap();
|
||||
}
|
||||
ProtocolMessage::Pong { peer_id } => {
|
||||
log(msg!(DEBUG, "Received Pong from {peer_id}"));
|
||||
|
||||
@ -4,17 +4,16 @@ use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||
use tokio::net;
|
||||
use tokio::sync::mpsc;
|
||||
use vlogger::*;
|
||||
use shared::core::print_error_chain;
|
||||
use thiserror::*;
|
||||
|
||||
use crate::error::print_error_chain;
|
||||
use crate::log;
|
||||
|
||||
use super::Connection;
|
||||
use crate::bus::*;
|
||||
use crate::executor::ExecutorCommand;
|
||||
use crate::node::node;
|
||||
use crate::node::{NetworkError, error};
|
||||
use crate::protocol::ProtocolMessage;
|
||||
use thiserror::*;
|
||||
|
||||
pub enum ConnectorCommand {
|
||||
ConnectToTcpPeer(SocketAddr),
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use crate::core::{self, ChainData};
|
||||
use shared::core::{self, ChainData};
|
||||
use std::fmt;
|
||||
use std::net::SocketAddr;
|
||||
|
||||
|
||||
@ -1,26 +0,0 @@
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum RenderCommand {
|
||||
StringToPaneId {
|
||||
str: String,
|
||||
pane: RenderTarget,
|
||||
},
|
||||
StringToPaneFocused {
|
||||
str: String,
|
||||
},
|
||||
KeyInput(KeyCode),
|
||||
ListMove {
|
||||
pane: RenderTarget,
|
||||
index: usize,
|
||||
},
|
||||
ChangeLayout(RenderLayoutKind),
|
||||
ClearPane,
|
||||
|
||||
/// Mouse Events
|
||||
MouseClickLeft(u16, u16),
|
||||
MouseScrollUp,
|
||||
MouseScrollDown,
|
||||
|
||||
SetMode(InputMode),
|
||||
Exit,
|
||||
}
|
||||
|
||||
@ -1,93 +0,0 @@
|
||||
use ratatui::layout::{ Rect, Flex };
|
||||
use ratatui::prelude::*;
|
||||
|
||||
use super::{Pane, RenderBuffer, RenderTarget};
|
||||
|
||||
#[derive(Debug, Clone, clap::ValueEnum)]
|
||||
pub enum RenderLayoutKind {
|
||||
#[value(name = "horizontal", aliases = ["h"])]
|
||||
CliHorizontal,
|
||||
#[value(name = "vertical", aliases = ["v"])]
|
||||
CliVertical,
|
||||
}
|
||||
|
||||
const CLI_INPUT_PREFIX: &str = "> ";
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RenderLayout {
|
||||
layout: Layout,
|
||||
pub panes: Vec<Pane>,
|
||||
}
|
||||
|
||||
impl Widget for &mut RenderLayout {
|
||||
fn render(self, area: Rect, buffer: &mut Buffer) {
|
||||
let rects = self.rects(area);
|
||||
|
||||
for (p, r) in self.panes.iter_mut().zip(rects.iter()) {
|
||||
p.render(*r, buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn center(area: Rect, horizontal: Constraint, vertical: Constraint) -> Rect {
|
||||
let [area] = Layout::horizontal([horizontal])
|
||||
.flex(Flex::Center)
|
||||
.areas(area);
|
||||
let [area] = Layout::vertical([vertical]).flex(Flex::Center).areas(area);
|
||||
area
|
||||
}
|
||||
|
||||
impl RenderLayout {
|
||||
pub fn rects(&self, area: Rect) -> std::rc::Rc<[Rect]> {
|
||||
self.layout.split(area)
|
||||
}
|
||||
|
||||
pub fn generate(kind: RenderLayoutKind) -> RenderLayout {
|
||||
match kind {
|
||||
RenderLayoutKind::CliVertical => RenderLayout {
|
||||
layout: Layout::default()
|
||||
.constraints([Constraint::Percentage(70), Constraint::Percentage(30)]),
|
||||
panes: vec![
|
||||
Pane::new(
|
||||
Some(" Input Pane ".to_string()),
|
||||
RenderTarget::CliInput,
|
||||
RenderBuffer::List {
|
||||
list: vec![String::new()],
|
||||
index: 0,
|
||||
prefix: CLI_INPUT_PREFIX,
|
||||
},
|
||||
true,
|
||||
),
|
||||
Pane::new(
|
||||
Some(" Output Pane ".to_string()),
|
||||
RenderTarget::CliOutput,
|
||||
RenderBuffer::String(String::new()),
|
||||
false,
|
||||
),
|
||||
],
|
||||
},
|
||||
RenderLayoutKind::CliHorizontal => RenderLayout {
|
||||
layout: Layout::default()
|
||||
.constraints([Constraint::Percentage(70), Constraint::Percentage(30)]),
|
||||
panes: vec![
|
||||
Pane::new(
|
||||
Some(" Output Pane ".to_string()),
|
||||
RenderTarget::CliOutput,
|
||||
RenderBuffer::String(String::new()),
|
||||
false,
|
||||
),
|
||||
Pane::new(
|
||||
Some(" Input Pane ".to_string()),
|
||||
RenderTarget::CliInput,
|
||||
RenderBuffer::List {
|
||||
list: vec![String::new()],
|
||||
index: 0,
|
||||
prefix: CLI_INPUT_PREFIX,
|
||||
},
|
||||
true,
|
||||
),
|
||||
],
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4,11 +4,10 @@ use tokio::sync::mpsc;
|
||||
use vlogger::*;
|
||||
|
||||
use crate::bus::{NetworkEvent, SystemEvent, subscribe_system_event};
|
||||
use crate::core;
|
||||
use crate::executor::{Executor, ExecutorCommand};
|
||||
use crate::log;
|
||||
use crate::{log, node};
|
||||
use crate::node::{Node, NodeCommand};
|
||||
use crate::renderer::{RenderLayoutKind, Renderer};
|
||||
use cli_renderer::{RenderLayoutKind, Renderer};
|
||||
use crate::watcher::Watcher;
|
||||
|
||||
#[derive(Default)]
|
||||
@ -71,7 +70,7 @@ impl WatcherBuilder {
|
||||
self.addr = Some(crate::seeds_constants::SEED_NODES[0]);
|
||||
}
|
||||
|
||||
let chain = core::Blockchain::build(None).unwrap();
|
||||
let chain = node::Blockchain::build(None).unwrap();
|
||||
let mut node = Node::new(self.addr.clone(), exec_tx.clone(), chain);
|
||||
log(msg!(INFO, "Built Node"));
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::{executor::ExecutorCommand, renderer::RenderCommand};
|
||||
use cli_renderer::RenderCommand;
|
||||
use crate::executor::ExecutorCommand;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum WatcherCommand {
|
||||
|
||||
@ -1,9 +1,15 @@
|
||||
use crate::{bus::{publish_system_event, subscribe_system_event, SystemEvent}, cli::cli, error::print_error_chain, node::node::NodeCommand, watcher::WatcherMode};
|
||||
use crate::{
|
||||
bus::{publish_system_event, subscribe_system_event, SystemEvent},
|
||||
cli::cli,
|
||||
node::node::NodeCommand,
|
||||
watcher::WatcherMode
|
||||
};
|
||||
|
||||
use shared::core::print_error_chain;
|
||||
use crossterm::event::{Event, EventStream, KeyCode, KeyEventKind, MouseButton, MouseEventKind};
|
||||
use futures::StreamExt;
|
||||
use memory_stats::memory_stats;
|
||||
use ratatui::{layout::Rect, Terminal};
|
||||
use std::io::{self, Stdout, Write};
|
||||
use std::io::{self, Write};
|
||||
use tokio::{
|
||||
select,
|
||||
sync::mpsc,
|
||||
@ -17,7 +23,11 @@ use crate::bus::subscribe_watcher_event;
|
||||
use crate::executor::*;
|
||||
use crate::log;
|
||||
|
||||
use crate::renderer::*;
|
||||
use cli_renderer::{
|
||||
Renderer,
|
||||
InputMode,
|
||||
RenderCommand
|
||||
};
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct Watcher {
|
||||
@ -78,19 +88,17 @@ impl Watcher {
|
||||
)
|
||||
}
|
||||
|
||||
pub fn handle_cmd(&mut self, cmd: WatcherCommand, terminal: &mut Terminal<ratatui::backend::CrosstermBackend<Stdout>>) {
|
||||
pub fn handle_cmd(&mut self, cmd: WatcherCommand) {
|
||||
match cmd {
|
||||
WatcherCommand::Render(rend_cmd) => {
|
||||
let frame = terminal.get_frame();
|
||||
self.renderer.apply(rend_cmd, frame.area());
|
||||
self.renderer.apply(rend_cmd);
|
||||
}
|
||||
WatcherCommand::SetMode(mode) => {
|
||||
match &mode {
|
||||
WatcherMode::Input => {}
|
||||
WatcherMode::Select{content, title, ..} => {
|
||||
let rd_cmd = RenderCommand::SetMode(InputMode::PopUp(content.clone(), title.clone(), 0));
|
||||
let frame = terminal.get_frame();
|
||||
self.renderer.apply(rd_cmd, frame.area());
|
||||
self.renderer.apply(rd_cmd);
|
||||
}
|
||||
}
|
||||
self.mode = mode;
|
||||
@ -111,7 +119,8 @@ impl Watcher {
|
||||
poll_res = self.poll() => {
|
||||
match poll_res {
|
||||
Ok(event) => {
|
||||
match self.handle_event(event, terminal.get_frame().area()).await {
|
||||
self.renderer.set_area(terminal.get_frame().area());
|
||||
match self.handle_event(event).await {
|
||||
Ok(ret) => if !ret { self.exit(); break }
|
||||
Err(e) => log(msg!(ERROR, "{}", e)),
|
||||
}
|
||||
@ -122,7 +131,8 @@ impl Watcher {
|
||||
ui_event = ui_rx.recv() => {
|
||||
match ui_event {
|
||||
Ok(cmd) => {
|
||||
self.handle_cmd(cmd, &mut terminal);
|
||||
self.renderer.set_area(terminal.get_frame().area());
|
||||
self.handle_cmd(cmd);
|
||||
},
|
||||
Err(e) => {
|
||||
log(msg!(ERROR, "{}", e))
|
||||
@ -140,6 +150,7 @@ impl Watcher {
|
||||
}
|
||||
}
|
||||
_ = render_interval.tick() => {
|
||||
self.renderer.set_area(terminal.get_frame().area());
|
||||
terminal.draw(|frame| self.renderer.draw(frame))?;
|
||||
}
|
||||
}
|
||||
@ -183,7 +194,7 @@ impl Watcher {
|
||||
}
|
||||
self.mode = WatcherMode::Input;
|
||||
let rd_cmd = RenderCommand::SetMode(InputMode::Input);
|
||||
self.renderer.apply(rd_cmd, Rect::default());
|
||||
self.renderer.apply(rd_cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -251,7 +262,7 @@ impl Watcher {
|
||||
});
|
||||
}
|
||||
|
||||
pub async fn handle_event(&mut self, event: Event, area: Rect) -> io::Result<bool> {
|
||||
pub async fn handle_event(&mut self, event: Event) -> io::Result<bool> {
|
||||
match event {
|
||||
Event::Mouse(event) => match event.kind {
|
||||
MouseEventKind::ScrollUp => {
|
||||
@ -262,7 +273,7 @@ impl Watcher {
|
||||
}
|
||||
MouseEventKind::Down(b) => match b {
|
||||
MouseButton::Left => {
|
||||
let rects = self.renderer.rects(area);
|
||||
let rects = self.renderer.rects();
|
||||
self
|
||||
.renderer
|
||||
.handle_mouse_click_left(event.column, event.row, rects);
|
||||
|
||||
620
shared/Cargo.lock
generated
Normal file
620
shared/Cargo.lock
generated
Normal file
@ -0,0 +1,620 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ae563653d1938f79b1ab1b5e668c87c76a9930414574a6583a7b7e11a8e6192"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
"anstyle-query",
|
||||
"anstyle-wincon",
|
||||
"colorchoice",
|
||||
"is_terminal_polyfill",
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"once_cell_polyfill",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740"
|
||||
dependencies = [
|
||||
"bincode_derive",
|
||||
"serde",
|
||||
"unty",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bincode_derive"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf95709a440f45e986983918d0e8a1f30a9b1df04918fc828670606804ac3c09"
|
||||
dependencies = [
|
||||
"virtue",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitcoin-io"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b47c4ab7a93edb0c7198c5535ed9b52b63095f4e9b45279c6736cec4b856baf"
|
||||
|
||||
[[package]]
|
||||
name = "bitcoin_hashes"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16"
|
||||
dependencies = [
|
||||
"bitcoin-io",
|
||||
"hex-conservative",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "590f9024a68a8c40351881787f1934dc11afd69090f5edb6831464694d836ea3"
|
||||
dependencies = [
|
||||
"find-msvc-tools",
|
||||
"shlex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.47"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7eac00902d9d136acd712710d71823fb8ac8004ca445a89e73a41d45aa712931"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.47"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2ad9bbf750e73b5884fb8a211a9424a1906c1e156724260fdae972f31d70e1d6"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
"strsim",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.5.47"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbfd7eae0b0f1a6e63d4b13c9c478de77c2eb546fba158ad50b4203dc24b9f9c"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"crypto-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "find-msvc-tools"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e178e4fba8a2726903f6ba98a6d221e76f9c12c650d5dc0e6afdc50677b49650"
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"r-efi",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||
|
||||
[[package]]
|
||||
name = "hex-conservative"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.175"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell_polyfill"
|
||||
version = "1.70.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
|
||||
dependencies = [
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.101"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "r-efi"
|
||||
version = "5.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
|
||||
dependencies = [
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
|
||||
|
||||
[[package]]
|
||||
name = "secp256k1"
|
||||
version = "0.31.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c3c81b43dc2d8877c216a3fccf76677ee1ebccd429566d3e67447290d0c42b2"
|
||||
dependencies = [
|
||||
"bitcoin_hashes",
|
||||
"rand",
|
||||
"secp256k1-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "secp256k1-sys"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dcb913707158fadaf0d8702c2db0e857de66eb003ccfdda5924b5f5ac98efb38"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.219"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.219"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.143"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shared"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
"clap",
|
||||
"hex",
|
||||
"secp256k1",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "2.0.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
|
||||
|
||||
[[package]]
|
||||
name = "unty"
|
||||
version = "0.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "virtue"
|
||||
version = "0.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.14.3+wasi-0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a51ae83037bdd272a9e28ce236db8c07016dd0d50c27038b3f407533c030c95"
|
||||
dependencies = [
|
||||
"wit-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.60.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.53.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.53.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.53.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.53.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.53.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.53.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.53.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.53.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.53.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen"
|
||||
version = "0.45.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "052283831dbae3d879dc7f51f3d92703a316ca49f91540417d38591826127814"
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.8.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.8.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
21
shared/Cargo.toml
Normal file
21
shared/Cargo.toml
Normal file
@ -0,0 +1,21 @@
|
||||
[package]
|
||||
name = "shared"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
node = []
|
||||
client = []
|
||||
full = ["node", "client"]
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.99"
|
||||
bincode = "2.0.1"
|
||||
clap = { version = "4.5.47", features = ["derive"] }
|
||||
hex = "0.4.3"
|
||||
secp256k1 = { version = "0.31.1", features = ["rand"] }
|
||||
serde = { version = "1.0.219", features = ["derive"] }
|
||||
serde_json = "1.0.143"
|
||||
sha2 = "0.10.9"
|
||||
thiserror = "2.0.16"
|
||||
1
shared/src/core/address.rs
Normal file
1
shared/src/core/address.rs
Normal file
@ -0,0 +1 @@
|
||||
pub type Address = String;
|
||||
@ -1,5 +1,7 @@
|
||||
use crate::error::TxError;
|
||||
use super::{ Address, Account};
|
||||
use super::Address;
|
||||
use crate::log;
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
//use secp256k1::{
|
||||
// ecdsa::{RecoveryId, Signature},
|
||||
@ -8,6 +10,36 @@ use super::{ Address, Account};
|
||||
//
|
||||
//use ring::digest;
|
||||
//
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Error, Debug)]
|
||||
pub enum TxError {
|
||||
#[error("from field is empty")]
|
||||
FromEmpty,
|
||||
#[error("to field is empty")]
|
||||
ToEmpty,
|
||||
#[error("insuffitient fonds")]
|
||||
FromInsuffitientFonds,
|
||||
#[error("0 value transaction")]
|
||||
ValueEmpty,
|
||||
#[error("account {0} not found in database")]
|
||||
UnknownAccount(String),
|
||||
}
|
||||
|
||||
pub fn print_error_chain(err: &anyhow::Error) {
|
||||
let mut err_string = String::from(format!("Error: {}\n", err));
|
||||
|
||||
let mut source = err.source();
|
||||
let mut level = 1;
|
||||
|
||||
while let Some(err) = source {
|
||||
err_string.push_str(format!(" {}: {}\n", level, err).as_str());
|
||||
source = err.source();
|
||||
level += 1;
|
||||
}
|
||||
log(err_string)
|
||||
}
|
||||
|
||||
#[derive(
|
||||
serde::Deserialize, serde::Serialize, Debug, clap::Args, Clone, bincode::Encode, bincode::Decode,
|
||||
)]
|
||||
@ -21,13 +53,13 @@ pub struct Tx {
|
||||
}
|
||||
|
||||
impl Tx {
|
||||
pub fn new(from: &Account, to: Address, value: u64, data: String) -> Self {
|
||||
pub fn new(from: Address, to: Address, value: u64, nonce: u64, data: String) -> Self {
|
||||
Self {
|
||||
from: from.address().to_string(),
|
||||
from,
|
||||
to,
|
||||
value,
|
||||
data,
|
||||
nonce: from.nonce() + 1,
|
||||
nonce,
|
||||
signature: vec![],
|
||||
}
|
||||
}
|
||||
20
shared/src/lib.rs
Normal file
20
shared/src/lib.rs
Normal file
@ -0,0 +1,20 @@
|
||||
pub mod core {
|
||||
pub mod block;
|
||||
pub use block::*;
|
||||
|
||||
pub mod tx;
|
||||
pub use tx::*;
|
||||
|
||||
pub mod data;
|
||||
pub use data::*;
|
||||
|
||||
pub mod hasher;
|
||||
pub use hasher::*;
|
||||
|
||||
pub mod address;
|
||||
pub use address::*;
|
||||
}
|
||||
|
||||
pub fn log(msg: String) {
|
||||
println!("{msg}")
|
||||
}
|
||||
0
shared/src/utils.rs
Normal file
0
shared/src/utils.rs
Normal file
3344
wallet/Cargo.lock
generated
3344
wallet/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -3,9 +3,235 @@ name = "wallet"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
targets = ["x86_64-unknown-linux-gnu", "wasm32-unknown-unknown"]
|
||||
|
||||
[dependencies]
|
||||
crossterm = "0.29.0"
|
||||
ratatui = "0.29.0"
|
||||
ws = "0.9.2"
|
||||
vlogger = { path = "../lib/logger-rs" }
|
||||
clap = { version = "4.5.47", features = ["derive"] }
|
||||
egui = "0.32"
|
||||
eframe = { version = "0.32", default-features = false, features = [
|
||||
"accesskit", # Make egui compatible with screen readers. NOTE: adds a lot of dependencies.
|
||||
"default_fonts", # Embed the default egui fonts.
|
||||
"glow", # Use the glow rendering backend. Alternative: "wgpu".
|
||||
"persistence", # Enable restoring app state when restarting the app.
|
||||
"wayland", # To support Linux (and CI)
|
||||
"x11", # To support older Linux distributions (restores one of the default features)
|
||||
] }
|
||||
log = "0.4.27"
|
||||
|
||||
# You only need serde if you want app persistence:
|
||||
serde = { version = "1.0.219", features = ["derive"] }
|
||||
|
||||
# native:
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
env_logger = "0.11.8"
|
||||
|
||||
# web:
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
wasm-bindgen-futures = "0.4.50"
|
||||
web-sys = "0.3.70" # to access the DOM (to hide the loading text)
|
||||
|
||||
[profile.release]
|
||||
opt-level = 2 # fast and small wasm
|
||||
|
||||
# Optimize all dependencies even in debug builds:
|
||||
[profile.dev.package."*"]
|
||||
opt-level = 2
|
||||
|
||||
|
||||
[patch.crates-io]
|
||||
|
||||
# If you want to use the bleeding edge version of egui and eframe:
|
||||
# egui = { git = "https://github.com/emilk/egui", branch = "main" }
|
||||
# eframe = { git = "https://github.com/emilk/egui", branch = "main" }
|
||||
|
||||
# If you fork https://github.com/emilk/egui you can test with:
|
||||
# egui = { path = "../egui/crates/egui" }
|
||||
# eframe = { path = "../egui/crates/eframe" }
|
||||
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------------------
|
||||
# Lints:
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[workspace.lints.rust]
|
||||
unsafe_code = "deny"
|
||||
|
||||
elided_lifetimes_in_paths = "warn"
|
||||
future_incompatible = { level = "warn", priority = -1 }
|
||||
nonstandard_style = { level = "warn", priority = -1 }
|
||||
rust_2018_idioms = { level = "warn", priority = -1 }
|
||||
rust_2021_prelude_collisions = "warn"
|
||||
semicolon_in_expressions_from_macros = "warn"
|
||||
trivial_numeric_casts = "warn"
|
||||
unsafe_op_in_unsafe_fn = "warn" # `unsafe_op_in_unsafe_fn` may become the default in future Rust versions: https://github.com/rust-lang/rust/issues/71668
|
||||
unused_extern_crates = "warn"
|
||||
unused_import_braces = "warn"
|
||||
unused_lifetimes = "warn"
|
||||
|
||||
trivial_casts = "allow"
|
||||
unused_qualifications = "allow"
|
||||
|
||||
|
||||
[workspace.lints.rustdoc]
|
||||
all = "warn"
|
||||
missing_crate_level_docs = "warn"
|
||||
|
||||
|
||||
[workspace.lints.clippy]
|
||||
allow_attributes = "warn"
|
||||
as_ptr_cast_mut = "warn"
|
||||
await_holding_lock = "warn"
|
||||
bool_to_int_with_if = "warn"
|
||||
char_lit_as_u8 = "warn"
|
||||
checked_conversions = "warn"
|
||||
clear_with_drain = "warn"
|
||||
cloned_instead_of_copied = "warn"
|
||||
dbg_macro = "warn"
|
||||
debug_assert_with_mut_call = "warn"
|
||||
derive_partial_eq_without_eq = "warn"
|
||||
disallowed_macros = "warn" # See clippy.toml
|
||||
disallowed_methods = "warn" # See clippy.toml
|
||||
disallowed_names = "warn" # See clippy.toml
|
||||
disallowed_script_idents = "warn" # See clippy.toml
|
||||
disallowed_types = "warn" # See clippy.toml
|
||||
doc_include_without_cfg = "warn"
|
||||
doc_link_with_quotes = "warn"
|
||||
doc_markdown = "warn"
|
||||
empty_enum = "warn"
|
||||
empty_enum_variants_with_brackets = "warn"
|
||||
enum_glob_use = "warn"
|
||||
equatable_if_let = "warn"
|
||||
exit = "warn"
|
||||
expl_impl_clone_on_copy = "warn"
|
||||
explicit_deref_methods = "warn"
|
||||
explicit_into_iter_loop = "warn"
|
||||
explicit_iter_loop = "warn"
|
||||
fallible_impl_from = "warn"
|
||||
filter_map_next = "warn"
|
||||
flat_map_option = "warn"
|
||||
float_cmp_const = "warn"
|
||||
fn_params_excessive_bools = "warn"
|
||||
fn_to_numeric_cast_any = "warn"
|
||||
from_iter_instead_of_collect = "warn"
|
||||
get_unwrap = "warn"
|
||||
implicit_clone = "warn"
|
||||
imprecise_flops = "warn"
|
||||
index_refutable_slice = "warn"
|
||||
inefficient_to_string = "warn"
|
||||
infinite_loop = "warn"
|
||||
into_iter_without_iter = "warn"
|
||||
invalid_upcast_comparisons = "warn"
|
||||
iter_filter_is_ok = "warn"
|
||||
iter_filter_is_some = "warn"
|
||||
iter_not_returning_iterator = "warn"
|
||||
iter_on_empty_collections = "warn"
|
||||
iter_on_single_items = "warn"
|
||||
iter_over_hash_type = "warn"
|
||||
iter_without_into_iter = "warn"
|
||||
large_digit_groups = "warn"
|
||||
large_include_file = "warn"
|
||||
large_stack_arrays = "warn"
|
||||
large_stack_frames = "warn"
|
||||
large_types_passed_by_value = "warn"
|
||||
let_underscore_must_use = "warn"
|
||||
let_underscore_untyped = "warn"
|
||||
let_unit_value = "warn"
|
||||
linkedlist = "warn"
|
||||
literal_string_with_formatting_args = "warn"
|
||||
lossy_float_literal = "warn"
|
||||
macro_use_imports = "warn"
|
||||
manual_assert = "warn"
|
||||
manual_clamp = "warn"
|
||||
manual_instant_elapsed = "warn"
|
||||
manual_is_power_of_two = "warn"
|
||||
manual_is_variant_and = "warn"
|
||||
manual_let_else = "warn"
|
||||
manual_ok_or = "warn"
|
||||
manual_string_new = "warn"
|
||||
map_err_ignore = "warn"
|
||||
map_flatten = "warn"
|
||||
match_bool = "warn"
|
||||
match_on_vec_items = "warn"
|
||||
match_same_arms = "warn"
|
||||
match_wild_err_arm = "warn"
|
||||
match_wildcard_for_single_variants = "warn"
|
||||
mem_forget = "warn"
|
||||
mismatching_type_param_order = "warn"
|
||||
missing_assert_message = "warn"
|
||||
missing_enforced_import_renames = "warn"
|
||||
missing_safety_doc = "warn"
|
||||
mixed_attributes_style = "warn"
|
||||
mut_mut = "warn"
|
||||
mutex_integer = "warn"
|
||||
needless_borrow = "warn"
|
||||
needless_continue = "warn"
|
||||
needless_for_each = "warn"
|
||||
needless_pass_by_ref_mut = "warn"
|
||||
needless_pass_by_value = "warn"
|
||||
negative_feature_names = "warn"
|
||||
non_zero_suggestions = "warn"
|
||||
nonstandard_macro_braces = "warn"
|
||||
option_as_ref_cloned = "warn"
|
||||
option_option = "warn"
|
||||
path_buf_push_overwrite = "warn"
|
||||
pathbuf_init_then_push = "warn"
|
||||
ptr_as_ptr = "warn"
|
||||
ptr_cast_constness = "warn"
|
||||
pub_underscore_fields = "warn"
|
||||
pub_without_shorthand = "warn"
|
||||
rc_mutex = "warn"
|
||||
readonly_write_lock = "warn"
|
||||
redundant_type_annotations = "warn"
|
||||
ref_as_ptr = "warn"
|
||||
ref_option_ref = "warn"
|
||||
rest_pat_in_fully_bound_structs = "warn"
|
||||
same_functions_in_if_condition = "warn"
|
||||
semicolon_if_nothing_returned = "warn"
|
||||
set_contains_or_insert = "warn"
|
||||
should_panic_without_expect = "warn"
|
||||
single_char_pattern = "warn"
|
||||
single_match_else = "warn"
|
||||
str_split_at_newline = "warn"
|
||||
str_to_string = "warn"
|
||||
string_add = "warn"
|
||||
string_add_assign = "warn"
|
||||
string_lit_as_bytes = "warn"
|
||||
string_lit_chars_any = "warn"
|
||||
string_to_string = "warn"
|
||||
suspicious_command_arg_space = "warn"
|
||||
suspicious_xor_used_as_pow = "warn"
|
||||
todo = "warn"
|
||||
too_long_first_doc_paragraph = "warn"
|
||||
too_many_lines = "warn"
|
||||
trailing_empty_array = "warn"
|
||||
trait_duplication_in_bounds = "warn"
|
||||
tuple_array_conversions = "warn"
|
||||
unchecked_duration_subtraction = "warn"
|
||||
undocumented_unsafe_blocks = "warn"
|
||||
unimplemented = "warn"
|
||||
uninhabited_references = "warn"
|
||||
uninlined_format_args = "warn"
|
||||
unnecessary_box_returns = "warn"
|
||||
unnecessary_literal_bound = "warn"
|
||||
unnecessary_safety_doc = "warn"
|
||||
unnecessary_struct_initialization = "warn"
|
||||
unnecessary_wraps = "warn"
|
||||
unnested_or_patterns = "warn"
|
||||
unused_peekable = "warn"
|
||||
unused_rounding = "warn"
|
||||
unused_self = "warn"
|
||||
unused_trait_names = "warn"
|
||||
unwrap_used = "warn"
|
||||
use_self = "warn"
|
||||
useless_transmute = "warn"
|
||||
verbose_file_reads = "warn"
|
||||
wildcard_dependencies = "warn"
|
||||
wildcard_imports = "warn"
|
||||
zero_sized_map_values = "warn"
|
||||
|
||||
manual_range_contains = "allow" # this is better on 'allow'
|
||||
map_unwrap_or = "allow" # this is better on 'allow'
|
||||
|
||||
151
wallet/dist/index.html
vendored
Normal file
151
wallet/dist/index.html
vendored
Normal file
@ -0,0 +1,151 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>My App</title>
|
||||
|
||||
<script type="module">
|
||||
import init, * as bindings from '/wallet-5d1b8085460fdcf6.js';
|
||||
const wasm = await init({ module_or_path: '/wallet-5d1b8085460fdcf6_bg.wasm' });
|
||||
|
||||
|
||||
window.wasmBindings = bindings;
|
||||
|
||||
|
||||
dispatchEvent(new CustomEvent("TrunkApplicationStarted", {detail: {wasm}}));
|
||||
|
||||
</script>
|
||||
<link rel="modulepreload" href="/wallet-5d1b8085460fdcf6.js" crossorigin="anonymous" integrity="sha384-phKOKZTFYPix/VFiKjin1txUn2nxtPk30fPdrro5PTdkGPq/+5dP1m7tONQ21dTf"><link rel="preload" href="/wallet-5d1b8085460fdcf6_bg.wasm" crossorigin="anonymous" integrity="sha384-gEKa9S/QlWrheWFbm/lNELMj8L9QLKbE4RYtCB9dU2Jl3Y4OvRmehoHMdNb7JceO" as="fetch" type="application/wasm"></head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script>"use strict";
|
||||
|
||||
(function () {
|
||||
|
||||
const address = '{{__TRUNK_ADDRESS__}}';
|
||||
const base = '{{__TRUNK_WS_BASE__}}';
|
||||
let protocol = '';
|
||||
protocol =
|
||||
protocol
|
||||
? protocol
|
||||
: window.location.protocol === 'https:'
|
||||
? 'wss'
|
||||
: 'ws';
|
||||
const url = protocol + '://' + address + base + '.well-known/trunk/ws';
|
||||
|
||||
class Overlay {
|
||||
constructor() {
|
||||
// create an overlay
|
||||
this._overlay = document.createElement("div");
|
||||
const style = this._overlay.style;
|
||||
style.height = "100vh";
|
||||
style.width = "100vw";
|
||||
style.position = "fixed";
|
||||
style.top = "0";
|
||||
style.left = "0";
|
||||
style.backgroundColor = "rgba(222, 222, 222, 0.5)";
|
||||
style.fontFamily = "sans-serif";
|
||||
// not sure that's the right approach
|
||||
style.zIndex = "1000000";
|
||||
style.backdropFilter = "blur(1rem)";
|
||||
|
||||
const container = document.createElement("div");
|
||||
// center it
|
||||
container.style.position = "absolute";
|
||||
container.style.top = "30%";
|
||||
container.style.left = "15%";
|
||||
container.style.maxWidth = "85%";
|
||||
|
||||
this._title = document.createElement("div");
|
||||
this._title.innerText = "Build failure";
|
||||
this._title.style.paddingBottom = "2rem";
|
||||
this._title.style.fontSize = "2.5rem";
|
||||
|
||||
this._message = document.createElement("div");
|
||||
this._message.style.whiteSpace = "pre-wrap";
|
||||
|
||||
const icon= document.createElement("div");
|
||||
icon.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" fill="#dc3545" viewBox="0 0 16 16"><path d="M8.982 1.566a1.13 1.13 0 0 0-1.96 0L.165 13.233c-.457.778.091 1.767.98 1.767h13.713c.889 0 1.438-.99.98-1.767L8.982 1.566zM8 5c.535 0 .954.462.9.995l-.35 3.507a.552.552 0 0 1-1.1 0L7.1 5.995A.905.905 0 0 1 8 5zm.002 6a1 1 0 1 1 0 2 1 1 0 0 1 0-2z"/></svg>';
|
||||
this._title.prepend(icon);
|
||||
|
||||
container.append(this._title, this._message);
|
||||
this._overlay.append(container);
|
||||
|
||||
this._inject();
|
||||
window.setInterval(() => {
|
||||
this._inject();
|
||||
}, 250);
|
||||
}
|
||||
|
||||
set reason(reason) {
|
||||
this._message.textContent = reason;
|
||||
}
|
||||
|
||||
_inject() {
|
||||
if (!this._overlay.isConnected) {
|
||||
// prepend it
|
||||
document.body?.prepend(this._overlay);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Client {
|
||||
constructor(url) {
|
||||
this.url = url;
|
||||
this.poll_interval = 5000;
|
||||
this._overlay = null;
|
||||
}
|
||||
|
||||
start() {
|
||||
const ws = new WebSocket(this.url);
|
||||
ws.onmessage = (ev) => {
|
||||
const msg = JSON.parse(ev.data);
|
||||
switch (msg.type) {
|
||||
case "reload":
|
||||
this.reload();
|
||||
break;
|
||||
case "buildFailure":
|
||||
this.buildFailure(msg.data)
|
||||
break;
|
||||
}
|
||||
};
|
||||
ws.onclose = () => this.onclose();
|
||||
}
|
||||
|
||||
onclose() {
|
||||
window.setTimeout(
|
||||
() => {
|
||||
// when we successfully reconnect, we'll force a
|
||||
// reload (since we presumably lost connection to
|
||||
// trunk due to it being killed, so it will have
|
||||
// rebuilt on restart)
|
||||
const ws = new WebSocket(this.url);
|
||||
ws.onopen = () => window.location.reload();
|
||||
ws.onclose = () => this.onclose();
|
||||
},
|
||||
this.poll_interval);
|
||||
}
|
||||
|
||||
reload() {
|
||||
window.location.reload();
|
||||
}
|
||||
|
||||
buildFailure({reason}) {
|
||||
// also log the console
|
||||
console.error("Build failed:", reason);
|
||||
|
||||
console.debug("Overlay", this._overlay);
|
||||
|
||||
if (!this._overlay) {
|
||||
this._overlay = new Overlay();
|
||||
}
|
||||
this._overlay.reason = reason;
|
||||
}
|
||||
}
|
||||
|
||||
new Client(url).start();
|
||||
|
||||
})()
|
||||
</script></body>
|
||||
</html>
|
||||
1578
wallet/dist/wallet-5d1b8085460fdcf6.js
vendored
Normal file
1578
wallet/dist/wallet-5d1b8085460fdcf6.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
BIN
wallet/dist/wallet-5d1b8085460fdcf6_bg.wasm
vendored
Normal file
BIN
wallet/dist/wallet-5d1b8085460fdcf6_bg.wasm
vendored
Normal file
Binary file not shown.
11
wallet/index.html
Normal file
11
wallet/index.html
Normal file
@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>My App</title>
|
||||
<link data-trunk rel="rust" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
</body>
|
||||
</html>
|
||||
50
wallet/src/account.rs
Normal file
50
wallet/src/account.rs
Normal file
@ -0,0 +1,50 @@
|
||||
// use sha2::{Sha256, Digest};
|
||||
// use secp256k1::rand;
|
||||
// use secp256k1::{Secp256k1, PublicKey, SecretKey};
|
||||
// use shared::core::Address;
|
||||
//
|
||||
// #[derive(Debug)]
|
||||
// pub struct Account {
|
||||
// address: Address,
|
||||
// balance: u64,
|
||||
// nonce: u64,
|
||||
// }
|
||||
//
|
||||
// impl Account {
|
||||
// pub fn public_key_to_address(public_key: &PublicKey) -> Address {
|
||||
// let pk_ser = public_key.serialize();
|
||||
// let hash = Sha256::digest(&pk_ser);
|
||||
// hex::encode(&hash[..20])
|
||||
// }
|
||||
//
|
||||
// pub fn nonce(&self) -> u64 {
|
||||
// self.nonce
|
||||
// }
|
||||
//
|
||||
// pub fn balance(&self) -> u64 {
|
||||
// self.balance
|
||||
// }
|
||||
//
|
||||
// pub fn address(&self) -> &Address {
|
||||
// &self.address
|
||||
// }
|
||||
//
|
||||
// pub fn new() -> Self {
|
||||
// let secp = Secp256k1::new();
|
||||
// let (secret_key, public_key) = secp.generate_keypair(&mut rand::rng());
|
||||
// let addr = Self::public_key_to_address(&public_key);
|
||||
//
|
||||
// println!("{:?}", secret_key);
|
||||
//
|
||||
// Self {
|
||||
// address: addr,
|
||||
// balance: 0,
|
||||
// nonce: 0,
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn test_acc_new() {
|
||||
// Account::new();
|
||||
// }
|
||||
109
wallet/src/app.rs
Normal file
109
wallet/src/app.rs
Normal file
@ -0,0 +1,109 @@
|
||||
/// We derive Deserialize/Serialize so we can persist app state on shutdown.
|
||||
#[derive(serde::Deserialize, serde::Serialize)]
|
||||
#[serde(default)] // if we add new fields, give them default values when deserializing old state
|
||||
pub struct TemplateApp {
|
||||
// Example stuff:
|
||||
label: String,
|
||||
|
||||
#[serde(skip)] // This how you opt-out of serialization of a field
|
||||
value: f32,
|
||||
}
|
||||
|
||||
impl Default for TemplateApp {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
// Example stuff:
|
||||
label: "Hello World!".to_owned(),
|
||||
value: 2.7,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TemplateApp {
|
||||
/// Called once before the first frame.
|
||||
pub fn new(cc: &eframe::CreationContext<'_>) -> Self {
|
||||
// This is also where you can customize the look and feel of egui using
|
||||
// `cc.egui_ctx.set_visuals` and `cc.egui_ctx.set_fonts`.
|
||||
|
||||
// Load previous app state (if any).
|
||||
// Note that you must enable the `persistence` feature for this to work.
|
||||
if let Some(storage) = cc.storage {
|
||||
eframe::get_value(storage, eframe::APP_KEY).unwrap_or_default()
|
||||
} else {
|
||||
Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl eframe::App for TemplateApp {
|
||||
/// Called by the framework to save state before shutdown.
|
||||
fn save(&mut self, storage: &mut dyn eframe::Storage) {
|
||||
eframe::set_value(storage, eframe::APP_KEY, self);
|
||||
}
|
||||
|
||||
/// Called each time the UI needs repainting, which may be many times per second.
|
||||
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||
// Put your widgets into a `SidePanel`, `TopBottomPanel`, `CentralPanel`, `Window` or `Area`.
|
||||
// For inspiration and more examples, go to https://emilk.github.io/egui
|
||||
|
||||
egui::TopBottomPanel::top("top_panel").show(ctx, |ui| {
|
||||
// The top panel is often a good place for a menu bar:
|
||||
|
||||
egui::MenuBar::new().ui(ui, |ui| {
|
||||
// NOTE: no File->Quit on web pages!
|
||||
let is_web = cfg!(target_arch = "wasm32");
|
||||
if !is_web {
|
||||
ui.menu_button("File", |ui| {
|
||||
if ui.button("Quit").clicked() {
|
||||
ctx.send_viewport_cmd(egui::ViewportCommand::Close);
|
||||
}
|
||||
});
|
||||
ui.add_space(16.0);
|
||||
}
|
||||
|
||||
egui::widgets::global_theme_preference_buttons(ui);
|
||||
});
|
||||
});
|
||||
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
// The central panel the region left after adding TopPanel's and SidePanel's
|
||||
ui.heading("eframe template");
|
||||
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Write something: ");
|
||||
ui.text_edit_singleline(&mut self.label);
|
||||
});
|
||||
|
||||
ui.add(egui::Slider::new(&mut self.value, 0.0..=10.0).text("value"));
|
||||
if ui.button("Increment").clicked() {
|
||||
self.value += 1.0;
|
||||
}
|
||||
|
||||
ui.separator();
|
||||
|
||||
ui.add(egui::github_link_file!(
|
||||
"https://github.com/emilk/eframe_template/blob/main/",
|
||||
"Source code."
|
||||
));
|
||||
|
||||
ui.with_layout(egui::Layout::bottom_up(egui::Align::LEFT), |ui| {
|
||||
powered_by_egui_and_eframe(ui);
|
||||
egui::warn_if_debug_build(ui);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn powered_by_egui_and_eframe(ui: &mut egui::Ui) {
|
||||
ui.horizontal(|ui| {
|
||||
ui.spacing_mut().item_spacing.x = 0.0;
|
||||
ui.label("Powered by ");
|
||||
ui.hyperlink_to("egui", "https://github.com/emilk/egui");
|
||||
ui.label(" and ");
|
||||
ui.hyperlink_to(
|
||||
"eframe",
|
||||
"https://github.com/emilk/egui/tree/master/crates/eframe",
|
||||
);
|
||||
ui.label(".");
|
||||
});
|
||||
}
|
||||
@ -1,13 +1,2 @@
|
||||
pub mod renderer {
|
||||
pub mod renderer;
|
||||
pub use renderer::*;
|
||||
|
||||
pub mod pane;
|
||||
pub use pane::*;
|
||||
|
||||
pub mod layout;
|
||||
pub use layout::*;
|
||||
|
||||
pub mod command;
|
||||
pub use command::*;
|
||||
}
|
||||
mod app;
|
||||
pub use app::TemplateApp;
|
||||
|
||||
@ -1,3 +1,72 @@
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
#![warn(clippy::all, rust_2018_idioms)]
|
||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
||||
|
||||
// When compiling natively:
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
fn main() -> eframe::Result {
|
||||
env_logger::init(); // Log to stderr (if you run with `RUST_LOG=debug`).
|
||||
|
||||
let native_options = eframe::NativeOptions {
|
||||
viewport: egui::ViewportBuilder::default()
|
||||
.with_inner_size([400.0, 300.0])
|
||||
.with_min_inner_size([300.0, 220.0])
|
||||
.with_icon(
|
||||
// NOTE: Adding an icon is optional
|
||||
eframe::icon_data::from_png_bytes(&include_bytes!("../assets/icon-256.png")[..])
|
||||
.expect("Failed to load icon"),
|
||||
),
|
||||
..Default::default()
|
||||
};
|
||||
eframe::run_native(
|
||||
"eframe template",
|
||||
native_options,
|
||||
Box::new(|cc| Ok(Box::new(wallet::TemplateApp::new(cc)))),
|
||||
)
|
||||
}
|
||||
|
||||
// When compiling to web using trunk:
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
fn main() {
|
||||
use eframe::wasm_bindgen::JsCast as _;
|
||||
|
||||
// Redirect `log` message to `console.log` and friends:
|
||||
eframe::WebLogger::init(log::LevelFilter::Debug).ok();
|
||||
|
||||
let web_options = eframe::WebOptions::default();
|
||||
|
||||
wasm_bindgen_futures::spawn_local(async {
|
||||
let document = web_sys::window()
|
||||
.expect("No window")
|
||||
.document()
|
||||
.expect("No document");
|
||||
|
||||
let canvas = document
|
||||
.get_element_by_id("the_canvas_id")
|
||||
.expect("Failed to find the_canvas_id")
|
||||
.dyn_into::<web_sys::HtmlCanvasElement>()
|
||||
.expect("the_canvas_id was not a HtmlCanvasElement");
|
||||
|
||||
let start_result = eframe::WebRunner::new()
|
||||
.start(
|
||||
canvas,
|
||||
web_options,
|
||||
Box::new(|cc| Ok(Box::new(wallet::TemplateApp::new(cc)))),
|
||||
)
|
||||
.await;
|
||||
|
||||
// Remove the loading text and spinner:
|
||||
if let Some(loading_text) = document.get_element_by_id("loading_text") {
|
||||
match start_result {
|
||||
Ok(_) => {
|
||||
loading_text.remove();
|
||||
}
|
||||
Err(e) => {
|
||||
loading_text.set_inner_html(
|
||||
"<p> The app has crashed. See the developer console for details. </p>",
|
||||
);
|
||||
panic!("Failed to start eframe: {e:?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -1,168 +0,0 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use ratatui::prelude::*;
|
||||
use ratatui::widgets::{Clear, Wrap};
|
||||
use ratatui::{
|
||||
buffer::Buffer,
|
||||
layout::Rect,
|
||||
symbols::border,
|
||||
widgets::{Block, List, Paragraph, Widget},
|
||||
};
|
||||
|
||||
use super::center;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum RenderBuffer {
|
||||
List {
|
||||
list: Vec<String>,
|
||||
index: usize,
|
||||
prefix: &'static str,
|
||||
},
|
||||
String(String),
|
||||
Select(Arc<Vec<String>>, usize),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum RenderTarget {
|
||||
All,
|
||||
|
||||
CliInput,
|
||||
|
||||
CliOutput,
|
||||
|
||||
PopUp
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Pane {
|
||||
pub title: Option<String>,
|
||||
pub target: RenderTarget,
|
||||
pub buffer: RenderBuffer,
|
||||
pub focused: bool,
|
||||
pub scroll: i16,
|
||||
pub max_scroll: i16,
|
||||
}
|
||||
|
||||
impl Pane {
|
||||
pub fn new(
|
||||
title: Option<String>,
|
||||
target: RenderTarget,
|
||||
buffer: RenderBuffer,
|
||||
focused: bool,
|
||||
) -> Self {
|
||||
Self {
|
||||
title,
|
||||
target,
|
||||
buffer,
|
||||
focused,
|
||||
scroll: 0,
|
||||
max_scroll: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Widget for &mut Pane {
|
||||
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||
let block = Block::bordered()
|
||||
.title({
|
||||
if let Some(t) = &self.title {
|
||||
t.clone()
|
||||
} else {
|
||||
Default::default()
|
||||
}
|
||||
})
|
||||
.border_set(border::PLAIN)
|
||||
.border_style({
|
||||
if self.focused {
|
||||
Style::new().green()
|
||||
} else {
|
||||
Style::new().white()
|
||||
}
|
||||
});
|
||||
let inner_area = block.inner(area);
|
||||
let content_width = inner_area.width as usize;
|
||||
let content_height = inner_area.height as usize;
|
||||
match &self.buffer {
|
||||
RenderBuffer::String(s) => {
|
||||
let wrapped_lines = s
|
||||
.lines()
|
||||
.map(|line| {
|
||||
if line.is_empty() {
|
||||
1
|
||||
} else {
|
||||
(line.len() + content_width - 1) / { content_width + (content_width == 0) as usize }
|
||||
}
|
||||
})
|
||||
.sum::<usize>();
|
||||
|
||||
self.max_scroll = if wrapped_lines > content_height {
|
||||
(wrapped_lines - content_height) as i16
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
let scroll_offset = self.max_scroll.saturating_sub(self.scroll) as u16;
|
||||
|
||||
Paragraph::new(s.clone())
|
||||
.wrap(Wrap::default())
|
||||
.left_aligned()
|
||||
.block(block)
|
||||
.scroll((scroll_offset as u16, 0))
|
||||
.render(area, buf);
|
||||
}
|
||||
RenderBuffer::Select(list, idx) => {
|
||||
let rect = center(area, Constraint::Percentage(60), Constraint::Percentage(60));
|
||||
Clear.render(rect, buf);
|
||||
self.max_scroll = if list.len() > content_height {
|
||||
(list.len() - content_height) as i16
|
||||
} else {
|
||||
0
|
||||
};
|
||||
let scroll_offset = self.max_scroll.saturating_sub(self.scroll) as u16;
|
||||
let list_w = List::new(
|
||||
list
|
||||
.iter()
|
||||
.skip(scroll_offset as usize)
|
||||
.take(content_height)
|
||||
.enumerate()
|
||||
.map(|(i, s)| {
|
||||
Line::from(format!(
|
||||
"{}{}",
|
||||
"",
|
||||
textwrap::fill(s, content_width.saturating_sub(2))
|
||||
)).style(if i + scroll_offset as usize == *idx {
|
||||
Style::new().fg(Color::Blue).bg(Color::Green)
|
||||
} else {
|
||||
Style::default()
|
||||
})
|
||||
}),
|
||||
)
|
||||
.block(block);
|
||||
Widget::render(list_w, rect, buf);
|
||||
}
|
||||
RenderBuffer::List { list, prefix, .. } => {
|
||||
self.max_scroll = if list.len() > content_height {
|
||||
(list.len() - content_height) as i16
|
||||
} else {
|
||||
0
|
||||
};
|
||||
let scroll_offset = self.max_scroll.saturating_sub(self.scroll) as u16;
|
||||
let list_w = List::new(
|
||||
list
|
||||
.iter()
|
||||
.skip(scroll_offset as usize)
|
||||
.take(content_height)
|
||||
.map(|s| {
|
||||
format!(
|
||||
"{}{}",
|
||||
prefix,
|
||||
textwrap::fill(s, content_width.saturating_sub(2))
|
||||
)
|
||||
}),
|
||||
)
|
||||
.block(block);
|
||||
Widget::render(list_w, area, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,302 +0,0 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use crossterm::event::KeyCode;
|
||||
use ratatui::{Frame, buffer::Buffer, layout::Rect, widgets::Widget};
|
||||
use vlogger::*;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum InputMode {
|
||||
Input,
|
||||
PopUp(Arc<Vec<String>>, String, usize),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Renderer {
|
||||
buffer: String,
|
||||
exit: bool,
|
||||
layout: RenderLayout,
|
||||
mode: InputMode,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum RenderCommand {
|
||||
StringToPaneId {
|
||||
str: String,
|
||||
pane: RenderTarget,
|
||||
},
|
||||
StringToPaneFocused {
|
||||
str: String,
|
||||
},
|
||||
KeyInput(KeyCode),
|
||||
ListMove {
|
||||
pane: RenderTarget,
|
||||
index: usize,
|
||||
},
|
||||
ChangeLayout(RenderLayoutKind),
|
||||
ClearPane,
|
||||
|
||||
/// Mouse Events
|
||||
MouseClickLeft(u16, u16),
|
||||
MouseScrollUp,
|
||||
MouseScrollDown,
|
||||
|
||||
SetMode(InputMode),
|
||||
Exit,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl Renderer {
|
||||
pub fn new(layout: RenderLayoutKind) -> Self {
|
||||
Self {
|
||||
buffer: String::new(),
|
||||
exit: false,
|
||||
layout: RenderLayout::generate(layout),
|
||||
mode: InputMode::Input,
|
||||
}
|
||||
}
|
||||
|
||||
fn log(&mut self, msg: String) {
|
||||
self.apply(RenderCommand::StringToPaneFocused(msg))
|
||||
}
|
||||
|
||||
pub fn draw(&mut self, frame: &mut Frame) {
|
||||
frame.render_widget(self, frame.area());
|
||||
}
|
||||
|
||||
fn exit(&mut self) {
|
||||
log!(DEBUG, "Renderer Exit");
|
||||
self.exit = true;
|
||||
}
|
||||
|
||||
fn buffer_extend<S: AsRef<str>>(&mut self, input: S) {
|
||||
self.buffer.push_str(input.as_ref());
|
||||
}
|
||||
|
||||
fn input_pane(&mut self) -> Option<&mut Pane> {
|
||||
self
|
||||
.layout
|
||||
.panes
|
||||
.iter_mut()
|
||||
.find(|p| p.target == RenderTarget::CliInput)
|
||||
}
|
||||
|
||||
fn get_pane(&mut self, pane: RenderTarget) -> Option<&mut Pane> {
|
||||
self.layout.panes.iter_mut().find(|p| p.target == pane)
|
||||
}
|
||||
|
||||
fn focused(&mut self) -> Option<&mut Pane> {
|
||||
self.layout.panes.iter_mut().find(|p| p.focused == true)
|
||||
}
|
||||
|
||||
pub fn rects(&self, area: Rect) -> std::rc::Rc<[Rect]> {
|
||||
self.layout.rects(area)
|
||||
}
|
||||
|
||||
pub fn handle_mouse_click_left(&mut self, x: u16, y: u16, rects: std::rc::Rc<[Rect]>) {
|
||||
for (i, r) in rects.iter().enumerate() {
|
||||
if r.contains(ratatui::layout::Position { x, y }) {
|
||||
self.layout.panes[i].focused = true;
|
||||
} else {
|
||||
self.layout.panes[i].focused = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_scroll_up(&mut self) {
|
||||
if let Some(p) = self.focused() {
|
||||
if p.scroll < p.max_scroll {
|
||||
p.scroll += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_scroll_down(&mut self) {
|
||||
if let Some(p) = self.focused() {
|
||||
if p.scroll > i16::MIN {
|
||||
p.scroll -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_char_input(&mut self, c: char) {
|
||||
if let Some(p) = self.input_pane() {
|
||||
if let RenderBuffer::List { list, index, .. } = &mut p.buffer {
|
||||
list[*index].push(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_backspace(&mut self) {
|
||||
if let Some(p) = self.input_pane() {
|
||||
if let RenderBuffer::List { list, index, .. } = &mut p.buffer {
|
||||
list[*index].pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_enter(&mut self) {
|
||||
if let Some(p) = self.input_pane() {
|
||||
if let RenderBuffer::List { list, index, .. } = &mut p.buffer {
|
||||
list.push(String::new());
|
||||
*index += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_arrow_key(&mut self, key: KeyCode) {
|
||||
if let Some(pane) = self.focused() {
|
||||
match &mut pane.target {
|
||||
RenderTarget::CliInput => {}
|
||||
RenderTarget::CliOutput => {}
|
||||
RenderTarget::PopUp => {
|
||||
match &mut pane.buffer {
|
||||
RenderBuffer::Select(content, idx) => {
|
||||
self.log(msg!(DEBUG, "idx before: {idx}"));
|
||||
match key {
|
||||
KeyCode::Up => { *idx = idx.saturating_sub(1) }
|
||||
KeyCode::Down => {
|
||||
if *idx < content.len().saturating_sub(1) {
|
||||
*idx += 1;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
self.log(msg!(DEBUG, "idx after: {idx}"))
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn list_move(&mut self, pane: RenderTarget, index: usize) {
|
||||
if let Some(p) = self.get_pane(pane) {
|
||||
if let RenderBuffer::List {
|
||||
list, index: idx, ..
|
||||
} = &mut p.buffer
|
||||
{
|
||||
if index > 0 && index < list.len() {
|
||||
list[*idx] = list[index].clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render_string_to_focused(&mut self, str: String) {
|
||||
if let Some(p) = self.focused() {
|
||||
match &mut p.buffer {
|
||||
RenderBuffer::List { list, index, .. } => {
|
||||
list.push(str);
|
||||
*index += 1;
|
||||
}
|
||||
RenderBuffer::String(s) => s.push_str(&str),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render_string_to_id(&mut self, str: String, pane: RenderTarget) {
|
||||
if let Some(p) = self.layout.panes.iter_mut().find(|p| p.target == pane) {
|
||||
match &mut p.buffer {
|
||||
RenderBuffer::List { list, index, .. } => {
|
||||
list.push(str);
|
||||
*index += 1;
|
||||
}
|
||||
RenderBuffer::String(s) => s.push_str(&str),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn clear_focus(&mut self) {
|
||||
while let Some(focused) = self.focused() {
|
||||
focused.focused = false;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clear_pane(&mut self, pane: RenderTarget) {
|
||||
if matches!(pane, RenderTarget::All) {
|
||||
for p in self.layout.panes.iter_mut() {
|
||||
match &mut p.buffer {
|
||||
RenderBuffer::List { list, index, .. } => {
|
||||
list.clear();
|
||||
*index = 0;
|
||||
list.push(String::new());
|
||||
}
|
||||
RenderBuffer::String(s) => s.clear(),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
} else if let Some(p) = self.layout.panes.iter_mut().find(|p| p.target == pane) {
|
||||
match &mut p.buffer {
|
||||
RenderBuffer::List { list, index, .. } => {
|
||||
list.clear();
|
||||
*index = 0;
|
||||
list.push(String::new());
|
||||
}
|
||||
RenderBuffer::String(s) => s.clear(),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn apply(&mut self, mes: RenderCommand, area: Rect) {
|
||||
let rects = self.layout.rects(area);
|
||||
match mes {
|
||||
RenderCommand::MouseClickLeft(x, y) => self.handle_mouse_click_left(x, y, rects),
|
||||
RenderCommand::MouseScrollUp => self.handle_scroll_up(),
|
||||
RenderCommand::MouseScrollDown => self.handle_scroll_down(),
|
||||
RenderCommand::KeyInput(k) => match k {
|
||||
KeyCode::Char(c) => self.handle_char_input(c),
|
||||
KeyCode::Backspace => self.handle_backspace(),
|
||||
KeyCode::Enter => self.handle_enter(),
|
||||
KeyCode::Up | KeyCode::Down | KeyCode::Left | KeyCode::Right => self.handle_arrow_key(k),
|
||||
_ => {}
|
||||
},
|
||||
RenderCommand::ListMove { pane, index } => self.list_move(pane, index),
|
||||
RenderCommand::StringToPaneFocused { str } => self.render_string_to_focused(str),
|
||||
RenderCommand::StringToPaneId { str, pane } => self.render_string_to_id(str, pane),
|
||||
RenderCommand::Exit => self.exit(),
|
||||
RenderCommand::ChangeLayout(l) => self.layout = RenderLayout::generate(l),
|
||||
RenderCommand::ClearPane => self.clear_pane(RenderTarget::All),
|
||||
RenderCommand::SetMode(mode) => {
|
||||
match &mode {
|
||||
InputMode::Input => {
|
||||
if let InputMode::PopUp(..) = self.mode {
|
||||
self.layout.panes.pop();
|
||||
}
|
||||
}
|
||||
InputMode::PopUp(content, title, ..) => {
|
||||
self.clear_focus();
|
||||
let pane = Pane::new(
|
||||
Some(title.to_string()),
|
||||
RenderTarget::PopUp,
|
||||
RenderBuffer::Select(content.clone(), 0),
|
||||
true,
|
||||
);
|
||||
self.layout.panes.push(pane);
|
||||
}
|
||||
}
|
||||
self.mode = mode
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl Widget for &mut Renderer {
|
||||
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||
let rects = self.layout.rects(area);
|
||||
for (i, p) in self.layout.panes.iter_mut().enumerate() {
|
||||
if p.target == RenderTarget::PopUp {
|
||||
p.render(area, buf);
|
||||
} else {
|
||||
p.render(rects[i], buf)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user