From c24d2b51f91888993e3460af39ed7fb666dc51b1 Mon Sep 17 00:00:00 2001 From: dr-frmr Date: Fri, 18 Oct 2024 15:42:39 -0400 Subject: [PATCH] contacts: make kimap work in sim-mode, improve FE --- kinode/packages/contacts/contacts/src/lib.rs | 48 ++++++++++++----- kinode/packages/contacts/pkg/ui/index.html | 55 +++++++++++++++++--- kinode/packages/contacts/pkg/ui/script.js | 40 +++++++++++++- 3 files changed, 122 insertions(+), 21 deletions(-) diff --git a/kinode/packages/contacts/contacts/src/lib.rs b/kinode/packages/contacts/contacts/src/lib.rs index 35463455..f59f0a73 100644 --- a/kinode/packages/contacts/contacts/src/lib.rs +++ b/kinode/packages/contacts/contacts/src/lib.rs @@ -5,9 +5,22 @@ use kinode_process_lib::{ }; use serde::{Deserialize, Serialize}; use std::collections::HashMap; +use std::str::FromStr; const ICON: &str = include_str!("icon"); +#[cfg(not(feature = "simulation-mode"))] +const CHAIN_ID: u64 = kimap::KIMAP_CHAIN_ID; +#[cfg(feature = "simulation-mode")] +const CHAIN_ID: u64 = 31337; // local + +const CHAIN_TIMEOUT: u64 = 60; // 60s + +#[cfg(not(feature = "simulation-mode"))] +const KIMAP_ADDRESS: &'static str = kimap::KIMAP_ADDRESS; // optimism +#[cfg(feature = "simulation-mode")] +const KIMAP_ADDRESS: &str = "0xEce71a05B36CA55B895427cD9a440eEF7Cf3669D"; + #[derive(Debug, Serialize, Deserialize)] struct Contact(HashMap); @@ -17,7 +30,6 @@ struct Contacts(HashMap); #[derive(Debug, Serialize, Deserialize)] struct ContactsState { our: Address, - kimap: kimap::Kimap, contacts: Contacts, } @@ -25,7 +37,6 @@ impl ContactsState { fn new(our: Address) -> Self { get_typed_state(|bytes| serde_json::from_slice(bytes)).unwrap_or(Self { our, - kimap: kimap::Kimap::default(30), contacts: Contacts(HashMap::new()), }) } @@ -96,6 +107,11 @@ fn initialize(our: Address) { let mut state: ContactsState = ContactsState::new(our); + let kimap = kimap::Kimap::new( + eth::Provider::new(CHAIN_ID, CHAIN_TIMEOUT), + eth::Address::from_str(KIMAP_ADDRESS).unwrap(), + ); + let mut http_server = http::server::HttpServer::new(5); // serve the frontend on a secure subdomain @@ -110,10 +126,14 @@ fn initialize(our: Address) { http_server.secure_bind_http_path("/ask").unwrap(); http_server.secure_bind_ws_path("/").unwrap(); - main_loop(&mut state, &mut http_server); + main_loop(&mut state, &kimap, &mut http_server); } -fn main_loop(state: &mut ContactsState, http_server: &mut http::server::HttpServer) { +fn main_loop( + state: &mut ContactsState, + kimap: &kimap::Kimap, + http_server: &mut http::server::HttpServer, +) { loop { match await_message() { Err(_send_error) => { @@ -131,7 +151,7 @@ fn main_loop(state: &mut ContactsState, http_server: &mut http::server::HttpServ if source.node() != state.our.node { continue; } - handle_request(&source, &body, capabilities, state, http_server); + handle_request(&source, &body, capabilities, state, kimap, http_server); } _ => continue, // ignore responses } @@ -143,6 +163,7 @@ fn handle_request( body: &[u8], capabilities: Vec, state: &mut ContactsState, + kimap: &kimap::Kimap, http_server: &mut http::server::HttpServer, ) { // source node is ALWAYS ourselves since networking is disabled @@ -152,14 +173,14 @@ fn handle_request( http_server.handle_request( server_request, - |req| handle_http_request(state, &req), + |req| handle_http_request(state, kimap, &req), |_channel_id, _message_type, _blob| { // we don't expect websocket messages }, ); } else { // if request is not from frontend, check that it has the required capabilities - let (response, blob) = handle_contacts_request(state, body, Some(capabilities)); + let (response, blob) = handle_contacts_request(state, kimap, body, Some(capabilities)); let mut response = Response::new().body(serde_json::to_vec(&response).unwrap()); if let Some(blob) = blob { response = response.blob(blob); @@ -172,6 +193,7 @@ fn handle_request( /// Handle HTTP requests from our own frontend. fn handle_http_request( state: &mut ContactsState, + kimap: &kimap::Kimap, http_request: &http::server::IncomingHttpRequest, ) -> (http::server::HttpResponse, Option) { match http_request.method().unwrap().as_str() { @@ -185,7 +207,7 @@ fn handle_http_request( ), "POST" => { let blob = get_blob().unwrap(); - let (response, blob) = handle_contacts_request(state, blob.bytes(), None); + let (response, blob) = handle_contacts_request(state, kimap, blob.bytes(), None); if let contacts::Response::Error(e) = response { return ( http::server::HttpResponse::new(http::StatusCode::BAD_REQUEST) @@ -218,6 +240,7 @@ fn handle_http_request( fn handle_contacts_request( state: &mut ContactsState, + kimap: &kimap::Kimap, request_bytes: &[u8], capabilities: Option>, ) -> (contacts::Response, Option) { @@ -281,14 +304,14 @@ fn handle_contacts_request( )), ), contacts::Request::AddContact(node) => { - if let Some((response, blob)) = invalid_node(state, &node) { + if let Some((response, blob)) = invalid_node(kimap, &node) { return (response, blob); } state.add_contact(node); (contacts::Response::AddContact, None) } contacts::Request::AddField((node, field, value)) => { - if let Some((response, blob)) = invalid_node(state, &node) { + if let Some((response, blob)) = invalid_node(kimap, &node) { return (response, blob); } let Ok(value) = serde_json::from_str::(&value) else { @@ -312,11 +335,10 @@ fn handle_contacts_request( } fn invalid_node( - state: &ContactsState, + kimap: &kimap::Kimap, node: &str, ) -> Option<(contacts::Response, Option)> { - if state - .kimap + if kimap .get(&node) .map(|(tba, _, _)| tba != eth::Address::ZERO) .unwrap_or(false) diff --git a/kinode/packages/contacts/pkg/ui/index.html b/kinode/packages/contacts/pkg/ui/index.html index bad57611..2f20c2ae 100644 --- a/kinode/packages/contacts/pkg/ui/index.html +++ b/kinode/packages/contacts/pkg/ui/index.html @@ -9,7 +9,7 @@ @@ -48,7 +92,6 @@

