implement Serialize/Deserialize for Entry, Address, remove as_json
+ cosmetics (to_str -> to_string)feat/vaults
parent
99f6c6c052
commit
dc71bec67a
|
@ -1,14 +1,15 @@
|
||||||
|
use crate::hash::{decode, encode, Hash};
|
||||||
|
use anyhow::{anyhow, Result};
|
||||||
|
use serde::de::Visitor;
|
||||||
|
use serde::{de, ser, Deserialize, Deserializer, Serialize, Serializer};
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
|
use std::fmt;
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
|
|
||||||
use anyhow::{anyhow, Result};
|
|
||||||
use unsigned_varint::encode;
|
|
||||||
use uuid::Uuid;
|
|
||||||
|
|
||||||
use crate::hash::{encode, Hash};
|
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use thiserror::private::DisplayAsDisplay;
|
use thiserror::private::DisplayAsDisplay;
|
||||||
|
use unsigned_varint::encode;
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq)]
|
#[derive(Clone, PartialEq)]
|
||||||
pub enum Address {
|
pub enum Address {
|
||||||
|
@ -57,6 +58,42 @@ impl Address {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Serialize for Address {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
serializer.serialize_str(encode(self.encode().map_err(ser::Error::custom)?).as_str())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AddressVisitor;
|
||||||
|
|
||||||
|
impl<'de> Visitor<'de> for AddressVisitor {
|
||||||
|
type Value = Address;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
formatter.write_str("a valid UpEnd address (hash/UUID) as a multi-hashed string")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E>(self, str: &str) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: de::Error,
|
||||||
|
{
|
||||||
|
let bytes = decode(str).map_err(de::Error::custom)?;
|
||||||
|
Ok(Address::decode(bytes.as_ref()).map_err(de::Error::custom)?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for Address {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Address, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
deserializer.deserialize_str(AddressVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl FromStr for Address {
|
impl FromStr for Address {
|
||||||
type Err = anyhow::Error;
|
type Err = anyhow::Error;
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ use lexpr::value::Value::Symbol;
|
||||||
use lexpr::Value::Cons;
|
use lexpr::Value::Cons;
|
||||||
use log::{debug, trace};
|
use log::{debug, trace};
|
||||||
use nonempty::NonEmpty;
|
use nonempty::NonEmpty;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
@ -23,34 +24,20 @@ use std::path::{Path, PathBuf};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct Entry {
|
pub struct Entry {
|
||||||
pub target: Address,
|
pub target: Address,
|
||||||
pub key: String,
|
pub key: String,
|
||||||
pub value: EntryValue,
|
pub value: EntryValue,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub enum EntryValue {
|
pub enum EntryValue {
|
||||||
Value(serde_json::Value),
|
Value(serde_json::Value),
|
||||||
Address(Address),
|
Address(Address),
|
||||||
Invalid,
|
Invalid,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Entry {
|
|
||||||
pub fn as_json(&self) -> serde_json::Value {
|
|
||||||
json!({
|
|
||||||
"target": self.target.to_string(),
|
|
||||||
"key": self.key,
|
|
||||||
"value": match &self.value {
|
|
||||||
EntryValue::Value(value) => ("VALUE", value.clone()),
|
|
||||||
EntryValue::Address(address) => ("ADDR", json!(address.to_string())),
|
|
||||||
EntryValue::Invalid => ("INVALID", json!("INVALID")),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<models::Entry> for Entry {
|
impl TryFrom<models::Entry> for Entry {
|
||||||
type Error = anyhow::Error;
|
type Error = anyhow::Error;
|
||||||
|
|
||||||
|
@ -74,13 +61,13 @@ impl Hashable for Entry {
|
||||||
let mut result = Cursor::new(vec![0u8; 0]);
|
let mut result = Cursor::new(vec![0u8; 0]);
|
||||||
result.write_all(self.target.encode()?.as_slice())?;
|
result.write_all(self.target.encode()?.as_slice())?;
|
||||||
result.write_all(self.key.as_bytes())?;
|
result.write_all(self.key.as_bytes())?;
|
||||||
result.write_all(self.value.to_str()?.as_bytes())?;
|
result.write_all(self.value.to_string()?.as_bytes())?;
|
||||||
Ok(hash(result.get_ref()))
|
Ok(hash(result.get_ref()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EntryValue {
|
impl EntryValue {
|
||||||
pub fn to_str(&self) -> Result<String> {
|
pub fn to_string(&self) -> Result<String> {
|
||||||
let (type_char, content) = match self {
|
let (type_char, content) = match self {
|
||||||
EntryValue::Value(value) => ('J', serde_json::to_string(value)?),
|
EntryValue::Value(value) => ('J', serde_json::to_string(value)?),
|
||||||
EntryValue::Address(address) => ('O', address.to_string()),
|
EntryValue::Address(address) => ('O', address.to_string()),
|
||||||
|
@ -193,7 +180,7 @@ pub fn retrieve_object<C: Connection<Backend = Sqlite>>(
|
||||||
|
|
||||||
let matches = data
|
let matches = data
|
||||||
.filter(target.eq(object_address.encode()?))
|
.filter(target.eq(object_address.encode()?))
|
||||||
.or_filter(value.eq(EntryValue::Address(object_address).to_str()?))
|
.or_filter(value.eq(EntryValue::Address(object_address).to_string()?))
|
||||||
.load::<models::Entry>(connection)?;
|
.load::<models::Entry>(connection)?;
|
||||||
let entries = matches
|
let entries = matches
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -239,7 +226,7 @@ pub fn remove_object<C: Connection<Backend = Sqlite>>(
|
||||||
|
|
||||||
let matches = data
|
let matches = data
|
||||||
.filter(target.eq(object_address.encode()?))
|
.filter(target.eq(object_address.encode()?))
|
||||||
.or_filter(value.eq(EntryValue::Address(object_address).to_str()?));
|
.or_filter(value.eq(EntryValue::Address(object_address).to_string()?));
|
||||||
|
|
||||||
Ok(diesel::delete(matches).execute(connection)?)
|
Ok(diesel::delete(matches).execute(connection)?)
|
||||||
}
|
}
|
||||||
|
@ -499,11 +486,11 @@ fn query_to_sqlite(query: &Query) -> Result<Box<Predicate>> {
|
||||||
|
|
||||||
match &eq.value {
|
match &eq.value {
|
||||||
QueryComponent::Exact(q_value) => {
|
QueryComponent::Exact(q_value) => {
|
||||||
subqueries.push(Box::new(data::value.eq(q_value.to_str()?)))
|
subqueries.push(Box::new(data::value.eq(q_value.to_string()?)))
|
||||||
}
|
}
|
||||||
QueryComponent::In(q_values) => {
|
QueryComponent::In(q_values) => {
|
||||||
let values: Result<Vec<_>, _> =
|
let values: Result<Vec<_>, _> =
|
||||||
q_values.iter().map(|v| v.to_str()).collect();
|
q_values.iter().map(|v| v.to_string()).collect();
|
||||||
subqueries.push(Box::new(data::value.eq_any(values?)))
|
subqueries.push(Box::new(data::value.eq_any(values?)))
|
||||||
}
|
}
|
||||||
QueryComponent::Contains(q_value) => {
|
QueryComponent::Contains(q_value) => {
|
||||||
|
@ -583,9 +570,9 @@ pub fn query_entries<C: Connection<Backend = Sqlite>>(
|
||||||
};
|
};
|
||||||
|
|
||||||
query = match entry_query.value {
|
query = match entry_query.value {
|
||||||
QueryComponent::Exact(q_value) => query.filter(value.eq(q_value.to_str()?)),
|
QueryComponent::Exact(q_value) => query.filter(value.eq(q_value.to_string()?)),
|
||||||
QueryComponent::In(q_values) => {
|
QueryComponent::In(q_values) => {
|
||||||
let values: Result<Vec<_>, _> = q_values.into_iter().map(|v| v.to_str()).collect();
|
let values: Result<Vec<_>, _> = q_values.into_iter().map(|v| v.to_string()).collect();
|
||||||
query.filter(value.eq_any(values?))
|
query.filter(value.eq_any(values?))
|
||||||
}
|
}
|
||||||
QueryComponent::Contains(q_value_string) => {
|
QueryComponent::Contains(q_value_string) => {
|
||||||
|
@ -617,7 +604,7 @@ pub fn insert_entry<C: Connection<Backend = Sqlite>>(
|
||||||
identity: entry.hash()?.0,
|
identity: entry.hash()?.0,
|
||||||
target: entry.target.encode()?,
|
target: entry.target.encode()?,
|
||||||
key: entry.key,
|
key: entry.key,
|
||||||
value: entry.value.to_str()?,
|
value: entry.value.to_string()?,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(diesel::insert_into(data::table)
|
Ok(diesel::insert_into(data::table)
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
use actix::prelude::*;
|
use actix::prelude::*;
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use filebuffer::FileBuffer;
|
use filebuffer::FileBuffer;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use tiny_keccak::{Hasher, KangarooTwelve};
|
use tiny_keccak::{Hasher, KangarooTwelve};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct Hash(pub Vec<u8>);
|
pub struct Hash(pub Vec<u8>);
|
||||||
|
|
||||||
impl AsRef<[u8]> for Hash {
|
impl AsRef<[u8]> for Hash {
|
||||||
|
|
|
@ -53,11 +53,11 @@ pub async fn get_object(
|
||||||
|
|
||||||
debug!("{:?}", response);
|
debug!("{:?}", response);
|
||||||
|
|
||||||
let mut result: HashMap<String, serde_json::Value> = HashMap::new();
|
let mut result: HashMap<String, Entry> = HashMap::new();
|
||||||
for entry in response.map_err(error::ErrorInternalServerError)? {
|
for entry in response.map_err(error::ErrorInternalServerError)? {
|
||||||
result.insert(
|
result.insert(
|
||||||
encode(entry.hash().map_err(ErrorInternalServerError)?),
|
encode(entry.hash().map_err(ErrorInternalServerError)?),
|
||||||
entry.as_json(),
|
entry,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Ok(HttpResponse::Ok().json(result))
|
Ok(HttpResponse::Ok().json(result))
|
||||||
|
@ -90,12 +90,7 @@ pub async fn list_hier(
|
||||||
.await
|
.await
|
||||||
.map_err(ErrorNotFound)?; // todo: 500 if actual error occurs
|
.map_err(ErrorNotFound)?; // todo: 500 if actual error occurs
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().json(
|
Ok(HttpResponse::Ok().json(entries))
|
||||||
entries
|
|
||||||
.iter()
|
|
||||||
.map(Entry::as_json)
|
|
||||||
.collect::<serde_json::Value>(),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
|
@ -111,12 +106,7 @@ pub async fn get_lookup(
|
||||||
let connection = state.db_pool.get().map_err(ErrorInternalServerError)?;
|
let connection = state.db_pool.get().map_err(ErrorInternalServerError)?;
|
||||||
let response = lookup_by_filename(&connection, info.query).map_err(ErrorInternalServerError)?;
|
let response = lookup_by_filename(&connection, info.query).map_err(ErrorInternalServerError)?;
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().json(
|
Ok(HttpResponse::Ok().json(response))
|
||||||
response
|
|
||||||
.iter()
|
|
||||||
.map(Entry::as_json)
|
|
||||||
.collect::<serde_json::Value>(),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
|
@ -135,12 +125,7 @@ pub async fn get_query(
|
||||||
let in_query = Query::from_sexp(&sexp).map_err(ErrorInternalServerError)?;
|
let in_query = Query::from_sexp(&sexp).map_err(ErrorInternalServerError)?;
|
||||||
let result = query(&connection, in_query).map_err(ErrorInternalServerError)?;
|
let result = query(&connection, in_query).map_err(ErrorInternalServerError)?;
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().json(
|
Ok(HttpResponse::Ok().json(result))
|
||||||
result
|
|
||||||
.iter()
|
|
||||||
.map(Entry::as_json)
|
|
||||||
.collect::<serde_json::Value>(),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[post("/api/refresh")]
|
#[post("/api/refresh")]
|
||||||
|
|
Loading…
Reference in New Issue