mirror of
https://github.com/uqbar-dao/nectar.git
synced 2024-12-29 19:41:39 +03:00
contacts: versioned state
This commit is contained in:
parent
5616efd942
commit
df6b9ecd95
@ -35,17 +35,27 @@ struct Contact(HashMap<String, serde_json::Value>);
|
||||
struct Contacts(HashMap<NodeId, Contact>);
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
struct ContactsState {
|
||||
struct ContactsStateV1 {
|
||||
our: Address,
|
||||
contacts: Contacts,
|
||||
}
|
||||
|
||||
impl ContactsState {
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(tag = "version")]
|
||||
enum VersionedState {
|
||||
/// State fully stored in memory, persisted using serde_json.
|
||||
/// Future state version will use SQLite.
|
||||
V1(ContactsStateV1),
|
||||
}
|
||||
|
||||
impl VersionedState {
|
||||
fn new(our: Address) -> Self {
|
||||
get_typed_state(|bytes| serde_json::from_slice(bytes)).unwrap_or(Self {
|
||||
our,
|
||||
contacts: Contacts(HashMap::new()),
|
||||
})
|
||||
get_typed_state(|bytes| serde_json::from_slice(bytes)).unwrap_or(Self::V1(
|
||||
ContactsStateV1 {
|
||||
our,
|
||||
contacts: Contacts(HashMap::new()),
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
fn save(&self) {
|
||||
@ -53,36 +63,57 @@ impl ContactsState {
|
||||
}
|
||||
|
||||
fn contacts(&self) -> &Contacts {
|
||||
&self.contacts
|
||||
match self {
|
||||
VersionedState::V1(state) => &state.contacts,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_contact(&self, node: NodeId) -> Option<&Contact> {
|
||||
self.contacts.0.get(&node)
|
||||
match self {
|
||||
VersionedState::V1(state) => state.contacts.0.get(&node),
|
||||
}
|
||||
}
|
||||
|
||||
fn add_contact(&mut self, node: NodeId) {
|
||||
self.contacts.0.insert(node, Contact(HashMap::new()));
|
||||
match self {
|
||||
VersionedState::V1(state) => {
|
||||
state.contacts.0.insert(node, Contact(HashMap::new()));
|
||||
}
|
||||
}
|
||||
self.save();
|
||||
}
|
||||
|
||||
fn remove_contact(&mut self, node: NodeId) {
|
||||
self.contacts.0.remove(&node);
|
||||
match self {
|
||||
VersionedState::V1(state) => {
|
||||
state.contacts.0.remove(&node);
|
||||
}
|
||||
}
|
||||
self.save();
|
||||
}
|
||||
|
||||
fn add_field(&mut self, node: NodeId, field: String, value: serde_json::Value) {
|
||||
self.contacts
|
||||
.0
|
||||
.entry(node)
|
||||
.or_insert_with(|| Contact(HashMap::new()))
|
||||
.0
|
||||
.insert(field, value);
|
||||
match self {
|
||||
VersionedState::V1(state) => {
|
||||
state
|
||||
.contacts
|
||||
.0
|
||||
.entry(node)
|
||||
.or_insert_with(|| Contact(HashMap::new()))
|
||||
.0
|
||||
.insert(field, value);
|
||||
}
|
||||
}
|
||||
self.save();
|
||||
}
|
||||
|
||||
fn remove_field(&mut self, node: NodeId, field: String) {
|
||||
if let Some(contact) = self.contacts.0.get_mut(&node) {
|
||||
contact.0.remove(&field);
|
||||
match self {
|
||||
VersionedState::V1(state) => {
|
||||
if let Some(contact) = state.contacts.0.get_mut(&node) {
|
||||
contact.0.remove(&field);
|
||||
}
|
||||
}
|
||||
}
|
||||
self.save();
|
||||
}
|
||||
@ -97,13 +128,20 @@ impl ContactsState {
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
fn our(&self) -> &Address {
|
||||
match self {
|
||||
VersionedState::V1(state) => &state.our,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
call_init!(initialize);
|
||||
fn initialize(our: Address) {
|
||||
homepage::add_to_homepage("Contacts", Some(ICON), Some("/"), None);
|
||||
|
||||
let mut state: ContactsState = ContactsState::new(our);
|
||||
let mut state: VersionedState = get_typed_state(|bytes| serde_json::from_slice(bytes))
|
||||
.unwrap_or_else(|| VersionedState::new(our));
|
||||
|
||||
let kimap = kimap::Kimap::new(
|
||||
eth::Provider::new(CHAIN_ID, CHAIN_TIMEOUT),
|
||||
@ -115,7 +153,7 @@ fn initialize(our: Address) {
|
||||
// serve the frontend on a secure subdomain
|
||||
http_server
|
||||
.serve_ui(
|
||||
&state.our,
|
||||
state.our(),
|
||||
"ui",
|
||||
vec!["/"],
|
||||
http::server::HttpBindingConfig::default().secure_subdomain(true),
|
||||
@ -128,7 +166,7 @@ fn initialize(our: Address) {
|
||||
}
|
||||
|
||||
fn main_loop(
|
||||
state: &mut ContactsState,
|
||||
state: &mut VersionedState,
|
||||
kimap: &kimap::Kimap,
|
||||
http_server: &mut http::server::HttpServer,
|
||||
) {
|
||||
@ -146,7 +184,7 @@ fn main_loop(
|
||||
}) => {
|
||||
// ignore messages from other nodes -- technically superfluous check
|
||||
// since manifest does not acquire networking capability
|
||||
if source.node() != state.our.node {
|
||||
if source.node() != state.our().node {
|
||||
continue;
|
||||
}
|
||||
handle_request(&source, &body, capabilities, state, kimap, http_server);
|
||||
@ -160,7 +198,7 @@ fn handle_request(
|
||||
source: &Address,
|
||||
body: &[u8],
|
||||
capabilities: Vec<Capability>,
|
||||
state: &mut ContactsState,
|
||||
state: &mut VersionedState,
|
||||
kimap: &kimap::Kimap,
|
||||
http_server: &mut http::server::HttpServer,
|
||||
) {
|
||||
@ -190,7 +228,7 @@ fn handle_request(
|
||||
|
||||
/// Handle HTTP requests from our own frontend.
|
||||
fn handle_http_request(
|
||||
state: &mut ContactsState,
|
||||
state: &mut VersionedState,
|
||||
kimap: &kimap::Kimap,
|
||||
http_request: &http::server::IncomingHttpRequest,
|
||||
) -> (http::server::HttpResponse, Option<LazyLoadBlob>) {
|
||||
@ -237,7 +275,7 @@ fn handle_http_request(
|
||||
}
|
||||
|
||||
fn handle_contacts_request(
|
||||
state: &mut ContactsState,
|
||||
state: &mut VersionedState,
|
||||
kimap: &kimap::Kimap,
|
||||
request_bytes: &[u8],
|
||||
capabilities: Option<Vec<Capability>>,
|
||||
@ -252,7 +290,7 @@ fn handle_contacts_request(
|
||||
// each request requires one of read-name-only, read, add, or remove
|
||||
if let Some(capabilities) = capabilities {
|
||||
let required_capability = Capability::new(
|
||||
&state.our,
|
||||
state.our(),
|
||||
serde_json::to_string(&match request {
|
||||
contacts::Request::GetNames => contacts::Capability::ReadNameOnly,
|
||||
contacts::Request::GetAllContacts | contacts::Request::GetContact(_) => {
|
||||
|
Loading…
Reference in New Issue
Block a user