mostro_client/cli/
send_msg.rs1use crate::db::{Order, User};
2use crate::util::send_message_sync;
3use crate::{cli::Commands, db::connect};
4
5use anyhow::Result;
6use mostro_core::prelude::*;
7use nostr_sdk::prelude::*;
8use sqlx::SqlitePool;
9use std::process;
10use uuid::Uuid;
11
12pub async fn execute_send_msg(
13 command: Commands,
14 order_id: Option<Uuid>,
15 identity_keys: Option<&Keys>,
16 mostro_key: PublicKey,
17 client: &Client,
18 text: Option<&str>,
19) -> Result<()> {
20 let requested_action = match command {
22 Commands::FiatSent { .. } => Action::FiatSent,
23 Commands::Release { .. } => Action::Release,
24 Commands::Cancel { .. } => Action::Cancel,
25 Commands::Dispute { .. } => Action::Dispute,
26 Commands::AdmCancel { .. } => Action::AdminCancel,
27 Commands::AdmSettle { .. } => Action::AdminSettle,
28 Commands::AdmAddSolver { .. } => Action::AdminAddSolver,
29 _ => {
30 eprintln!("Not a valid command!");
31 process::exit(0);
32 }
33 };
34
35 println!(
36 "Sending {} command for order {:?} to mostro pubId {}",
37 requested_action, order_id, mostro_key
38 );
39
40 let pool = connect().await?;
41
42 let payload = match requested_action {
44 Action::FiatSent | Action::Release => create_next_trade_payload(&pool, &order_id).await?,
45 _ => text.map(|t| Payload::TextMessage(t.to_string())),
46 };
47 if let Some(Payload::NextTrade(_, trade_index)) = &payload {
49 match User::get(&pool).await {
51 Ok(mut user) => {
52 user.set_last_trade_index(*trade_index as i64);
53 if let Err(e) = user.save(&pool).await {
54 println!("Failed to update user: {}", e);
55 }
56 }
57 Err(e) => println!("Failed to get user: {}", e),
58 }
59 }
60
61 let request_id = Uuid::new_v4().as_u128() as u64;
62
63 let message = Message::new_order(order_id, Some(request_id), None, requested_action, payload);
65 if let Some(order_id) = order_id {
68 handle_order_response(
69 &pool,
70 client,
71 identity_keys,
72 mostro_key,
73 message,
74 order_id,
75 request_id,
76 )
77 .await?;
78 } else {
79 println!("Error: Missing order ID");
80 }
81
82 Ok(())
83}
84
85async fn create_next_trade_payload(
86 pool: &SqlitePool,
87 order_id: &Option<Uuid>,
88) -> Result<Option<Payload>> {
89 if let Some(order_id) = order_id {
90 let order = Order::get_by_id(pool, &order_id.to_string()).await?;
91
92 if let (Some(_), Some(min_amount), Some(max_amount)) =
93 (order.is_mine, order.min_amount, order.max_amount)
94 {
95 if max_amount - order.fiat_amount >= min_amount {
96 let (trade_keys, trade_index) = User::get_next_trade_keys(pool).await?;
97 return Ok(Some(Payload::NextTrade(
98 trade_keys.public_key().to_string(),
99 trade_index.try_into()?,
100 )));
101 }
102 }
103 }
104 Ok(None)
105}
106
107async fn handle_order_response(
108 pool: &SqlitePool,
109 client: &Client,
110 identity_keys: Option<&Keys>,
111 mostro_key: PublicKey,
112 message: Message,
113 order_id: Uuid,
114 request_id: u64,
115) -> Result<()> {
116 let order = Order::get_by_id(pool, &order_id.to_string()).await;
117
118 match order {
119 Ok(order) => {
120 if let Some(trade_keys_str) = order.trade_keys {
121 let trade_keys = Keys::parse(&trade_keys_str)?;
122 let dm = send_message_sync(
123 client,
124 identity_keys,
125 &trade_keys,
126 mostro_key,
127 message,
128 true,
129 false,
130 )
131 .await?;
132 process_order_response(dm, pool, &trade_keys, request_id).await?;
133 } else {
134 println!("Error: Missing trade keys for order {}", order_id);
135 }
136 }
137 Err(e) => {
138 println!("Error: {}", e);
139 }
140 }
141
142 Ok(())
143}
144
145async fn process_order_response(
146 dm: Vec<(Message, u64)>,
147 pool: &SqlitePool,
148 trade_keys: &Keys,
149 request_id: u64,
150) -> Result<()> {
151 for (message, _) in dm {
152 let kind = message.get_inner_message_kind();
153 if let Some(req_id) = kind.request_id {
154 if req_id != request_id {
155 continue;
156 }
157
158 match kind.action {
159 Action::NewOrder => {
160 if let Some(Payload::Order(order)) = kind.payload.as_ref() {
161 Order::new(pool, order.clone(), trade_keys, Some(request_id as i64))
162 .await
163 .map_err(|e| anyhow::anyhow!("Failed to create new order: {}", e))?;
164 return Ok(());
165 }
166 }
167 Action::Canceled => {
168 if let Some(id) = kind.id {
169 if Order::get_by_id(pool, &id.to_string()).await.is_ok() {
171 Order::delete_by_id(pool, &id.to_string())
172 .await
173 .map_err(|e| anyhow::anyhow!("Failed to delete order: {}", e))?;
174 return Ok(());
175 } else {
176 return Err(anyhow::anyhow!("Order not found: {}", id));
177 }
178 }
179 }
180 _ => (),
181 }
182 }
183 }
184
185 Ok(())
186}