mostro_client/util/
events.rs

1use anyhow::Result;
2use mostro_core::prelude::*;
3use nostr_sdk::prelude::*;
4
5use crate::db::User;
6use crate::parser::{parse_dispute_events, parse_dm_events, parse_orders_events};
7use crate::util::messaging::get_admin_keys;
8
9pub const FETCH_EVENTS_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(15);
10const FAKE_SINCE: i64 = 2880;
11
12use super::types::{Event, ListKind};
13
14fn create_fake_timestamp() -> Result<Timestamp> {
15    let fake_since_time = chrono::Utc::now()
16        .checked_sub_signed(chrono::Duration::minutes(FAKE_SINCE))
17        .ok_or(anyhow::anyhow!("Failed to get fake since time"))?
18        .timestamp() as u64;
19    Ok(Timestamp::from(fake_since_time))
20}
21
22fn create_seven_days_filter(letter: Alphabet, value: String, pubkey: PublicKey) -> Result<Filter> {
23    let since_time = chrono::Utc::now()
24        .checked_sub_signed(chrono::Duration::days(7))
25        .ok_or(anyhow::anyhow!("Failed to get since days ago"))?
26        .timestamp() as u64;
27    let timestamp = Timestamp::from(since_time);
28    Ok(Filter::new()
29        .author(pubkey)
30        .limit(50)
31        .since(timestamp)
32        .custom_tag(SingleLetterTag::lowercase(letter), value)
33        .kind(nostr_sdk::Kind::Custom(NOSTR_REPLACEABLE_EVENT_KIND)))
34}
35
36pub fn create_filter(
37    list_kind: ListKind,
38    pubkey: PublicKey,
39    since: Option<&i64>,
40) -> Result<Filter> {
41    match list_kind {
42        ListKind::Orders => create_seven_days_filter(Alphabet::Z, "order".to_string(), pubkey),
43        ListKind::Disputes => create_seven_days_filter(Alphabet::Z, "dispute".to_string(), pubkey),
44        ListKind::DirectMessagesAdmin | ListKind::DirectMessagesUser => {
45            let fake_timestamp = create_fake_timestamp()?;
46            Ok(Filter::new()
47                .kind(nostr_sdk::Kind::GiftWrap)
48                .pubkey(pubkey)
49                .since(fake_timestamp))
50        }
51        ListKind::PrivateDirectMessagesUser => {
52            let since = if let Some(mins) = since {
53                chrono::Utc::now()
54                    .checked_sub_signed(chrono::Duration::minutes(*mins))
55                    .unwrap()
56                    .timestamp()
57            } else {
58                chrono::Utc::now()
59                    .checked_sub_signed(chrono::Duration::minutes(30))
60                    .unwrap()
61                    .timestamp()
62            } as u64;
63            Ok(Filter::new()
64                .kind(nostr_sdk::Kind::PrivateDirectMessage)
65                .pubkey(pubkey)
66                .since(Timestamp::from(since)))
67        }
68    }
69}
70
71#[allow(clippy::too_many_arguments)]
72pub async fn fetch_events_list(
73    list_kind: ListKind,
74    status: Option<Status>,
75    currency: Option<String>,
76    kind: Option<mostro_core::order::Kind>,
77    ctx: &crate::cli::Context,
78    since: Option<&i64>,
79) -> Result<Vec<Event>> {
80    match list_kind {
81        ListKind::Orders => {
82            let filters = create_filter(list_kind, ctx.mostro_pubkey, None)?;
83            let fetched_events = ctx
84                .client
85                .fetch_events(filters, FETCH_EVENTS_TIMEOUT)
86                .await?;
87            let orders = parse_orders_events(fetched_events, currency, status, kind);
88            Ok(orders.into_iter().map(Event::SmallOrder).collect())
89        }
90        ListKind::DirectMessagesAdmin => {
91            // Get admin keys
92            let admin_keys = get_admin_keys(ctx)?;
93            // Create filter
94            let filters = create_filter(list_kind, admin_keys.public_key(), None)?;
95            let fetched_events = ctx
96                .client
97                .fetch_events(filters, FETCH_EVENTS_TIMEOUT)
98                .await?;
99            let direct_messages_mostro = parse_dm_events(fetched_events, admin_keys, since).await;
100            Ok(direct_messages_mostro
101                .into_iter()
102                .map(|(message, timestamp, sender_pubkey)| {
103                    Event::MessageTuple(Box::new((message, timestamp, sender_pubkey)))
104                })
105                .collect())
106        }
107        ListKind::PrivateDirectMessagesUser => {
108            let mut direct_messages: Vec<(Message, u64, PublicKey)> = Vec::new();
109            for index in 1..=ctx.trade_index {
110                let trade_key = User::get_trade_keys(&ctx.pool, index).await?;
111                let filter = create_filter(
112                    ListKind::PrivateDirectMessagesUser,
113                    trade_key.public_key(),
114                    None,
115                )?;
116                let fetched_user_messages = ctx
117                    .client
118                    .fetch_events(filter, FETCH_EVENTS_TIMEOUT)
119                    .await?;
120                let direct_messages_for_trade_key =
121                    parse_dm_events(fetched_user_messages, &trade_key, since).await;
122                // Extend the direct messages
123                direct_messages.extend(direct_messages_for_trade_key);
124            }
125            Ok(direct_messages
126                .into_iter()
127                .map(|t| Event::MessageTuple(Box::new(t)))
128                .collect())
129        }
130        ListKind::DirectMessagesUser => {
131            let mut direct_messages: Vec<(Message, u64, PublicKey)> = Vec::new();
132            for index in 1..=ctx.trade_index {
133                let trade_key = User::get_trade_keys(&ctx.pool, index).await?;
134                let filter =
135                    create_filter(ListKind::DirectMessagesUser, trade_key.public_key(), None)?;
136                let fetched_user_messages = ctx
137                    .client
138                    .fetch_events(filter, FETCH_EVENTS_TIMEOUT)
139                    .await?;
140                let direct_messages_for_trade_key =
141                    parse_dm_events(fetched_user_messages, &trade_key, since).await;
142                // Extend the direct messages
143                direct_messages.extend(direct_messages_for_trade_key);
144            }
145            Ok(direct_messages
146                .into_iter()
147                .map(|t| Event::MessageTuple(Box::new(t)))
148                .collect())
149        }
150        ListKind::Disputes => {
151            let filters = create_filter(list_kind, ctx.mostro_pubkey, None)?;
152            let fetched_events = ctx
153                .client
154                .fetch_events(filters, FETCH_EVENTS_TIMEOUT)
155                .await?;
156            let disputes = parse_dispute_events(fetched_events);
157            Ok(disputes.into_iter().map(Event::Dispute).collect())
158        }
159    }
160}