diff --git a/neveko-core/src/db.rs b/neveko-core/src/db.rs index d9f5f96..1567f35 100644 --- a/neveko-core/src/db.rs +++ b/neveko-core/src/db.rs @@ -8,9 +8,9 @@ use lmdb::{ Environment, }; use log::{ - info, debug, error, + info, }; use crate::utils; diff --git a/neveko-core/src/monero.rs b/neveko-core/src/monero.rs index 41e3cd2..d06db4a 100644 --- a/neveko-core/src/monero.rs +++ b/neveko-core/src/monero.rs @@ -429,7 +429,12 @@ pub async fn sign(data: String) -> reqres::XmrRpcSignResponse { /// Performs the xmr rpc 'verify' method pub async fn verify(address: String, data: String, signature: String) -> bool { - info!("executing {} for sig: {} on {}", RpcFields::Verify.value(), &signature, &data); + info!( + "executing {} for sig: {} on {}", + RpcFields::Verify.value(), + &signature, + &data + ); let client = reqwest::Client::new(); let host = get_rpc_host(); let params = reqres::XmrRpcVerifyParams { diff --git a/neveko-core/src/order.rs b/neveko-core/src/order.rs index 5db4361..ded0571 100644 --- a/neveko-core/src/order.rs +++ b/neveko-core/src/order.rs @@ -4,6 +4,7 @@ use crate::{ contact, db, gpg, + i2p, message, models::*, monero, @@ -287,11 +288,43 @@ pub async fn validate_order_for_ship(orid: &String) -> reqres::FinalizeOrderResp } } +/// NASR (neveko auto-ship request) +pub async fn trigger_nasr( + contact: &String, + jwp: &String, + orid: &String, +) -> Result> { + info!("executing trigger_nasr"); + let host = utils::get_i2p_http_proxy(); + let proxy = reqwest::Proxy::http(&host)?; + let client = reqwest::Client::builder().proxy(proxy).build(); + match client? + .get(format!("http://{}/ship/{}/{}", contact, orid, contact)) + .header("proof", jwp) + .send() + .await + { + Ok(response) => { + let res = response.json::().await; + debug!("order retrieve response: {:?}", res); + match res { + Ok(r) => Ok(r), + _ => Ok(Default::default()), + } + } + Err(e) => { + error!("failed to trigger due to: {:?}", e); + Ok(Default::default()) + } + } +} + /// Write encrypted delivery info to lmdb. Once the customer releases the signed /// txset /// -/// This will also attempt to notify the customer to trigger the NASR (neveko auto-ship request). -/// +/// This will also attempt to notify the customer to trigger the NASR (neveko +/// auto-ship request). +/// /// they will have access to this information (tracking number, locker code, /// etc.) pub async fn upload_delivery_info( @@ -300,7 +333,8 @@ pub async fn upload_delivery_info( ) -> reqres::FinalizeOrderResponse { info!("uploading delivery info"); let lookup: Order = order::find(orid); - let e_delivery_info: Vec = gpg::encrypt(lookup.cid, &delivery_info).unwrap_or(Vec::new()); + let e_delivery_info: Vec = + gpg::encrypt(String::from(&lookup.cid), &delivery_info).unwrap_or(Vec::new()); if e_delivery_info.is_empty() { error!("unable to encrypt delivery info"); } @@ -313,11 +347,23 @@ pub async fn upload_delivery_info( m_order.ship_date = chrono::offset::Utc::now().timestamp(); m_order.hash = String::from(&sweep.result.tx_hash_list.remove(0)); m_order.vend_msig_txset = sweep.result.multisig_txset; - // delivery info will be stored encrypted and separate from the rest of the order + // delivery info will be stored encrypted and separate from the rest of the + // order let s = db::Interface::async_open().await; let k = String::from(crate::DELIVERY_INFO_DB_KEY); db::Interface::async_write(&s.env, &s.handle, &k, &hex::encode(&delivery_info)).await; modify(Json(m_order)); + // trigger nasr, this will cause the customer's neveko instance to request the + // txset + let i2p_address = i2p::get_destination(None); + let s = db::Interface::open(); + // get jwp from db + let k = format!("{}-{}", crate::FTS_JWP_DB_KEY, &lookup.cid); + let jwp = db::Interface::read(&s.env, &s.handle, &k); + let nasr_order = trigger_nasr(&i2p_address, &jwp, orid).await; + if nasr_order.is_err() { + return Default::default(); + } FinalizeOrderResponse { delivery_info: delivery_info.to_vec(), orid: String::from(orid), @@ -471,11 +517,7 @@ pub async fn transmit_sor_request( /// A decomposition trigger for the shipping request so that the logic /// /// can be executed from the gui. -pub async fn trigger_ship_request( - contact: &String, - jwp: &String, - orid: &String, -) -> Order { +pub async fn trigger_ship_request(contact: &String, jwp: &String, orid: &String) -> Order { info!("executing trigger_ship_request"); let data = String::from(orid); let wallet_password = @@ -495,16 +537,17 @@ pub async fn trigger_ship_request( } /// Decomposition trigger for the shipping request -pub async fn d_trigger_ship_request( - contact: &String, - jwp: &String, - orid: &String, -) -> Order { +pub async fn d_trigger_ship_request(contact: &String, orid: &String) -> Order { + // ugh, sorry seems we need to get jwp for vendor from fts cache + // get jwp from db + let s = db::Interface::async_open().await; + let k = format!("{}-{}", crate::FTS_JWP_DB_KEY, &contact); + let jwp = db::Interface::async_read(&s.env, &s.handle, &k).await; info!("executing d_trigger_ship_request"); // request shipment if the order status is MultisigComplete - let trigger = trigger_ship_request(contact, jwp, orid).await; + let trigger = trigger_ship_request(contact, &jwp, orid).await; if trigger.status == order::StatusType::MulitsigComplete.value() { - let ship_res = transmit_ship_request(contact, jwp, orid).await; + let ship_res = transmit_ship_request(contact, &jwp, orid).await; if ship_res.is_err() { error!("failure to decompose trigger_ship_request"); return Default::default(); diff --git a/neveko-gui/src/apps/market.rs b/neveko-gui/src/apps/market.rs index 3b135ef..6245152 100644 --- a/neveko-gui/src/apps/market.rs +++ b/neveko-gui/src/apps/market.rs @@ -109,8 +109,8 @@ pub struct MarketApp { _refresh_on_delete_product_rx: Receiver, submit_order_tx: Sender, submit_order_rx: Receiver, - ship_request_tx: Sender, - ship_request_rx: Receiver, + // ship_request_tx: Sender, + // ship_request_rx: Receiver, s_contact: models::Contact, s_order: models::Order, vendor_status: utils::ContactStatus, @@ -132,7 +132,7 @@ impl Default for MarketApp { let (get_vendor_products_tx, get_vendor_products_rx) = std::sync::mpsc::channel(); let (get_vendor_product_tx, get_vendor_product_rx) = std::sync::mpsc::channel(); let (submit_order_tx, submit_order_rx) = std::sync::mpsc::channel(); - let (ship_request_tx, ship_request_rx) = std::sync::mpsc::channel(); + // let (ship_request_tx, ship_request_rx) = std::sync::mpsc::channel(); let (our_prepare_info_tx, our_prepare_info_rx) = std::sync::mpsc::channel(); let (our_make_info_tx, our_make_info_rx) = std::sync::mpsc::channel(); let (order_xmr_address_tx, order_xmr_address_rx) = std::sync::mpsc::channel(); @@ -201,8 +201,8 @@ impl Default for MarketApp { _refresh_on_delete_product_rx, s_contact: Default::default(), s_order: Default::default(), - ship_request_rx, - ship_request_tx, + // ship_request_rx, + // ship_request_tx, submit_order_rx, submit_order_tx, vendor_status: Default::default(), @@ -301,12 +301,12 @@ impl eframe::App for MarketApp { self.is_loading = false; } - if let Ok(shipped) = self.ship_request_rx.try_recv() { - if shipped.status != order::StatusType::Shipped.value() { - log::error!("failure to obtain shipment please contact vendor") - } - self.is_loading = false; - } + // if let Ok(shipped) = self.ship_request_rx.try_recv() { + // if shipped.status != order::StatusType::Shipped.value() { + // log::error!("failure to obtain shipment please contact vendor") + // } + // self.is_loading = false; + // } // Vendor status window //----------------------------------------------------------------------------------- @@ -625,32 +625,49 @@ impl eframe::App for MarketApp { }); } if self.msig.completed_export && !self.msig.completed_shipping_request { + // idk if manual shipping request will be necessary with the new nasr logic, + // let's see ui.horizontal(|ui| { - ui.label("Request Shipping: \t"); - if ui.button("Send").clicked() { - let vendor_prefix = String::from(crate::GUI_OVL_DB_KEY); - let vendor = utils::search_gui_db(vendor_prefix, self.m_order.orid.clone()); - self.is_loading = true; - let jwp = utils::search_gui_db( - String::from(crate::GUI_JWP_DB_KEY), - String::from(&vendor), - ); - shipping_req( - self.ship_request_tx.clone(), - ctx.clone(), - &self.m_order.orid, - &vendor, - &jwp, - ); - } + ui.label( + RichText::new("Delivery Pending") + .small() + .color(ui.visuals().code_bg_color), + ) + .on_hover_text("Please wait for the vendor to upload delivery info."); if ui.button("Check").clicked() { - let order = order::find(&self.m_order.orid); + let order = order::find(&self.m_order.orid.clone()); if order.status == order::StatusType::Shipped.value() { self.msig.completed_shipping_request = true; } } }); } + // ui.horizontal(|ui| { + // ui.label("Request Shipping: \t"); + // if ui.button("Send").clicked() { + // let vendor_prefix = String::from(crate::GUI_OVL_DB_KEY); + // let vendor = utils::search_gui_db(vendor_prefix, + // self.m_order.orid.clone()); self.is_loading = true; + // let jwp = utils::search_gui_db( + // String::from(crate::GUI_JWP_DB_KEY), + // String::from(&vendor), + // ); + // shipping_req( + // self.ship_request_tx.clone(), + // ctx.clone(), + // &self.m_order.orid, + // &vendor, + // &jwp, + // ); + // } + // if ui.button("Check").clicked() { + // let order = order::find(&self.m_order.orid); + // if order.status == order::StatusType::Shipped.value() { + // self.msig.completed_shipping_request = true; + // } + // } + // }); + // } if self.msig.completed_shipping_request && !self.msig.completed_payment_release { ui.horizontal(|ui| { ui.label("Release Payment: \t"); @@ -2141,23 +2158,23 @@ fn send_import_info_req(tx: Sender, ctx: egui::Context, orid: &String, v ctx.request_repaint(); } -fn shipping_req( - tx: Sender, - ctx: egui::Context, - orid: &String, - contact: &String, - jwp: &String, -) { - let ship_orid = String::from(orid); - let vendor_i2p = String::from(contact); - let v_jwp = String::from(jwp); - tokio::spawn(async move { - log::info!("shipping order req: {}", ship_orid); - let order = order::d_trigger_ship_request(&vendor_i2p, &v_jwp, &ship_orid).await; - let _ = tx.send(order); - ctx.request_repaint(); - }); -} +// fn shipping_req( +// tx: Sender, +// ctx: egui::Context, +// orid: &String, +// contact: &String, +// jwp: &String, +// ) { +// let ship_orid = String::from(orid); +// let vendor_i2p = String::from(contact); +// let v_jwp = String::from(jwp); +// tokio::spawn(async move { +// log::info!("shipping order req: {}", ship_orid); +// let order = order::d_trigger_ship_request(&vendor_i2p, &v_jwp, &ship_orid).await; +// let _ = tx.send(order); +// ctx.request_repaint(); +// }); +// } // End Async fn requests fn validate_msig_step( diff --git a/neveko-market/src/controller.rs b/neveko-market/src/controller.rs index 388cb11..5b6584f 100644 --- a/neveko-market/src/controller.rs +++ b/neveko-market/src/controller.rs @@ -102,6 +102,8 @@ pub async fn sign_and_submit_multisig( /// API for uploading delivery info in vendor mode /// +/// Attempts to trigger NASR so that and automate txset draft from vendor. +/// /// Protected: true #[post("/", data = "")] pub async fn upload_delivery_info( diff --git a/src/controller.rs b/src/controller.rs index eb96a80..b89f040 100644 --- a/src/controller.rs +++ b/src/controller.rs @@ -197,6 +197,28 @@ pub async fn request_shipment( Custom(Status::Ok, Json(finalize)) } +/// The vendor should trigger nasr once they have uploaded delivery info. +/// +/// This will automate txset release from the customer +/// +/// orid - `order id of the nasr` +/// +/// vedor - `vendor's .b32.i2p` +/// +/// Protected: true +#[post("/ship//")] +pub async fn trigger_nasr( + orid: String, + vendor: String, + _jwp: proof::PaymentProof, +) -> Custom> { + let order: models::Order = order::d_trigger_ship_request(&orid, &vendor).await; + if order.orid == utils::empty_string() { + return Custom(Status::BadRequest, Json(Default::default())); + } + Custom(Status::Ok, Json(order)) +} + /// Create a dispute (customer) #[post("/create", data = "")] pub async fn create_dispute(