2021-04-18 16:55:10 +02:00
extern crate open ;
2021-03-10 22:21:50 +01:00
extern crate serde ;
extern crate serde_json ;
2021-04-18 16:55:10 +02:00
extern crate tinyfiledialogs as tfd ;
extern crate web_view ;
2021-03-10 22:21:50 +01:00
2021-04-15 12:21:41 +02:00
use std ::sync ::{ Arc , Mutex , MutexGuard } ;
2021-03-10 22:21:50 +01:00
use std ::thread ;
use std ::time ::{ Duration , Instant } ;
2021-05-02 12:55:51 +02:00
use alfis ::blockchain ::transaction ::DomainData ;
2021-04-10 09:47:21 +02:00
use alfis ::blockchain ::types ::MineResult ;
2021-05-02 12:55:51 +02:00
use alfis ::commons ::* ;
2021-06-09 20:36:36 +02:00
use alfis ::crypto ::CryptoBox ;
2021-03-10 22:21:50 +01:00
use alfis ::dns ::protocol ::DnsRecord ;
2021-04-10 09:47:21 +02:00
use alfis ::event ::Event ;
2021-06-09 20:36:36 +02:00
use alfis ::eventbus ::{ post , register } ;
2021-04-10 09:47:21 +02:00
use alfis ::miner ::Miner ;
2021-06-09 20:36:36 +02:00
use alfis ::{ keystore , Block , Bytes , Context , Keystore , Transaction } ;
2022-05-12 14:50:31 +02:00
use chrono ::{ DateTime , Local , Utc } ;
2021-06-09 20:36:36 +02:00
#[ allow(unused_imports) ]
use log ::{ debug , error , info , trace , warn , LevelFilter } ;
use serde ::{ Deserialize , Serialize } ;
use web_view ::Content ;
2021-03-10 22:21:50 +01:00
use Cmd ::* ;
2021-04-10 09:47:21 +02:00
use self ::web_view ::{ Handle , WebView } ;
2021-03-10 22:21:50 +01:00
pub fn run_interface ( context : Arc < Mutex < Context > > , miner : Arc < Mutex < Miner > > ) {
let file_content = include_str! ( " webview/index.html " ) ;
let mut styles = inline_style ( include_str! ( " webview/bulma.css " ) ) ;
2021-03-24 19:06:22 +01:00
styles . push_str ( & inline_style ( include_str! ( " webview/styles.css " ) ) ) ;
2021-03-10 22:21:50 +01:00
styles . push_str ( & inline_style ( include_str! ( " webview/busy_indicator.css " ) ) ) ;
let scripts = inline_script ( include_str! ( " webview/scripts.js " ) ) ;
let html = Content ::Html ( file_content . to_owned ( ) . replace ( " {styles} " , & styles ) . replace ( " {scripts} " , & scripts ) ) ;
let title = format! ( " ALFIS {} " , env! ( " CARGO_PKG_VERSION " ) ) ;
let mut interface = web_view ::builder ( )
. title ( & title )
. content ( html )
. size ( 1023 , 720 )
2021-03-24 19:06:22 +01:00
. min_size ( 773 , 350 )
2021-03-10 22:21:50 +01:00
. resizable ( true )
2021-05-07 14:44:40 +02:00
. debug ( false )
2021-03-10 22:21:50 +01:00
. user_data ( ( ) )
. invoke_handler ( | web_view , arg | {
debug! ( " Command {} " , arg ) ;
match serde_json ::from_str ( arg ) . unwrap ( ) {
2021-03-18 00:16:17 +01:00
Loaded = > { action_loaded ( & context , web_view ) ; }
LoadKey = > { action_load_key ( & context , web_view ) ; }
2021-05-04 16:47:03 +02:00
CreateKey = > { keystore ::create_key ( Arc ::clone ( & context ) ) ; }
2021-03-18 00:16:17 +01:00
SaveKey = > { action_save_key ( & context ) ; }
2021-05-14 14:14:45 +02:00
SelectKey { index } = > { action_select_key ( & context , web_view , index ) ; }
2021-03-18 18:53:14 +01:00
CheckRecord { data } = > { action_check_record ( web_view , data ) ; }
2021-03-18 00:16:17 +01:00
CheckDomain { name } = > { action_check_domain ( & context , web_view , name ) ; }
2022-04-13 13:02:58 +02:00
MineDomain { name , data , signing , encryption , renewal } = > {
action_create_domain ( Arc ::clone ( & context ) , Arc ::clone ( & miner ) , web_view , name , data , signing , encryption , renewal ) ;
2021-03-10 22:21:50 +01:00
}
2024-07-10 20:15:10 +02:00
TransferDomain { name , owner } = > { info! ( " Transferring '{name}' to '{owner}' " ) ; }
2021-05-10 00:49:01 +02:00
StopMining = > { post ( Event ::ActionStopMining ) ; }
2021-04-06 12:08:50 +02:00
Open { link } = > {
if open ::that ( & link ) . is_err ( ) {
show_warning ( web_view , " Something wrong, I can't open the link 😢 " ) ;
}
}
2021-03-10 22:21:50 +01:00
}
Ok ( ( ) )
} )
. build ( )
. expect ( " Error building GUI " ) ;
2021-05-10 00:49:01 +02:00
run_interface_loop ( & mut interface ) ;
2021-03-18 00:16:17 +01:00
}
/// Indefinitely loops through WebView steps
2021-05-10 00:49:01 +02:00
fn run_interface_loop ( interface : & mut WebView < ( ) > ) {
2021-03-10 22:21:50 +01:00
// We use this ugly loop to lower CPU usage a lot.
// If we use .run() or only .step() in a loop without sleeps it will try
// to support 60FPS and uses more CPU than it should.
let pause = Duration ::from_millis ( 25 ) ;
let mut start = Instant ::now ( ) ;
loop {
match interface . step ( ) {
None = > {
info! ( " Interface closed, exiting " ) ;
2021-05-10 00:49:01 +02:00
post ( Event ::ActionQuit ) ;
2021-03-23 18:55:11 +01:00
thread ::sleep ( Duration ::from_millis ( 100 ) ) ;
2021-03-10 22:21:50 +01:00
break ;
}
Some ( result ) = > {
match result {
Ok ( _ ) = > { }
Err ( _ ) = > {
error! ( " Something wrong with webview, exiting " ) ;
break ;
}
}
}
}
if start . elapsed ( ) . as_millis ( ) > 1 {
thread ::sleep ( pause ) ;
start = Instant ::now ( ) ;
}
}
2021-03-18 00:16:17 +01:00
}
2021-03-18 18:53:14 +01:00
fn action_check_record ( web_view : & mut WebView < ( ) > , data : String ) {
match serde_json ::from_str ::< DnsRecord > ( & data ) {
2021-05-05 09:11:23 +02:00
Ok ( record ) = > {
if let Some ( string ) = record . get_data ( ) {
if string . len ( ) > MAX_DATA_LEN {
web_view . eval ( " recordOkay(false) " ) . expect ( " Error evaluating! " ) ;
} else {
web_view . eval ( " recordOkay(true) " ) . expect ( " Error evaluating! " ) ;
}
}
}
2021-06-09 20:36:36 +02:00
Err ( e ) = > {
web_view . eval ( " recordOkay(false) " ) . expect ( " Error evaluating! " ) ;
dbg! ( e ) ;
}
2021-03-18 18:53:14 +01:00
}
}
2021-03-18 00:16:17 +01:00
fn action_check_domain ( context : & Arc < Mutex < Context > > , web_view : & mut WebView < ( ) > , name : String ) {
let c = context . lock ( ) . unwrap ( ) ;
2021-03-23 18:55:11 +01:00
if let Some ( keystore ) = c . get_keystore ( ) {
let name = name . to_lowercase ( ) ;
2022-09-05 19:12:46 +02:00
let available = match c . chain . can_mine_domain ( c . chain . get_height ( ) , & name , & keystore . get_public ( ) ) {
MineResult ::Fine = > true ,
_ = > false
} ;
2021-03-23 18:55:11 +01:00
web_view . eval ( & format! ( " domainAvailable( {} ) " , available ) ) . expect ( " Error evaluating! " ) ;
}
2021-03-18 00:16:17 +01:00
}
fn action_save_key ( context : & Arc < Mutex < Context > > ) {
2021-05-14 14:14:45 +02:00
if ! context . lock ( ) . unwrap ( ) . has_keys ( ) {
2021-03-23 18:55:11 +01:00
return ;
}
2021-05-04 16:47:03 +02:00
let result = tfd ::save_file_dialog_with_filter ( " Save keys file " , " " , & [ " *.toml " ] , " Key files (*.toml) " ) ;
2021-03-18 00:16:17 +01:00
match result {
None = > { }
2021-05-04 16:47:03 +02:00
Some ( mut new_path ) = > {
if ! new_path . ends_with ( " .toml " ) {
new_path . push_str ( " .toml " ) ;
}
2021-03-18 00:16:17 +01:00
let path = new_path . clone ( ) ;
2021-05-14 14:14:45 +02:00
if let Some ( keystore ) = context . lock ( ) . unwrap ( ) . get_keystore_mut ( ) {
2021-03-23 18:55:11 +01:00
let public = keystore . get_public ( ) . to_string ( ) ;
let hash = keystore . get_hash ( ) . to_string ( ) ;
keystore . save ( & new_path , " " ) ;
info! ( " Key file saved to {} " , & path ) ;
2021-05-10 00:49:01 +02:00
post ( Event ::KeySaved { path , public , hash } ) ;
2021-03-23 18:55:11 +01:00
}
2021-03-18 00:16:17 +01:00
}
}
}
2021-05-14 14:14:45 +02:00
fn action_select_key ( context : & Arc < Mutex < Context > > , web_view : & mut WebView < ( ) > , index : usize ) {
if context . lock ( ) . unwrap ( ) . select_key_by_index ( index ) {
let ( path , public , hash ) = {
let keystore = context . lock ( ) . unwrap ( ) . get_keystore ( ) . cloned ( ) . unwrap ( ) ;
let path = keystore . get_path ( ) . to_owned ( ) ;
let public = keystore . get_public ( ) . to_string ( ) ;
let hash = keystore . get_hash ( ) . to_string ( ) ;
( path , public , hash )
} ;
post ( Event ::KeyLoaded { path , public , hash } ) ;
web_view . eval ( & format! ( " keySelected( {} ) " , index ) ) . expect ( " Error evaluating! " ) ;
}
}
2021-03-23 19:29:51 +01:00
fn action_load_key ( context : & Arc < Mutex < Context > > , web_view : & mut WebView < ( ) > ) {
2021-05-04 16:47:03 +02:00
let result = tfd ::open_file_dialog ( " Open keys file " , " " , Some ( ( & [ " *.key " , " *.toml " ] , " Key files " ) ) ) ;
2021-03-18 00:16:17 +01:00
match result {
None = > { }
Some ( file_name ) = > {
match Keystore ::from_file ( & file_name , " " ) {
None = > {
error! ( " Error loading keystore '{}'! " , & file_name ) ;
2021-03-23 19:29:51 +01:00
show_warning ( web_view , " Error loading key!<br>Key cannot be loaded or its difficulty is not enough. " ) ;
2021-04-10 09:47:21 +02:00
event_fail ( web_view , & format! ( " Error loading key from \\ ' {} \\ '! " , & file_name ) ) ;
2021-03-18 00:16:17 +01:00
}
Some ( keystore ) = > {
2021-05-05 11:50:00 +02:00
info! ( " Loaded keystore with keys: {:?}, {:?} " , & keystore . get_public ( ) , & keystore . get_encryption_public ( ) ) ;
2021-03-18 00:16:17 +01:00
let path = keystore . get_path ( ) . to_owned ( ) ;
let public = keystore . get_public ( ) . to_string ( ) ;
let hash = keystore . get_hash ( ) . to_string ( ) ;
2021-05-10 00:49:01 +02:00
post ( Event ::KeyLoaded { path , public , hash } ) ;
2021-05-14 14:14:45 +02:00
if ! context . lock ( ) . unwrap ( ) . select_key_by_public ( & keystore . get_public ( ) ) {
context . lock ( ) . unwrap ( ) . add_keystore ( keystore ) ;
} else {
warn! ( " This key is already loaded! " ) ;
}
2021-03-18 00:16:17 +01:00
}
}
}
}
}
fn action_loaded ( context : & Arc < Mutex < Context > > , web_view : & mut WebView < ( ) > ) {
2021-05-07 11:28:24 +02:00
info! ( " Interface loaded " ) ;
2021-03-18 00:16:17 +01:00
web_view . eval ( " showMiningIndicator(false, false); " ) . expect ( " Error evaluating! " ) ;
2021-03-26 18:22:43 +01:00
let handle : Handle < ( ) > = web_view . handle ( ) ;
2021-04-10 09:47:21 +02:00
let threads = context . lock ( ) . unwrap ( ) . settings . mining . threads ;
let threads = match threads {
0 = > num_cpus ::get ( ) ,
_ = > threads
} ;
2021-09-21 15:25:42 +02:00
let status = Arc ::new ( Mutex ::new ( UiStatus ::new ( threads ) ) ) ;
2021-12-25 18:40:36 +01:00
let context_copy = Arc ::clone ( context ) ;
2021-05-10 00:49:01 +02:00
let c = context . lock ( ) . unwrap ( ) ;
2021-04-15 12:21:41 +02:00
2021-05-10 00:49:01 +02:00
register ( move | _uuid , e | {
2021-03-21 00:19:09 +01:00
//debug!("Got event from bus {:?}", &e);
2021-03-26 18:22:43 +01:00
let status = Arc ::clone ( & status ) ;
let handle = handle . clone ( ) ;
let context_copy = Arc ::clone ( & context_copy ) ;
2021-04-02 20:05:46 +02:00
let _ = thread ::Builder ::new ( ) . name ( String ::from ( " webui " ) ) . spawn ( move | | {
2021-03-26 18:22:43 +01:00
let mut status = status . lock ( ) . unwrap ( ) ;
2021-04-15 12:21:41 +02:00
let mut context = context_copy . lock ( ) . unwrap ( ) ;
2021-03-26 18:22:43 +01:00
let eval = match e {
2021-04-06 00:31:50 +02:00
Event ::KeyCreated { path , public , hash } = > {
2021-04-15 12:21:41 +02:00
load_domains ( & mut context , & handle ) ;
2021-12-25 18:40:36 +01:00
send_keys_to_ui ( & context , & handle ) ;
2021-04-06 00:31:50 +02:00
event_handle_luck ( & handle , " Key successfully created! Don \\ 't forget to save it! " ) ;
2021-04-06 11:21:31 +02:00
let mut s = format! ( " keystoreChanged(' {} ', ' {} ', ' {} '); " , & path , & public , & hash ) ;
2021-04-15 10:26:05 +02:00
s . push_str ( " showSuccess('New key mined successfully! Save it to a safe place!') " ) ;
2021-04-06 11:21:31 +02:00
s
2021-04-06 00:31:50 +02:00
}
2021-03-26 18:22:43 +01:00
Event ::KeyLoaded { path , public , hash } |
Event ::KeySaved { path , public , hash } = > {
2021-04-15 12:21:41 +02:00
load_domains ( & mut context , & handle ) ;
2021-12-25 18:40:36 +01:00
send_keys_to_ui ( & context , & handle ) ;
2021-03-26 18:22:43 +01:00
format! ( " keystoreChanged(' {} ', ' {} ', ' {} '); " , & path , & public , & hash )
}
Event ::MinerStarted | Event ::KeyGeneratorStarted = > {
status . mining = true ;
2021-04-23 17:36:47 +02:00
status . max_diff = 0 ;
2021-04-06 00:31:50 +02:00
event_handle_info ( & handle , " Mining started " ) ;
2021-03-26 18:22:43 +01:00
String ::from ( " setLeftStatusBarText('Mining...'); showMiningIndicator(true, false); " )
}
2021-06-09 20:36:36 +02:00
Event ::MinerStopped { success , full } = > {
2021-03-26 18:22:43 +01:00
status . mining = false ;
2021-04-23 17:36:47 +02:00
status . max_diff = 0 ;
2021-03-26 18:22:43 +01:00
let mut s = if status . syncing {
String ::from ( " setLeftStatusBarText('Syncing...'); showMiningIndicator(true, true); " )
} else {
String ::from ( " setLeftStatusBarText('Idle'); showMiningIndicator(false, false); " )
} ;
if full {
match success {
2021-04-06 00:31:50 +02:00
true = > {
2021-04-27 19:52:05 +02:00
load_domains ( & mut context , & handle ) ;
2021-04-06 00:31:50 +02:00
event_handle_luck ( & handle , " Mining is successful! " ) ;
s . push_str ( " showSuccess('Block successfully mined!') " ) ;
}
false = > {
event_handle_info ( & handle , " Mining finished without result. " ) ;
2021-05-24 17:36:07 +02:00
s . push_str ( " showWarning('Mining unsuccessful, sorry.') " ) ;
2021-04-06 00:31:50 +02:00
}
2021-03-26 18:22:43 +01:00
}
}
s
}
2021-04-23 13:20:26 +02:00
Event ::MinerStats { thread , speed , max_diff , target_diff } = > {
2021-04-10 09:47:21 +02:00
if status . max_diff < max_diff {
status . max_diff = max_diff ;
}
status . set_thread_speed ( thread , speed ) ;
2021-05-24 17:44:35 +02:00
if thread as usize = = threads - 1 {
2021-04-23 13:20:26 +02:00
format! ( " setLeftStatusBarText('Mining speed {} H/s, max found difficulty {} / {} .'); showMiningIndicator(true, false); " , status . get_speed ( ) , status . max_diff , target_diff )
2021-04-10 09:47:21 +02:00
} else {
String ::new ( )
}
}
2021-04-06 11:21:31 +02:00
Event ::KeyGeneratorStopped = > {
2021-03-26 18:22:43 +01:00
status . mining = false ;
2021-04-06 11:21:31 +02:00
if status . syncing {
2021-03-26 18:22:43 +01:00
String ::from ( " setLeftStatusBarText('Syncing...'); showMiningIndicator(true, true); " )
} else {
String ::from ( " setLeftStatusBarText('Idle'); showMiningIndicator(false, false); " )
2021-03-25 20:55:09 +01:00
}
}
2021-03-26 18:22:43 +01:00
Event ::Syncing { have , height } = > {
status . syncing = true ;
status . synced_blocks = have ;
2021-04-27 19:52:05 +02:00
if height ! = status . sync_height {
event_handle_info ( & handle , " Syncing started... " ) ;
status . sync_height = height ;
}
2021-03-26 18:22:43 +01:00
if status . mining {
String ::from ( " setLeftStatusBarText('Mining...'); showMiningIndicator(true, false); " )
} else {
format! ( " setLeftStatusBarText('Synchronizing {} / {} '); showMiningIndicator(true, true); " , have , height )
}
2021-03-18 00:16:17 +01:00
}
2021-03-26 18:22:43 +01:00
Event ::SyncFinished = > {
2021-04-27 19:52:05 +02:00
load_domains ( & mut context , & handle ) ;
2021-04-06 00:31:50 +02:00
event_handle_info ( & handle , " Syncing finished. " ) ;
2021-03-26 18:22:43 +01:00
status . syncing = false ;
if status . mining {
String ::from ( " setLeftStatusBarText('Mining...'); showMiningIndicator(true, false); " )
} else {
2021-12-25 18:40:36 +01:00
String ::from ( " setLeftStatusBarText('Idle'); showMiningIndicator(false, false); " )
2021-03-26 18:22:43 +01:00
}
2021-03-18 00:16:17 +01:00
}
2021-05-21 23:32:46 +02:00
Event ::NetworkStatus { blocks , domains , keys , nodes } = > {
2021-03-26 18:22:43 +01:00
if status . mining | | status . syncing | | nodes < 3 {
2021-05-21 23:32:46 +02:00
format! ( " setStats( {} , {} , {} , {} ); " , blocks , domains , keys , nodes )
2021-03-26 18:22:43 +01:00
} else {
2021-05-21 23:32:46 +02:00
format! ( " setLeftStatusBarText('Idle'); setStats( {} , {} , {} , {} ); " , blocks , domains , keys , nodes )
2021-03-26 18:22:43 +01:00
}
2021-03-18 00:16:17 +01:00
}
2021-06-09 20:36:36 +02:00
Event ::BlockchainChanged { index } = > {
2021-04-27 17:10:05 +02:00
debug! ( " Current blockchain height is {} " , index ) ;
event_handle_info ( & handle , & format! ( " Blockchain changed, current block count is {} now. " , index ) ) ;
String ::new ( ) // Nothing
}
2021-11-20 16:11:05 +01:00
Event ::Error { text } = > format! ( " showError(' {} ') " , & text ) ,
2021-06-09 20:36:36 +02:00
_ = > String ::new ( )
2021-03-26 18:22:43 +01:00
} ;
2021-03-18 00:16:17 +01:00
2021-03-26 18:22:43 +01:00
if ! eval . is_empty ( ) {
handle . dispatch ( move | web_view | {
web_view . eval ( & eval . replace ( " \\ " , " \\ \\ " ) )
} ) . expect ( " Error dispatching! " ) ;
}
} ) ;
2021-03-18 00:16:17 +01:00
true
} ) ;
2021-03-26 18:22:43 +01:00
2021-03-23 18:55:11 +01:00
if let Some ( keystore ) = c . get_keystore ( ) {
2021-03-26 18:22:43 +01:00
let path = keystore . get_path ( ) . to_owned ( ) ;
let public = keystore . get_public ( ) . to_string ( ) ;
let hash = keystore . get_hash ( ) . to_string ( ) ;
2021-05-10 00:49:01 +02:00
post ( Event ::KeyLoaded { path , public , hash } ) ;
2021-03-23 18:55:11 +01:00
}
2021-04-20 20:54:45 +02:00
let index = c . chain . get_height ( ) ;
2021-04-27 19:52:05 +02:00
if index > 0 {
2021-05-10 00:49:01 +02:00
post ( Event ::BlockchainChanged { index } ) ;
2021-05-02 12:55:51 +02:00
}
2021-05-02 16:02:14 +02:00
let zones = c . chain . get_zones ( ) ;
info! ( " Loaded zones: {:?} " , & zones ) ;
if let Ok ( zones ) = serde_json ::to_string ( & zones ) {
2021-05-02 12:55:51 +02:00
let _ = web_view . eval ( & format! ( " zonesChanged(' {} '); " , & zones ) ) ;
2021-04-27 17:10:05 +02:00
}
2021-05-14 14:14:45 +02:00
send_keys_to_ui ( & c , & web_view . handle ( ) ) ;
2021-06-09 20:36:36 +02:00
let command = format! ( " setStats( {} , {} , {} , {} ); " , c . chain . get_height ( ) , c . chain . get_domains_count ( ) , c . chain . get_users_count ( ) , 0 ) ;
if let Err ( e ) = web_view . eval ( & command ) {
2021-05-21 23:32:46 +02:00
error! ( " Error evaluating stats: {} " , e ) ;
}
2021-04-06 00:31:50 +02:00
event_info ( web_view , " Application loaded " ) ;
2021-03-18 00:16:17 +01:00
}
2021-04-15 12:21:41 +02:00
fn load_domains ( context : & mut MutexGuard < Context > , handle : & Handle < ( ) > ) {
let _ = handle . dispatch ( move | web_view | {
web_view . eval ( " clearMyDomains(); " )
} ) ;
2021-05-14 14:14:45 +02:00
let domains = context . chain . get_my_domains ( context . get_keystore ( ) ) ;
2024-07-10 20:15:10 +02:00
let mut domains = domains . iter ( ) . map ( | ( _ , d ) | d ) . collect ::< Vec < _ > > ( ) ;
domains . sort_by ( | a , b | a . 0. cmp ( & b . 0 ) ) ;
for ( domain , timestamp , data ) in domains {
2021-04-15 12:21:41 +02:00
let d = serde_json ::to_string ( & data ) . unwrap ( ) ;
2024-07-10 20:15:10 +02:00
let d = d . replace ( " ' " , " \\ ' " ) . replace ( " \\ n " , " \\ \\ n " ) . replace ( " \" " , " \\ \" " ) ;
2021-05-18 18:16:28 +02:00
let command = format! ( " addMyDomain(' {} ', {} , {} , ' {} '); " , & domain , timestamp , timestamp + DOMAIN_LIFETIME , & d ) ;
2021-04-15 12:21:41 +02:00
let _ = handle . dispatch ( move | web_view | {
web_view . eval ( & command )
} ) ;
}
let _ = handle . dispatch ( move | web_view | {
web_view . eval ( " refreshMyDomains(); " )
} ) ;
}
2021-05-14 14:14:45 +02:00
fn send_keys_to_ui ( context : & MutexGuard < Context > , handle : & Handle < ( ) > ) {
let keys = {
let mut keys = Vec ::new ( ) ;
for key in context . get_keystores ( ) {
let path = key . get_path ( ) . replace ( " \\ " , " / " ) ;
2021-12-25 18:40:36 +01:00
let parts : Vec < & str > = path . rsplitn ( 2 , '/' ) . collect ( ) ;
2021-05-14 14:14:45 +02:00
keys . push ( KeysForJS { file_name : parts [ 0 ] . to_owned ( ) , public : key . get_public ( ) . to_string ( ) } ) ;
}
keys
} ;
if ! keys . is_empty ( ) {
let index = context . get_active_key_index ( ) ;
let _ = handle . dispatch ( move | web_view | {
let command = format! ( " keysChanged(' {} '); keySelected( {} ); " , serde_json ::to_string ( & keys ) . unwrap ( ) , index ) ;
web_view . eval ( & command )
} ) ;
}
}
2022-04-13 13:02:58 +02:00
fn action_create_domain ( context : Arc < Mutex < Context > > , miner : Arc < Mutex < Miner > > , web_view : & mut WebView < ( ) > , name : String , data : String , signing : String , encryption : String , renewal : bool ) {
2021-04-10 09:47:21 +02:00
debug! ( " Creating domain with data: {} " , & data ) ;
2021-03-18 00:16:17 +01:00
let c = Arc ::clone ( & context ) ;
let context = context . lock ( ) . unwrap ( ) ;
2021-05-14 14:14:45 +02:00
if ! context . has_keys ( ) {
2021-03-23 19:29:51 +01:00
show_warning ( web_view , " You don't have keys loaded!<br>Load or mine the keys and try again. " ) ;
2021-05-01 11:28:01 +02:00
let _ = web_view . eval ( " domainMiningUnavailable(); " ) ;
2021-03-23 18:55:11 +01:00
return ;
}
2021-04-18 18:34:32 +02:00
if context . chain . is_waiting_signers ( ) {
show_warning ( web_view , " Waiting for last full block to be signed. Try again later. " ) ;
2021-05-01 11:28:01 +02:00
let _ = web_view . eval ( " domainMiningUnavailable(); " ) ;
2021-04-18 18:34:32 +02:00
info! ( " Waiting for last full block to be signed. Try again later. " ) ;
return ;
}
2021-05-14 14:14:45 +02:00
let keystore = context . get_keystore ( ) . unwrap ( ) . clone ( ) ;
2021-03-23 18:55:11 +01:00
let pub_key = keystore . get_public ( ) ;
2021-04-23 19:17:05 +02:00
let data = match serde_json ::from_str ::< DomainData > ( & data ) {
2021-06-09 20:36:36 +02:00
Ok ( data ) = > data ,
2021-04-11 17:50:55 +02:00
Err ( e ) = > {
2021-04-10 09:47:21 +02:00
show_warning ( web_view , " Something wrong with domain data. I cannot mine it. " ) ;
2021-05-01 11:28:01 +02:00
let _ = web_view . eval ( " domainMiningUnavailable(); " ) ;
2021-04-11 17:50:55 +02:00
warn! ( " Error parsing data: {} " , e ) ;
2021-04-10 09:47:21 +02:00
return ;
}
} ;
2021-05-07 10:14:14 +02:00
info! ( " Parsed domain data: \n {:#?} " , & data ) ;
2021-05-05 09:11:23 +02:00
if data . records . len ( ) > MAX_RECORDS {
show_warning ( web_view , " Too many records. Mining more than 30 records not allowed. " ) ;
let _ = web_view . eval ( " domainMiningUnavailable(); " ) ;
return ;
}
2021-04-10 20:02:51 +02:00
// Check if yggdrasil only quality of zone is not violated
let zones = context . chain . get_zones ( ) ;
2021-05-02 12:55:51 +02:00
for z in zones {
2021-12-25 18:40:36 +01:00
if z . name = = data . zone & & z . yggdrasil {
for record in & data . records {
if ! is_yggdrasil_record ( record ) {
show_warning ( web_view , & format! ( " Zone {} is Yggdrasil only, you cannot use IPs from clearnet! " , & data . zone ) ) ;
let _ = web_view . eval ( " domainMiningUnavailable(); " ) ;
return ;
2021-04-10 20:02:51 +02:00
}
}
}
}
2021-05-05 11:50:00 +02:00
let ( signing , encryption ) = if signing . is_empty ( ) | | encryption . is_empty ( ) {
( keystore . get_public ( ) , keystore . get_encryption_public ( ) )
2021-05-04 16:47:03 +02:00
} else {
2021-05-05 11:50:00 +02:00
( Bytes ::new ( from_hex ( & signing ) . unwrap ( ) ) , Bytes ::new ( from_hex ( & encryption ) . unwrap ( ) ) )
2021-05-04 16:47:03 +02:00
} ;
2021-04-26 21:49:01 +02:00
match context . chain . can_mine_domain ( context . chain . get_height ( ) , & name , & pub_key ) {
2021-03-18 00:16:17 +01:00
MineResult ::Fine = > {
2022-07-10 23:07:59 +02:00
drop ( context ) ;
2022-04-13 13:02:58 +02:00
create_domain ( c , miner , CLASS_DOMAIN , & name , data , DOMAIN_DIFFICULTY , & keystore , signing , encryption , renewal ) ;
2021-04-10 09:47:21 +02:00
let _ = web_view . eval ( " domainMiningStarted(); " ) ;
event_info ( web_view , & format! ( " Mining of domain \\ ' {} \\ ' has started " , & name ) ) ;
2021-03-18 00:16:17 +01:00
}
2021-05-01 11:28:01 +02:00
MineResult ::WrongName = > {
show_warning ( web_view , " You can't mine this domain! " ) ;
let _ = web_view . eval ( " domainMiningUnavailable(); " ) ;
}
MineResult ::WrongData = > {
show_warning ( web_view , " You have an error in records! " ) ;
let _ = web_view . eval ( " domainMiningUnavailable(); " ) ;
}
MineResult ::WrongKey = > {
show_warning ( web_view , " You can't mine with current key! " ) ;
let _ = web_view . eval ( " domainMiningUnavailable(); " ) ;
}
MineResult ::WrongZone = > {
show_warning ( web_view , " You can't mine domain in this zone! " ) ;
let _ = web_view . eval ( " domainMiningUnavailable(); " ) ;
}
MineResult ::NotOwned = > {
show_warning ( web_view , " This domain is already taken, and it is not yours! " ) ;
let _ = web_view . eval ( " domainMiningUnavailable(); " ) ;
}
2021-03-18 00:16:17 +01:00
MineResult ::Cooldown { time } = > {
2021-05-09 18:44:09 +02:00
event_info ( web_view , & format! ( " You have cooldown {} ! " , format_cooldown ( time ) ) ) ;
show_warning ( web_view , & format! ( " You have cooldown {} ! " , format_cooldown ( time ) ) ) ;
2021-05-01 11:28:01 +02:00
let _ = web_view . eval ( " domainMiningUnavailable(); " ) ;
2021-03-18 00:16:17 +01:00
}
}
}
2021-05-09 18:44:09 +02:00
fn format_cooldown ( time : i64 ) -> String {
if time < = 60 {
return format! ( " {} seconds " , time ) ;
}
let minutes = time / 60 ;
if minutes < = 60 {
return format! ( " {} minutes " , minutes ) ;
}
format! ( " {} hours " , minutes / 60 )
}
2021-03-18 00:16:17 +01:00
fn show_warning ( web_view : & mut WebView < ( ) > , text : & str ) {
2021-03-24 19:06:22 +01:00
let str = text . replace ( '\'' , " \\ ' " ) ;
match web_view . eval ( & format! ( " showWarning(' {} '); " , & str ) ) {
2021-03-18 00:16:17 +01:00
Ok ( _ ) = > { }
Err ( _ ) = > { warn! ( " Error showing warning! " ) ; }
}
2021-03-10 22:21:50 +01:00
}
2021-03-26 12:39:19 +01:00
#[ allow(dead_code) ]
2021-03-25 20:55:09 +01:00
fn show_success ( web_view : & mut WebView < ( ) > , text : & str ) {
let str = text . replace ( '\'' , " \\ ' " ) ;
match web_view . eval ( & format! ( " showSuccess(' {} '); " , & str ) ) {
Ok ( _ ) = > { }
Err ( _ ) = > { warn! ( " Error showing success! " ) ; }
}
}
2021-04-06 00:31:50 +02:00
#[ allow(dead_code) ]
fn event_info ( web_view : & mut WebView < ( ) > , message : & str ) {
let _ = web_view . eval ( & format_event_now ( " info " , message ) ) ;
}
#[ allow(dead_code) ]
fn event_warn ( web_view : & mut WebView < ( ) > , message : & str ) {
let _ = web_view . eval ( & format_event_now ( " warn " , message ) ) ;
}
#[ allow(dead_code) ]
fn event_fail ( web_view : & mut WebView < ( ) > , message : & str ) {
let _ = web_view . eval ( & format_event_now ( " fail " , message ) ) ;
}
#[ allow(dead_code) ]
fn event_handle_info ( handle : & Handle < ( ) > , message : & str ) {
let message = message . to_owned ( ) ;
let _ = handle . dispatch ( move | web_view | {
web_view . eval ( & format_event_now ( " info " , & message ) )
} ) ;
}
#[ allow(dead_code) ]
fn event_handle_warn ( handle : & Handle < ( ) > , message : & str ) {
let message = message . to_owned ( ) ;
let _ = handle . dispatch ( move | web_view | {
web_view . eval ( & format_event_now ( " warn " , & message ) )
} ) ;
}
#[ allow(dead_code) ]
fn event_handle_fail ( handle : & Handle < ( ) > , message : & str ) {
let message = message . to_owned ( ) ;
let _ = handle . dispatch ( move | web_view | {
web_view . eval ( & format_event_now ( " fail " , & message ) )
} ) ;
}
#[ allow(dead_code) ]
fn event_handle_luck ( handle : & Handle < ( ) > , message : & str ) {
let message = message . to_owned ( ) ;
let _ = handle . dispatch ( move | web_view | {
web_view . eval ( & format_event_now ( " luck " , & message ) )
} ) ;
}
#[ allow(dead_code) ]
fn format_event ( kind : & str , time : DateTime < Local > , message : & str ) -> String {
format! ( " addEvent(' {} ', ' {} ', ' {} '); " , kind , time . format ( " %d.%m.%y %X " ) , message )
}
fn format_event_now ( kind : & str , message : & str ) -> String {
let time = Local ::now ( ) ;
format! ( " addEvent(' {} ', ' {} ', ' {} '); " , kind , time . format ( " %d.%m.%y %X " ) , message )
}
2021-12-25 18:40:36 +01:00
#[ allow(clippy::too_many_arguments) ]
2022-04-13 13:02:58 +02:00
fn create_domain ( context : Arc < Mutex < Context > > , miner : Arc < Mutex < Miner > > , class : & str , name : & str , mut data : DomainData , difficulty : u32 , keystore : & Keystore , signing : Bytes , encryption : Bytes , renewal : bool ) {
2021-04-23 19:17:05 +02:00
let name = name . to_owned ( ) ;
2021-05-04 16:47:03 +02:00
let encrypted = CryptoBox ::encrypt ( encryption . as_slice ( ) , name . as_bytes ( ) ) . expect ( " Error encrypting domain name! " ) ;
data . encrypted = Bytes ::from_bytes ( & encrypted ) ;
2021-04-23 19:17:05 +02:00
let data = serde_json ::to_string ( & data ) . unwrap ( ) ;
2021-05-04 16:47:03 +02:00
let ( signing , encryption ) = if signing . is_empty ( ) | | encryption . is_empty ( ) {
( keystore . get_public ( ) , keystore . get_encryption_public ( ) )
} else {
( signing , encryption )
} ;
let transaction = Transaction ::from_str ( name , class . to_owned ( ) , data , signing , encryption ) ;
2021-06-30 13:25:43 +02:00
// If this domain is already in blockchain we approve slightly smaller difficulty
2022-05-12 14:50:31 +02:00
let height = context . lock ( ) . unwrap ( ) . chain . get_height ( ) ;
let discount = context . lock ( ) . unwrap ( ) . chain . get_identity_discount ( & transaction . identity , renewal , height , Utc ::now ( ) . timestamp ( ) ) ;
2021-06-30 13:25:43 +02:00
let block = Block ::new ( Some ( transaction ) , keystore . get_public ( ) , Bytes ::default ( ) , difficulty - discount ) ;
2021-04-23 19:17:05 +02:00
miner . lock ( ) . unwrap ( ) . add_block ( block , keystore . clone ( ) ) ;
}
2021-03-10 22:21:50 +01:00
#[ derive(Deserialize) ]
#[ serde(tag = " cmd " , rename_all = " camelCase " ) ]
pub enum Cmd {
Loaded ,
2021-03-18 00:16:17 +01:00
LoadKey ,
CreateKey ,
SaveKey ,
2021-05-14 14:14:45 +02:00
SelectKey { index : usize } ,
2021-03-18 18:53:14 +01:00
CheckRecord { data : String } ,
2021-03-10 22:21:50 +01:00
CheckDomain { name : String } ,
2022-04-13 13:02:58 +02:00
MineDomain { name : String , data : String , signing : String , encryption : String , renewal : bool } ,
2021-03-10 22:21:50 +01:00
TransferDomain { name : String , owner : String } ,
StopMining ,
2021-06-09 20:36:36 +02:00
Open { link : String }
2021-03-10 22:21:50 +01:00
}
2021-09-21 15:25:42 +02:00
struct UiStatus {
2021-03-10 22:21:50 +01:00
pub mining : bool ,
pub syncing : bool ,
pub synced_blocks : u64 ,
pub sync_height : u64 ,
2021-04-10 09:47:21 +02:00
pub max_diff : u32 ,
pub speed : Vec < u64 >
2021-03-10 22:21:50 +01:00
}
2021-09-21 15:25:42 +02:00
impl UiStatus {
2021-04-10 09:47:21 +02:00
fn new ( threads : usize ) -> Self {
2021-12-25 18:40:36 +01:00
let speed = vec! [ 0 ; threads ] ;
2021-09-21 15:25:42 +02:00
UiStatus { mining : false , syncing : false , synced_blocks : 0 , sync_height : 0 , max_diff : 0 , speed }
2021-04-10 09:47:21 +02:00
}
2021-05-24 17:36:07 +02:00
fn set_thread_speed ( & mut self , thread : u32 , speed : u64 ) {
self . speed [ thread as usize ] = speed ;
2021-04-10 09:47:21 +02:00
}
fn get_speed ( & self ) -> u64 {
self . speed . iter ( ) . sum ( )
2021-03-10 22:21:50 +01:00
}
}
2021-05-14 14:14:45 +02:00
#[ derive(Serialize) ]
struct KeysForJS {
file_name : String ,
public : String
}
2021-03-10 22:21:50 +01:00
fn inline_style ( s : & str ) -> String {
format! ( r # "<style type="text/css">{}</style>"# , s )
}
fn inline_script ( s : & str ) -> String {
format! ( r # "<script type="text/javascript">{}</script>"# , s )
2021-06-09 20:36:36 +02:00
}