From 9b093a8172e8913595f34dad5b94cac270a412a3 Mon Sep 17 00:00:00 2001 From: Revertron Date: Thu, 15 Apr 2021 12:21:41 +0200 Subject: [PATCH] Implemented presentation and editing for domains. --- src/blockchain/chain.rs | 32 +++++++++++++++++++++++++ src/main.rs | 7 ++++++ src/web_ui.rs | 25 ++++++++++++++++++-- src/webview/index.html | 4 ++++ src/webview/scripts.js | 52 +++++++++++++++++++++++++++++++++++++++++ src/webview/styles.css | 21 +++++++++++++++++ 6 files changed, 139 insertions(+), 2 deletions(-) diff --git a/src/blockchain/chain.rs b/src/blockchain/chain.rs index 5824a93..5c7e2c8 100644 --- a/src/blockchain/chain.rs +++ b/src/blockchain/chain.rs @@ -40,6 +40,7 @@ const SQL_GET_LAST_FULL_BLOCK_FOR_KEY: &str = "SELECT * FROM blocks WHERE `trans const SQL_GET_DOMAIN_PUBLIC_KEY_BY_ID: &str = "SELECT pub_key FROM domains WHERE identity = ? ORDER BY id DESC LIMIT 1;"; const SQL_GET_ZONE_PUBLIC_KEY_BY_ID: &str = "SELECT pub_key FROM zones WHERE identity = ? ORDER BY id DESC LIMIT 1;"; const SQL_GET_DOMAIN_BY_ID: &str = "SELECT * FROM domains WHERE identity = ? ORDER BY id DESC LIMIT 1;"; +const SQL_GET_DOMAINS_BY_KEY: &str = "SELECT * FROM domains WHERE pub_key = ?;"; const SQL_GET_ZONES: &str = "SELECT data FROM zones;"; const SQL_GET_OPTIONS: &str = "SELECT * FROM options;"; @@ -521,6 +522,37 @@ impl Chain { } } + pub fn get_my_domains(&self, keystore: &Option) -> HashMap { + if keystore.is_none() { + return HashMap::new(); + } + + let mut result = HashMap::new(); + let keystore = keystore.clone().unwrap(); + let pub_key = keystore.get_public(); + let mut statement = self.db.prepare(SQL_GET_DOMAINS_BY_KEY).unwrap(); + statement.bind(1, &**pub_key).expect("Error in bind"); + while let State::Row = statement.next().unwrap() { + let index = statement.read::(0).unwrap() as u64; + let timestamp = statement.read::(1).unwrap(); + let identity = Bytes::from_bytes(&statement.read::>(2).unwrap()); + let confirmation = Bytes::from_bytes(&statement.read::>(3).unwrap()); + let class = String::from("domain"); + let data = statement.read::(4).unwrap(); + let pub_key = Bytes::from_bytes(&statement.read::>(5).unwrap()); + let transaction = Transaction { identity, confirmation, class, data, pub_key }; + //debug!("Found transaction for domain {}: {:?}", domain, &transaction); + if let Some(data) = transaction.get_domain_data() { + let b = self.get_block(index - 1).unwrap(); + let domain = keystore.decrypt(data.domain.as_slice(), &b.hash.as_slice()[..12]); + let domain = String::from_utf8(domain.to_vec()).unwrap(); + trace!("Found my domain {}", domain); + result.insert(domain, (timestamp, data)); + } + } + result + } + pub fn get_zone_difficulty(&self, zone: &str) -> u32 { let zones = self.get_zones(); for z in zones.iter() { diff --git a/src/main.rs b/src/main.rs index bbd22cf..ece5f88 100644 --- a/src/main.rs +++ b/src/main.rs @@ -129,6 +129,7 @@ fn main() { create_genesis_if_needed(&context, &miner); if no_gui { + print_my_domains(&context); let sleep = Duration::from_millis(1000); loop { thread::sleep(sleep); @@ -145,6 +146,12 @@ fn main() { } } +fn print_my_domains(context: &Arc>) { + let context = context.lock().unwrap(); + let domains = context.chain.get_my_domains(&context.keystore); + debug!("Domains: {:?}", &domains); +} + fn create_genesis_if_needed(context: &Arc>, miner: &Arc>) { // If there is no origin in settings and no blockchain in DB, generate genesis block let context = context.lock().unwrap(); diff --git a/src/web_ui.rs b/src/web_ui.rs index a052c29..a4026be 100644 --- a/src/web_ui.rs +++ b/src/web_ui.rs @@ -4,7 +4,7 @@ extern crate serde; extern crate serde_json; extern crate open; -use std::sync::{Arc, Mutex}; +use std::sync::{Arc, Mutex, MutexGuard}; use std::thread; use std::time::{Duration, Instant}; @@ -195,6 +195,7 @@ fn action_loaded(context: &Arc>, web_view: &mut WebView<()>) { let status = Arc::new(Mutex::new(Status::new(threads))); let context_copy = Arc::clone(&context); let mut c = context.lock().unwrap(); + c.bus.register(move |_uuid, e| { //debug!("Got event from bus {:?}", &e); let status = Arc::clone(&status); @@ -202,9 +203,10 @@ fn action_loaded(context: &Arc>, web_view: &mut WebView<()>) { let context_copy = Arc::clone(&context_copy); let _ = thread::Builder::new().name(String::from("webui")).spawn(move || { let mut status = status.lock().unwrap(); - let context = context_copy.lock().unwrap(); + let mut context = context_copy.lock().unwrap(); let eval = match e { Event::KeyCreated { path, public, hash } => { + load_domains(&mut context, &handle); event_handle_luck(&handle, "Key successfully created! Don\\'t forget to save it!"); let mut s = format!("keystoreChanged('{}', '{}', '{}');", &path, &public, &hash); s.push_str(" showSuccess('New key mined successfully! Save it to a safe place!')"); @@ -212,6 +214,7 @@ fn action_loaded(context: &Arc>, web_view: &mut WebView<()>) { } Event::KeyLoaded { path, public, hash } | Event::KeySaved { path, public, hash } => { + load_domains(&mut context, &handle); format!("keystoreChanged('{}', '{}', '{}');", &path, &public, &hash) } Event::MinerStarted | Event::KeyGeneratorStarted => { @@ -319,6 +322,24 @@ fn action_loaded(context: &Arc>, web_view: &mut WebView<()>) { event_info(web_view, "Application loaded"); } +fn load_domains(context: &mut MutexGuard, handle: &Handle<()>) { + let _ = handle.dispatch(move |web_view|{ + web_view.eval("clearMyDomains();") + }); + let domains = context.chain.get_my_domains(&context.keystore); + debug!("Domains: {:?}", &domains); + for (domain, (timestamp, data)) in domains { + 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();") + }); +} + fn action_create_domain(context: Arc>, miner: Arc>, web_view: &mut WebView<()>, name: String, data: String) { debug!("Creating domain with data: {}", &data); let c = Arc::clone(&context); diff --git a/src/webview/index.html b/src/webview/index.html index 63cbdc2..f76575e 100644 --- a/src/webview/index.html +++ b/src/webview/index.html @@ -116,6 +116,10 @@
+ +
+ +
diff --git a/src/webview/scripts.js b/src/webview/scripts.js index a4dc6c7..d167822 100644 --- a/src/webview/scripts.js +++ b/src/webview/scripts.js @@ -1,5 +1,6 @@ var recordsBuffer = []; var availableZones = []; +var myDomains = []; var currentZone; function addRecord(record) { @@ -96,6 +97,57 @@ function get_record_from_dialog() { return { type: record_type, domain: record_name, ttl: record_ttl, addr: record_data } } +function clearMyDomains() { + myDomains = []; +} + +function addMyDomain(name, timestamp, data) { + myDomains.push({name: name, timestamp: timestamp, data: data}); +} + +function refreshMyDomains() { + var edit_icon = ''; + var card = '

{title}

{tags}{edit}
'; + var tag = '{domain}'; + var cards = ""; + myDomains.forEach(function(value, index, array) { + var title = value.name; + var domain_data = JSON.parse(value.data); + var tags = ""; + var edit = edit_icon.replace("{domain}", title); + domain_data.records.forEach(function(v, i, a) { + if (typeof v.domain !== 'undefined') { + var buf = tag.replace("{domain}", v.domain); + if (typeof v.addr !== 'undefined') { + buf = buf.replace("{ip}", v.addr); + } else if (typeof v.host !== 'undefined') { + buf = buf.replace("{ip}", v.host); + } + tags = tags + buf; + } + }); + cards = cards + card.replace("{title}", title).replace("{tags}", tags).replace("{edit}", edit); + }); + document.getElementById("my_domains").innerHTML = cards; +} + +function editDomain(domain) { + myDomains.forEach(function(value, index, array) { + if (domain != value.name) { + return; + } + var title = value.name; + var domain_data = JSON.parse(value.data); + recordsBuffer = []; + domain_data.records.forEach(function(v, i, a) { + recordsBuffer.push(v); + }); + document.getElementById("new_domain").value = title.replace("." + domain_data.zone, ""); + changeZone(domain_data.zone); + refreshRecordsList(); + }); +} + function onLoad() { external.invoke(JSON.stringify({cmd: 'loaded'})); } diff --git a/src/webview/styles.css b/src/webview/styles.css index 36754f7..686359f 100644 --- a/src/webview/styles.css +++ b/src/webview/styles.css @@ -63,6 +63,21 @@ body { right: 10pt; } +.container.is-fluid.cards-container { + display: flex; + flex-grow: 0; + /*gap: .8em; supported only in Firefox/Edge/Chrome */ + justify-content: center !important; + padding-left: 0 !important; + padding-right: 0 !important; + margin-left: 0 !important; + margin-right: 0 !important; +} + +.container.is-fluid.cards-container .card:not(:last-child) { + margin-right: 0.8rem; +} + .list { overflow-y: auto; } @@ -85,4 +100,10 @@ path { .is-danger:hover > span.icon > svg > path { fill: #ffffff; +} + +svg.tag-button { + width: 24px; + height: 24px; + margin-bottom: .5rem; } \ No newline at end of file