mirror of
https://github.com/creating2morrow/neveko.git
synced 2024-12-22 11:39:22 +00:00
update order module serialization
This commit is contained in:
parent
84c5044975
commit
f8570df9a6
4 changed files with 216 additions and 165 deletions
|
@ -5,10 +5,16 @@ use thiserror::Error;
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
#[error("Neveko error. See logs for more info.")]
|
#[error("Neveko error. See logs for more info.")]
|
||||||
pub enum NevekoError {
|
pub enum NevekoError {
|
||||||
///J4I2PRS(J4RsError),
|
Auth,
|
||||||
|
Contact,
|
||||||
Database(MdbError),
|
Database(MdbError),
|
||||||
Dispute,
|
Dispute,
|
||||||
|
I2P,
|
||||||
|
J4I2PRS,
|
||||||
MoneroRpc,
|
MoneroRpc,
|
||||||
MoneroDaemon,
|
MoneroDaemon,
|
||||||
|
Nasr,
|
||||||
|
Order,
|
||||||
|
Product,
|
||||||
Unknown,
|
Unknown,
|
||||||
}
|
}
|
|
@ -3,17 +3,9 @@
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
contact,
|
contact, db, error::NevekoError, i2p, models::*, monero, neveko25519, order, product, reqres, utils
|
||||||
db,
|
|
||||||
i2p,
|
|
||||||
models::*,
|
|
||||||
monero,
|
|
||||||
neveko25519,
|
|
||||||
order,
|
|
||||||
product,
|
|
||||||
reqres,
|
|
||||||
utils,
|
|
||||||
};
|
};
|
||||||
|
use kn0sys_lmdb_rs::MdbError;
|
||||||
use log::{
|
use log::{
|
||||||
debug,
|
debug,
|
||||||
error,
|
error,
|
||||||
|
@ -42,7 +34,7 @@ impl StatusType {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a intial order
|
/// Create a intial order
|
||||||
pub async fn create(j_order: Json<reqres::OrderRequest>) -> Order {
|
pub async fn create(j_order: Json<reqres::OrderRequest>) -> Result<Order, MdbError> {
|
||||||
info!("creating order");
|
info!("creating order");
|
||||||
let wallet_name = String::from(crate::APP_NAME);
|
let wallet_name = String::from(crate::APP_NAME);
|
||||||
let wallet_password =
|
let wallet_password =
|
||||||
|
@ -70,95 +62,109 @@ pub async fn create(j_order: Json<reqres::OrderRequest>) -> Order {
|
||||||
if !m_wallet {
|
if !m_wallet {
|
||||||
error!("error creating msig wallet for order {}", &orid);
|
error!("error creating msig wallet for order {}", &orid);
|
||||||
monero::close_wallet(&orid, &wallet_password).await;
|
monero::close_wallet(&orid, &wallet_password).await;
|
||||||
return Default::default();
|
return Err(MdbError::NotFound);
|
||||||
}
|
}
|
||||||
monero::close_wallet(&orid, &order_wallet_password).await;
|
monero::close_wallet(&orid, &order_wallet_password).await;
|
||||||
debug!("insert order: {:?}", &new_order);
|
debug!("insert order: {:?}", &new_order);
|
||||||
let s = db::DatabaseEnvironment::async_open().await;
|
let s = db::DatabaseEnvironment::open()?;
|
||||||
// inject adjudicator separately, modifying the order model is mendokusai
|
// inject adjudicator separately, modifying the order model is mendokusai
|
||||||
let adjudicator_k = format!("{}-{}", crate::ADJUDICATOR_DB_KEY, &orid);
|
let adjudicator_k = format!("{}-{}", crate::ADJUDICATOR_DB_KEY, &orid);
|
||||||
db::DatabaseEnvironment::async_write(&s.env, &s.handle, &adjudicator_k, &j_order.adjudicator).await;
|
db::write_chunks(&s.env, &s.handle?, adjudicator_k.as_bytes(), j_order.adjudicator.as_bytes());
|
||||||
let k = &new_order.orid;
|
let k = &new_order.orid;
|
||||||
db::DatabaseEnvironment::async_write(&s.env, &s.handle, k, &Order::to_db(&new_order)).await;
|
let s = db::DatabaseEnvironment::open()?;
|
||||||
|
let order = bincode::serialize(&new_order).unwrap_or_default();
|
||||||
|
db::write_chunks(&s.env, &s.handle?, k.as_bytes(), &order);
|
||||||
// in order to retrieve all orders, write keys to with ol
|
// in order to retrieve all orders, write keys to with ol
|
||||||
let list_key = crate::ORDER_LIST_DB_KEY;
|
let list_key = crate::ORDER_LIST_DB_KEY;
|
||||||
let r = db::DatabaseEnvironment::async_read(&s.env, &s.handle, &String::from(list_key)).await;
|
let s = db::DatabaseEnvironment::open()?;
|
||||||
|
let r = db::DatabaseEnvironment::read(&s.env, &s.handle?, &list_key.as_bytes().to_vec())?;
|
||||||
if r.is_empty() {
|
if r.is_empty() {
|
||||||
debug!("creating order index");
|
debug!("creating order index");
|
||||||
}
|
}
|
||||||
let order_list = [r, String::from(&orid)].join(",");
|
let old: String = bincode::deserialize(&r[..]).unwrap_or_default();
|
||||||
|
let order_list = [old, String::from(&orid)].join(",");
|
||||||
debug!("writing order index {} for id: {}", order_list, list_key);
|
debug!("writing order index {} for id: {}", order_list, list_key);
|
||||||
db::DatabaseEnvironment::async_write(&s.env, &s.handle, &String::from(list_key), &order_list).await;
|
let s = db::DatabaseEnvironment::open()?;
|
||||||
new_order
|
db::write_chunks(&s.env, &s.handle?, list_key.as_bytes(), &order_list.as_bytes());
|
||||||
|
Ok(new_order)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Backup order for customer
|
/// Backup order for customer
|
||||||
pub fn backup(order: &Order) {
|
pub fn backup(order: &Order) -> Result<(), MdbError> {
|
||||||
info!("creating backup of order: {}", order.orid);
|
info!("creating backup of order: {}", order.orid);
|
||||||
let s = db::DatabaseEnvironment::open();
|
let s = db::DatabaseEnvironment::open()?;
|
||||||
let k = &order.orid;
|
let k = &order.orid;
|
||||||
db::DatabaseEnvironment::delete(&s.env, &s.handle, k);
|
db::DatabaseEnvironment::delete(&s.env, &s.handle?, k.as_bytes());
|
||||||
db::DatabaseEnvironment::write(&s.env, &s.handle, k, &Order::to_db(order));
|
let s = db::DatabaseEnvironment::open()?;
|
||||||
|
let order_to_db = bincode::serialize(&order).unwrap_or_default();
|
||||||
|
db::write_chunks(&s.env, &s.handle?, k.as_bytes(), &order_to_db);
|
||||||
// in order to retrieve all orders, write keys to with col
|
// in order to retrieve all orders, write keys to with col
|
||||||
let list_key = crate::CUSTOMER_ORDER_LIST_DB_KEY;
|
let list_key = crate::CUSTOMER_ORDER_LIST_DB_KEY;
|
||||||
let r = db::DatabaseEnvironment::read(&s.env, &s.handle, &String::from(list_key));
|
let s = db::DatabaseEnvironment::open()?;
|
||||||
|
let r = db::DatabaseEnvironment::read(&s.env, &s.handle?, &list_key.as_bytes().to_vec())?;
|
||||||
if r.is_empty() {
|
if r.is_empty() {
|
||||||
debug!("creating customer order index");
|
debug!("creating customer order index");
|
||||||
}
|
}
|
||||||
let mut order_list = [String::from(&r), String::from(&order.orid)].join(",");
|
let d_r: String = bincode::deserialize(&r[..]).unwrap_or_default();
|
||||||
|
let mut order_list = [String::from(&d_r), String::from(&order.orid)].join(",");
|
||||||
// don't duplicate order ids when backing up updates from vendor
|
// don't duplicate order ids when backing up updates from vendor
|
||||||
if String::from(&r).contains(&String::from(&order.orid)) {
|
if String::from(&d_r).contains(&String::from(&order.orid)) {
|
||||||
order_list = r;
|
order_list = d_r;
|
||||||
}
|
}
|
||||||
debug!("writing order index {} for id: {}", order_list, list_key);
|
debug!("writing order index {} for id: {}", order_list, list_key);
|
||||||
db::DatabaseEnvironment::write(&s.env, &s.handle, &String::from(list_key), &order_list);
|
let s = db::DatabaseEnvironment::open()?;
|
||||||
|
db::write_chunks(&s.env, &s.handle?, list_key.as_bytes(), order_list.as_bytes());
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Lookup order
|
/// Lookup order
|
||||||
pub fn find(oid: &String) -> Order {
|
pub fn find(oid: &String) -> Result<Order, MdbError> {
|
||||||
info!("find order: {}", &oid);
|
info!("find order: {}", &oid);
|
||||||
let s = db::DatabaseEnvironment::open();
|
let s = db::DatabaseEnvironment::open()?;
|
||||||
let r = db::DatabaseEnvironment::read(&s.env, &s.handle, &String::from(oid));
|
let r = db::DatabaseEnvironment::read(&s.env, &s.handle?, &oid.as_bytes().to_vec())?;
|
||||||
if r.is_empty() {
|
if r.is_empty() {
|
||||||
error!("order not found");
|
error!("order not found");
|
||||||
return Default::default();
|
return Err(MdbError::NotFound);
|
||||||
}
|
}
|
||||||
Order::from_db(String::from(oid), r)
|
let result: Order = bincode::deserialize(&r[..]).unwrap_or_default();
|
||||||
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Lookup all orders from admin server
|
/// Lookup all orders from admin server
|
||||||
pub fn find_all() -> Vec<Order> {
|
pub fn find_all() -> Result<Vec<Order>, MdbError> {
|
||||||
let i_s = db::DatabaseEnvironment::open();
|
let i_s = db::DatabaseEnvironment::open()?;
|
||||||
let i_list_key = crate::ORDER_LIST_DB_KEY;
|
let i_list_key = crate::ORDER_LIST_DB_KEY;
|
||||||
let i_r = db::DatabaseEnvironment::read(&i_s.env, &i_s.handle, &String::from(i_list_key));
|
let i_r = db::DatabaseEnvironment::read(&i_s.env, &i_s.handle?, &i_list_key.as_bytes().to_vec())?;
|
||||||
if i_r.is_empty() {
|
if i_r.is_empty() {
|
||||||
error!("order index not found");
|
error!("order index not found");
|
||||||
}
|
}
|
||||||
let i_v_oid = i_r.split(",");
|
let de: String = bincode::deserialize(&i_r[..]).unwrap_or_default();
|
||||||
|
let i_v_oid = de.split(",");
|
||||||
let i_v: Vec<String> = i_v_oid.map(String::from).collect();
|
let i_v: Vec<String> = i_v_oid.map(String::from).collect();
|
||||||
let mut orders: Vec<Order> = Vec::new();
|
let mut orders: Vec<Order> = Vec::new();
|
||||||
for o in i_v {
|
for o in i_v {
|
||||||
let order: Order = find(&o);
|
let order: Order = find(&o)?;
|
||||||
if !order.orid.is_empty() {
|
if !order.orid.is_empty() {
|
||||||
orders.push(order);
|
orders.push(order);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
orders
|
Ok(orders)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Lookup all orders that customer has saved from gui
|
/// Lookup all orders that customer has saved from gui
|
||||||
pub fn find_all_backup() -> Vec<Order> {
|
pub fn find_all_backup() -> Result<Vec<Order>, MdbError> {
|
||||||
let i_s = db::DatabaseEnvironment::open();
|
let i_s = db::DatabaseEnvironment::open()?;
|
||||||
let i_list_key = crate::CUSTOMER_ORDER_LIST_DB_KEY;
|
let i_list_key = crate::CUSTOMER_ORDER_LIST_DB_KEY;
|
||||||
let i_r = db::DatabaseEnvironment::read(&i_s.env, &i_s.handle, &String::from(i_list_key));
|
let i_r = db::DatabaseEnvironment::read(&i_s.env, &i_s.handle?, &i_list_key.as_bytes().to_vec())?;
|
||||||
if i_r.is_empty() {
|
if i_r.is_empty() {
|
||||||
error!("customer order index not found");
|
error!("customer order index not found");
|
||||||
}
|
}
|
||||||
let i_v_oid = i_r.split(",");
|
let de: String = bincode::deserialize(&i_r[..]).unwrap_or_default();
|
||||||
|
let i_v_oid = de.split(",");
|
||||||
let i_v: Vec<String> = i_v_oid.map(String::from).collect();
|
let i_v: Vec<String> = i_v_oid.map(String::from).collect();
|
||||||
let mut orders: Vec<Order> = Vec::new();
|
let mut orders: Vec<Order> = Vec::new();
|
||||||
for o in i_v {
|
for o in i_v {
|
||||||
let order: Order = find(&o);
|
let order: Order = find(&o)?;
|
||||||
let visible = !order.orid.is_empty()
|
let visible = !order.orid.is_empty()
|
||||||
&& order.status != order::StatusType::Delivered.value()
|
&& order.status != order::StatusType::Delivered.value()
|
||||||
&& order.status != order::StatusType::Cancelled.value();
|
&& order.status != order::StatusType::Cancelled.value();
|
||||||
|
@ -166,45 +172,47 @@ pub fn find_all_backup() -> Vec<Order> {
|
||||||
orders.push(order);
|
orders.push(order);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
orders
|
Ok(orders)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Lookup all orders for customer
|
/// Lookup all orders for customer
|
||||||
pub async fn find_all_customer_orders(cid: String) -> Vec<Order> {
|
pub async fn find_all_customer_orders(cid: String) -> Result<Vec<Order>, MdbError> {
|
||||||
info!("lookup orders for customer: {}", &cid);
|
info!("lookup orders for customer: {}", &cid);
|
||||||
let i_s = db::DatabaseEnvironment::open();
|
let i_s = db::DatabaseEnvironment::open()?;
|
||||||
let i_list_key = crate::ORDER_LIST_DB_KEY;
|
let i_list_key = crate::ORDER_LIST_DB_KEY;
|
||||||
let i_r = db::DatabaseEnvironment::read(&i_s.env, &i_s.handle, &String::from(i_list_key));
|
let i_r = db::DatabaseEnvironment::read(&i_s.env, &i_s.handle?, &i_list_key.as_bytes().to_vec())?;
|
||||||
if i_r.is_empty() {
|
if i_r.is_empty() {
|
||||||
error!("order index not found");
|
error!("order index not found");
|
||||||
}
|
}
|
||||||
let i_v_oid = i_r.split(",");
|
let de: String = bincode::deserialize(&i_r[..]).unwrap_or_default();
|
||||||
|
let i_v_oid = de.split(",");
|
||||||
let i_v: Vec<String> = i_v_oid.map(String::from).collect();
|
let i_v: Vec<String> = i_v_oid.map(String::from).collect();
|
||||||
let mut orders: Vec<Order> = Vec::new();
|
let mut orders: Vec<Order> = Vec::new();
|
||||||
for o in i_v {
|
for o in i_v {
|
||||||
let order: Order = find(&o);
|
let order: Order = find(&o)?;
|
||||||
if !order.orid.is_empty() && order.cid == cid {
|
if !order.orid.is_empty() && order.cid == cid {
|
||||||
orders.push(order);
|
orders.push(order);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
orders
|
Ok(orders)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Lookup all orders for vendor
|
/// Lookup all orders for vendor
|
||||||
pub fn find_all_vendor_orders() -> Vec<Order> {
|
pub fn find_all_vendor_orders() -> Result<Vec<Order>, MdbError> {
|
||||||
info!("lookup orders for vendor");
|
info!("lookup orders for vendor");
|
||||||
let i_s = db::DatabaseEnvironment::open();
|
let i_s = db::DatabaseEnvironment::open()?;
|
||||||
let i_list_key = crate::ORDER_LIST_DB_KEY;
|
let i_list_key = crate::ORDER_LIST_DB_KEY;
|
||||||
let i_r = db::DatabaseEnvironment::read(&i_s.env, &i_s.handle, &String::from(i_list_key));
|
let i_r = db::DatabaseEnvironment::read(&i_s.env, &i_s.handle?, &i_list_key.as_bytes().to_vec())?;
|
||||||
if i_r.is_empty() {
|
if i_r.is_empty() {
|
||||||
error!("order index not found");
|
error!("order index not found");
|
||||||
}
|
}
|
||||||
let i_v_oid = i_r.split(",");
|
let de: String = bincode::deserialize(&i_r[..]).unwrap_or_default();
|
||||||
|
let i_v_oid = de.split(",");
|
||||||
let i_v: Vec<String> = i_v_oid.map(String::from).collect();
|
let i_v: Vec<String> = i_v_oid.map(String::from).collect();
|
||||||
let mut orders: Vec<Order> = Vec::new();
|
let mut orders: Vec<Order> = Vec::new();
|
||||||
let vendor_b32: String = i2p::get_destination(None);
|
let vendor_b32: String = i2p::get_destination(None);
|
||||||
for o in i_v {
|
for o in i_v {
|
||||||
let order: Order = find(&o);
|
let order: Order = find(&o)?;
|
||||||
if !order.orid.is_empty() && order.cid != vendor_b32 {
|
if !order.orid.is_empty() && order.cid != vendor_b32 {
|
||||||
// TODO(c2m): separate functionality for archived orders
|
// TODO(c2m): separate functionality for archived orders
|
||||||
if order.status != order::StatusType::Cancelled.value()
|
if order.status != order::StatusType::Cancelled.value()
|
||||||
|
@ -214,22 +222,24 @@ pub fn find_all_vendor_orders() -> Vec<Order> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
orders
|
Ok(orders)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Modify order from admin server
|
/// Modify order from admin server
|
||||||
pub fn modify(o: Json<Order>) -> Order {
|
pub fn modify(o: Json<Order>) -> Result<Order, MdbError> {
|
||||||
info!("modify order: {}", &o.orid);
|
info!("modify order: {}", &o.orid);
|
||||||
let f_order: Order = find(&o.orid);
|
let f_order: Order = find(&o.orid)?;
|
||||||
if f_order.orid.is_empty() {
|
if f_order.orid.is_empty() {
|
||||||
error!("order not found");
|
error!("order not found");
|
||||||
return Default::default();
|
return Err(MdbError::NotFound);
|
||||||
}
|
}
|
||||||
let u_order = Order::update(String::from(&f_order.orid), &o);
|
let u_order = Order::update(String::from(&f_order.orid), &o);
|
||||||
let s = db::DatabaseEnvironment::open();
|
let s = db::DatabaseEnvironment::open()?;
|
||||||
db::DatabaseEnvironment::delete(&s.env, &s.handle, &u_order.orid);
|
db::DatabaseEnvironment::delete(&s.env, &s.handle?, &u_order.orid.as_bytes());
|
||||||
db::DatabaseEnvironment::write(&s.env, &s.handle, &u_order.orid, &Order::to_db(&u_order));
|
let v = bincode::serialize(&u_order).unwrap_or_default();
|
||||||
u_order
|
let s = db::DatabaseEnvironment::open()?;
|
||||||
|
db::write_chunks(&s.env, &s.handle?, &u_order.orid.as_bytes(), &v);
|
||||||
|
Ok(u_order)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sign and submit multisig
|
/// Sign and submit multisig
|
||||||
|
@ -259,12 +269,12 @@ pub async fn sign_and_submit_multisig(
|
||||||
/// access
|
/// access
|
||||||
///
|
///
|
||||||
/// the details of said order.
|
/// the details of said order.
|
||||||
pub async fn secure_retrieval(orid: &String, signature: &String) -> Order {
|
pub async fn secure_retrieval(orid: &String, signature: &String) -> Result<Order, NevekoError> {
|
||||||
info!("secure order retrieval for {}", orid);
|
info!("secure order retrieval for {}", orid);
|
||||||
// get customer address for NEVEKO NOT order wallet
|
// get customer address for NEVEKO NOT order wallet
|
||||||
let m_order: Order = find(orid);
|
let m_order: Order = find(orid).map_err(|_| NevekoError::Order)?;
|
||||||
let mut xmr_address: String = String::new();
|
let mut xmr_address: String = String::new();
|
||||||
let a_customers: Vec<Contact> = contact::find_all();
|
let a_customers: Vec<Contact> = contact::find_all().map_err(|_| NevekoError::Contact)?;
|
||||||
for customer in a_customers {
|
for customer in a_customers {
|
||||||
if customer.i2p_address == m_order.cid {
|
if customer.i2p_address == m_order.cid {
|
||||||
xmr_address = customer.xmr_address;
|
xmr_address = customer.xmr_address;
|
||||||
|
@ -281,20 +291,20 @@ pub async fn secure_retrieval(orid: &String, signature: &String) -> Order {
|
||||||
let is_valid_signature = monero::verify(xmr_address, id, sig).await;
|
let is_valid_signature = monero::verify(xmr_address, id, sig).await;
|
||||||
monero::close_wallet(&wallet_name, &wallet_password).await;
|
monero::close_wallet(&wallet_name, &wallet_password).await;
|
||||||
if !is_valid_signature {
|
if !is_valid_signature {
|
||||||
return Default::default();
|
return Err(NevekoError::Order);
|
||||||
}
|
}
|
||||||
m_order
|
Ok(m_order)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// In order for the order (...ha) to only be cancelled by the customer
|
/// In order for the order (...ha) to only be cancelled by the customer
|
||||||
///
|
///
|
||||||
/// they must sign the order id with their NEVEKO wallet instance.
|
/// they must sign the order id with their NEVEKO wallet instance.
|
||||||
pub async fn cancel_order(orid: &String, signature: &String) -> Order {
|
pub async fn cancel_order(orid: &String, signature: &String) -> Result<Order, NevekoError> {
|
||||||
info!("cancel order {}", orid);
|
info!("cancel order {}", orid);
|
||||||
// get customer address for NEVEKO NOT order wallet
|
// get customer address for NEVEKO NOT order wallet
|
||||||
let mut m_order: Order = find(orid);
|
let mut m_order: Order = find(orid).map_err(|_| NevekoError::Order)?;
|
||||||
let mut xmr_address: String = String::new();
|
let mut xmr_address: String = String::new();
|
||||||
let a_customers: Vec<Contact> = contact::find_all();
|
let a_customers: Vec<Contact> = contact::find_all().map_err(|_| NevekoError::Contact)?;
|
||||||
for customer in a_customers {
|
for customer in a_customers {
|
||||||
if customer.i2p_address == m_order.cid {
|
if customer.i2p_address == m_order.cid {
|
||||||
xmr_address = customer.xmr_address;
|
xmr_address = customer.xmr_address;
|
||||||
|
@ -311,27 +321,29 @@ pub async fn cancel_order(orid: &String, signature: &String) -> Order {
|
||||||
let is_valid_signature = monero::verify(xmr_address, id, sig).await;
|
let is_valid_signature = monero::verify(xmr_address, id, sig).await;
|
||||||
monero::close_wallet(&wallet_name, &wallet_password).await;
|
monero::close_wallet(&wallet_name, &wallet_password).await;
|
||||||
if !is_valid_signature {
|
if !is_valid_signature {
|
||||||
return Default::default();
|
return Err(NevekoError::Order);
|
||||||
}
|
}
|
||||||
// update the order status and send to customer
|
// update the order status and send to customer
|
||||||
m_order.status = order::StatusType::Cancelled.value();
|
m_order.status = order::StatusType::Cancelled.value();
|
||||||
order::modify(Json(m_order));
|
order::modify(Json(m_order));
|
||||||
order::find(orid)
|
order::find(orid).map_err(|_| NevekoError::Order)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check for import multisig info, validate block time and that the
|
/// Check for import multisig info, validate block time and that the
|
||||||
///
|
///
|
||||||
/// order wallet has been funded properly. Update the order to multisig complete
|
/// order wallet has been funded properly. Update the order to multisig complete
|
||||||
pub async fn validate_order_for_ship(orid: &String) -> reqres::FinalizeOrderResponse {
|
pub async fn validate_order_for_ship(orid: &String) -> Result<reqres::FinalizeOrderResponse, NevekoError> {
|
||||||
info!("validating order for shipment");
|
info!("validating order for shipment");
|
||||||
let m_order: Order = find(orid);
|
let m_order: Order = find(orid).map_err(|_| NevekoError::Order)?;
|
||||||
let contact: Contact = contact::find(&m_order.cid);
|
let contact: Contact = contact::find(&m_order.cid).map_err(|_| NevekoError::Contact)?;
|
||||||
let hex_nmpk: String = contact.nmpk;
|
let hex_nmpk: String = contact.nmpk;
|
||||||
let s = db::DatabaseEnvironment::async_open().await;
|
let s = db::DatabaseEnvironment::open().map_err(|_| NevekoError::Database(MdbError::Panic))?;
|
||||||
let k = String::from(crate::DELIVERY_INFO_DB_KEY);
|
let k = String::from(crate::DELIVERY_INFO_DB_KEY);
|
||||||
let delivery_info: String = db::DatabaseEnvironment::async_read(&s.env, &s.handle, &k).await;
|
let handle = &s.handle.map_err(|_| NevekoError::Database(MdbError::Panic))?;
|
||||||
let mut j_order: Order = find(orid);
|
let delivery_info = db::DatabaseEnvironment::read(&s.env, handle, &k.as_bytes().to_vec())
|
||||||
let m_product: Product = product::find(&m_order.pid);
|
.map_err(|_| NevekoError::Database(MdbError::Panic))?;
|
||||||
|
let mut j_order: Order = find(orid).map_err(|_| NevekoError::Order)?;
|
||||||
|
let m_product: Product = product::find(&m_order.pid).map_err(|_| NevekoError::Product)?;
|
||||||
let price = m_product.price;
|
let price = m_product.price;
|
||||||
let total = price * &m_order.quantity;
|
let total = price * &m_order.quantity;
|
||||||
let wallet_password = String::new();
|
let wallet_password = String::new();
|
||||||
|
@ -346,17 +358,18 @@ pub async fn validate_order_for_ship(orid: &String) -> reqres::FinalizeOrderResp
|
||||||
j_order.status = StatusType::Shipped.value();
|
j_order.status = StatusType::Shipped.value();
|
||||||
order::modify(Json(j_order));
|
order::modify(Json(j_order));
|
||||||
}
|
}
|
||||||
|
let d_info: String = bincode::deserialize(&delivery_info[..]).unwrap_or_default();
|
||||||
let e_delivery_info: String = neveko25519::cipher(
|
let e_delivery_info: String = neveko25519::cipher(
|
||||||
&hex_nmpk,
|
&hex_nmpk,
|
||||||
hex::encode(delivery_info),
|
hex::encode(d_info),
|
||||||
Some(String::from(neveko25519::ENCIPHER)),
|
Some(String::from(neveko25519::ENCIPHER)),
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
reqres::FinalizeOrderResponse {
|
Ok(reqres::FinalizeOrderResponse {
|
||||||
orid: String::from(orid),
|
orid: String::from(orid),
|
||||||
delivery_info: e_delivery_info,
|
delivery_info: e_delivery_info,
|
||||||
vendor_update_success: false,
|
vendor_update_success: false,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// NASR (neveko auto-ship request)
|
/// NASR (neveko auto-ship request)
|
||||||
|
@ -405,10 +418,10 @@ pub async fn trigger_nasr(
|
||||||
pub async fn upload_delivery_info(
|
pub async fn upload_delivery_info(
|
||||||
orid: &String,
|
orid: &String,
|
||||||
delivery_info: &String,
|
delivery_info: &String,
|
||||||
) -> reqres::FinalizeOrderResponse {
|
) -> Result<reqres::FinalizeOrderResponse, NevekoError> {
|
||||||
info!("uploading delivery info");
|
info!("uploading delivery info");
|
||||||
let lookup: Order = order::find(orid);
|
let lookup: Order = order::find(orid).map_err(|_| NevekoError::Order)?;
|
||||||
let contact: Contact = contact::find(&lookup.cid);
|
let contact: Contact = contact::find(&lookup.cid).map_err(|_| NevekoError::Contact)?;
|
||||||
let hex_nmpk: String = contact.nmpk;
|
let hex_nmpk: String = contact.nmpk;
|
||||||
let e_delivery_info: String = neveko25519::cipher(
|
let e_delivery_info: String = neveko25519::cipher(
|
||||||
&hex_nmpk,
|
&hex_nmpk,
|
||||||
|
@ -428,35 +441,42 @@ pub async fn upload_delivery_info(
|
||||||
monero::close_wallet(orid, &wallet_password).await;
|
monero::close_wallet(orid, &wallet_password).await;
|
||||||
if sweep.result.multisig_txset.is_empty() {
|
if sweep.result.multisig_txset.is_empty() {
|
||||||
error!("unable to create draft txset");
|
error!("unable to create draft txset");
|
||||||
return Default::default();
|
return Err(NevekoError::MoneroRpc);
|
||||||
}
|
}
|
||||||
// update the order
|
// update the order
|
||||||
let mut m_order: Order = find(orid);
|
let mut m_order: Order = find(orid).map_err(|_| NevekoError::Order)?;
|
||||||
m_order.status = StatusType::Shipped.value();
|
m_order.status = StatusType::Shipped.value();
|
||||||
m_order.ship_date = chrono::offset::Utc::now().timestamp();
|
m_order.ship_date = chrono::offset::Utc::now().timestamp();
|
||||||
m_order.vend_msig_txset = sweep.result.multisig_txset;
|
m_order.vend_msig_txset = sweep.result.multisig_txset;
|
||||||
// delivery info will be stored enciphered and separate from the rest of the
|
// delivery info will be stored enciphered and separate from the rest of the
|
||||||
// order
|
// order
|
||||||
let s = db::DatabaseEnvironment::async_open().await;
|
let s = db::DatabaseEnvironment::open().map_err(|_| NevekoError::Database(MdbError::Panic))?;
|
||||||
let k = String::from(crate::DELIVERY_INFO_DB_KEY);
|
let k = String::from(crate::DELIVERY_INFO_DB_KEY);
|
||||||
db::DatabaseEnvironment::async_write(&s.env, &s.handle, &k, &hex::encode(delivery_info)).await;
|
let handle = &s.handle.map_err(|_| NevekoError::Database(MdbError::Panic))?;
|
||||||
|
db::write_chunks(&s.env, handle, k.as_bytes(), delivery_info.as_bytes());
|
||||||
modify(Json(m_order));
|
modify(Json(m_order));
|
||||||
// trigger nasr, this will cause the customer's neveko instance to request the
|
// trigger nasr, this will cause the customer's neveko instance to request the
|
||||||
// txset
|
// txset
|
||||||
let i2p_address = i2p::get_destination(None);
|
let i2p_address = i2p::get_destination(None);
|
||||||
let s = db::DatabaseEnvironment::open();
|
|
||||||
// get jwp from db
|
// get jwp from db
|
||||||
|
let s = db::DatabaseEnvironment::open().map_err(|_| NevekoError::Database(MdbError::Panic))?;
|
||||||
|
let handle = &s.handle.map_err(|_| NevekoError::Database(MdbError::Panic))?;
|
||||||
let k = format!("{}-{}", crate::FTS_JWP_DB_KEY, &lookup.cid);
|
let k = format!("{}-{}", crate::FTS_JWP_DB_KEY, &lookup.cid);
|
||||||
let jwp = db::DatabaseEnvironment::read(&s.env, &s.handle, &k);
|
let jwp = db::DatabaseEnvironment::read(&s.env, handle, &k.as_bytes().to_vec())
|
||||||
let nasr_order = trigger_nasr(&lookup.cid, &i2p_address, &jwp, orid).await;
|
.map_err(|_| NevekoError::Database(MdbError::Panic))?;
|
||||||
|
let str_jwp: String = bincode::deserialize(&jwp[..]).unwrap_or_default();
|
||||||
|
let nasr_order = trigger_nasr(&lookup.cid, &i2p_address, &str_jwp, orid).await;
|
||||||
if nasr_order.is_err() {
|
if nasr_order.is_err() {
|
||||||
return Default::default();
|
error!("failed to trigger nasr");
|
||||||
}
|
return Err(NevekoError::Nasr);
|
||||||
reqres::FinalizeOrderResponse {
|
|
||||||
delivery_info: e_delivery_info,
|
|
||||||
orid: String::from(orid),
|
|
||||||
vendor_update_success: false,
|
|
||||||
}
|
}
|
||||||
|
Ok(
|
||||||
|
reqres::FinalizeOrderResponse {
|
||||||
|
delivery_info: e_delivery_info,
|
||||||
|
orid: String::from(orid),
|
||||||
|
vendor_update_success: false,
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Vendor will very txset submission and then update the order to `Delivered`
|
/// Vendor will very txset submission and then update the order to `Delivered`
|
||||||
|
@ -464,13 +484,13 @@ pub async fn upload_delivery_info(
|
||||||
/// status type. Then customer will update the status on the neveko instanced
|
/// status type. Then customer will update the status on the neveko instanced
|
||||||
///
|
///
|
||||||
/// upon a `vendor_update_success: true` response
|
/// upon a `vendor_update_success: true` response
|
||||||
pub async fn finalize_order(orid: &String) -> reqres::FinalizeOrderResponse {
|
pub async fn finalize_order(orid: &String) -> Result< reqres::FinalizeOrderResponse, NevekoError> {
|
||||||
info!("finalizing order: {}", orid);
|
info!("finalizing order: {}", orid);
|
||||||
// verify recipient and unlock time
|
// verify recipient and unlock time
|
||||||
let mut m_order: Order = order::find(orid);
|
let mut m_order: Order = order::find(orid).map_err(|_| NevekoError::Order)?;
|
||||||
if m_order.vend_msig_txset.is_empty() {
|
if m_order.vend_msig_txset.is_empty() {
|
||||||
error!("txset missing");
|
error!("txset missing");
|
||||||
return Default::default();
|
return Err(NevekoError::MoneroRpc);
|
||||||
}
|
}
|
||||||
// get draft payment txset
|
// get draft payment txset
|
||||||
let wallet_password = String::new();
|
let wallet_password = String::new();
|
||||||
|
@ -489,22 +509,24 @@ pub async fn finalize_order(orid: &String) -> reqres::FinalizeOrderResponse {
|
||||||
if !valid {
|
if !valid {
|
||||||
monero::close_wallet(orid, &wallet_password).await;
|
monero::close_wallet(orid, &wallet_password).await;
|
||||||
error!("invalid txset");
|
error!("invalid txset");
|
||||||
return Default::default();
|
return Err(NevekoError::MoneroRpc);
|
||||||
}
|
}
|
||||||
// verify order wallet has been swept clean
|
// verify order wallet has been swept clean
|
||||||
let balance = monero::get_balance().await;
|
let balance = monero::get_balance().await;
|
||||||
if balance.result.unlocked_balance != 0 {
|
if balance.result.unlocked_balance != 0 {
|
||||||
monero::close_wallet(orid, &wallet_password).await;
|
monero::close_wallet(orid, &wallet_password).await;
|
||||||
error!("order wallet not swept");
|
error!("order wallet not swept");
|
||||||
return Default::default();
|
return Err(NevekoError::MoneroRpc);
|
||||||
}
|
}
|
||||||
monero::close_wallet(orid, &wallet_password).await;
|
monero::close_wallet(orid, &wallet_password).await;
|
||||||
m_order.status = order::StatusType::Delivered.value();
|
m_order.status = order::StatusType::Delivered.value();
|
||||||
order::modify(Json(m_order));
|
order::modify(Json(m_order));
|
||||||
reqres::FinalizeOrderResponse {
|
Ok(
|
||||||
vendor_update_success: true,
|
reqres::FinalizeOrderResponse {
|
||||||
..Default::default()
|
vendor_update_success: true,
|
||||||
}
|
..Default::default()
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Executes POST /order/finalize/{orid}
|
/// Executes POST /order/finalize/{orid}
|
||||||
|
@ -551,41 +573,44 @@ pub async fn trigger_finalize_request(
|
||||||
contact: &String,
|
contact: &String,
|
||||||
jwp: &String,
|
jwp: &String,
|
||||||
orid: &String,
|
orid: &String,
|
||||||
) -> reqres::FinalizeOrderResponse {
|
) -> Result<reqres::FinalizeOrderResponse, NevekoError> {
|
||||||
info!("executing trigger_finalize_request");
|
info!("executing trigger_finalize_request");
|
||||||
let finalize = transmit_finalize_request(contact, jwp, orid).await;
|
let finalize = transmit_finalize_request(contact, jwp, orid).await;
|
||||||
// cache finalize order request to db
|
// cache finalize order request to db
|
||||||
if finalize.is_err() {
|
if finalize.is_err() {
|
||||||
log::error!("failed to trigger cancel request");
|
log::error!("failed to trigger cancel request");
|
||||||
return Default::default();
|
return Err(NevekoError::Order);
|
||||||
}
|
}
|
||||||
let unwrap: reqres::FinalizeOrderResponse = finalize.unwrap();
|
let unwrap: reqres::FinalizeOrderResponse = finalize.unwrap();
|
||||||
let mut m_order: Order = order::find(orid);
|
let mut m_order: Order = order::find(orid).map_err(|_| NevekoError::Order)?;
|
||||||
m_order.status = order::StatusType::Delivered.value();
|
m_order.status = order::StatusType::Delivered.value();
|
||||||
backup(&m_order);
|
backup(&m_order);
|
||||||
unwrap
|
Ok(unwrap)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Decomposition trigger for `finalize_order()`
|
/// Decomposition trigger for `finalize_order()`
|
||||||
pub async fn d_trigger_finalize_request(
|
pub async fn d_trigger_finalize_request(
|
||||||
contact: &String,
|
contact: &String,
|
||||||
orid: &String,
|
orid: &String,
|
||||||
) -> reqres::FinalizeOrderResponse {
|
) -> Result<reqres::FinalizeOrderResponse, NevekoError> {
|
||||||
// ugh, sorry seems we need to get jwp for vendor from fts cache
|
// ugh, sorry seems we need to get jwp for vendor from fts cache
|
||||||
// get jwp from db
|
// get jwp from db
|
||||||
let s = db::DatabaseEnvironment::async_open().await;
|
let s = db::DatabaseEnvironment::open().map_err(|_| NevekoError::Database(MdbError::NotFound))?;
|
||||||
let k = format!("{}-{}", crate::FTS_JWP_DB_KEY, &contact);
|
let k = format!("{}-{}", crate::FTS_JWP_DB_KEY, &contact);
|
||||||
let jwp = db::DatabaseEnvironment::async_read(&s.env, &s.handle, &k).await;
|
let handle = &s.handle.map_err(|_| NevekoError::Database(MdbError::Panic))?;
|
||||||
|
let jwp = db::DatabaseEnvironment::read(&s.env, handle, &k.as_bytes().to_vec())
|
||||||
|
.map_err(|_| NevekoError::Database(MdbError::Panic))?;
|
||||||
info!("executing d_trigger_finalize_request");
|
info!("executing d_trigger_finalize_request");
|
||||||
// request finalize if the order status is shipped
|
// request finalize if the order status is shipped
|
||||||
let order: Order = order::find(orid);
|
let order: Order = order::find(orid).map_err(|_| NevekoError::Order)?;
|
||||||
|
let str_jwp: String = bincode::deserialize(&jwp[..]).unwrap_or_default();
|
||||||
if order.status != order::StatusType::Shipped.value() {
|
if order.status != order::StatusType::Shipped.value() {
|
||||||
let trigger = trigger_finalize_request(contact, &jwp, orid).await;
|
let trigger = trigger_finalize_request(contact, &str_jwp, orid).await?;
|
||||||
if trigger.vendor_update_success {
|
if trigger.vendor_update_success {
|
||||||
return trigger;
|
return Ok(trigger);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Default::default()
|
Err(NevekoError::Order)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send order request to vendor and start multisig flow
|
/// Send order request to vendor and start multisig flow
|
||||||
|
@ -735,27 +760,34 @@ pub async fn trigger_cancel_request(contact: &String, jwp: &String, orid: &Strin
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Decomposition trigger for the shipping request
|
/// Decomposition trigger for the shipping request
|
||||||
pub async fn d_trigger_ship_request(contact: &String, orid: &String) -> Order {
|
pub async fn d_trigger_ship_request(contact: &String, orid: &String) -> Result<Order, NevekoError> {
|
||||||
// ugh, sorry seems we need to get jwp for vendor from fts cache
|
// ugh, sorry seems we need to get jwp for vendor from fts cache
|
||||||
// get jwp from db
|
// get jwp from db
|
||||||
let s = db::DatabaseEnvironment::async_open().await;
|
let s = db::DatabaseEnvironment::open()
|
||||||
|
.map_err(|_| NevekoError::Database(MdbError::Panic))?;
|
||||||
let k = format!("{}-{}", crate::FTS_JWP_DB_KEY, &contact);
|
let k = format!("{}-{}", crate::FTS_JWP_DB_KEY, &contact);
|
||||||
let jwp = db::DatabaseEnvironment::async_read(&s.env, &s.handle, &k).await;
|
let handle = &s.handle.map_err(|_| NevekoError::Database(MdbError::Panic))?;
|
||||||
|
let jwp = db::DatabaseEnvironment::read(&s.env, handle, &k.as_bytes().to_vec())
|
||||||
|
.map_err(|_| NevekoError::Database(MdbError::Panic))?;
|
||||||
info!("executing d_trigger_ship_request");
|
info!("executing d_trigger_ship_request");
|
||||||
// request shipment if the order status is MultisigComplete
|
// request shipment if the order status is MultisigComplete
|
||||||
let trigger = trigger_ship_request(contact, &jwp, orid).await;
|
let str_jwp: String = bincode::deserialize(&jwp[..]).unwrap_or_default();
|
||||||
|
let trigger = trigger_ship_request(contact, &str_jwp, orid).await;
|
||||||
if trigger.status == order::StatusType::MulitsigComplete.value() {
|
if trigger.status == order::StatusType::MulitsigComplete.value() {
|
||||||
let ship_res = transmit_ship_request(contact, &jwp, orid).await;
|
let ship_res = transmit_ship_request(contact, &str_jwp, orid).await;
|
||||||
if ship_res.is_err() {
|
if ship_res.is_err() {
|
||||||
error!("failure to decompose trigger_ship_request");
|
error!("failure to decompose trigger_ship_request");
|
||||||
return Default::default();
|
return Err(NevekoError::Order);
|
||||||
}
|
}
|
||||||
let u_ship_res = ship_res.unwrap_or(Default::default());
|
let u_ship_res = ship_res.unwrap_or(Default::default());
|
||||||
let hex_delivery_info: String = hex::encode(u_ship_res.delivery_info);
|
let hex_delivery_info: String = hex::encode(u_ship_res.delivery_info);
|
||||||
let key = format!("{}-{}", crate::DELIVERY_INFO_DB_KEY, orid);
|
let key = format!("{}-{}", crate::DELIVERY_INFO_DB_KEY, orid);
|
||||||
db::DatabaseEnvironment::write(&s.env, &s.handle, &key, &hex_delivery_info);
|
let s = db::DatabaseEnvironment::open()
|
||||||
|
.map_err(|_| NevekoError::Database(MdbError::Panic))?;
|
||||||
|
let handle = &s.handle.map_err(|_| NevekoError::Database(MdbError::Panic))?;
|
||||||
|
db::write_chunks(&s.env, handle, key.as_bytes(), hex_delivery_info.as_bytes());
|
||||||
}
|
}
|
||||||
trigger
|
Ok(trigger)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Executes POST /order/cancel/orid/signature
|
/// Executes POST /order/cancel/orid/signature
|
||||||
|
@ -800,22 +832,26 @@ pub async fn transmit_cancel_request(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Decomposition trigger for the cancel request
|
/// Decomposition trigger for the cancel request
|
||||||
pub async fn d_trigger_cancel_request(contact: &String, orid: &String) -> Order {
|
pub async fn d_trigger_cancel_request(contact: &String, orid: &String) -> Result<Order, NevekoError> {
|
||||||
// ugh, sorry seems we need to get jwp for vendor from fts cache
|
// ugh, sorry seems we need to get jwp for vendor from fts cache
|
||||||
// get jwp from db
|
// get jwp from db
|
||||||
let s = db::DatabaseEnvironment::async_open().await;
|
let s = db::DatabaseEnvironment::open()
|
||||||
|
.map_err(|_| NevekoError::Database(MdbError::Panic))?;
|
||||||
let k = format!("{}-{}", crate::FTS_JWP_DB_KEY, &contact);
|
let k = format!("{}-{}", crate::FTS_JWP_DB_KEY, &contact);
|
||||||
let jwp = db::DatabaseEnvironment::async_read(&s.env, &s.handle, &k).await;
|
let handle = &s.handle.map_err(|_| NevekoError::Database(MdbError::Panic))?;
|
||||||
|
let jwp = db::DatabaseEnvironment::read(&s.env, handle, &k.as_bytes().to_vec())
|
||||||
|
.map_err(|_| NevekoError::Database(MdbError::Panic))?;
|
||||||
info!("executing d_trigger_cancel_request");
|
info!("executing d_trigger_cancel_request");
|
||||||
// request cancel if the order status is not MultisigComplete
|
// request cancel if the order status is not MultisigComplete
|
||||||
let order: Order = order::find(orid);
|
let order: Order = order::find(orid).map_err(|_| NevekoError::Order)?;
|
||||||
if order.status != order::StatusType::MulitsigComplete.value() {
|
if order.status != order::StatusType::MulitsigComplete.value() {
|
||||||
let trigger = trigger_cancel_request(contact, &jwp, orid).await;
|
let str_jwp: String = bincode::deserialize(&jwp[..]).unwrap_or_default();
|
||||||
|
let trigger = trigger_cancel_request(contact, &str_jwp, orid).await;
|
||||||
if trigger.status == order::StatusType::Cancelled.value() {
|
if trigger.status == order::StatusType::Cancelled.value() {
|
||||||
return trigger;
|
return Ok(trigger);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Default::default()
|
Err(NevekoError::Order)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn init_adjudicator_wallet(orid: &String) {
|
pub async fn init_adjudicator_wallet(orid: &String) {
|
||||||
|
|
|
@ -5,6 +5,7 @@ use crate::{
|
||||||
models::*,
|
models::*,
|
||||||
utils,
|
utils,
|
||||||
};
|
};
|
||||||
|
use kn0sys_lmdb_rs::MdbError;
|
||||||
use log::{
|
use log::{
|
||||||
debug,
|
debug,
|
||||||
error,
|
error,
|
||||||
|
@ -14,11 +15,11 @@ use rocket::serde::json::Json;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
/// Create a new product
|
/// Create a new product
|
||||||
pub fn create(d: Json<Product>) -> Product {
|
pub fn create(d: Json<Product>) -> Result<Product, MdbError> {
|
||||||
let pid: String = format!("{}{}", crate::PRODUCT_DB_KEY, utils::generate_rnd());
|
let pid: String = format!("{}{}", crate::PRODUCT_DB_KEY, utils::generate_rnd());
|
||||||
if !validate_product(&d) {
|
if !validate_product(&d) {
|
||||||
error!("invalid product");
|
error!("invalid product");
|
||||||
return Default::default();
|
return Err(MdbError::NotFound);
|
||||||
}
|
}
|
||||||
let new_product = Product {
|
let new_product = Product {
|
||||||
pid: String::from(&pid),
|
pid: String::from(&pid),
|
||||||
|
@ -30,71 +31,79 @@ pub fn create(d: Json<Product>) -> Product {
|
||||||
qty: d.qty,
|
qty: d.qty,
|
||||||
};
|
};
|
||||||
debug!("insert product: {:?}", &new_product);
|
debug!("insert product: {:?}", &new_product);
|
||||||
let s = db::DatabaseEnvironment::open();
|
let s = db::DatabaseEnvironment::open()?;
|
||||||
let k = &new_product.pid;
|
let k = &new_product.pid;
|
||||||
db::DatabaseEnvironment::write(&s.env, &s.handle, k, &Product::to_db(&new_product));
|
let product = bincode::serialize(&new_product).unwrap_or_default();
|
||||||
|
db::write_chunks(&s.env, &s.handle?, k.as_bytes(), &product);
|
||||||
// in order to retrieve all products, write keys to with pl
|
// in order to retrieve all products, write keys to with pl
|
||||||
let list_key = crate::PRODUCT_LIST_DB_KEY;
|
let list_key = crate::PRODUCT_LIST_DB_KEY;
|
||||||
let r = db::DatabaseEnvironment::read(&s.env, &s.handle, &String::from(list_key));
|
let s = db::DatabaseEnvironment::open()?;
|
||||||
|
let r = db::DatabaseEnvironment::read(&s.env, &s.handle?, &list_key.as_bytes().to_vec())?;
|
||||||
if r.is_empty() {
|
if r.is_empty() {
|
||||||
debug!("creating product index");
|
debug!("creating product index");
|
||||||
}
|
}
|
||||||
let product_list = [r, String::from(&pid)].join(",");
|
let old: String = bincode::deserialize(&r[..]).unwrap_or_default();
|
||||||
|
let product_list = [old, String::from(&pid)].join(",");
|
||||||
debug!(
|
debug!(
|
||||||
"writing product index {} for id: {}",
|
"writing product index {} for id: {}",
|
||||||
product_list, list_key
|
product_list, list_key
|
||||||
);
|
);
|
||||||
db::DatabaseEnvironment::write(&s.env, &s.handle, &String::from(list_key), &product_list);
|
let s = db::DatabaseEnvironment::open()?;
|
||||||
new_product
|
db::write_chunks(&s.env, &s.handle?, list_key.as_bytes(), product_list.as_bytes());
|
||||||
|
Ok(new_product)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Single Product lookup
|
/// Single Product lookup
|
||||||
pub fn find(pid: &String) -> Product {
|
pub fn find(pid: &String) -> Result<Product, MdbError> {
|
||||||
let s = db::DatabaseEnvironment::open();
|
let s = db::DatabaseEnvironment::open()?;
|
||||||
let r = db::DatabaseEnvironment::read(&s.env, &s.handle, &String::from(pid));
|
let r = db::DatabaseEnvironment::read(&s.env, &s.handle?, &pid.as_bytes().to_vec())?;
|
||||||
if r.is_empty() {
|
if r.is_empty() {
|
||||||
error!("product not found");
|
error!("product not found");
|
||||||
return Default::default();
|
return Err(MdbError::NotFound);
|
||||||
}
|
}
|
||||||
Product::from_db(String::from(pid), r)
|
let result: Product = bincode::deserialize(&r[..]).unwrap_or_default();
|
||||||
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Product lookup for all
|
/// Product lookup for all
|
||||||
pub fn find_all() -> Vec<Product> {
|
pub fn find_all() -> Result<Vec<Product>, MdbError> {
|
||||||
let i_s = db::DatabaseEnvironment::open();
|
let i_s = db::DatabaseEnvironment::open()?;
|
||||||
let i_list_key = crate::PRODUCT_LIST_DB_KEY;
|
let i_list_key = crate::PRODUCT_LIST_DB_KEY;
|
||||||
let i_r = db::DatabaseEnvironment::read(&i_s.env, &i_s.handle, &String::from(i_list_key));
|
let i_r = db::DatabaseEnvironment::read(&i_s.env, &i_s.handle?, &i_list_key.as_bytes().to_vec())?;
|
||||||
if i_r.is_empty() {
|
if i_r.is_empty() {
|
||||||
error!("product index not found");
|
error!("product index not found");
|
||||||
}
|
}
|
||||||
let i_v_pid = i_r.split(",");
|
let str_r: String = bincode::deserialize(&i_r[..]).unwrap_or_default();
|
||||||
|
let i_v_pid = str_r.split(",");
|
||||||
let i_v: Vec<String> = i_v_pid.map(String::from).collect();
|
let i_v: Vec<String> = i_v_pid.map(String::from).collect();
|
||||||
let mut products: Vec<Product> = Vec::new();
|
let mut products: Vec<Product> = Vec::new();
|
||||||
for p in i_v {
|
for p in i_v {
|
||||||
let mut product: Product = find(&p);
|
let mut product: Product = find(&p)?;
|
||||||
if !product.pid.is_empty() {
|
if !product.pid.is_empty() {
|
||||||
// don't return images
|
// don't return images
|
||||||
product.image = Vec::new();
|
product.image = Vec::new();
|
||||||
products.push(product);
|
products.push(product);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
products
|
Ok(products)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Modify product
|
/// Modify product
|
||||||
pub fn modify(p: Json<Product>) -> Product {
|
pub fn modify(p: Json<Product>) -> Result<Product, MdbError> {
|
||||||
// TODO(c2m): don't allow modification to products with un-delivered orders
|
// TODO(c2m): don't allow modification to products with un-delivered orders
|
||||||
info!("modify product: {}", &p.pid);
|
info!("modify product: {}", &p.pid);
|
||||||
let f_prod: Product = find(&p.pid);
|
let f_prod: Product = find(&p.pid)?;
|
||||||
if f_prod.pid.is_empty() {
|
if f_prod.pid.is_empty() {
|
||||||
error!("product not found");
|
error!("product not found");
|
||||||
return Default::default();
|
return Err(MdbError::NotFound);
|
||||||
}
|
}
|
||||||
let u_prod = Product::update(f_prod, &p);
|
let u_prod = Product::update(f_prod, &p);
|
||||||
let s = db::DatabaseEnvironment::open();
|
let s = db::DatabaseEnvironment::open()?;
|
||||||
db::DatabaseEnvironment::delete(&s.env, &s.handle, &u_prod.pid);
|
db::DatabaseEnvironment::delete(&s.env, &s.handle?, u_prod.pid.as_bytes())?;
|
||||||
db::DatabaseEnvironment::write(&s.env, &s.handle, &u_prod.pid, &Product::to_db(&u_prod));
|
let product = bincode::serialize(&u_prod).unwrap_or_default();
|
||||||
u_prod
|
let s = db::DatabaseEnvironment::open()?;
|
||||||
|
db::write_chunks(&s.env, &s.handle?, u_prod.pid.as_bytes(), &product);
|
||||||
|
Ok(u_prod)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// check product field lengths to prevent db spam
|
/// check product field lengths to prevent db spam
|
||||||
|
|
|
@ -52,7 +52,7 @@ mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
fn cleanup(k: &String) -> Result<(), MdbError> {
|
fn cleanup(k: &String) -> Result<(), MdbError> {
|
||||||
let s = db::DatabaseEnvironment::open("test")?;
|
let s = db::DatabaseEnvironment::open()?;
|
||||||
db::DatabaseEnvironment::delete(&s.env, &s.handle?, k.as_bytes());
|
db::DatabaseEnvironment::delete(&s.env, &s.handle?, k.as_bytes());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,7 @@ mod tests {
|
||||||
"73a4nWuvkYoYoksGurDjKZQcZkmaxLaKbbeiKzHnMmqKivrCzq5Q2JtJG1UZNZFqLPbQ3MiXCk2Q5bdwdUNSr7X9QrPubkn"
|
"73a4nWuvkYoYoksGurDjKZQcZkmaxLaKbbeiKzHnMmqKivrCzq5Q2JtJG1UZNZFqLPbQ3MiXCk2Q5bdwdUNSr7X9QrPubkn"
|
||||||
);
|
);
|
||||||
let test_user = create(&address);
|
let test_user = create(&address);
|
||||||
let s = db::DatabaseEnvironment::open("test")?;
|
let s = db::DatabaseEnvironment::open()?;
|
||||||
let r = db::DatabaseEnvironment::read(&s.env, &s.handle?, &test_user.uid);
|
let r = db::DatabaseEnvironment::read(&s.env, &s.handle?, &test_user.uid);
|
||||||
let id = String::from(&test_user.uid);
|
let id = String::from(&test_user.uid);
|
||||||
let cleanup_id = String::from(&test_user.uid);
|
let cleanup_id = String::from(&test_user.uid);
|
||||||
|
@ -83,7 +83,7 @@ mod tests {
|
||||||
xmr_address: address,
|
xmr_address: address,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let s = db::DatabaseEnvironment::open("test")?;
|
let s = db::DatabaseEnvironment::open()?;
|
||||||
db::DatabaseEnvironment::write_chunks(&s.env, &s.handle?, k, &User::to_db(&expected_user));
|
db::DatabaseEnvironment::write_chunks(&s.env, &s.handle?, k, &User::to_db(&expected_user));
|
||||||
let actual_user: User = find(&String::from(k));
|
let actual_user: User = find(&String::from(k));
|
||||||
assert_eq!(expected_user.xmr_address, actual_user.xmr_address);
|
assert_eq!(expected_user.xmr_address, actual_user.xmr_address);
|
||||||
|
|
Loading…
Reference in a new issue