bless
This commit is contained in:
parent
3a8440c2cd
commit
82ca86f03d
6
TODO
Normal file
6
TODO
Normal file
@ -0,0 +1,6 @@
|
||||
Non Exaustive list of ideas:
|
||||
|
||||
- Scripting with rhai []
|
||||
- Mouse Input []
|
||||
- Http server []
|
||||
- RCI []
|
||||
310
node/Cargo.lock
generated
310
node/Cargo.lock
generated
@ -105,12 +105,6 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atomic-waker"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.5.0"
|
||||
@ -132,12 +126,6 @@ dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.22.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.9.3"
|
||||
@ -171,12 +159,12 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
"textwrap",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tokio-tungstenite",
|
||||
"uuid",
|
||||
"vlogger",
|
||||
"warp",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
@ -498,24 +486,6 @@ version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
version = "1.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf"
|
||||
dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.31"
|
||||
@ -576,25 +546,6 @@ version = "0.31.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.4.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386"
|
||||
dependencies = [
|
||||
"atomic-waker",
|
||||
"bytes",
|
||||
"fnv",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"http",
|
||||
"indexmap",
|
||||
"slab",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.5"
|
||||
@ -606,30 +557,6 @@ dependencies = [
|
||||
"foldhash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "headers"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3314d5adb5d94bcdf56771f2e50dbbc80bb4bdf88967526706205ac9eff24eb"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"bytes",
|
||||
"headers-core",
|
||||
"http",
|
||||
"httpdate",
|
||||
"mime",
|
||||
"sha1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "headers-core"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4"
|
||||
dependencies = [
|
||||
"http",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
@ -653,79 +580,12 @@ dependencies = [
|
||||
"itoa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http-body"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"http",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http-body-util"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"http",
|
||||
"http-body",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "httparse"
|
||||
version = "1.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
|
||||
|
||||
[[package]]
|
||||
name = "httpdate"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e"
|
||||
dependencies = [
|
||||
"atomic-waker",
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"h2",
|
||||
"http",
|
||||
"http-body",
|
||||
"httparse",
|
||||
"httpdate",
|
||||
"itoa",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
"smallvec",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-util"
|
||||
version = "0.1.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d9b05277c7e8da2c93a568989bb6207bef0112e8d17df7a6eda4a3cf143bc5e"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"http",
|
||||
"http-body",
|
||||
"hyper",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.63"
|
||||
@ -756,16 +616,6 @@ version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2481980430f9f78649238835720ddccc57e52df14ffce1c6f37391d61b563e9"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indoc"
|
||||
version = "2.0.6"
|
||||
@ -930,22 +780,6 @@ dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mime"
|
||||
version = "0.3.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
||||
|
||||
[[package]]
|
||||
name = "mime_guess"
|
||||
version = "2.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e"
|
||||
dependencies = [
|
||||
"mime",
|
||||
"unicase",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.9"
|
||||
@ -1026,32 +860,6 @@ version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
|
||||
|
||||
[[package]]
|
||||
name = "pin-project"
|
||||
version = "1.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a"
|
||||
dependencies = [
|
||||
"pin-project-internal",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-internal"
|
||||
version = "1.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.16"
|
||||
@ -1206,12 +1014,6 @@ version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
|
||||
|
||||
[[package]]
|
||||
name = "scoped-tls"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.2.0"
|
||||
@ -1250,18 +1052,6 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_urlencoded"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha1"
|
||||
version = "0.10.6"
|
||||
@ -1332,6 +1122,12 @@ version = "1.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
|
||||
|
||||
[[package]]
|
||||
name = "smawk"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c"
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.6.0"
|
||||
@ -1387,6 +1183,17 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.16.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057"
|
||||
dependencies = [
|
||||
"smawk",
|
||||
"unicode-linebreak",
|
||||
"unicode-width 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.16"
|
||||
@ -1450,45 +1257,6 @@ dependencies = [
|
||||
"tungstenite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-util"
|
||||
version = "0.7.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower-service"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
|
||||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
version = "0.1.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
|
||||
dependencies = [
|
||||
"log",
|
||||
"pin-project-lite",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-core"
|
||||
version = "0.1.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tungstenite"
|
||||
version = "0.27.0"
|
||||
@ -1512,18 +1280,18 @@ version = "1.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f"
|
||||
|
||||
[[package]]
|
||||
name = "unicase"
|
||||
version = "2.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-linebreak"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.12.0"
|
||||
@ -1590,36 +1358,6 @@ dependencies = [
|
||||
"colored",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "warp"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51d06d9202adc1f15d709c4f4a2069be5428aa912cc025d6f268ac441ab066b0"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"headers",
|
||||
"http",
|
||||
"http-body",
|
||||
"http-body-util",
|
||||
"hyper",
|
||||
"hyper-util",
|
||||
"log",
|
||||
"mime",
|
||||
"mime_guess",
|
||||
"percent-encoding",
|
||||
"pin-project",
|
||||
"scoped-tls",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"tokio",
|
||||
"tokio-tungstenite",
|
||||
"tokio-util",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.1+wasi-snapshot-preview1"
|
||||
|
||||
@ -14,7 +14,6 @@ thiserror = "2.0.16"
|
||||
tokio = { version = "1.47.1", features = ["full"] }
|
||||
tokio-tungstenite = "0.27.0"
|
||||
uuid = { version = "1.18.0", features = ["v4", "serde"] }
|
||||
warp = { version = "0.4.2", features = ["server", "websocket"] }
|
||||
wasm-bindgen = "0.2.100"
|
||||
web-sys = { version = "0.3.77", features = ["WebSocket"] }
|
||||
vlogger = { path = "./lib/logger-rs" }
|
||||
@ -26,3 +25,4 @@ anyhow = "1.0.99"
|
||||
memory-stats = "1.2.0"
|
||||
jemalloc = "0.3.0"
|
||||
jemallocator = "0.5.4"
|
||||
textwrap = "0.16.2"
|
||||
|
||||
@ -2,17 +2,29 @@
|
||||
{
|
||||
"head": {
|
||||
"previous_hash": "",
|
||||
"timestamp": 1756157257,
|
||||
"merkle_root": "3f99805580f3b4bbd1a903180d2057cfd7dace97d820d7170ffd83c95ce3852c",
|
||||
"block_hash": "06af1aabb570a702dfd2ee7654200890c26e1fdc380589ae76825976524d5d09",
|
||||
"nonce": 9
|
||||
"timestamp": 1756502951,
|
||||
"merkle_root": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"block_hash": "04e5cdf592f6ab35dccdc41add80568c0de8be60609f5f9053cbe0d156fb8ea0",
|
||||
"nonce": 6
|
||||
},
|
||||
"tx": [
|
||||
"data": []
|
||||
},
|
||||
{
|
||||
"head": {
|
||||
"previous_hash": "04e5cdf592f6ab35dccdc41add80568c0de8be60609f5f9053cbe0d156fb8ea0",
|
||||
"timestamp": 1756503577,
|
||||
"merkle_root": "3f99805580f3b4bbd1a903180d2057cfd7dace97d820d7170ffd83c95ce3852c",
|
||||
"block_hash": "0655c8ab80aeda9ed1db6e72ec48cdf9d9c7799356b11519979f3d7dbce57677",
|
||||
"nonce": 7
|
||||
},
|
||||
"data": [
|
||||
{
|
||||
"from": "victor",
|
||||
"to": "pia",
|
||||
"value": 500,
|
||||
"data": "almosen"
|
||||
"Transaction": {
|
||||
"from": "victor",
|
||||
"to": "pia",
|
||||
"value": 500,
|
||||
"data": "almosen"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@ use std::net::SocketAddr;
|
||||
|
||||
use clap::{Parser, Subcommand};
|
||||
use crate::core;
|
||||
use crate::watcher::RenderPane;
|
||||
use crate::watcher::{RenderLayoutKind, RenderPane};
|
||||
|
||||
|
||||
use clap::*;
|
||||
@ -59,6 +59,11 @@ pub enum CliCommand{
|
||||
#[command(name = "clear", aliases = ["c"])]
|
||||
Clear{
|
||||
pane: RenderPane
|
||||
},
|
||||
|
||||
#[command(name = "layout", aliases = ["lay"])]
|
||||
Layout {
|
||||
mode: RenderLayoutKind
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
use crate::args::*;
|
||||
use crate::core::NetworkData;
|
||||
use crate::event_bus::publish_render_event;
|
||||
use crate::native_node::node::*;
|
||||
use clap::Parser;
|
||||
use crate::watcher::ExecutorCommand;
|
||||
use crate::watcher::{ExecutorCommand, RenderCommand};
|
||||
|
||||
pub fn handle_peer_command(cmd: CliPeerCommand) -> NodeCommand {
|
||||
match cmd {
|
||||
@ -36,7 +37,8 @@ fn handle_ping(cmd: CliPingCommand) -> NodeCommand {
|
||||
pub fn cli(input: &[&str]) -> ExecutorCommand {
|
||||
match Cli::try_parse_from(input) {
|
||||
Ok(cmd) => match cmd.command {
|
||||
CliCommand::Clear { pane } => ExecutorCommand::Clear(pane),
|
||||
CliCommand::Layout { mode } => ExecutorCommand::Render(RenderCommand::ChangeLayout(mode)),
|
||||
CliCommand::Clear { pane } => ExecutorCommand::Render(RenderCommand::ClearPane(pane)),
|
||||
CliCommand::Peer { peer_cmd } => ExecutorCommand::Node(handle_peer_command(peer_cmd)),
|
||||
CliCommand::Block { block_cmd } => ExecutorCommand::Node(handle_block_command(block_cmd)),
|
||||
CliCommand::Transaction(tx)=> ExecutorCommand::Node(NodeCommand::ProcessNetworkData(NetworkData::Transaction(tx))),
|
||||
|
||||
@ -12,7 +12,7 @@ pub struct BlockHeader {
|
||||
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize, Default)]
|
||||
pub struct Block {
|
||||
pub head: BlockHeader,
|
||||
pub tx: Vec<NetworkData>
|
||||
pub data: Vec<NetworkData>
|
||||
}
|
||||
|
||||
impl BlockHeader {
|
||||
@ -34,13 +34,13 @@ impl BlockHeader {
|
||||
}
|
||||
|
||||
impl Block {
|
||||
pub fn new(head: BlockHeader, tx: Vec<NetworkData>) -> Self {
|
||||
Self { head, tx }
|
||||
pub fn new(head: BlockHeader, data: Vec<NetworkData>) -> Self {
|
||||
Self { head, data }
|
||||
}
|
||||
pub fn head(&self) -> &BlockHeader {
|
||||
&self.head
|
||||
}
|
||||
pub fn tx(&self) -> &[NetworkData] {
|
||||
&self.tx
|
||||
pub fn data(&self) -> &[NetworkData] {
|
||||
&self.data
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ use sha2::Sha256;
|
||||
|
||||
use vlogger::*;
|
||||
use crate::core::NetworkData;
|
||||
use crate::error::print_error_chain;
|
||||
use crate::log;
|
||||
|
||||
use crate::core;
|
||||
@ -15,11 +16,14 @@ const BLOCKCHAIN_ID: &str = "watch-chain";
|
||||
|
||||
pub type Account = String;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum ValidationError {
|
||||
#[error("Invalid Block Hash Detected")]
|
||||
InvalidBlockHash,
|
||||
#[error("Previous Block Hash doesn't match")]
|
||||
InvalidPreviousBlockHash,
|
||||
InvalidBlockJson
|
||||
#[error("Invalid Block JSON: {0}")]
|
||||
InvalidBlockJson(#[from] serde_json::Error)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
@ -34,7 +38,7 @@ pub struct Blockchain {
|
||||
#[allow(dead_code)]
|
||||
impl Blockchain {
|
||||
pub fn add(&mut self, data: NetworkData) -> Result<(), BlockchainError> {
|
||||
self.apply(&data)?;
|
||||
self.apply(data.clone())?;
|
||||
self.mempool.push(data);
|
||||
Ok(())
|
||||
}
|
||||
@ -147,6 +151,7 @@ impl Blockchain {
|
||||
|
||||
fn apply_transaction(&mut self, tx: &core::Tx) -> Result<(), BlockchainError> {
|
||||
tx.validate()?;
|
||||
return Ok(());
|
||||
if let Some(from_balance) = self.balances.get_mut(tx.from()) {
|
||||
if *from_balance > tx.value() {
|
||||
*from_balance -= tx.value();
|
||||
@ -169,10 +174,11 @@ impl Blockchain {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn apply(&mut self, data: &NetworkData) -> Result<(), BlockchainError> {
|
||||
pub fn apply(&mut self, data: NetworkData) -> Result<(), BlockchainError> {
|
||||
match &data {
|
||||
NetworkData::Transaction(tx) => {
|
||||
self.apply_transaction(tx)?;
|
||||
self.mempool.push(data);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
@ -203,7 +209,7 @@ pub fn calculate_block_hash(head: &core::BlockHeader) -> String {
|
||||
|
||||
impl Blockchain {
|
||||
pub fn list_blocks(&self) -> String {
|
||||
let mut ret = String::from("Blocks List\n-------------------");
|
||||
let mut ret = String::from("Blocks List\n-------------------\n");
|
||||
for (i, b) in self.blocks.iter().enumerate() {
|
||||
ret.push_str(format!("Block Hash #{i}: {}\n", b.head.block_hash()).as_str())
|
||||
}
|
||||
@ -224,7 +230,7 @@ impl Blockchain {
|
||||
Err(e) => match e {
|
||||
ValidationError::InvalidBlockHash => log(msg!(ERROR, "Invalid Block Hash")),
|
||||
ValidationError::InvalidPreviousBlockHash => log(msg!(ERROR, "Invalid Previos Block Hash")),
|
||||
ValidationError::InvalidBlockJson => log(msg!(ERROR, "Invalid Block JSON"))
|
||||
ValidationError::InvalidBlockJson(e) => print_error_chain(e.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -257,17 +263,20 @@ impl Blockchain {
|
||||
}
|
||||
|
||||
pub fn build(blocks: &str) -> Result<Blockchain, ValidationError> {
|
||||
if let Ok(blocks) = serde_json::from_str::<Vec<core::Block>>(&blocks) {
|
||||
let chain = Blockchain {
|
||||
blocks,
|
||||
balances: HashMap::new(),
|
||||
mempool: vec![],
|
||||
id: BLOCKCHAIN_ID.to_string(),
|
||||
};
|
||||
|
||||
chain.validate_chain()?;
|
||||
return Ok(chain)
|
||||
match serde_json::from_str::<Vec<core::Block>>(&blocks) {
|
||||
Ok(blocks) => {
|
||||
let chain = Blockchain {
|
||||
blocks,
|
||||
balances: HashMap::new(),
|
||||
mempool: vec![],
|
||||
id: BLOCKCHAIN_ID.to_string(),
|
||||
};
|
||||
chain.validate_chain()?;
|
||||
Ok(chain)
|
||||
}
|
||||
Err(e) => {
|
||||
Err(ValidationError::InvalidBlockJson(e))
|
||||
}
|
||||
}
|
||||
Err(ValidationError::InvalidBlockJson)
|
||||
}
|
||||
}
|
||||
|
||||
6
node/src/core/data.rs
Normal file
6
node/src/core/data.rs
Normal file
@ -0,0 +1,6 @@
|
||||
use super::Tx;
|
||||
|
||||
#[derive(serde::Deserialize, serde::Serialize, Debug, Clone)]
|
||||
pub enum NetworkData {
|
||||
Transaction(Tx)
|
||||
}
|
||||
@ -1,11 +1,6 @@
|
||||
use crate::core::Account;
|
||||
use crate::error::TxError;
|
||||
|
||||
#[derive(serde::Deserialize, serde::Serialize, Debug, Clone)]
|
||||
pub enum NetworkData {
|
||||
Transaction(Tx)
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, serde::Serialize, Debug, clap::Args, Clone)]
|
||||
pub struct Tx {
|
||||
from: Account,
|
||||
|
||||
@ -62,7 +62,10 @@ impl<T: Clone + std::fmt::Debug> EventBus<T> {
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum SystemEvent {
|
||||
Exit
|
||||
ExecutorStarted,
|
||||
RendererStarted,
|
||||
NodeStarted,
|
||||
Exit,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
||||
@ -47,6 +47,10 @@ pub mod core {
|
||||
|
||||
pub mod tx;
|
||||
pub use tx::*;
|
||||
|
||||
pub mod data;
|
||||
pub use data::*;
|
||||
|
||||
}
|
||||
|
||||
pub mod seeds_constants;
|
||||
|
||||
@ -2,14 +2,14 @@ use blockchain::watcher::Watcher;
|
||||
use blockchain::args;
|
||||
use clap::Parser;
|
||||
|
||||
// src/main.rs
|
||||
use jemallocator::Jemalloc;
|
||||
|
||||
#[global_allocator]
|
||||
static GLOBAL: Jemalloc = Jemalloc;
|
||||
|
||||
// // src/main.rs
|
||||
// use jemallocator::Jemalloc;
|
||||
//
|
||||
// #[global_allocator]
|
||||
// static GLOBAL: Jemalloc = Jemalloc;
|
||||
//
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
async fn main() -> Result<(), std::io::Error> {
|
||||
|
||||
let args = args::CliArgs::parse();
|
||||
|
||||
@ -21,6 +21,12 @@ async fn main() {
|
||||
.bootstrap(args.bootstrap)
|
||||
.start().await;
|
||||
|
||||
crossterm::execute!(
|
||||
std::io::stdout(),
|
||||
crossterm::event::EnableBracketedPaste,
|
||||
crossterm::event::EnableFocusChange,
|
||||
crossterm::event::EnableMouseCapture,
|
||||
)?;
|
||||
|
||||
loop {
|
||||
if !watcher.poll().await.is_ok_and(|b| b) {
|
||||
@ -28,6 +34,13 @@ async fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
crossterm::execute!(
|
||||
std::io::stdout(),
|
||||
crossterm::event::DisableBracketedPaste,
|
||||
crossterm::event::DisableFocusChange,
|
||||
crossterm::event::DisableMouseCapture
|
||||
)?;
|
||||
ratatui::restore();
|
||||
println!("Hello, world!");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
use crate::core::{self, Blockchain, NetworkData, ValidationError};
|
||||
use crate::error::print_error_chain;
|
||||
use crate::event_bus::{publish_system_event, SystemEvent};
|
||||
use crate::protocol::ProtocolMessage;
|
||||
|
||||
use crate::seeds_constants::SEED_NODES;
|
||||
@ -125,10 +126,15 @@ impl NativeNode {
|
||||
exec_tx: mpsc::Sender<ExecutorCommand>,
|
||||
) -> Self {
|
||||
let (tx, rx) = mpsc::channel::<NodeCommand>(100);
|
||||
let chain = Blockchain::build(blocks_json)
|
||||
.unwrap_or_else(|e| {
|
||||
print_error_chain(e.into());
|
||||
Default::default()
|
||||
});
|
||||
Self {
|
||||
id: Uuid::new_v4(),
|
||||
tcp_peers: HashMap::new(),
|
||||
chain: Blockchain::build(blocks_json).unwrap_or(Default::default()),
|
||||
chain,
|
||||
addr,
|
||||
exec_tx,
|
||||
listner_handle: None,
|
||||
@ -138,7 +144,7 @@ impl NativeNode {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn process_message(&mut self, peer_id: uuid::Uuid, message: &ProtocolMessage) {
|
||||
pub async fn process_message(&mut self, peer_id: uuid::Uuid, message: ProtocolMessage) {
|
||||
|
||||
match message {
|
||||
ProtocolMessage::BootstrapRequest { .. } => {
|
||||
@ -155,19 +161,19 @@ impl NativeNode {
|
||||
},
|
||||
ProtocolMessage::BootstrapResponse { blocks } => {
|
||||
log(msg!(DEBUG, "Received BootstrapResponse from seed"));
|
||||
self.chain = core::Blockchain::build(blocks).unwrap();
|
||||
self.chain = core::Blockchain::build(&blocks).unwrap();
|
||||
},
|
||||
ProtocolMessage::Ping {peer_id} => {
|
||||
log(msg!(DEBUG, "Received Ping from {peer_id}"));
|
||||
let resp = ProtocolMessage::Pong { peer_id: self.id.clone() };
|
||||
let peer = &self.tcp_peers[peer_id];
|
||||
let peer = &self.tcp_peers[&peer_id];
|
||||
peer.sender.send(resp).await.unwrap();
|
||||
},
|
||||
ProtocolMessage::GetPeersRequest { peer_id } => {
|
||||
log(msg!(DEBUG, "Received GetPeersRequest from {peer_id}"));
|
||||
let peers = self.peer_addresses();
|
||||
let resp = ProtocolMessage::GetPeersResponse { peer_addresses: peers };
|
||||
let peer = &self.tcp_peers[peer_id];
|
||||
let peer = &self.tcp_peers[&peer_id];
|
||||
peer.sender.send(resp).await.unwrap();
|
||||
}
|
||||
ProtocolMessage::Block { block, ..} => {
|
||||
@ -225,7 +231,7 @@ impl NativeNode {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn broadcast_network_data(&self, data: &NetworkData) {
|
||||
async fn broadcast_network_data(&self, data: NetworkData) {
|
||||
for (id, peer) in &self.tcp_peers {
|
||||
let message = ProtocolMessage::NetworkData{peer_id: self.id, data: data.clone()};
|
||||
peer.sender.send(message).await.unwrap();
|
||||
@ -253,7 +259,7 @@ impl NativeNode {
|
||||
return self.exec_tx.clone()
|
||||
}
|
||||
|
||||
async fn network_data(&mut self, data: &NetworkData) {
|
||||
async fn network_data(&mut self, data: NetworkData) {
|
||||
match self.chain.apply(data) {
|
||||
Ok(_) => log(msg!(DEBUG, "NetworkData Applied")),
|
||||
Err(e) => print_error_chain(e.into())
|
||||
@ -301,7 +307,7 @@ impl NativeNode {
|
||||
self.start_connection_listner(SocketAddr::new(std::net::IpAddr::V4(std::net::Ipv4Addr::new(0,0,0,0)), 8080)).await;
|
||||
};
|
||||
|
||||
log(msg!(INFO, "Started Node"));
|
||||
publish_system_event(SystemEvent::NodeStarted);
|
||||
|
||||
while let Some(command) = self.rx.recv().await {
|
||||
match command {
|
||||
@ -347,11 +353,11 @@ impl NativeNode {
|
||||
self.remove_tcp_peer(peer_id).await;
|
||||
}
|
||||
NodeCommand::ProcessMessage { peer_id, message } => {
|
||||
self.process_message(peer_id, &message).await;
|
||||
self.process_message(peer_id, message).await;
|
||||
},
|
||||
NodeCommand::ProcessNetworkData(data) => {
|
||||
self.network_data(&data).await;
|
||||
self.broadcast_network_data(&data).await;
|
||||
self.network_data(data.clone()).await;
|
||||
self.broadcast_network_data(data).await;
|
||||
},
|
||||
NodeCommand::CreateBlock => {
|
||||
log(msg!(DEBUG, "Received CreateBlock Command"));
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use crate::{event_bus::publish_render_event, log, native_node::node::NodeCommand, watcher::renderer::*};
|
||||
use crate::{event_bus::{publish_render_event, publish_system_event, SystemEvent}, log, native_node::node::NodeCommand, watcher::renderer::*};
|
||||
use thiserror::Error;
|
||||
use tokio::sync::mpsc;
|
||||
use vlogger::*;
|
||||
@ -10,7 +10,7 @@ pub enum ExecutorCommand {
|
||||
Print(String),
|
||||
InvalidCommand(String),
|
||||
Node(NodeCommand),
|
||||
Clear(RenderPane),
|
||||
Render(RenderCommand),
|
||||
Exit
|
||||
}
|
||||
|
||||
@ -36,6 +36,7 @@ impl Executor {
|
||||
}
|
||||
|
||||
pub async fn run(&mut self) {
|
||||
publish_system_event(SystemEvent::ExecutorStarted);
|
||||
while !self.exit {
|
||||
self.listen().await;
|
||||
}
|
||||
@ -70,11 +71,6 @@ impl Executor {
|
||||
publish_render_event(rd_cmd);
|
||||
}
|
||||
|
||||
async fn clear(&self, p: RenderPane) {
|
||||
let rd_cmd = RenderCommand::ClearPane(p);
|
||||
publish_render_event(rd_cmd);
|
||||
}
|
||||
|
||||
async fn invalid_command(&self, str: String) {
|
||||
let rd_cmd = RenderCommand::RenderStringToPane{
|
||||
str,
|
||||
@ -87,7 +83,7 @@ impl Executor {
|
||||
match cmd {
|
||||
ExecutorCommand::NodeResponse(resp) => log(resp),
|
||||
ExecutorCommand::Node(n) => self.handle_node_cmd(n).await,
|
||||
ExecutorCommand::Clear(p) => self.clear(p).await,
|
||||
ExecutorCommand::Render(p) => publish_render_event(p),
|
||||
ExecutorCommand::Echo(s) => self.echo(s).await,
|
||||
ExecutorCommand::Print(s) => log(s),
|
||||
ExecutorCommand::InvalidCommand(str) => self.invalid_command(str).await,
|
||||
|
||||
@ -11,8 +11,8 @@ use ratatui::{
|
||||
|
||||
use vlogger::*;
|
||||
|
||||
use crate::event_bus::subscribe_render_event;
|
||||
use tokio::time::{timeout, Duration};
|
||||
use crate::event_bus::{publish_system_event, subscribe_render_event, SystemEvent};
|
||||
use tokio::time::{interval, timeout, Duration};
|
||||
use std::io;
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -27,6 +27,9 @@ pub struct Pane {
|
||||
title: Option<String>,
|
||||
target: RenderPane,
|
||||
buffer: RenderBuffer,
|
||||
focused: bool,
|
||||
scroll: i16,
|
||||
max_scroll: i16,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, clap::ValueEnum)]
|
||||
@ -46,7 +49,7 @@ enum RenderBuffer {
|
||||
}
|
||||
|
||||
impl Pane {
|
||||
fn render(&self, area: Rect, buf: &mut Buffer) {
|
||||
fn render(&mut self, area: Rect, buf: &mut Buffer) {
|
||||
let block = Block::bordered()
|
||||
.title({
|
||||
if let Some(t) = &self.title {
|
||||
@ -55,27 +58,38 @@ impl Pane {
|
||||
Default::default()
|
||||
}
|
||||
})
|
||||
.border_set(border::PLAIN);
|
||||
.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 inner_area = block.inner(area);
|
||||
let content_width = inner_area.width as usize;
|
||||
let content_height = inner_area.height as usize;
|
||||
let wrapped_lines = s
|
||||
.lines()
|
||||
.map(|line| {
|
||||
if line.is_empty() {
|
||||
1
|
||||
} else {
|
||||
(line.len() + content_width - 1) / content_width
|
||||
}
|
||||
})
|
||||
.sum::<usize>();
|
||||
let scroll_offset = if wrapped_lines > content_height {
|
||||
wrapped_lines - content_height
|
||||
.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
|
||||
0
|
||||
};
|
||||
|
||||
let scroll_offset = self.max_scroll.saturating_sub(self.scroll) as u16;
|
||||
|
||||
Paragraph::new(s.clone())
|
||||
.wrap(Wrap::default())
|
||||
.left_aligned()
|
||||
@ -84,13 +98,12 @@ impl Pane {
|
||||
.render(area, buf);
|
||||
}
|
||||
RenderBuffer::List { list, .. } => {
|
||||
let items: Vec<String> = list
|
||||
let list_w = List::new(list
|
||||
.iter()
|
||||
.map(|s| {
|
||||
format!("> {s}")
|
||||
})
|
||||
.collect();
|
||||
Widget::render(List::new(items).block(block), area, buf);
|
||||
format!("> {}", textwrap::fill(s, content_width.saturating_sub(2)))
|
||||
})).block(block);
|
||||
Widget::render(list_w, area, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -109,12 +122,21 @@ pub enum RenderCommand {
|
||||
},
|
||||
ChangeLayout(RenderLayoutKind),
|
||||
ClearPane(RenderPane),
|
||||
|
||||
|
||||
/// Mouse Events
|
||||
MouseClickLeft(u16, u16),
|
||||
MouseScrollUp,
|
||||
MouseScrollDown,
|
||||
Exit,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, clap::ValueEnum)]
|
||||
pub enum RenderLayoutKind {
|
||||
Cli,
|
||||
#[value(name = "horizontal", aliases = ["h"])]
|
||||
CliHorizontal,
|
||||
#[value(name = "vertical", aliases = ["v"])]
|
||||
CliVertical
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -126,12 +148,21 @@ pub struct RenderLayout {
|
||||
impl RenderLayoutKind {
|
||||
pub fn rects(&self, area: Rect) -> std::rc::Rc<[Rect]> {
|
||||
match self {
|
||||
Self::Cli => {
|
||||
Self::CliHorizontal => {
|
||||
Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.constraints(vec![
|
||||
Constraint::Percentage(70),
|
||||
Constraint::Percentage(30),
|
||||
])
|
||||
.split(area)
|
||||
}
|
||||
Self::CliVertical => {
|
||||
Layout::default()
|
||||
.direction(Direction::Horizontal)
|
||||
.constraints(vec![
|
||||
Constraint::Percentage(30),
|
||||
Constraint::Percentage(70)
|
||||
Constraint::Percentage(70),
|
||||
])
|
||||
.split(area)
|
||||
}
|
||||
@ -139,23 +170,59 @@ impl RenderLayoutKind {
|
||||
}
|
||||
|
||||
pub fn generate(&self) -> RenderLayout {
|
||||
RenderLayout {
|
||||
kind: self.clone(),
|
||||
panes: vec![
|
||||
Pane {
|
||||
title: Some(" Input Pane ".to_string()),
|
||||
target: RenderPane::CliInput,
|
||||
buffer: RenderBuffer::List{
|
||||
list: vec![String::new()],
|
||||
index: 0
|
||||
}
|
||||
},
|
||||
Pane {
|
||||
title: Some(" Output Pane ".to_string()),
|
||||
target: RenderPane::CliOutput,
|
||||
buffer: RenderBuffer::String(String::new()),
|
||||
match self {
|
||||
RenderLayoutKind::CliVertical => {
|
||||
RenderLayout {
|
||||
kind: self.clone(),
|
||||
panes: vec![
|
||||
Pane {
|
||||
title: Some(" Input Pane ".to_string()),
|
||||
target: RenderPane::CliInput,
|
||||
buffer: RenderBuffer::List{
|
||||
list: vec![String::new()],
|
||||
index: 0
|
||||
},
|
||||
focused: true,
|
||||
scroll: 0,
|
||||
max_scroll: 0,
|
||||
},
|
||||
Pane {
|
||||
title: Some(" Output Pane ".to_string()),
|
||||
target: RenderPane::CliOutput,
|
||||
buffer: RenderBuffer::String(String::new()),
|
||||
focused: false,
|
||||
scroll: 0,
|
||||
max_scroll: 0,
|
||||
},
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
RenderLayoutKind::CliHorizontal => {
|
||||
RenderLayout {
|
||||
kind: self.clone(),
|
||||
panes: vec![
|
||||
Pane {
|
||||
title: Some(" Output Pane ".to_string()),
|
||||
target: RenderPane::CliOutput,
|
||||
buffer: RenderBuffer::String(String::new()),
|
||||
focused: false,
|
||||
scroll: 0,
|
||||
max_scroll: 0,
|
||||
},
|
||||
Pane {
|
||||
title: Some(" Input Pane ".to_string()),
|
||||
target: RenderPane::CliInput,
|
||||
buffer: RenderBuffer::List{
|
||||
list: vec![String::new()],
|
||||
index: 0
|
||||
},
|
||||
focused: true,
|
||||
scroll: 0,
|
||||
max_scroll: 0,
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -174,11 +241,23 @@ impl Renderer {
|
||||
self.log(msg!(INFO, "Started Renderer"));
|
||||
let mut rx = subscribe_render_event();
|
||||
let mut terminal = ratatui::init();
|
||||
publish_system_event(SystemEvent::RendererStarted);
|
||||
|
||||
let mut render_interval = interval(Duration::from_millis(32)); // 60 FPS
|
||||
|
||||
while !self.exit {
|
||||
terminal.draw(|frame| self.draw(frame))?;
|
||||
if let Ok(mes) = self.listen(&mut rx).await {
|
||||
self.apply(mes);
|
||||
}
|
||||
tokio::select! {
|
||||
_ = render_interval.tick() => {
|
||||
terminal.draw(|frame| self.draw(frame))?;
|
||||
}
|
||||
mes = rx.recv() => {
|
||||
if let Ok(mes) = mes {
|
||||
let frame = terminal.get_frame();
|
||||
let rects = self.layout.kind.rects(frame.area());
|
||||
self.apply(mes, rects);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ratatui::restore();
|
||||
Ok(())
|
||||
@ -188,7 +267,7 @@ impl Renderer {
|
||||
self.buffer.push_str(&msg)
|
||||
}
|
||||
|
||||
pub fn draw(&self, frame: &mut Frame) {
|
||||
pub fn draw(&mut self, frame: &mut Frame) {
|
||||
frame.render_widget(self, frame.area());
|
||||
}
|
||||
|
||||
@ -205,78 +284,95 @@ impl Renderer {
|
||||
self.layout.panes.iter_mut().find(|p| p.target == RenderPane::CliInput)
|
||||
}
|
||||
|
||||
fn apply(&mut self, mes: RenderCommand) {
|
||||
match mes {
|
||||
RenderCommand::RenderInput(k) => {
|
||||
if let Some(p) = self.input_pane() {
|
||||
match k {
|
||||
KeyCode::Char(c) => {
|
||||
if let RenderBuffer::List{list, index} = &mut p.buffer {
|
||||
list[*index].push(c);
|
||||
}
|
||||
}
|
||||
KeyCode::Backspace => {
|
||||
if let RenderBuffer::List{list, index} = &mut p.buffer {
|
||||
list[*index].pop();
|
||||
}
|
||||
}
|
||||
KeyCode::Enter => {
|
||||
if let RenderBuffer::List{list, index} = &mut p.buffer {
|
||||
list.push(String::new());
|
||||
*index += 1;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
},
|
||||
fn focused(&mut self) -> Option<&mut Pane> {
|
||||
self.layout.panes.iter_mut().find(|p| p.focused == true)
|
||||
}
|
||||
|
||||
RenderCommand::ListMove{ pane, index } => {
|
||||
if let Some(p) = self.layout.panes.iter_mut().find(|p| p.target == pane) {
|
||||
if let RenderBuffer::List { list, index: idx } = &mut p.buffer {
|
||||
if index > 0 && index < list.len() {
|
||||
list[*idx] = list[index].clone();
|
||||
}
|
||||
}
|
||||
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(layout::Position{x, y}) {
|
||||
self.layout.panes[i].focused = true;
|
||||
} else {
|
||||
self.layout.panes[i].focused = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn apply(&mut self, mes: RenderCommand, rects: std::rc::Rc<[Rect]>) {
|
||||
match mes {
|
||||
RenderCommand::MouseClickLeft(x, y) => {
|
||||
self.handle_mouse_click_left(x, y, rects);
|
||||
}
|
||||
RenderCommand::MouseScrollUp => {
|
||||
if let Some(p) = self.focused() {
|
||||
if p.scroll < p.max_scroll {
|
||||
p.scroll += 1;
|
||||
}
|
||||
}
|
||||
|
||||
RenderCommand::RenderStringToPane{ str, pane } => {
|
||||
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);
|
||||
}
|
||||
RenderCommand::MouseScrollDown => {
|
||||
if let Some(p) = self.focused() {
|
||||
if p.scroll > i16::MIN {
|
||||
p.scroll -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
RenderCommand::RenderInput(k) => {
|
||||
if let Some(p) = self.layout.panes.iter_mut().find(|p| p.focused) {
|
||||
match k {
|
||||
KeyCode::Char(c) => {
|
||||
if let RenderBuffer::List{list, index} = &mut p.buffer {
|
||||
list[*index].push(c);
|
||||
}
|
||||
}
|
||||
KeyCode::Backspace => {
|
||||
if let RenderBuffer::List{list, index} = &mut p.buffer {
|
||||
list[*index].pop();
|
||||
}
|
||||
}
|
||||
KeyCode::Enter => {
|
||||
if let RenderBuffer::List{list, index} = &mut p.buffer {
|
||||
list.push(String::new());
|
||||
*index += 1;
|
||||
}
|
||||
RenderBuffer::String(s) => {
|
||||
s.push_str(&str)
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
RenderCommand::ListMove{ pane, index } => {
|
||||
if let Some(p) = self.layout.panes.iter_mut().find(|p| p.target == pane) {
|
||||
if let RenderBuffer::List { list, index: idx } = &mut p.buffer {
|
||||
if index > 0 && index < list.len() {
|
||||
list[*idx] = list[index].clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
RenderCommand::Exit => {
|
||||
self.exit();
|
||||
}
|
||||
RenderCommand::ChangeLayout(l) => {
|
||||
match l {
|
||||
RenderLayoutKind::Cli => {
|
||||
self.layout = l.generate();
|
||||
}
|
||||
|
||||
RenderCommand::RenderStringToPane{ str, pane } => {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
RenderCommand::ClearPane(pane) => {
|
||||
if matches!(pane, RenderPane::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) {
|
||||
}
|
||||
RenderCommand::Exit => {
|
||||
self.exit();
|
||||
}
|
||||
RenderCommand::ChangeLayout(l) => {
|
||||
self.layout = l.generate();
|
||||
}
|
||||
RenderCommand::ClearPane(pane) => {
|
||||
if matches!(pane, RenderPane::All) {
|
||||
for p in self.layout.panes.iter_mut() {
|
||||
match &mut p.buffer {
|
||||
RenderBuffer::List { list, index } => {
|
||||
list.clear();
|
||||
@ -286,8 +382,18 @@ impl Renderer {
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn listen(&mut self, rx: &mut tokio::sync::broadcast::Receiver<RenderCommand>) -> Result<RenderCommand, ()> {
|
||||
@ -298,13 +404,12 @@ impl Renderer {
|
||||
}
|
||||
}
|
||||
|
||||
impl Widget for &Renderer {
|
||||
impl Widget for &mut Renderer {
|
||||
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||
|
||||
let layout = self.layout.kind.rects(area);
|
||||
|
||||
for (i, p) in self.layout.panes.iter().enumerate() {
|
||||
p.render(layout[i], buf)
|
||||
let rects = self.layout.kind.rects(area);
|
||||
for (i, p) in self.layout.panes.iter_mut().enumerate() {
|
||||
p.render(rects[i], buf)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
use crossterm::event::{self, Event, KeyCode, KeyEventKind};
|
||||
use crossterm::event::{self, Event, KeyCode, KeyEventKind, MouseButton, MouseEventKind};
|
||||
use memory_stats::memory_stats;
|
||||
use tokio::sync::mpsc;
|
||||
use std::{io::{self, Write}, net::SocketAddr, time::Duration};
|
||||
|
||||
use crate::{event_bus::NetworkEvent, native_node::node::{NativeNode, NodeCommand}};
|
||||
use crate::{error::print_error_chain, event_bus::{subscribe_system_event, NetworkEvent, SystemEvent}, native_node::node::{NativeNode, NodeCommand}};
|
||||
use vlogger::*;
|
||||
|
||||
use super::*;
|
||||
@ -67,6 +67,21 @@ impl Watcher {
|
||||
|
||||
pub async fn poll(&mut self) -> io::Result<bool> {
|
||||
match event::read()? {
|
||||
Event::Mouse(event) => {
|
||||
match event.kind {
|
||||
MouseEventKind::ScrollUp => { publish_render_event(RenderCommand::MouseScrollUp); }
|
||||
MouseEventKind::ScrollDown => { publish_render_event(RenderCommand::MouseScrollDown); }
|
||||
MouseEventKind::Down(b) => {
|
||||
match b {
|
||||
MouseButton::Left => {
|
||||
publish_render_event(RenderCommand::MouseClickLeft(event.column, event.row));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Event::Key(k) if k.kind == KeyEventKind::Press => {
|
||||
match k.code {
|
||||
KeyCode::Char(c) => {
|
||||
@ -167,31 +182,34 @@ impl WatcherBuilder {
|
||||
pub async fn start(mut self) -> Watcher {
|
||||
let (parser_tx, parser_rx) = mpsc::channel::<ParserCommand>(100);
|
||||
let (exec_tx, exec_rx) = mpsc::channel::<ExecutorCommand>(100);
|
||||
|
||||
let mut sys_event = subscribe_system_event();
|
||||
|
||||
if self.debug {
|
||||
Watcher::log_memory().await;
|
||||
}
|
||||
|
||||
let render_handle = if self.render {
|
||||
Some(tokio::spawn({
|
||||
async move {
|
||||
let _ = Renderer::new(RenderLayoutKind::Cli).run().await;
|
||||
let _ = Renderer::new(RenderLayoutKind::CliHorizontal).run().await;
|
||||
}
|
||||
}))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let blocks = self.seed_file
|
||||
.as_ref()
|
||||
.and_then(|path| std::fs::read_to_string(path).ok())
|
||||
.unwrap_or_default();
|
||||
|
||||
if self.seed {
|
||||
self.addr = Some(crate::seeds_constants::SEED_NODES[0]);
|
||||
for i in 0..3 {
|
||||
if let Ok(ev) = sys_event.recv().await {
|
||||
match ev {
|
||||
SystemEvent::RendererStarted => {
|
||||
log(msg!(INFO, "Renderer Started"));
|
||||
break;
|
||||
},
|
||||
_ => { log(msg!(WARNING, "Wrong Event: {ev:?}! Retrying... (try {i})")) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut node = NativeNode::new(self.addr.clone(), &blocks, exec_tx.clone()).await;
|
||||
log(msg!(INFO, "Build Node"));
|
||||
|
||||
let parser_handle = tokio::spawn({
|
||||
let exec_tx = exec_tx.clone();
|
||||
@ -200,6 +218,28 @@ impl WatcherBuilder {
|
||||
}
|
||||
});
|
||||
|
||||
log(msg!(DEBUG, "Seed File: {:?}", self.seed_file));
|
||||
let blocks = self.seed_file
|
||||
.as_ref()
|
||||
.and_then(|path| {
|
||||
log(msg!(INFO, "Reading chain data from {path}"));
|
||||
match std::fs::read_to_string(path) {
|
||||
Ok(s) => Some(s),
|
||||
Err(e) => {
|
||||
print_error_chain(e.into());
|
||||
None
|
||||
},
|
||||
}
|
||||
})
|
||||
.unwrap_or_default();
|
||||
|
||||
if self.seed {
|
||||
self.addr = Some(crate::seeds_constants::SEED_NODES[0]);
|
||||
}
|
||||
|
||||
let mut node = NativeNode::new(self.addr.clone(), &blocks, exec_tx.clone()).await;
|
||||
log(msg!(INFO, "Built Node"));
|
||||
|
||||
let executor_handle = tokio::spawn({
|
||||
let node_tx = node.tx();
|
||||
async move {
|
||||
@ -207,14 +247,37 @@ impl WatcherBuilder {
|
||||
}
|
||||
});
|
||||
|
||||
let node_tx = node.tx();
|
||||
for i in 0..3 {
|
||||
if let Ok(ev) = sys_event.recv().await {
|
||||
match ev {
|
||||
SystemEvent::ExecutorStarted => {
|
||||
log(msg!(INFO, "Executor Started"));
|
||||
break;
|
||||
},
|
||||
_ => { log(msg!(WARNING, "Wrong Event: {ev:?}! Retrying... (try {i})")) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let node_tx = node.tx();
|
||||
let node_handle = tokio::spawn({
|
||||
async move {
|
||||
node.run().await;
|
||||
}
|
||||
});
|
||||
|
||||
for i in 0..3 {
|
||||
if let Ok(ev) = sys_event.recv().await {
|
||||
match ev {
|
||||
SystemEvent::NodeStarted => {
|
||||
log(msg!(INFO, "Executor Started"));
|
||||
break;
|
||||
},
|
||||
_ => { log(msg!(WARNING, "Wrong Event: {ev:?}! Retrying... (try {i})")) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if self.bootstrap {
|
||||
let exec_tx = exec_tx.clone();
|
||||
|
||||
@ -234,7 +297,6 @@ impl WatcherBuilder {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Watcher {
|
||||
node_tx,
|
||||
cmd_history: Vec::new(),
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user