contacts

-

Contacts

diff --git a/kinode/packages/contacts/pkg/ui/script.js b/kinode/packages/contacts/pkg/ui/script.js index 67b3cac0..03bf4324 100644 --- a/kinode/packages/contacts/pkg/ui/script.js +++ b/kinode/packages/contacts/pkg/ui/script.js @@ -20,9 +20,45 @@ function populate_contacts(contacts) { ul.innerHTML = ''; Object.entries(contacts).forEach(([node, contact]) => { const li = document.createElement('li'); - li.innerHTML = `${JSON.stringify(node, undefined, 2)}`; + const div = document.createElement('div'); + div.classList.add('contact'); + div.innerHTML = `

${node}

+
    + ${Object.entries(contact).map(([field, value]) => `
  • ${field}: ${value}
  • `).join('')} +
+ + +
+
+ + + +
+ `; + li.appendChild(div); ul.appendChild(li); }); + + ul.querySelectorAll('.delete-contact').forEach(form => { + form.addEventListener('submit', function (e) { + e.preventDefault(); + const node = this.getAttribute('id'); + api_call({ + "RemoveContact": node + }); + }); + }); + + ul.querySelectorAll('.add-field').forEach(form => { + form.addEventListener('submit', function (e) { + e.preventDefault(); + const node = this.getAttribute('id'); + const data = new FormData(e.target); + api_call({ + "AddField": [node, data.get('field'), data.get('value')] + }); + }); + }); } document.getElementById('add-contact').addEventListener('submit', (e) => { @@ -39,6 +75,7 @@ document.getElementById('add-contact').addEventListener('submit', (e) => { }, body: JSON.stringify(body), }).then(response => { + e.target.reset(); if (response.status === 200) { return null; } else { @@ -46,7 +83,6 @@ document.getElementById('add-contact').addEventListener('submit', (e) => { } }).then(data => { if (data === null) { - e.target.reset(); return; } else { alert(JSON.stringify(data));