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-04-10 09:47:21 +02:00
use chrono ::{ DateTime , Local };
2021-03-10 22:21:50 +01:00
#[allow(unused_imports)]
use log ::{ debug , error , info , LevelFilter , trace , warn };
2021-05-14 14:14:45 +02:00
use serde ::{ Serialize , Deserialize };
2021-04-10 09:47:21 +02:00
use web_view ::Content ;
2021-03-10 22:21:50 +01:00
2021-05-02 12:55:51 +02:00
use alfis ::{ Block , Bytes , Context , Keystore , Transaction };
2021-05-04 16:47:03 +02:00
use alfis ::keystore ;
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-03-10 22:21:50 +01:00
use alfis ::dns ::protocol ::DnsRecord ;
2021-04-10 09:47:21 +02:00
use alfis ::event ::Event ;
use alfis ::miner ::Miner ;
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-05-04 16:47:03 +02:00
use alfis ::crypto ::CryptoBox ;
2021-05-10 00:49:01 +02:00
use alfis ::eventbus ::{ register , post };
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 ); }
2021-05-04 16:47:03 +02:00
MineDomain { name , data , signing , encryption } => {
action_create_domain ( Arc ::clone ( & context ), Arc ::clone ( & miner ), web_view , name , data , signing , encryption );
2021-03-10 22:21:50 +01:00
}
TransferDomain { .. } => {}
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-03-18 18:53:14 +01:00
Err ( e ) => { web_view . eval ( "recordOkay(false)" ). expect ( "Error evaluating!" ); dbg! ( e ); }
}
}
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 ();
2021-04-26 21:49:01 +02:00
let available = c . get_chain (). is_domain_available ( c . get_chain (). get_height (), & name , & keystore );
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
};
let status = Arc ::new ( Mutex ::new ( Status ::new ( threads )));
2021-03-26 18:22:43 +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-05-14 14:14:45 +02:00
send_keys_to_ui ( & mut 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-05-14 14:14:45 +02:00
send_keys_to_ui ( & mut 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-04-10 09:47:21 +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." );
s . push_str ( " showSuccess('Mining unsuccessful, sorry.')" );
}
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 );
if thread == 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 {
format! ( "setLeftStatusBarText('Idle'); showMiningIndicator(false, false);" )
}
2021-03-18 00:16:17 +01:00
}
2021-03-26 18:22:43 +01:00
Event ::NetworkStatus { nodes , blocks } => {
if status . mining || status . syncing || nodes < 3 {
format! ( "setRightStatusBarText('Nodes: {} , Blocks: {} ')" , nodes , blocks )
} else {
format! ( "setLeftStatusBarText('Idle'); setRightStatusBarText('Nodes: {} , Blocks: {} ')" , nodes , blocks )
}
2021-03-18 00:16:17 +01:00
}
2021-04-27 17:10:05 +02:00
Event ::BlockchainChanged { index } => {
debug! ( "Current blockchain height is {}" , index );
event_handle_info ( & handle , & format! ( "Blockchain changed, current block count is {} now." , index ));
String ::new () // Nothing
}
2021-03-26 18:22:43 +01:00
_ => { String ::new () }
};
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-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 ());
2021-04-17 13:15:53 +02:00
debug! ( "Domains: {:?}" , & domains . values ());
for ( _identity , ( domain , timestamp , data )) in domains {
2021-04-15 12:21:41 +02:00
let d = serde_json ::to_string ( & data ). unwrap ();
let command = format! ( "addMyDomain(' {} ', {} , ' {} ');" , & domain , timestamp , & d );
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 ( " \\ " , "/" );
let parts : Vec <& str > = path . rsplitn ( 2 , "/" ). collect ();
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 )
});
}
}
2021-05-04 16:47:03 +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 ) {
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-04-10 09:47:21 +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-04-10 20:02:51 +02:00
if z . name == data . zone {
if 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 ));
2021-05-01 11:28:01 +02:00
let _ = web_view . eval ( "domainMiningUnavailable();" );
2021-04-10 20:02:51 +02:00
return ;
}
}
}
}
}
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 => {
2021-04-10 09:47:21 +02:00
std ::mem ::drop ( context );
2021-05-04 16:47:03 +02:00
create_domain ( c , miner , CLASS_DOMAIN , & name , data , DOMAIN_DIFFICULTY , & keystore , signing , encryption );
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-05-04 16:47:03 +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 ) {
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-04-23 19:17:05 +02:00
let block = Block ::new ( Some ( transaction ), keystore . get_public (), Bytes ::default (), difficulty );
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 },
2021-05-04 16:47:03 +02:00
MineDomain { name : String , data : String , signing : String , encryption : String },
2021-03-10 22:21:50 +01:00
TransferDomain { name : String , owner : String },
StopMining ,
2021-04-06 12:08:50 +02:00
Open { link : String },
2021-03-10 22:21:50 +01:00
}
struct Status {
pub mining : bool ,
pub syncing : bool ,
pub synced_blocks : u64 ,
pub sync_height : u64 ,
pub nodes_connected : usize ,
2021-04-10 09:47:21 +02:00
pub chain_height : u64 ,
pub max_diff : u32 ,
pub speed : Vec < u64 >
2021-03-10 22:21:50 +01:00
}
impl Status {
2021-04-10 09:47:21 +02:00
fn new ( threads : usize ) -> Self {
let mut speed = Vec ::with_capacity ( threads );
speed . resize ( threads , 0 u64 );
Status { mining : false , syncing : false , synced_blocks : 0 , sync_height : 0 , nodes_connected : 0 , chain_height : 0 , max_diff : 0 , speed }
}
fn set_thread_speed ( & mut self , thread : usize , speed : u64 ) {
self . speed [ thread ] = speed ;
}
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 )
}