Skip to content

Commit

Permalink
Add general notifications support for console wallet.
Browse files Browse the repository at this point in the history
Add update notification to the wallet.
  • Loading branch information
Cifko committed Sep 3, 2021
1 parent cedb1d4 commit d325ff0
Show file tree
Hide file tree
Showing 27 changed files with 369 additions and 40 deletions.
3 changes: 2 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 1 addition & 8 deletions applications/tari_app_grpc/proto/base_node.proto
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ service BaseNode {
rpc GetBlockFees (BlockGroupRequest) returns (BlockGroupResponse);
// Get Version
rpc GetVersion(Empty) returns (StringValue);
// Get Version
// Check for new updates
rpc CheckForUpdates(Empty) returns (SoftwareUpdate);
// Get coins in circulation
rpc GetTokensInCirculation(GetBlocksRequest) returns (stream ValueAtHeightResponse);
Expand Down Expand Up @@ -333,13 +333,6 @@ enum TransactionLocation {
NOT_STORED = 3;
}

message SoftwareUpdate {
bool has_update = 1;
string version = 2;
string sha = 3;
string download_url = 4;
}

message MempoolStatsResponse {
uint64 total_txs = 1;
uint64 unconfirmed_txs = 2;
Expand Down
6 changes: 6 additions & 0 deletions applications/tari_app_grpc/proto/types.proto
Original file line number Diff line number Diff line change
Expand Up @@ -352,3 +352,9 @@ message ListConnectedPeersResponse {
repeated Peer connected_peers = 1;
}

message SoftwareUpdate {
bool has_update = 1;
string version = 2;
string sha = 3;
string download_url = 4;
}
2 changes: 2 additions & 0 deletions applications/tari_app_grpc/proto/wallet.proto
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ import "types.proto";
service Wallet {
// This returns the current version
rpc GetVersion (GetVersionRequest) returns (GetVersionResponse);
// Check for new updates
rpc CheckForUpdates (Empty) returns (SoftwareUpdate);
// This returns the identity information
rpc Identify (GetIdentityRequest) returns (GetIdentityResponse);
// This returns a coinbase transaction
Expand Down
2 changes: 1 addition & 1 deletion applications/tari_console_wallet/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ tari_app_utilities = { path = "../tari_app_utilities", features = ["wallet"]}
tari_comms = { path = "../../comms"}
tari_comms_dht = { path = "../../comms/dht"}
tari_common_types = {path = "../../base_layer/common_types"}
tari_p2p = { path = "../../base_layer/p2p" }
tari_p2p = { path = "../../base_layer/p2p", features = ["auto-update"] }
tari_app_grpc = { path = "../tari_app_grpc", features = ["wallet"] }
tari_shutdown = { path = "../../infrastructure/shutdown" }
tari_key_manager = { path = "../../base_layer/key_manager" }
Expand Down
16 changes: 16 additions & 0 deletions applications/tari_console_wallet/src/grpc/wallet_grpc_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,22 @@ impl wallet_server::Wallet for WalletGrpcServer {
}))
}

async fn check_for_updates(
&self,
_: Request<tari_rpc::Empty>,
) -> Result<Response<tari_rpc::SoftwareUpdate>, Status> {
let mut resp = tari_rpc::SoftwareUpdate::default();

if let Some(ref update) = *self.wallet.get_software_updater().new_update_notifier().borrow() {
resp.has_update = true;
resp.version = update.version().to_string();
resp.sha = update.to_hash_hex();
resp.download_url = update.download_url().to_string();
}

Ok(Response::new(resp))
}

