mixin_sdk_rs/
url_scheme.rs

1use std::collections::HashMap;
2use std::fmt;
3use url::Url;
4
5const URL_SCHEME: &str = "mixin";
6
7/// scheme of a user
8///
9/// userId required
10///
11/// https://developers.mixin.one/docs/schema#popups-user-profile
12pub fn scheme_users(user_id: &str) -> String {
13    let mut u = Url::parse(&format!("{}://users", URL_SCHEME)).unwrap();
14    u.set_path(user_id);
15    u.to_string()
16}
17
18/// scheme of a transfer
19///
20/// userId required
21///
22/// https://developers.mixin.one/docs/schema#invoke-transfer-page
23pub fn scheme_transfer(user_id: &str) -> String {
24    let mut u = Url::parse(&format!("{}://transfer", URL_SCHEME)).unwrap();
25    u.set_path(user_id);
26    u.to_string()
27}
28
29/// scheme of a pay
30///
31/// assetId required
32/// recipientId required, receiver's user id
33/// amount require, transfer amount
34/// traceId optional, UUID, prevent duplicate payment
35/// memo optional, transaction memo
36///
37/// https://developers.mixin.one/docs/schema#invoke-payment-page
38pub fn scheme_pay(
39    asset_id: &str,
40    trace_id: &str,
41    recipient_id: &str,
42    memo: &str,
43    amount: &str,
44) -> String {
45    let mut u = Url::parse(&format!("{}://pay", URL_SCHEME)).unwrap();
46    u.query_pairs_mut()
47        .append_pair("asset", asset_id)
48        .append_pair("trace", trace_id)
49        .append_pair("amount", amount)
50        .append_pair("recipient", recipient_id)
51        .append_pair("memo", memo);
52    u.to_string()
53}
54
55/// scheme of a code
56///
57/// code required
58///
59/// https://developers.mixin.one/docs/schema#popus-code-info
60pub fn scheme_codes(code_id: &str) -> String {
61    let mut u = Url::parse(&format!("{}://codes", URL_SCHEME)).unwrap();
62    u.set_path(code_id);
63    u.to_string()
64}
65
66/// scheme of a snapshot
67///
68/// snapshotId required if no traceId
69/// traceId required if no snapshotId
70///
71/// https://developers.mixin.one/docs/schema#transfer-details-interface
72pub fn scheme_snapshots(snapshot_id: &str, trace_id: &str) -> String {
73    let mut u = Url::parse(&format!("{}://snapshots", URL_SCHEME)).unwrap();
74    if !snapshot_id.is_empty() {
75        u.set_path(snapshot_id);
76    }
77    if !trace_id.is_empty() {
78        u.query_pairs_mut().append_pair("trace", trace_id);
79    }
80    u.to_string()
81}
82
83/// scheme of a conversation
84///
85/// userID optional, for user conversation only, if there's not conversation with the user, messenger will create the conversation first
86///
87/// https://developers.mixin.one/docs/schema#open-an-conversation
88pub fn scheme_conversations(conversation_id: &str, user_id: &str) -> String {
89    let mut u = Url::parse(&format!("{}://conversations", URL_SCHEME)).unwrap();
90    if !conversation_id.is_empty() {
91        u.set_path(conversation_id);
92    }
93    if !user_id.is_empty() {
94        u.query_pairs_mut().append_pair("user", user_id);
95    }
96    u.to_string()
97}
98
99/// scheme of an app
100///
101/// appID required, userID of an app
102/// action optional, action about this scheme, default is "open"
103/// params optional, parameters of any name or type can be passed when opening the bot homepage to facilitate the development of features like invitation codes, visitor tracking, etc
104///
105/// https://developers.mixin.one/docs/schema#popups-bot-profile
106pub fn scheme_apps(app_id: &str, action: &str, params: &HashMap<String, String>) -> String {
107    let mut u = Url::parse(&format!("{}://apps", URL_SCHEME)).unwrap();
108    if !app_id.is_empty() {
109        u.set_path(app_id);
110    }
111
112    let mut query = u.query_pairs_mut();
113    if !action.is_empty() {
114        query.append_pair("action", action);
115    } else {
116        query.append_pair("action", "open");
117    }
118
119    for (k, v) in params {
120        query.append_pair(k, v);
121    }
122    // query_pairs_mut() returns a mutable borrow which must be dropped
123    // before `u` can be used again.
124    drop(query);
125
126    u.to_string()
127}
128
129#[derive(Debug)]
130pub enum SendSchemeCategory {
131    Text,
132    Image,
133    Contact,
134    AppCard,
135    Live,
136    Post,
137}
138
139impl fmt::Display for SendSchemeCategory {
140    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
141        match self {
142            SendSchemeCategory::Text => write!(f, "text"),
143            SendSchemeCategory::Image => write!(f, "image"),
144            SendSchemeCategory::Contact => write!(f, "contact"),
145            SendSchemeCategory::AppCard => write!(f, "app_card"),
146            SendSchemeCategory::Live => write!(f, "live"),
147            SendSchemeCategory::Post => write!(f, "post"),
148        }
149    }
150}
151
152/// scheme of a share
153///
154/// category required, category of shared content
155/// data required, shared content
156/// conversationID optional, If you specify conversation and it is the conversation of the user's current session, the confirmation box shown above will appear, the message will be sent after the user clicks the confirmation; if the conversation is not specified or is not the conversation of the current session, an interface where the user chooses which session to share with will show up.
157///
158/// https://developers.mixin.one/docs/schema#sharing
159pub fn scheme_send(category: SendSchemeCategory, data: &[u8], conversation_id: &str) -> String {
160    let mut u = Url::parse(&format!("{}://send", URL_SCHEME)).unwrap();
161    let mut query = u.query_pairs_mut();
162    query.append_pair("category", &category.to_string());
163    if !data.is_empty() {
164        let encoded_data = base64::Engine::encode(&base64::engine::general_purpose::STANDARD, data);
165        query.append_pair("data", &encoded_data);
166    }
167    if !conversation_id.is_empty() {
168        query.append_pair("conversation", conversation_id);
169    }
170    drop(query);
171    u.to_string()
172}
173
174#[cfg(test)]
175mod tests {
176    use super::*;
177
178    #[test]
179    fn test_scheme_users() {
180        let url = scheme_users("123");
181        assert_eq!(url, "mixin://users/123");
182    }
183
184    #[test]
185    fn test_scheme_transfer() {
186        let url = scheme_transfer("123");
187        assert_eq!(url, "mixin://transfer/123");
188    }
189
190    #[test]
191    fn test_scheme_pay() {
192        let url = scheme_pay("123", "456", "789", "memo", "10.5");
193        assert_eq!(
194            url,
195            "mixin://pay?asset=123&trace=456&amount=10.5&recipient=789&memo=memo"
196        );
197    }
198
199    #[test]
200    fn test_scheme_codes() {
201        let url = scheme_codes("123");
202        assert_eq!(url, "mixin://codes/123");
203    }
204
205    #[test]
206    fn test_scheme_conversations() {
207        let url = scheme_conversations("123", "456");
208        assert_eq!(url, "mixin://conversations/123?user=456");
209    }
210
211    #[test]
212    fn test_scheme_apps() {
213        let url = scheme_apps("123", "456", &HashMap::new());
214        assert_eq!(url, "mixin://apps/123?action=456");
215    }
216
217    #[test]
218    fn test_scheme_send() {
219        let url = scheme_send(SendSchemeCategory::Text, &[], "456");
220        assert_eq!(url, "mixin://send?category=text&conversation=456");
221    }
222}