mirror of
https://github.com/creating2morrow/neveko.git
synced 2024-12-22 03:29:22 +00:00
v0.1.0-beta
This commit is contained in:
parent
b94802711c
commit
57e2be6384
30 changed files with 399 additions and 38 deletions
14
Cargo.lock
generated
14
Cargo.lock
generated
|
@ -1932,7 +1932,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "neveko"
|
||||
version = "0.4.8-alpha"
|
||||
version = "0.1.0-beta"
|
||||
dependencies = [
|
||||
"env_logger",
|
||||
"neveko_auth",
|
||||
|
@ -1946,7 +1946,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "neveko_auth"
|
||||
version = "0.4.8-alpha"
|
||||
version = "0.1.0-beta"
|
||||
dependencies = [
|
||||
"env_logger",
|
||||
"log 0.4.19",
|
||||
|
@ -1956,7 +1956,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "neveko_contact"
|
||||
version = "0.4.8-alpha"
|
||||
version = "0.1.0-beta"
|
||||
dependencies = [
|
||||
"env_logger",
|
||||
"log 0.4.19",
|
||||
|
@ -1966,7 +1966,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "neveko_core"
|
||||
version = "0.4.8-alpha"
|
||||
version = "0.1.0-beta"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"clap",
|
||||
|
@ -1993,7 +1993,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "neveko_gui"
|
||||
version = "0.4.8-alpha"
|
||||
version = "0.1.0-beta"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"console_error_panic_hook",
|
||||
|
@ -2017,7 +2017,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "neveko_market"
|
||||
version = "0.4.8-alpha"
|
||||
version = "0.1.0-beta"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"env_logger",
|
||||
|
@ -2028,7 +2028,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "neveko_message"
|
||||
version = "0.4.8-alpha"
|
||||
version = "0.1.0-beta"
|
||||
dependencies = [
|
||||
"env_logger",
|
||||
"log 0.4.19",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "neveko"
|
||||
version = "0.4.8-alpha"
|
||||
version = "0.1.0-beta"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
|
|
@ -41,6 +41,7 @@ NEVidebla-EKOnomia (invisible economy)
|
|||
* just remember to put cli password in the original window, not the log file window
|
||||
* https://stackoverflow.com/questions/6674327/redirect-all-output-to-file-in-bash
|
||||
* gui built with rust [egui](https://docs.rs/egui/latest/egui/)
|
||||
* darknet release server links are located at: http://c2m66oddrzozztxyzjegbdwtgbeiibq5vz2tpchmqamrzcahcfoq.b32.i2p/index.txt
|
||||
|
||||
## Installation Mananger
|
||||
|
||||
|
@ -111,5 +112,8 @@ most of the complex logic stays in neveko-core, exported from [lib.rs](./neveko-
|
|||
|
||||
## Donations
|
||||
|
||||
This is just a hobby project but if anything here is useful donations are much appreciated!
|
||||
No need to send xmr, donating time is fine. Just test code if you can and open issues. Thanks!
|
||||
This is a research project as of v0.1.0-beta but if anything here is useful donations are much appreciated!
|
||||
Features and bug fixes aren't guaranteed by donations but they will supply coffee for devs on
|
||||
sleepless nights!
|
||||
|
||||
87TzQS4g6mN4oAcEhcnEHGCxw9bFwMXR8WHJEEZoCd7tPHgcH3NsiCF5FSWSkKYVa7EYJjuosPZBiNAh9LqHaRSiBUhsAcC
|
||||
|
|
BIN
assets/customer_manage_orders.png
Normal file
BIN
assets/customer_manage_orders.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 88 KiB |
BIN
assets/msig_management.png
Normal file
BIN
assets/msig_management.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 109 KiB |
BIN
assets/neveko-market_main.png
Normal file
BIN
assets/neveko-market_main.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 57 KiB |
BIN
assets/vendor_manage_orders.png
Normal file
BIN
assets/vendor_manage_orders.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 77 KiB |
BIN
assets/view_vendors.png
Normal file
BIN
assets/view_vendors.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 72 KiB |
28
docs/man.md
28
docs/man.md
|
@ -67,4 +67,30 @@
|
|||
|
||||
## Market
|
||||
|
||||
WIP
|
||||
![market main view](../assets/neveko-market_main.png)
|
||||
|
||||
* neveko market allows 3 i2p users to create an order
|
||||
* first you need to have a contact in vendor `enabled` mode
|
||||
* vendors must also have products in stock
|
||||
|
||||
![vendor order management](../assets/vendor_manage_orders.png)
|
||||
|
||||
* here vendors can upload delivery info
|
||||
* all other functionality including payment is automated
|
||||
* funds will need to manually swept from neveko for now
|
||||
|
||||
![view vendors](../assets/view_vendors.png)
|
||||
|
||||
* don't forget to `check status` often
|
||||
* expired jwp will cause errors when orchestrated multisig operations
|
||||
|
||||
![customer order management](../assets/customer_manage_orders.png)
|
||||
|
||||
* customers are responsible for orchestrated multisig information exchange with `MSIG`
|
||||
* orders can also be disputed or cancelled from here
|
||||
|
||||
![create_jwp](../assets/msig_management.png)
|
||||
|
||||
* burden of multisig is on the customer
|
||||
* click the msig step and use `check` to cycle to the next step
|
||||
* upon delivery don't forget to `release txset`
|
||||
|
|
4
neveko-auth/Cargo.lock
generated
4
neveko-auth/Cargo.lock
generated
|
@ -1195,7 +1195,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "neveko_auth"
|
||||
version = "0.4.8-alpha"
|
||||
version = "0.1.0-beta"
|
||||
dependencies = [
|
||||
"env_logger",
|
||||
"log 0.4.17",
|
||||
|
@ -1205,7 +1205,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "neveko_core"
|
||||
version = "0.4.8-alpha"
|
||||
version = "0.1.0-beta"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"clap",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "neveko_auth"
|
||||
version = "0.4.8-alpha"
|
||||
version = "0.1.0-beta"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
|
4
neveko-contact/Cargo.lock
generated
4
neveko-contact/Cargo.lock
generated
|
@ -1195,7 +1195,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "neveko_contact"
|
||||
version = "0.4.8-alpha"
|
||||
version = "0.1.0-beta"
|
||||
dependencies = [
|
||||
"env_logger",
|
||||
"log 0.4.17",
|
||||
|
@ -1205,7 +1205,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "neveko_core"
|
||||
version = "0.4.8-alpha"
|
||||
version = "0.1.0-beta"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"clap",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "neveko_contact"
|
||||
version = "0.4.8-alpha"
|
||||
version = "0.1.0-beta"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
|
2
neveko-core/Cargo.lock
generated
2
neveko-core/Cargo.lock
generated
|
@ -1195,7 +1195,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "neveko_core"
|
||||
version = "0.4.8-alpha"
|
||||
version = "0.1.0-beta"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"clap",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "neveko_core"
|
||||
version = "0.4.8-alpha"
|
||||
version = "0.1.0-beta"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
|
|
@ -148,6 +148,13 @@ pub struct Args {
|
|||
default_value = "false"
|
||||
)]
|
||||
pub clear_fts: bool,
|
||||
/// Remove all disputes from db on app startup
|
||||
#[arg(
|
||||
long,
|
||||
help = "this will clear disputes from the database",
|
||||
default_value = "false"
|
||||
)]
|
||||
pub clear_disputes: bool,
|
||||
/// Manually configure i2p
|
||||
#[arg(
|
||||
long,
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
use std::error::Error;
|
||||
|
||||
use crate::{
|
||||
db,
|
||||
models::*,
|
||||
monero,
|
||||
utils,
|
||||
};
|
||||
use log::{
|
||||
|
@ -24,6 +27,24 @@ pub fn create(d: Json<Dispute>) -> Dispute {
|
|||
let s = db::Interface::open();
|
||||
let k = &d.did;
|
||||
db::Interface::write(&s.env, &s.handle, k, &Dispute::to_db(&new_dispute));
|
||||
// in order to retrieve all orders, write keys to with dl
|
||||
let list_key = crate::DISPUTE_LIST_DB_KEY;
|
||||
let r = db::Interface::read(&s.env, &s.handle, &String::from(list_key));
|
||||
if r == utils::empty_string() {
|
||||
debug!("creating dispute index");
|
||||
}
|
||||
let dispute_list = [String::from(&r), String::from(&f_did)].join(",");
|
||||
debug!(
|
||||
"writing dispute index {} for id: {}",
|
||||
dispute_list, list_key
|
||||
);
|
||||
db::Interface::write(&s.env, &s.handle, &String::from(list_key), &dispute_list);
|
||||
// restart the dispute aut-settle thread
|
||||
let cleared = is_dispute_clear(r);
|
||||
if !cleared {
|
||||
debug!("restarting dispute auto-settle");
|
||||
utils::restart_dispute_auto_settle();
|
||||
}
|
||||
new_dispute
|
||||
}
|
||||
|
||||
|
@ -37,3 +58,183 @@ pub fn find(did: &String) -> Dispute {
|
|||
}
|
||||
Dispute::from_db(String::from(did), r)
|
||||
}
|
||||
|
||||
/// Lookup all disputes
|
||||
pub fn find_all() -> Vec<Dispute> {
|
||||
let d_s = db::Interface::open();
|
||||
let d_list_key = crate::DISPUTE_LIST_DB_KEY;
|
||||
let d_r = db::Interface::read(&d_s.env, &d_s.handle, &String::from(d_list_key));
|
||||
if d_r == utils::empty_string() {
|
||||
error!("dispute index not found");
|
||||
}
|
||||
let d_v_did = d_r.split(",");
|
||||
let d_v: Vec<String> = d_v_did.map(|s| String::from(s)).collect();
|
||||
let mut disputes: Vec<Dispute> = Vec::new();
|
||||
for o in d_v {
|
||||
let dispute: Dispute = find(&o);
|
||||
if dispute.did != utils::empty_string() {
|
||||
disputes.push(dispute);
|
||||
}
|
||||
}
|
||||
disputes
|
||||
}
|
||||
|
||||
/// Dispute deletion
|
||||
pub fn delete(did: &String) {
|
||||
let s = db::Interface::open();
|
||||
let r = db::Interface::read(&s.env, &s.handle, &String::from(did));
|
||||
if r == utils::empty_string() {
|
||||
error!("dispute not found");
|
||||
return Default::default();
|
||||
}
|
||||
db::Interface::delete(&s.env, &s.handle, &String::from(did))
|
||||
}
|
||||
|
||||
/// Triggered on DISPUTE_LAST_CHECK_DB_KEY.
|
||||
///
|
||||
/// If the current UNIX timestamp is less than the
|
||||
///
|
||||
/// creation date of the dispute plus the one week
|
||||
///
|
||||
/// grace period then the dispute is auto-settled.
|
||||
pub async fn settle_dispute() {
|
||||
let tick: std::sync::mpsc::Receiver<()> =
|
||||
schedule_recv::periodic_ms(crate::DISPUTE_CHECK_INTERVAL);
|
||||
loop {
|
||||
debug!("running dispute auto-settle thread");
|
||||
tick.recv().unwrap();
|
||||
let s = db::Interface::open();
|
||||
let list_key = crate::DISPUTE_LIST_DB_KEY;
|
||||
let r = db::Interface::read(&s.env, &s.handle, &String::from(list_key));
|
||||
if r == utils::empty_string() {
|
||||
info!("dispute index not found");
|
||||
}
|
||||
let v_mid = r.split(",");
|
||||
let d_vec: Vec<String> = v_mid.map(|s| String::from(s)).collect();
|
||||
debug!("dispute contents: {:#?}", d_vec);
|
||||
let cleared = is_dispute_clear(r);
|
||||
if cleared {
|
||||
// index was created but cleared
|
||||
info!("terminating dispute auto-settle thread");
|
||||
db::Interface::delete(&s.env, &s.handle, list_key);
|
||||
return;
|
||||
}
|
||||
for d in d_vec {
|
||||
let dispute: Dispute = find(&d);
|
||||
if dispute.did != utils::empty_string() {
|
||||
let now = chrono::offset::Utc::now().timestamp();
|
||||
let settle_date = dispute.created + crate::DISPUTE_AUTO_SETTLE as i64;
|
||||
if settle_date > now {
|
||||
let wallet_name = String::from(dispute.orid);
|
||||
let wallet_password = utils::empty_string();
|
||||
monero::open_wallet(&wallet_name, &wallet_password).await;
|
||||
let signed = monero::sign_multisig(dispute.tx_set).await;
|
||||
let submit = monero::submit_multisig(signed.result.tx_data_hex).await;
|
||||
monero::close_wallet(&wallet_name, &wallet_password).await;
|
||||
if submit.result.tx_hash_list.is_empty() {
|
||||
error!("could not broadcast txset for dispute: {}", &dispute.did);
|
||||
return;
|
||||
}
|
||||
// remove the dispute from the db
|
||||
remove_from_auto_settle(dispute.did);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_dispute_clear(r: String) -> bool {
|
||||
let v_mid = r.split(",");
|
||||
let v: Vec<String> = v_mid.map(|s| String::from(s)).collect();
|
||||
debug!("dispute index contents: {:#?}", v);
|
||||
let limit = v.len() <= 1;
|
||||
if !limit {
|
||||
return v.len() >= 2
|
||||
&& v[v.len() - 1] == utils::empty_string()
|
||||
&& v[0] == utils::empty_string();
|
||||
} else {
|
||||
return limit;
|
||||
}
|
||||
}
|
||||
|
||||
/// clear dispute from index
|
||||
fn remove_from_auto_settle(did: String) {
|
||||
info!("removing id {} from disputes", &did);
|
||||
let s = db::Interface::open();
|
||||
let list_key = crate::DISPUTE_LIST_DB_KEY;
|
||||
let r = db::Interface::read(&s.env, &s.handle, &String::from(list_key));
|
||||
if r == utils::empty_string() {
|
||||
debug!("dispute list index is empty");
|
||||
}
|
||||
let pre_v_fts = r.split(",");
|
||||
let v: Vec<String> = pre_v_fts
|
||||
.map(|s| {
|
||||
if s != &did {
|
||||
String::from(s)
|
||||
} else {
|
||||
utils::empty_string()
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
let dispute_list = v.join(",");
|
||||
debug!(
|
||||
"writing dipsute index {} for id: {}",
|
||||
dispute_list, list_key
|
||||
);
|
||||
db::Interface::write(&s.env, &s.handle, &String::from(list_key), &dispute_list);
|
||||
}
|
||||
|
||||
/// Executes POST /market/dispute/create
|
||||
///
|
||||
/// cancelling the order on the vendor side.
|
||||
///
|
||||
/// Customer needs to verify the response and update their lmdb.
|
||||
///
|
||||
/// see `cancel_order`
|
||||
async fn transmit_dispute_request(
|
||||
contact: &String,
|
||||
jwp: &String,
|
||||
request: &Dispute,
|
||||
) -> Result<Dispute, Box<dyn Error>> {
|
||||
info!("executing transmit_dispute_request");
|
||||
let host = utils::get_i2p_http_proxy();
|
||||
let proxy = reqwest::Proxy::http(&host)?;
|
||||
let client = reqwest::Client::builder().proxy(proxy).build();
|
||||
match client?
|
||||
.post(format!("http://{}/market/dispute/create", contact))
|
||||
.header("proof", jwp)
|
||||
.json(&request)
|
||||
.send()
|
||||
.await
|
||||
{
|
||||
Ok(response) => {
|
||||
let res = response.json::<Dispute>().await;
|
||||
debug!("dispute response: {:?}", res);
|
||||
match res {
|
||||
Ok(r) => Ok(r),
|
||||
_ => Ok(Default::default()),
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
error!("failed to create a dispute due to: {:?}", e);
|
||||
Ok(Default::default())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A decomposition trigger for the dispute request so that the logic
|
||||
///
|
||||
/// can be executed from the gui.
|
||||
pub async fn trigger_dispute_request(contact: &String, dispute: &Dispute) -> Dispute {
|
||||
info!("executing trigger_dispute_request");
|
||||
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;
|
||||
let dispute = transmit_dispute_request(contact, &jwp, dispute).await;
|
||||
// handle a failure to create dispute
|
||||
if dispute.is_err() {
|
||||
error!("failed to create dispute");
|
||||
return Default::default();
|
||||
}
|
||||
dispute.unwrap_or(Default::default())
|
||||
}
|
||||
|
|
|
@ -28,10 +28,12 @@ pub const ORDER_DB_KEY: &str = "o";
|
|||
pub const PRODUCT_DB_KEY: &str = "p";
|
||||
pub const USER_DB_KEY: &str = "u";
|
||||
pub const CONTACT_LIST_DB_KEY: &str = "cl";
|
||||
pub const DISPUTE_LIST_DB_KEY: &str = "dl";
|
||||
pub const MESSAGE_LIST_DB_KEY: &str = "ml";
|
||||
pub const ORDER_LIST_DB_KEY: &str = "ol";
|
||||
pub const PRODUCT_LIST_DB_KEY: &str = "pl";
|
||||
pub const RX_MESSAGE_DB_KEY: &str = "rx";
|
||||
pub const DISPUTE_LAST_CHECK_DB_KEY: &str = "dlc";
|
||||
pub const FTS_DB_KEY: &str = "fts";
|
||||
pub const CUSTOMER_ORDER_LIST_DB_KEY: &str = "olc";
|
||||
pub const MEDIATOR_DB_KEY: &str = "med8";
|
||||
|
@ -68,4 +70,9 @@ pub const I2P_ZERO_RELEASH_HASH: &str =
|
|||
|
||||
pub const LMDB_MAPSIZE: u64 = 1 * 1024 * 1024 * 1024;
|
||||
pub const I2P_CONNECTIVITY_CHECK_INTERVAL: u32 = 600000;
|
||||
pub const FTS_RETRY_INTERVAL: u32 = 60000;
|
||||
/// There is a one week grace period for manual intervention of disputes
|
||||
pub const DISPUTE_AUTO_SETTLE: u32 = 1000 * 60 * 60 * 24 * 7;
|
||||
/// Daily dispute auto-settle check interval
|
||||
pub const DISPUTE_CHECK_INTERVAL: u32 = 1000 * 60 * 60 * 24;
|
||||
// DO NOT EDIT BELOW THIS LINE
|
||||
|
|
|
@ -422,7 +422,7 @@ fn remove_from_fts(mid: String) {
|
|||
///
|
||||
/// failed-to-send message.
|
||||
pub async fn retry_fts() {
|
||||
let tick: std::sync::mpsc::Receiver<()> = schedule_recv::periodic_ms(60000);
|
||||
let tick: std::sync::mpsc::Receiver<()> = schedule_recv::periodic_ms(crate::FTS_RETRY_INTERVAL);
|
||||
loop {
|
||||
debug!("running retry failed-to-send thread");
|
||||
tick.recv().unwrap();
|
||||
|
|
|
@ -238,10 +238,13 @@ pub async fn sign_and_submit_multisig(
|
|||
tx_data_hex: &String,
|
||||
) -> reqres::XmrRpcSubmitMultisigResponse {
|
||||
info!("signing and submitting multisig");
|
||||
let wallet_password = utils::empty_string();
|
||||
monero::open_wallet(&orid, &wallet_password).await;
|
||||
let r_sign: reqres::XmrRpcSignMultisigResponse =
|
||||
monero::sign_multisig(String::from(tx_data_hex)).await;
|
||||
let r_submit: reqres::XmrRpcSubmitMultisigResponse =
|
||||
monero::submit_multisig(r_sign.result.tx_data_hex).await;
|
||||
monero::close_wallet(&orid, &wallet_password).await;
|
||||
if r_submit.result.tx_hash_list.is_empty() {
|
||||
error!("unable to submit payment for order: {}", orid);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ use crate::{
|
|||
args,
|
||||
contact,
|
||||
db,
|
||||
dispute,
|
||||
gpg,
|
||||
i2p,
|
||||
message,
|
||||
|
@ -348,6 +349,16 @@ pub fn order_to_json(o: &reqres::OrderRequest) -> Json<reqres::OrderRequest> {
|
|||
Json(r_order)
|
||||
}
|
||||
|
||||
pub fn dispute_to_json(d: &models::Dispute) -> Json<models::Dispute> {
|
||||
let dispute: models::Dispute = models::Dispute {
|
||||
created: d.created,
|
||||
did: String::from(&d.did),
|
||||
orid: String::from(&d.orid),
|
||||
tx_set: String::from(&d.tx_set),
|
||||
};
|
||||
Json(dispute)
|
||||
}
|
||||
|
||||
/// Instead of putting `String::from("")`
|
||||
pub fn empty_string() -> String {
|
||||
String::from("")
|
||||
|
@ -537,6 +548,9 @@ pub async fn start_up() {
|
|||
if args.clear_fts {
|
||||
clear_fts();
|
||||
}
|
||||
if args.clear_disputes {
|
||||
clear_disputes();
|
||||
}
|
||||
gen_signing_keys();
|
||||
if !is_using_remote_node() {
|
||||
monero::start_daemon();
|
||||
|
@ -565,9 +579,11 @@ pub async fn start_up() {
|
|||
gen_app_gpg().await;
|
||||
gen_app_wallet(&wallet_password).await;
|
||||
start_gui();
|
||||
// start async background tasks here
|
||||
{
|
||||
tokio::spawn(async {
|
||||
message::retry_fts().await;
|
||||
dispute::settle_dispute().await;
|
||||
});
|
||||
}
|
||||
info!("{} - neveko is online", env);
|
||||
|
@ -608,11 +624,25 @@ pub fn restart_retry_fts() {
|
|||
});
|
||||
}
|
||||
|
||||
/// We can restart dispute auto-settle from since it gets terminated when empty
|
||||
pub fn restart_dispute_auto_settle() {
|
||||
tokio::spawn(async move {
|
||||
dispute::settle_dispute().await;
|
||||
});
|
||||
}
|
||||
|
||||
/// Called on app startup if `--clear-fts` flag is passed.
|
||||
fn clear_fts() {
|
||||
info!("clear fts");
|
||||
let s = db::Interface::open();
|
||||
db::Interface::delete(&s.env, &s.handle, "fts");
|
||||
db::Interface::delete(&s.env, &s.handle, crate::FTS_DB_KEY);
|
||||
}
|
||||
|
||||
/// Called on app startup if `--clear-dispute` flag is passed.
|
||||
fn clear_disputes() {
|
||||
info!("clear_disputes");
|
||||
let s = db::Interface::open();
|
||||
db::Interface::delete(&s.env, &s.handle, crate::DISPUTE_LIST_DB_KEY);
|
||||
}
|
||||
|
||||
/// Destroy temp files
|
||||
|
|
4
neveko-gui/Cargo.lock
generated
4
neveko-gui/Cargo.lock
generated
|
@ -2415,7 +2415,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "neveko_core"
|
||||
version = "0.4.8-alpha"
|
||||
version = "0.1.0-beta"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"clap",
|
||||
|
@ -2442,7 +2442,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "neveko_gui"
|
||||
version = "0.4.8-alpha"
|
||||
version = "0.1.0-beta"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"chrono",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "neveko_gui"
|
||||
version = "0.4.8-alpha"
|
||||
version = "0.1.0-beta"
|
||||
authors = ["emilk", "creating2morrow"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
edition = "2021"
|
||||
|
|
|
@ -116,6 +116,8 @@ pub struct MarketApp {
|
|||
submit_txset_rx: Receiver<bool>,
|
||||
cancel_request_tx: Sender<models::Order>,
|
||||
cancel_request_rx: Receiver<models::Order>,
|
||||
dispute_request_tx: Sender<models::Dispute>,
|
||||
dispute_request_rx: Receiver<models::Dispute>,
|
||||
// ship_request_tx: Sender<models::Order>,
|
||||
// ship_request_rx: Receiver<models::Order>,
|
||||
upload_dinfo_tx: Sender<bool>,
|
||||
|
@ -144,6 +146,7 @@ impl Default for MarketApp {
|
|||
let (submit_order_tx, submit_order_rx) = std::sync::mpsc::channel();
|
||||
// let (ship_request_tx, ship_request_rx) = std::sync::mpsc::channel();
|
||||
let (cancel_request_tx, cancel_request_rx) = std::sync::mpsc::channel();
|
||||
let (dispute_request_tx, dispute_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();
|
||||
|
@ -219,6 +222,8 @@ impl Default for MarketApp {
|
|||
s_order: Default::default(),
|
||||
cancel_request_rx,
|
||||
cancel_request_tx,
|
||||
dispute_request_rx,
|
||||
dispute_request_tx,
|
||||
// ship_request_rx,
|
||||
// ship_request_tx,
|
||||
submit_order_rx,
|
||||
|
@ -341,6 +346,14 @@ impl eframe::App for MarketApp {
|
|||
self.is_loading = false;
|
||||
}
|
||||
|
||||
if let Ok(disputed) = self.dispute_request_rx.try_recv() {
|
||||
if disputed.tx_set != utils::empty_string() {
|
||||
log::info!("dispute in progress");
|
||||
}
|
||||
self.is_loading = false;
|
||||
self.is_customer_viewing_orders = false;
|
||||
}
|
||||
|
||||
if let Ok(finalized) = self.submit_txset_rx.try_recv() {
|
||||
if !finalized {
|
||||
log::error!("failure to finalize shipment please contact vendor")
|
||||
|
@ -734,10 +747,6 @@ impl eframe::App for MarketApp {
|
|||
}
|
||||
});
|
||||
}
|
||||
// ui.horizontal(|ui| {
|
||||
// ui.label("Create Dispute: \t\t");
|
||||
// if ui.button("Dispute").clicked() {}
|
||||
// });
|
||||
ui.label("\n");
|
||||
if ui.button("Exit").clicked() {
|
||||
self.is_managing_multisig = false;
|
||||
|
@ -816,6 +825,7 @@ impl eframe::App for MarketApp {
|
|||
.column(Column::auto())
|
||||
.column(Column::auto())
|
||||
.column(Column::auto())
|
||||
.column(Column::auto())
|
||||
.min_scrolled_height(0.0);
|
||||
|
||||
table
|
||||
|
@ -838,6 +848,9 @@ impl eframe::App for MarketApp {
|
|||
header.col(|ui| {
|
||||
ui.strong("");
|
||||
});
|
||||
header.col(|ui| {
|
||||
ui.strong("");
|
||||
});
|
||||
})
|
||||
.body(|mut body| {
|
||||
for o in &self.customer_orders {
|
||||
|
@ -898,6 +911,25 @@ impl eframe::App for MarketApp {
|
|||
}
|
||||
});
|
||||
});
|
||||
row.col(|ui| {
|
||||
ui.style_mut().wrap = Some(false);
|
||||
ui.horizontal(|ui| {
|
||||
if ui.button("Dispute").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;
|
||||
create_dispute_req(
|
||||
&self.m_order.orid.clone(),
|
||||
ctx.clone(),
|
||||
self.dispute_request_tx.clone(),
|
||||
&vendor,
|
||||
)
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -1003,7 +1035,8 @@ impl eframe::App for MarketApp {
|
|||
.labelled_by(delivery_info.id);
|
||||
});
|
||||
if self.new_order.orid != utils::empty_string()
|
||||
&& self.upload_dinfo_str != utils::empty_string() {
|
||||
&& self.upload_dinfo_str != utils::empty_string()
|
||||
{
|
||||
if ui.button("Trigger NASR").clicked() {
|
||||
// upload delivery info
|
||||
let dinfo_str = String::from(&self.upload_dinfo_str);
|
||||
|
@ -2402,3 +2435,53 @@ fn upload_dinfo_req(dinfo: Vec<u8>, orid: String, ctx: egui::Context, tx: Sender
|
|||
ctx.request_repaint();
|
||||
});
|
||||
}
|
||||
|
||||
fn create_dispute_req(
|
||||
orid: &String,
|
||||
ctx: egui::Context,
|
||||
tx: Sender<models::Dispute>,
|
||||
contact: &String,
|
||||
) {
|
||||
let d_orid: String = String::from(orid);
|
||||
let a_contact: String = String::from(contact);
|
||||
tokio::spawn(async move {
|
||||
log::info!("async create_dispute_req");
|
||||
// generate address for refund
|
||||
let wallet_password =
|
||||
std::env::var(neveko_core::MONERO_WALLET_PASSWORD).unwrap_or(String::from("password"));
|
||||
let wallet_name = String::from(neveko_core::APP_NAME);
|
||||
monero::open_wallet(&wallet_name, &wallet_password).await;
|
||||
let address_res = monero::get_address().await;
|
||||
monero::close_wallet(&wallet_name, &wallet_password).await;
|
||||
// generate a txset for the mediator
|
||||
let wallet_password = utils::empty_string();
|
||||
monero::open_wallet(&d_orid, &wallet_password).await;
|
||||
let transfer = monero::sweep_all(String::from(address_res.result.address)).await;
|
||||
monero::close_wallet(&d_orid, &wallet_password).await;
|
||||
if transfer.result.multisig_txset.is_empty() {
|
||||
log::error!("could not create txset");
|
||||
let _ = tx.send(Default::default());
|
||||
ctx.request_repaint();
|
||||
return;
|
||||
}
|
||||
let dispute: models::Dispute = models::Dispute {
|
||||
orid: String::from(&d_orid),
|
||||
tx_set: transfer.result.multisig_txset,
|
||||
..Default::default()
|
||||
};
|
||||
let res = dispute::trigger_dispute_request(&a_contact, &dispute).await;
|
||||
if res.created != 0 {
|
||||
// cancel the order and write the dispute to the db
|
||||
let wallet_password = std::env::var(neveko_core::MONERO_WALLET_PASSWORD)
|
||||
.unwrap_or(String::from("password"));
|
||||
monero::open_wallet(&String::from(neveko_core::APP_NAME), &wallet_password).await;
|
||||
let pre_sign = monero::sign(String::from(&d_orid)).await;
|
||||
monero::close_wallet(&String::from(neveko_core::APP_NAME), &wallet_password).await;
|
||||
order::cancel_order(&d_orid, &pre_sign.result.signature).await;
|
||||
let j_dispute = utils::dispute_to_json(&res);
|
||||
dispute::create(j_dispute);
|
||||
let _ = tx.send(res);
|
||||
ctx.request_repaint();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ fn main() -> Result<(), eframe::Error> {
|
|||
})
|
||||
});
|
||||
eframe::run_native(
|
||||
"neveko-gui-v0.4.8-alpha",
|
||||
"neveko-gui-v0.1.0-beta",
|
||||
options,
|
||||
Box::new(|cc| Box::new(neveko_gui::WrapApp::new(cc))),
|
||||
)
|
||||
|
|
4
neveko-market/Cargo.lock
generated
4
neveko-market/Cargo.lock
generated
|
@ -1244,7 +1244,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "neveko_core"
|
||||
version = "0.4.8-alpha"
|
||||
version = "0.1.0-beta"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"clap",
|
||||
|
@ -1271,7 +1271,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "neveko_market"
|
||||
version = "0.4.8-alpha"
|
||||
version = "0.1.0-beta"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"env_logger",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "neveko_market"
|
||||
version = "0.4.8-alpha"
|
||||
version = "0.1.0-beta"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
|
|
4
neveko-message/Cargo.lock
generated
4
neveko-message/Cargo.lock
generated
|
@ -1195,7 +1195,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "neveko_core"
|
||||
version = "0.4.8-alpha"
|
||||
version = "0.1.0-beta"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"clap",
|
||||
|
@ -1222,7 +1222,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "neveko_message"
|
||||
version = "0.4.8-alpha"
|
||||
version = "0.1.0-beta"
|
||||
dependencies = [
|
||||
"env_logger",
|
||||
"log 0.4.17",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "neveko_message"
|
||||
version = "0.4.8-alpha"
|
||||
version = "0.1.0-beta"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
|
|
@ -258,7 +258,7 @@ pub async fn finalize_order(
|
|||
}
|
||||
|
||||
/// Create a dispute
|
||||
#[post("/create", data = "<dispute>")]
|
||||
#[post("/dispute/create", data = "<dispute>")]
|
||||
pub async fn create_dispute(
|
||||
dispute: Json<models::Dispute>,
|
||||
_jwp: proof::PaymentProof,
|
||||
|
|
Loading…
Reference in a new issue