async fn identify(&self, _: Request<GetIdentityRequest>) -> Result<Response<GetIdentityResponse>, Status> {
let identity = self.wallet.comms.node_identity();
Ok(Response::new(GetIdentityResponse {
Expand Down
12 changes: 12 additions & 0 deletions applications/tari_console_wallet/src/init/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ use tari_comms::{
use tari_comms_dht::{DbConnectionUrl, DhtConfig};
use tari_core::transactions::CryptoFactories;
use tari_p2p::{
auto_update::AutoUpdateConfig,
initialization::CommsConfig,
peer_seeds::SeedPeer,
transport::TransportType::Tor,
Expand Down Expand Up @@ -360,6 +361,15 @@ pub async fn init_wallet(
config.base_node_event_channel_size,
);

let updater_config = AutoUpdateConfig {
name_server: config.dns_seeds_name_server,
update_uris: config.autoupdate_dns_hosts.clone(),
use_dnssec: config.dns_seeds_use_dnssec,
download_base_url: "https://tari-binaries.s3.amazonaws.com/latest".to_string(),
hashes_url: config.autoupdate_hashes_url.clone(),
hashes_sig_url: config.autoupdate_hashes_sig_url.clone(),
};

let factories = CryptoFactories::default();
let wallet_config = WalletConfig::new(
comms_config.clone(),
Expand Down Expand Up @@ -391,6 +401,8 @@ pub async fn init_wallet(
)),
Some(config.buffer_rate_limit_console_wallet),
Some(config.scan_for_utxo_interval),
Some(updater_config),
config.autoupdate_check_interval,
);

let mut wallet = Wallet::start(
Expand Down
8 changes: 5 additions & 3 deletions applications/tari_console_wallet/src/ui/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ use crate::{
log_tab::LogTab,
menu::Menu,
network_tab::NetworkTab,
notification_tab::NotificationTab,
receive_tab::ReceiveTab,
send_tab::SendTab,
tabs_container::TabsContainer,
Expand Down Expand Up @@ -87,7 +88,8 @@ impl<B: Backend> App<B> {
.add("Send".into(), Box::new(SendTab::new()))
.add("Receive".into(), Box::new(ReceiveTab::new()))
.add("Network".into(), Box::new(NetworkTab::new(base_node_selected)))
.add("Log".into(), Box::new(LogTab::new()));
.add("Log".into(), Box::new(LogTab::new()))
.add("Notifications".into(), Box::new(NotificationTab::new()));

let base_node_status = BaseNode::new();
let menu = Menu::new();
Expand Down Expand Up @@ -164,10 +166,10 @@ impl<B: Backend> App<B> {
.split(max_width_layout[0]);
let title_halves = Layout::default()
.direction(Direction::Horizontal)
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())
.constraints([Constraint::Percentage(55), Constraint::Percentage(45)].as_ref())
.split(title_chunks[0]);

self.tabs.draw_titles(f, title_halves[0]);
self.tabs.draw_titles(f, title_halves[0], &self.app_state);

self.base_node_status.draw(f, title_halves[1], &self.app_state);
self.tabs.draw_content(f, title_chunks[1], &mut self.app_state);
Expand Down
13 changes: 12 additions & 1 deletion applications/tari_console_wallet/src/ui/components/component.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
use crate::ui::state::AppState;
use tui::{backend::Backend, layout::Rect, Frame};
use tui::{
backend::Backend,
layout::Rect,
style::{Color, Style},
text::{Span, Spans},
Frame,
};

pub trait Component<B: Backend> {
fn draw(&mut self, f: &mut Frame<B>, area: Rect, app_state: &AppState);
Expand All @@ -13,4 +19,9 @@ pub trait Component<B: Backend> {
fn on_esc(&mut self, _app_state: &mut AppState) {}
fn on_backspace(&mut self, _app_state: &mut AppState) {}
fn on_tick(&mut self, _app_state: &mut AppState) {}

// Create custom title based on data in AppState.
fn format_title(&self, title: &str, _app_state: &AppState) -> Spans {
Spans::from(Span::styled(title.to_owned(), Style::default().fg(Color::White)))
}
}
1 change: 1 addition & 0 deletions applications/tari_console_wallet/src/ui/components/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ mod component;
pub mod log_tab;
pub(crate) mod menu;
pub mod network_tab;
pub mod notification_tab;
pub mod receive_tab;
pub mod send_tab;
pub mod tabs_container;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// This tab will show all the notifications. With timestamp automatically added.
// The tab title will turn green with notifications count (when there are any).
// The notifications lives as long as the app. Once the app is closed, the notifications
// are cleared.
// Currently notifications are only added from the wallet_event_monitor which has
// add_notification method.
// TODO: auto delete old notifications.
// TODO: add interaction with the notifications, e.g. if I have a pending transaction
// notification, the UI should go there if I click on it.

use crate::ui::{components::Component, state::AppState};
use tari_comms::runtime::Handle;
use tui::{
backend::Backend,
layout::{Constraint, Layout, Rect},
style::{Color, Modifier, Style},
text::{Span, Spans},
widgets::{Block, Borders, Paragraph, Wrap},
Frame,
};

pub struct NotificationTab {}

impl NotificationTab {
pub fn new() -> Self {
Self {}
}

fn draw_notifications<B>(&mut self, f: &mut Frame<B>, area: Rect, app_state: &AppState)
where B: Backend {
let block = Block::default().borders(Borders::ALL).title(Span::styled(
"Notifications",
Style::default().fg(Color::White).add_modifier(Modifier::BOLD),
));
f.render_widget(block, area);
let notifications_area = Layout::default()
.constraints([Constraint::Min(42)].as_ref())
.margin(1)
.split(area);
let mut text: Vec<Spans> = app_state
.get_notifications()
.iter()
.map(|(time, line)| {
Spans::from(vec![
Span::styled(
time.format("%Y-%m-%d %H:%M:%S ").to_string(),
Style::default().fg(Color::LightGreen),
),
Span::raw(line),
])
})
.collect();
text.reverse();
let paragraph = Paragraph::new(text.clone()).wrap(Wrap { trim: true });
f.render_widget(paragraph, notifications_area[0]);
}
}

impl<B: Backend> Component<B> for NotificationTab {
fn draw(&mut self, f: &mut Frame<B>, area: Rect, app_state: &AppState) {
let areas = Layout::default()
.constraints([Constraint::Min(42)].as_ref())
.split(area);
self.draw_notifications(f, areas[0], app_state);
}

fn on_tick(&mut self, app_state: &mut AppState) {
// Constantly read the messages when in this tab.
Handle::current().block_on(app_state.mark_notifications_as_read());
}

fn format_title(&self, title: &str, app_state: &AppState) -> Spans {
// Create custom title based on notifications count.
match app_state.unread_notifications_count() > 0 {
true => Spans::from(Span::styled(
format!("{}({})", title, app_state.unread_notifications_count()),
Style::default().fg(Color::LightGreen),
)),
false => Spans::from(Span::styled(title.to_owned(), Style::default().fg(Color::White))),
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use tui::{
backend::Backend,
layout::Rect,
style::{Color, Modifier, Style},
text::{Span, Spans},
text::Span,
widgets::{Block, Borders, Tabs},
Frame,
};
Expand Down Expand Up @@ -65,11 +65,12 @@ impl<B: Backend> TabsContainer<B> {
}
}

pub fn draw_titles(&self, f: &mut Frame<B>, area: Rect) {
pub fn draw_titles(&self, f: &mut Frame<B>, area: Rect, app_state: &AppState) {
let titles = self
.titles
.iter()
.map(|t| Spans::from(Span::styled(t, Style::default().fg(Color::White))))
.enumerate()
.map(|(i, title)| self.tabs[i].format_title(title, app_state))
.collect();
let tabs = Tabs::new(titles)
.block(Block::default().borders(Borders::ALL).title(Span::styled(
Expand Down
41 changes: 40 additions & 1 deletion applications/tari_console_wallet/src/ui/state/app_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,11 @@ use std::{
};

use bitflags::bitflags;
use chrono::{DateTime, Local};
use log::*;
use qrcode::{render::unicode, QrCode};
use tari_crypto::{ristretto::RistrettoPublicKey, tari_utilities::hex::Hex};
use tari_p2p::auto_update::SoftwareUpdaterHandle;
use tokio::{
sync::{watch, RwLock},
task,
Expand Down Expand Up @@ -415,8 +417,26 @@ impl AppState {
pub fn toggle_abandoned_coinbase_filter(&mut self) {
self.completed_tx_filter.toggle(TransactionFilter::ABANDONED_COINBASES);
}
}

pub fn get_notifications(&self) -> &Vec<(DateTime<Local>, String)> {
&self.cached_data.notifications
}

pub fn unread_notifications_count(&self) -> u32 {
self.cached_data.new_notification_count
}

pub async fn mark_notifications_as_read(&mut self) {
// Do not update if not necessary
if self.unread_notifications_count() > 0 {
{
let mut inner = self.inner.write().await;
inner.mark_notifications_as_read();
}
self.update_cache().await;
}
}
}
pub struct AppStateInner {
updated: bool,
data: AppStateData,
Expand Down Expand Up @@ -802,6 +822,21 @@ impl AppStateInner {
}
});
}

pub fn add_notification(&mut self, notification: String) {
self.data.notifications.push((Local::now(), notification));
self.data.new_notification_count += 1;
self.updated = true;
}

pub fn mark_notifications_as_read(&mut self) {
self.data.new_notification_count = 0;
self.updated = true;
}

pub fn get_software_updater(&self) -> SoftwareUpdaterHandle {
self.wallet.get_software_updater()
}
}

#[derive(Clone)]
Expand All @@ -818,6 +853,8 @@ struct AppStateData {
base_node_previous: Peer,
base_node_list: Vec<(String, Peer)>,
base_node_peer_custom: Option<Peer>,
notifications: Vec<(DateTime<Local>, String)>,
new_notification_count: u32,
}

impl AppStateData {
Expand Down Expand Up @@ -882,6 +919,8 @@ impl AppStateData {
base_node_previous,
base_node_list,
base_node_peer_custom: base_node_config.base_node_custom,
notifications: Vec::new(),
new_notification_count: 0,
}
}
}
Expand Down
Loading

0 comments on commit d325ff0

Please sign in to comment.