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 };
use serde ::Deserialize ;
2021-04-10 09:47:21 +02:00
use web_view ::Content ;
2021-03-10 22:21:50 +01:00
2021-04-10 20:02:51 +02:00
use alfis ::{ Block , Bytes , Context , get_domain_zone , Keystore , Transaction , ZONE_MIN_DIFFICULTY , is_yggdrasil_record };
2021-04-10 09:47:21 +02:00
use alfis ::{ check_domain , keys };
use alfis ::blockchain ::transaction ::{ DomainData , ZoneData };
use alfis ::blockchain ::types ::MineResult ;
use alfis ::commons ::{ ZONE_DIFFICULTY , ZONE_MAX_LENGTH , CLASS_DOMAIN , CLASS_ZONE };
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-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 )
. debug ( false )
. 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 ); }
CreateKey => { keys ::create_key ( Arc ::clone ( & context )); }
SaveKey => { action_save_key ( & context ); }
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-04-10 09:47:21 +02:00
MineDomain { name , data } => {
action_create_domain ( Arc ::clone ( & context ), Arc ::clone ( & miner ), web_view , name , data );
2021-03-10 22:21:50 +01:00
}
TransferDomain { .. } => {}
2021-03-18 00:16:17 +01:00
CheckZone { name } => { action_check_zone ( & context , web_view , name ); }
2021-04-10 09:47:21 +02:00
MineZone { name , data } => {
action_create_zone ( Arc ::clone ( & context ), Arc ::clone ( & miner ), web_view , name , data );
}
2021-03-18 00:16:17 +01:00
StopMining => { context . lock (). unwrap (). bus . 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-03-23 18:55:11 +01:00
let mut context = Arc ::clone ( & context );
run_interface_loop ( & mut context , & mut interface );
2021-03-18 00:16:17 +01:00
interface . exit ();
}
/// Indefinitely loops through WebView steps
2021-03-23 18:55:11 +01:00
fn run_interface_loop ( context : & mut Arc < Mutex < Context >> , 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-03-23 18:55:11 +01:00
context . lock (). unwrap (). bus . post ( Event ::ActionQuit );
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
}
fn action_check_zone ( context : & Arc < Mutex < Context >> , web_view : & mut WebView < () > , name : String ) {
let name = name . to_lowercase ();
if name . len () > ZONE_MAX_LENGTH || ! check_domain ( & name , false ) || context . lock (). unwrap (). x_zones . has_zone ( & name ) {
web_view . eval ( "zoneAvailable(false)" ). expect ( "Error evaluating!" );
} else {
let c = context . lock (). unwrap ();
2021-03-23 18:55:11 +01:00
if let Some ( keystore ) = c . get_keystore () {
let available = c . get_chain (). is_domain_available ( & name , & keystore );
web_view . eval ( & format! ( "zoneAvailable( {} )" , available )). expect ( "Error evaluating!" );
}
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 ) {
Ok ( _ ) => { web_view . eval ( "recordOkay(true)" ). expect ( "Error evaluating!" ); }
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 ();
let available = c . get_chain (). is_domain_available ( & name , & keystore );
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-03-23 18:55:11 +01:00
if context . lock (). unwrap (). get_keystore (). is_none () {
return ;
}
2021-03-18 00:16:17 +01:00
let result = tfd ::save_file_dialog_with_filter ( "Save keys file" , "" , & [ "*.key" ], "Key files (*.key)" );
match result {
None => {}
Some ( new_path ) => {
let mut context = context . lock (). unwrap ();
let path = new_path . clone ();
2021-03-23 18:55:11 +01:00
if let Some ( mut keystore ) = context . get_keystore () {
let public = keystore . get_public (). to_string ();
let hash = keystore . get_hash (). to_string ();
keystore . save ( & new_path , "" );
info! ( "Key file saved to {}" , & path );
context . bus . post ( Event ::KeySaved { path , public , hash });
}
2021-03-18 00:16:17 +01:00
}
}
}
2021-03-23 19:29:51 +01:00
fn action_load_key ( context : & Arc < Mutex < Context >> , web_view : & mut WebView < () > ) {
2021-03-18 00:16:17 +01:00
let result = tfd ::open_file_dialog ( "Open keys file" , "" , Some (( & [ "*.key" ], "*.key" )));
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 ) => {
info! ( "Loaded keystore with key: {:?}" , & keystore . get_public ());
let mut c = context . lock (). unwrap ();
let path = keystore . get_path (). to_owned ();
let public = keystore . get_public (). to_string ();
let hash = keystore . get_hash (). to_string ();
c . bus . post ( Event ::KeyLoaded { path , public , hash });
2021-03-23 18:55:11 +01:00
c . set_keystore ( Some ( keystore ));
2021-03-18 00:16:17 +01:00
}
}
}
}
}
fn action_loaded ( context : & Arc < Mutex < Context >> , web_view : & mut WebView < () > ) {
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-03-18 00:16:17 +01:00
let mut c = context . lock (). unwrap ();
2021-04-15 12:21:41 +02:00
2021-03-18 00:16:17 +01:00
c . bus . 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-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-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 => {
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 } => {
2021-04-06 00:31:50 +02:00
event_handle_info ( & handle , "Syncing started..." );
2021-03-26 18:22:43 +01:00
status . syncing = true ;
status . synced_blocks = have ;
status . sync_height = height ;
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-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-03-26 18:22:43 +01:00
Event ::BlockchainChanged { index } => {
2021-04-03 18:29:41 +02:00
debug! ( "Current blockchain height is {}" , index );
2021-04-06 00:31:50 +02:00
event_handle_info ( & handle , & format! ( "Blockchain changed, current block count is {} now." , index ));
2021-03-26 18:22:43 +01:00
if let Ok ( zones ) = serde_json ::to_string ( & context . chain . get_zones ()) {
let _ = handle . dispatch ( move | web_view | {
web_view . eval ( & format! ( "zonesChanged(' {} ');" , & zones ))
});
}
String ::new () // Nothing
2021-03-18 00:16:17 +01:00
}
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 ();
c . bus . 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-03-26 18:22:43 +01:00
c . bus . post ( Event ::BlockchainChanged { index });
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();" )
});
let domains = context . chain . get_my_domains ( & context . 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-04-10 09:47:21 +02:00
fn action_create_domain ( context : Arc < Mutex < Context >> , miner : Arc < Mutex < Miner >> , web_view : & mut WebView < () > , name : String , data : String ) {
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-03-23 18:55:11 +01:00
if context . get_keystore (). is_none () {
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-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." );
info! ( "Waiting for last full block to be signed. Try again later." );
return ;
}
2021-03-23 18:55:11 +01:00
let keystore = context . get_keystore (). unwrap ();
let pub_key = keystore . get_public ();
2021-04-10 09:47:21 +02:00
let mut data = match serde_json ::from_str ::< DomainData > ( & data ) {
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-04-11 17:50:55 +02:00
warn! ( "Error parsing data: {}" , e );
2021-04-10 09:47:21 +02:00
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 ();
for z in & zones {
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 ));
return ;
}
}
}
}
}
2021-04-10 09:47:21 +02:00
match context . chain . can_mine_domain ( & name , & pub_key ) {
2021-03-18 00:16:17 +01:00
MineResult ::Fine => {
let zone = get_domain_zone ( & name );
let difficulty = context . chain . get_zone_difficulty ( & zone );
2021-04-10 09:47:21 +02:00
let last_block = context . chain . last_block (). unwrap ();
let encrypted = keystore . encrypt ( name . as_bytes (), & last_block . hash . as_slice ()[ .. 12 ]);
data . domain = encrypted ;
let data = serde_json ::to_string ( & data ). unwrap ();
std ::mem ::drop ( context );
create_domain ( c , miner , CLASS_DOMAIN , & name , & data , difficulty , & keystore );
let _ = web_view . eval ( "domainMiningStarted();" );
event_info ( web_view , & format! ( "Mining of domain \\ ' {} \\ ' has started" , & name ));
2021-03-18 00:16:17 +01:00
}
MineResult ::WrongName => { show_warning ( web_view , "You can't mine this domain!" ); }
MineResult ::WrongData => { show_warning ( web_view , "You have an error in records!" ); }
MineResult ::WrongKey => { show_warning ( web_view , "You can't mine with current key!" ); }
MineResult ::WrongZone => { show_warning ( web_view , "You can't mine domain in this zone!" ); }
MineResult ::NotOwned => { show_warning ( web_view , "This domain is already taken, and it is not yours!" ); }
MineResult ::Cooldown { time } => {
2021-04-06 00:31:50 +02:00
event_info ( web_view , & format! ( "You have cooldown, just {} more minutes!" , time / 60 ));
2021-03-18 00:16:17 +01:00
show_warning ( web_view , & format! ( "You have cooldown, just {} more minutes!" , time / 60 ));
}
}
}
2021-03-18 22:48:29 +01:00
fn action_create_zone ( context : Arc < Mutex < Context >> , miner : Arc < Mutex < Miner >> , web_view : & mut WebView < () > , name : String , data : String ) {
2021-04-18 18:34:32 +02:00
if context . lock (). unwrap (). chain . is_waiting_signers () {
show_warning ( web_view , "Waiting for last full block to be signed. Try again later." );
info! ( "Waiting for last full block to be signed. Try again later." );
return ;
}
2021-03-18 00:16:17 +01:00
let name = name . to_lowercase ();
if name . len () > ZONE_MAX_LENGTH || ! check_domain ( & name , false ) || context . lock (). unwrap (). x_zones . has_zone ( & name ) {
warn! ( "This zone is unavailable for mining!" );
show_warning ( web_view , "This zone is unavailable for mining!" );
return ;
}
let data = data . to_lowercase ();
2021-04-10 09:47:21 +02:00
let mut data = match serde_json ::from_str ::< ZoneData > ( & data ) {
Ok ( zone ) => {
if zone . difficulty < ZONE_MIN_DIFFICULTY {
warn! ( "Zone difficulty cannot be lower than {}!" , ZONE_MIN_DIFFICULTY );
show_warning ( web_view , & format! ( "Zone difficulty cannot be lower than {} !" , ZONE_MIN_DIFFICULTY ));
return ;
}
if name != zone . name {
warn! ( "Something wrong with zone data!" );
show_warning ( web_view , "Something wrong with zone data!" );
return ;
}
zone
}
Err ( _ ) => {
warn! ( "Something wrong with zone data!" );
show_warning ( web_view , "Something wrong with zone data!" );
return ;
}
};
2021-03-18 00:16:17 +01:00
let ( keystore , transaction ) = {
let context = context . lock (). unwrap ();
( context . get_keystore (), context . chain . get_domain_transaction ( & name ))
};
2021-03-23 18:55:11 +01:00
if let Some ( keystore ) = keystore {
2021-04-10 09:47:21 +02:00
data . owners = if data . owners . is_empty () {
vec! ( keystore . get_public ())
} else {
data . owners
};
let data = serde_json ::to_string ( & data ). unwrap ();
2021-03-23 18:55:11 +01:00
match transaction {
None => {
2021-04-10 09:47:21 +02:00
create_domain ( Arc ::clone ( & context ), miner . clone (), CLASS_ZONE , & name , & data , ZONE_DIFFICULTY , & keystore );
2021-04-06 00:31:50 +02:00
event_info ( web_view , & format! ( "Mining of zone \\ ' {} \\ ' has started" , & name ));
2021-03-23 18:55:11 +01:00
}
Some ( transaction ) => {
if transaction . pub_key == keystore . get_public () {
2021-04-10 09:47:21 +02:00
create_domain ( Arc ::clone ( & context ), miner . clone (), CLASS_ZONE , & name , & data , ZONE_DIFFICULTY , & keystore );
2021-04-06 00:31:50 +02:00
event_info ( web_view , & format! ( "Mining of zone \\ ' {} \\ ' has started" , & name ));
2021-03-23 18:55:11 +01:00
} else {
warn! ( "Tried to mine not owned domain!" );
show_warning ( web_view , "You cannot change domain that you don't own!" );
}
2021-03-18 00:16:17 +01:00
}
}
2021-03-23 18:55:11 +01:00
} else {
warn! ( "Can not mine without 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-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-04-10 09:47:21 +02:00
fn create_domain ( context : Arc < Mutex < Context >> , miner : Arc < Mutex < Miner >> , class : & str , name : & str , data : & str , difficulty : u32 , keystore : & Keystore ) {
2021-03-16 14:00:14 +01:00
let name = name . to_owned ();
info! ( "Generating domain or zone {}" , & name );
2021-03-16 12:24:31 +01:00
if context . lock (). unwrap (). x_zones . has_zone ( & name ) {
2021-03-16 14:00:14 +01:00
error! ( "Unable to mine IANA/OpenNIC/etc zone {}!" , & name );
2021-03-11 01:41:19 +01:00
return ;
}
2021-04-10 09:47:21 +02:00
let transaction = Transaction ::from_str ( name , class . to_owned (), data . to_owned (), keystore . get_public (). clone ());
2021-03-17 14:55:05 +01:00
let block = Block ::new ( Some ( transaction ), keystore . get_public (), Bytes ::default (), difficulty );
2021-03-23 18:55:11 +01: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-03-10 22:21:50 +01:00
CheckZone { name : String },
2021-03-18 00:16:17 +01:00
MineZone { name : String , data : String },
2021-03-18 18:53:14 +01:00
CheckRecord { data : String },
2021-03-10 22:21:50 +01:00
CheckDomain { name : String },
2021-04-10 09:47:21 +02:00
MineDomain { name : String , data : 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
}
}
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 )
}