Implemented presentation and editing for domains.
This commit is contained in:
@@ -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_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_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_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_ZONES: &str = "SELECT data FROM zones;";
|
||||||
|
|
||||||
const SQL_GET_OPTIONS: &str = "SELECT * FROM options;";
|
const SQL_GET_OPTIONS: &str = "SELECT * FROM options;";
|
||||||
@@ -521,6 +522,37 @@ impl Chain {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_my_domains(&self, keystore: &Option<Keystore>) -> HashMap<String, (i64, DomainData)> {
|
||||||
|
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::<i64>(0).unwrap() as u64;
|
||||||
|
let timestamp = statement.read::<i64>(1).unwrap();
|
||||||
|
let identity = Bytes::from_bytes(&statement.read::<Vec<u8>>(2).unwrap());
|
||||||
|
let confirmation = Bytes::from_bytes(&statement.read::<Vec<u8>>(3).unwrap());
|
||||||
|
let class = String::from("domain");
|
||||||
|
let data = statement.read::<String>(4).unwrap();
|
||||||
|
let pub_key = Bytes::from_bytes(&statement.read::<Vec<u8>>(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 {
|
pub fn get_zone_difficulty(&self, zone: &str) -> u32 {
|
||||||
let zones = self.get_zones();
|
let zones = self.get_zones();
|
||||||
for z in zones.iter() {
|
for z in zones.iter() {
|
||||||
|
|||||||
@@ -129,6 +129,7 @@ fn main() {
|
|||||||
|
|
||||||
create_genesis_if_needed(&context, &miner);
|
create_genesis_if_needed(&context, &miner);
|
||||||
if no_gui {
|
if no_gui {
|
||||||
|
print_my_domains(&context);
|
||||||
let sleep = Duration::from_millis(1000);
|
let sleep = Duration::from_millis(1000);
|
||||||
loop {
|
loop {
|
||||||
thread::sleep(sleep);
|
thread::sleep(sleep);
|
||||||
@@ -145,6 +146,12 @@ fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn print_my_domains(context: &Arc<Mutex<Context>>) {
|
||||||
|
let context = context.lock().unwrap();
|
||||||
|
let domains = context.chain.get_my_domains(&context.keystore);
|
||||||
|
debug!("Domains: {:?}", &domains);
|
||||||
|
}
|
||||||
|
|
||||||
fn create_genesis_if_needed(context: &Arc<Mutex<Context>>, miner: &Arc<Mutex<Miner>>) {
|
fn create_genesis_if_needed(context: &Arc<Mutex<Context>>, miner: &Arc<Mutex<Miner>>) {
|
||||||
// If there is no origin in settings and no blockchain in DB, generate genesis block
|
// If there is no origin in settings and no blockchain in DB, generate genesis block
|
||||||
let context = context.lock().unwrap();
|
let context = context.lock().unwrap();
|
||||||
|
|||||||
+23
-2
@@ -4,7 +4,7 @@ extern crate serde;
|
|||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
extern crate open;
|
extern crate open;
|
||||||
|
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex, MutexGuard};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
@@ -195,6 +195,7 @@ fn action_loaded(context: &Arc<Mutex<Context>>, web_view: &mut WebView<()>) {
|
|||||||
let status = Arc::new(Mutex::new(Status::new(threads)));
|
let status = Arc::new(Mutex::new(Status::new(threads)));
|
||||||
let context_copy = Arc::clone(&context);
|
let context_copy = Arc::clone(&context);
|
||||||
let mut c = context.lock().unwrap();
|
let mut c = context.lock().unwrap();
|
||||||
|
|
||||||
c.bus.register(move |_uuid, e| {
|
c.bus.register(move |_uuid, e| {
|
||||||
//debug!("Got event from bus {:?}", &e);
|
//debug!("Got event from bus {:?}", &e);
|
||||||
let status = Arc::clone(&status);
|
let status = Arc::clone(&status);
|
||||||
@@ -202,9 +203,10 @@ fn action_loaded(context: &Arc<Mutex<Context>>, web_view: &mut WebView<()>) {
|
|||||||
let context_copy = Arc::clone(&context_copy);
|
let context_copy = Arc::clone(&context_copy);
|
||||||
let _ = thread::Builder::new().name(String::from("webui")).spawn(move || {
|
let _ = thread::Builder::new().name(String::from("webui")).spawn(move || {
|
||||||
let mut status = status.lock().unwrap();
|
let mut status = status.lock().unwrap();
|
||||||
let context = context_copy.lock().unwrap();
|
let mut context = context_copy.lock().unwrap();
|
||||||
let eval = match e {
|
let eval = match e {
|
||||||
Event::KeyCreated { path, public, hash } => {
|
Event::KeyCreated { path, public, hash } => {
|
||||||
|
load_domains(&mut context, &handle);
|
||||||
event_handle_luck(&handle, "Key successfully created! Don\\'t forget to save it!");
|
event_handle_luck(&handle, "Key successfully created! Don\\'t forget to save it!");
|
||||||
let mut s = format!("keystoreChanged('{}', '{}', '{}');", &path, &public, &hash);
|
let mut s = format!("keystoreChanged('{}', '{}', '{}');", &path, &public, &hash);
|
||||||
s.push_str(" showSuccess('New key mined successfully! Save it to a safe place!')");
|
s.push_str(" showSuccess('New key mined successfully! Save it to a safe place!')");
|
||||||
@@ -212,6 +214,7 @@ fn action_loaded(context: &Arc<Mutex<Context>>, web_view: &mut WebView<()>) {
|
|||||||
}
|
}
|
||||||
Event::KeyLoaded { path, public, hash } |
|
Event::KeyLoaded { path, public, hash } |
|
||||||
Event::KeySaved { path, public, hash } => {
|
Event::KeySaved { path, public, hash } => {
|
||||||
|
load_domains(&mut context, &handle);
|
||||||
format!("keystoreChanged('{}', '{}', '{}');", &path, &public, &hash)
|
format!("keystoreChanged('{}', '{}', '{}');", &path, &public, &hash)
|
||||||
}
|
}
|
||||||
Event::MinerStarted | Event::KeyGeneratorStarted => {
|
Event::MinerStarted | Event::KeyGeneratorStarted => {
|
||||||
@@ -319,6 +322,24 @@ fn action_loaded(context: &Arc<Mutex<Context>>, web_view: &mut WebView<()>) {
|
|||||||
event_info(web_view, "Application loaded");
|
event_info(web_view, "Application loaded");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
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<Mutex<Context>>, miner: Arc<Mutex<Miner>>, web_view: &mut WebView<()>, name: String, data: String) {
|
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);
|
debug!("Creating domain with data: {}", &data);
|
||||||
let c = Arc::clone(&context);
|
let c = Arc::clone(&context);
|
||||||
|
|||||||
@@ -116,6 +116,10 @@
|
|||||||
<div class="list pb-3" id="domain_records">
|
<div class="list pb-3" id="domain_records">
|
||||||
<!-- Here will be our domain records, added by dialog -->
|
<!-- Here will be our domain records, added by dialog -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="my_domains" class="container is-fluid cards-container">
|
||||||
|
<!-- Here will be our domains -->
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Zone mining -->
|
<!-- Zone mining -->
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
var recordsBuffer = [];
|
var recordsBuffer = [];
|
||||||
var availableZones = [];
|
var availableZones = [];
|
||||||
|
var myDomains = [];
|
||||||
var currentZone;
|
var currentZone;
|
||||||
|
|
||||||
function addRecord(record) {
|
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 }
|
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 = '<svg viewBox="0 0 24 24" class="tag-button" onclick="editDomain(\'{domain}\');"><path d="M21.04 12.13C21.18 12.13 21.31 12.19 21.42 12.3L22.7 13.58C22.92 13.79 22.92 14.14 22.7 14.35L21.7 15.35L19.65 13.3L20.65 12.3C20.76 12.19 20.9 12.13 21.04 12.13M19.07 13.88L21.12 15.93L15.06 22H13V19.94L19.07 13.88M11 19L9 21H5C3.9 21 3 20.1 3 19V5C3 3.9 3.9 3 5 3H9.18C9.6 1.84 10.7 1 12 1C13.3 1 14.4 1.84 14.82 3H19C20.1 3 21 3.9 21 5V9L19 11V5H17V7H7V5H5V19H11M12 3C11.45 3 11 3.45 11 4C11 4.55 11.45 5 12 5C12.55 5 13 4.55 13 4C13 3.45 12.55 3 12 3Z"></path></svg>';
|
||||||
|
var card = '<div class="card is-inline-block"><div class="card-content p-3"><div class="content is-small"><h3>{title}</h3><div class="tags">{tags}{edit}</div></div></div></div>';
|
||||||
|
var tag = '<span class="tag" title="{ip}">{domain}</span>';
|
||||||
|
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() {
|
function onLoad() {
|
||||||
external.invoke(JSON.stringify({cmd: 'loaded'}));
|
external.invoke(JSON.stringify({cmd: 'loaded'}));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,6 +63,21 @@ body {
|
|||||||
right: 10pt;
|
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 {
|
.list {
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
@@ -86,3 +101,9 @@ path {
|
|||||||
.is-danger:hover > span.icon > svg > path {
|
.is-danger:hover > span.icon > svg > path {
|
||||||
fill: #ffffff;
|
fill: #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
svg.tag-button {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
margin-bottom: .5rem;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user