Refactored interface. Added log events to Events tab.

This commit is contained in:
Revertron
2021-04-06 00:31:50 +02:00
parent 33a52c8e8a
commit 7830681b38
5 changed files with 186 additions and 60 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "alfis"
version = "0.3.13"
version = "0.3.14"
authors = ["Revertron <alfis@revertron.com>"]
edition = "2018"
build = "build.rs"
+81 -4
View File
@@ -22,6 +22,7 @@ use Cmd::*;
use alfis::blockchain::transaction::{DomainData, ZoneData};
use self::web_view::{WebView, Handle};
use alfis::blockchain::enums::MineResult;
use chrono::{DateTime, Local};
pub fn run_interface(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>) {
let file_content = include_str!("webview/index.html");
@@ -158,6 +159,7 @@ fn action_load_key(context: &Arc<Mutex<Context>>, web_view: &mut WebView<()>) {
None => {
error!("Error loading keystore '{}'!", &file_name);
show_warning(web_view, "Error loading key!<br>Key cannot be loaded or its difficulty is not enough.");
event_fail(web_view, &format!("Error loading key from '{}'!", &file_name));
}
Some(keystore) => {
info!("Loaded keystore with key: {:?}", &keystore.get_public());
@@ -188,13 +190,17 @@ fn action_loaded(context: &Arc<Mutex<Context>>, web_view: &mut WebView<()>) {
let mut status = status.lock().unwrap();
let context = context_copy.lock().unwrap();
let eval = match e {
Event::KeyCreated { path, public, hash } |
Event::KeyCreated { path, public, hash } => {
event_handle_luck(&handle, "Key successfully created! Don\\'t forget to save it!");
format!("keystoreChanged('{}', '{}', '{}');", &path, &public, &hash)
}
Event::KeyLoaded { path, public, hash } |
Event::KeySaved { path, public, hash } => {
format!("keystoreChanged('{}', '{}', '{}');", &path, &public, &hash)
}
Event::MinerStarted | Event::KeyGeneratorStarted => {
status.mining = true;
event_handle_info(&handle, "Mining started");
String::from("setLeftStatusBarText('Mining...'); showMiningIndicator(true, false);")
}
Event::MinerStopped {success, full} => {
@@ -206,8 +212,14 @@ fn action_loaded(context: &Arc<Mutex<Context>>, web_view: &mut WebView<()>) {
};
if full {
match success {
true => { s.push_str(" showSuccess('Block successfully mined!')"); }
false => { s.push_str(" showSuccess('Mining unsuccessful, sorry.')"); }
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.')");
}
}
}
s
@@ -226,6 +238,7 @@ fn action_loaded(context: &Arc<Mutex<Context>>, web_view: &mut WebView<()>) {
s
}
Event::Syncing { have, height } => {
event_handle_info(&handle, "Syncing started...");
status.syncing = true;
status.synced_blocks = have;
status.sync_height = height;
@@ -236,6 +249,7 @@ fn action_loaded(context: &Arc<Mutex<Context>>, web_view: &mut WebView<()>) {
}
}
Event::SyncFinished => {
event_handle_info(&handle, "Syncing finished.");
status.syncing = false;
if status.mining {
String::from("setLeftStatusBarText('Mining...'); showMiningIndicator(true, false);")
@@ -252,6 +266,7 @@ fn action_loaded(context: &Arc<Mutex<Context>>, web_view: &mut WebView<()>) {
}
Event::BlockchainChanged {index} => {
debug!("Current blockchain height is {}", index);
event_handle_info(&handle, &format!("Blockchain changed, current block count is {} now.", index));
if let Ok(zones) = serde_json::to_string(&context.chain.get_zones()) {
let _ = handle.dispatch(move |web_view|{
web_view.eval(&format!("zonesChanged('{}');", &zones))
@@ -279,6 +294,7 @@ fn action_loaded(context: &Arc<Mutex<Context>>, web_view: &mut WebView<()>) {
}
let index = c.chain.height();
c.bus.post(Event::BlockchainChanged { index });
event_info(web_view, "Application loaded");
}
fn action_create_domain(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>, web_view: &mut WebView<()>, name: String, records: &String) {
@@ -291,7 +307,7 @@ fn action_create_domain(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>,
}
let keystore = context.get_keystore().unwrap();
let pub_key = keystore.get_public();
match dbg!(context.chain.can_mine_domain(&name, &records, &pub_key)) {
match context.chain.can_mine_domain(&name, &records, &pub_key) {
MineResult::Fine => {
let zone = get_domain_zone(&name);
let difficulty = context.chain.get_zone_difficulty(&zone);
@@ -301,6 +317,7 @@ fn action_create_domain(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>,
std::mem::drop(context);
create_domain(c, miner, &name, &data, difficulty, &keystore);
let _ = web_view.eval("domainMiningStarted();");
event_info(web_view, &format!("Mining of domain \\'{}\\' has started", &name));
}
}
MineResult::WrongName => { show_warning(web_view, "You can't mine this domain!"); }
@@ -309,6 +326,7 @@ fn action_create_domain(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>,
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 } => {
event_info(web_view, &format!("You have cooldown, just {} more minutes!", time / 60));
show_warning(web_view, &format!("You have cooldown, just {} more minutes!", time / 60));
}
}
@@ -335,10 +353,12 @@ fn action_create_zone(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>, we
match transaction {
None => {
create_domain(Arc::clone(&context), miner.clone(), &name, &data, ZONE_DIFFICULTY, &keystore);
event_info(web_view, &format!("Mining of zone \\'{}\\' has started", &name));
}
Some(transaction) => {
if transaction.pub_key == keystore.get_public() {
create_domain(Arc::clone(&context), miner.clone(), &name, &data, ZONE_DIFFICULTY, &keystore);
event_info(web_view, &format!("Mining of zone \\'{}\\' has started", &name));
} else {
warn!("Tried to mine not owned domain!");
show_warning(web_view, "You cannot change domain that you don't own!");
@@ -368,6 +388,63 @@ fn show_success(web_view: &mut WebView<()>, text: &str) {
}
}
#[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)
}
fn create_domain(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>, name: &str, data: &str, difficulty: u32, keystore: &Keystore) {
let name = name.to_owned();
info!("Generating domain or zone {}", &name);
+44 -43
View File
@@ -9,9 +9,9 @@
</head>
<body onload="onLoad();">
<div class="container">
<div class="main">
<!-- Tabs -->
<div class="tabs is-centered is-boxed">
<div class="row header tabs is-centered is-boxed">
<ul>
<li class="tab is-active">
<a onclick="openTab(this, 'tab_credentials')">
@@ -57,7 +57,7 @@
</div>
<!-- Credentials (Key management) -->
<div class="tab content" id="tab_credentials">
<div class="tab row page" id="tab_credentials">
<div class="field is-grouped">
<div class="control is-expanded has-icons-left">
<input class="input is-expanded" type="text" id="public_key_hash" placeholder="No key loaded" readonly>
@@ -75,7 +75,7 @@
</div>
<!-- Domain mining -->
<div class="tab content is-hidden" id="tab_domains">
<div class="tab row page is-hidden" id="tab_domains">
<div class="field is-grouped is-fullwidth">
<div class="control field has-addons is-expanded">
<div class="control is-expanded has-icons-left">
@@ -113,13 +113,13 @@
</div>
<p class="help">Enter domain name, add some DNS-records, then hit the "Mine domain" button!</p>
<div id="domain_records">
<div class="list pb-3" id="domain_records">
<!-- Here will be our domain records, added by dialog -->
</div>
</div>
<!-- Zone mining -->
<div class="tab content is-hidden" id="tab_zones">
<div class="tab row page is-hidden" id="tab_zones">
<div class="field is-grouped">
<div class="control is-expanded has-icons-left">
<input class="input" type="text" placeholder="ygg" id="new_zone" oninput="onZoneChange()">
@@ -141,27 +141,48 @@
</div>
<!-- Events and notifications -->
<div class="tab content is-hidden" id="tab_events">
<div class="tab row page is-hidden list" id="tab_events">
<!-- TODO -->
</div>
<!-- Help -->
<div class="tab content is-hidden" id="tab_help">
<h1>Welcome to ALFIS!</h1>
<p>ALFIS stands for Alternative Free Identity System.</p>
<p>It gives you an opportunity to create your own domains and use them in decentralized networks, store security certificates for browsers to trust without any centralized CA.</p>
<h2>How this system works?</h2>
<h3>If you just want to be able to resolve our domains</h3>
<p>Carefully configure DNS section in <strong>alfis.toml</strong> and start ALFIS with <code>-n</code> command line switch.
It will start without GUI, but will work as local DNS-resolver.</p>
<h3>If you want to get your own domain</h3>
<ul>
<li>Generate a keypair in "Manage keys" part (you need just one for any number of domains)</li>
<li>Check available zones (for now we have a test zone <code>.yy</code>). In future version a list of available zones will be somewhere here</li>
<li>Go to "Mine domain" part and enter desired domain in first field, if it is not red - you can create it</li>
<li>Carefully add needed DNS-records (you can add them later, but you will need to mine it again)</li>
<li>Just click on "Mine domain" and wait for it, your domain (when properly cooked) will propagate to all blockchain nodes automatically</li>
</ul>
<div class="tab row page is-hidden" id="tab_help">
<div class="content">
<h2>Welcome to ALFIS!</h2>
<p>ALFIS stands for Alternative Free Identity System.</p>
<p>It gives you an opportunity to create your own domains and use them in decentralized networks, store security certificates for browsers to trust without any centralized CA.</p>
<h3>How this system works?</h3>
<h4>If you just want to be able to resolve our domains</h4>
<p>Carefully configure DNS section in <strong>alfis.toml</strong> and start ALFIS with <code>-n</code> command line switch.
It will start without GUI, but will work as local DNS-resolver.</p>
<h4>If you want to get your own domain</h4>
<ul>
<li>Generate a keypair in "Manage keys" part (you need just one for any number of domains)</li>
<li>Go to "Mine domain" part and enter desired domain in first field, choose appropriate zone from dropdown, if it is not red - you can create it</li>
<li>Carefully add needed DNS-records (you can add them later, but you will need to mine it again)</li>
<li>Just click on "Mine domain" and wait for it, your domain (when properly cooked) will propagate to all blockchain nodes automatically</li>
</ul>
</div>
</div>
<div class="row status is-family-code">
<div class="level">
<div class="level-left">
<div class="level-item" id="indicator_parent">
<div class="busy_indicator busy_blue" id="busy_indicator" onclick="miningIndicatorClick(this)">
<span></span>
<span></span>
</div>
</div>
<div class="level-item">
<div id="status_bar_left">Connecting...</div>
</div>
</div>
<div class="level-right">
<div class="level-item" id="status_bar_right">No data</div>
</div>
</div>
</div>
</div>
@@ -270,25 +291,5 @@
<p id="success_text"></p>
</div>
<div class="footer is-family-code">
<div class="level">
<div class="level-left">
<div class="level-item" id="indicator_parent">
<div class="busy_indicator busy_blue" id="busy_indicator" onclick="miningIndicatorClick(this)">
<span></span>
<span></span>
</div>
</div>
<div class="level-item">
<div id="status_bar_left">Connecting...</div>
</div>
</div>
<div class="level-right">
<div class="level-item" id="status_bar_right">No data</div>
</div>
</div>
</div>
</body>
</html>
+19 -3
View File
@@ -105,9 +105,9 @@ function openTab(element, tabName) {
var i, tabContent, tabLinks;
// Get all elements with class="content" and hide them
tabContent = document.getElementsByClassName("tab content");
tabContent = document.getElementsByClassName("tab row page");
for (i = 0; i < tabContent.length; i++) {
tabContent[i].className = "tab content is-hidden";
tabContent[i].className = "tab row page is-hidden";
}
// Get all elements with class="tab" and remove the class "is-active"
@@ -117,7 +117,7 @@ function openTab(element, tabName) {
}
// Show the current tab, and add an "is-active" class to the button that opened the tab
document.getElementById(tabName).className = "tab content";
document.getElementById(tabName).className = "tab row page";
element.parentElement.className = "tab is-active";
refreshRecordsList();
}
@@ -315,12 +315,28 @@ function setRightStatusBarText(text) {
bar.innerHTML = text;
}
function addEvent(type, time, message) {
var t = "";
if (type == 'warn') {
t = "is-warning";
} else if (type == 'fail') {
t = "is-danger";
} else if (type == 'luck') {
t = "is-success";
}
var buf = "<article class=\"message mb-1 {1}\"><div class=\"message-body px-2 py-1\"><strong>{2}</strong>&nbsp;&nbsp;{3}</div></article>".replace("{1}", t).replace("{2}", time).replace("{3}", message);
var tab_events = document.getElementById("tab_events");
tab_events.innerHTML = tab_events.innerHTML + buf;
}
function keystoreChanged(path, pub_key, hash) {
if (path == '') {
path = "In memory";
}
var public_key_hash = document.getElementById("public_key_hash");
public_key_hash.value = hash;
public_key_hash.title = path + "\n" + pub_key;
var save_key = document.getElementById("save_key");
save_key.disabled = false;
+41 -9
View File
@@ -1,8 +1,45 @@
html {
overflow-y: auto;
min-width: 768px;
overflow-y: hidden;
}
html,
body {
height: 100%;
margin: 0;
}
.main {
display: flex;
flex-flow: column;
height: 100%;
padding-top: 10pt;
}
.main .row {
/*border: 1px dotted grey;*/
}
.main .row.header {
flex: 0 1 auto;
}
.main .row.page {
display: flex;
flex-flow: column;
flex: 1 1 auto;
margin-left: 10pt;
margin-right: 10pt;
overflow-y: auto;
}
.main .row.status {
flex: 0 1 auto;
background-color: #f4f4f4;
padding: 0.2rem 0.5rem 0.2rem 0.5rem;
}
/* ========================================== */
.container {
margin: 10pt;
}
@@ -25,13 +62,8 @@ html {
right: 10pt;
}
.footer {
background-color: #f4f4f4;
padding: 0.2rem 0.5rem 0.2rem 0.5rem;
width: 100%;
position: absolute;
bottom: 0px;
z-index: 9;
.list {
overflow-y: auto;
}
path {