1use std::sync::Arc;
2
3use async_trait::async_trait;
4use bsv::remittance::error::RemittanceError;
5use bsv::remittance::types::PeerMessage;
6use bsv::remittance::CommsLayer;
7use bsv::wallet::interfaces::WalletInterface;
8
9use crate::client::MessageBoxClient;
10
11pub struct RemittanceAdapter<W: WalletInterface + Clone + 'static> {
21 inner: Arc<MessageBoxClient<W>>,
22}
23
24impl<W: WalletInterface + Clone + 'static> RemittanceAdapter<W> {
25 pub fn new(client: Arc<MessageBoxClient<W>>) -> Self {
27 Self { inner: client }
28 }
29}
30
31#[async_trait]
32impl<W: WalletInterface + Clone + 'static + Send + Sync> CommsLayer for RemittanceAdapter<W> {
33 async fn send_message(
39 &self,
40 recipient: &str,
41 message_box: &str,
42 body: &str,
43 host_override: Option<&str>,
44 ) -> Result<String, RemittanceError> {
45 match host_override {
46 Some(host) => self
47 .inner
48 .send_message_to_host(host, recipient, message_box, body, false, false, None, None)
49 .await
50 .map_err(|e| RemittanceError::Protocol(e.to_string())),
51 None => self
52 .inner
53 .send_message(recipient, message_box, body, false, false, None, None)
54 .await
55 .map_err(|e| RemittanceError::Protocol(e.to_string())),
56 }
57 }
58
59 async fn list_messages(
65 &self,
66 message_box: &str,
67 _host: Option<&str>,
68 ) -> Result<Vec<PeerMessage>, RemittanceError> {
69 let identity_key = self
71 .inner
72 .get_identity_key()
73 .await
74 .map_err(|e| RemittanceError::Protocol(e.to_string()))?;
75
76 let server_msgs = self
77 .inner
78 .list_messages_lite(message_box, _host)
79 .await
80 .map_err(|e| RemittanceError::Protocol(e.to_string()))?;
81
82 Ok(server_msgs
83 .into_iter()
84 .map(|m| PeerMessage {
85 message_id: m.message_id,
86 sender: m.sender,
87 recipient: identity_key.clone(), message_box: message_box.to_string(), body: m.body,
90 })
91 .collect())
92 }
93
94 async fn acknowledge_message(&self, message_ids: &[String]) -> Result<(), RemittanceError> {
98 self.inner
99 .acknowledge_message(message_ids.to_vec(), None)
100 .await
101 .map_err(|e| RemittanceError::Protocol(e.to_string()))
102 }
103
104 async fn send_live_message(
115 &self,
116 recipient: &str,
117 message_box: &str,
118 body: &str,
119 host_override: Option<&str>,
120 ) -> Result<String, RemittanceError> {
121 self.inner
122 .send_live_message(
123 recipient,
124 message_box,
125 body,
126 false,
127 false,
128 None,
129 host_override,
130 )
131 .await
132 .map(|d| d.message_id().to_string())
133 .map_err(|e| RemittanceError::Protocol(e.to_string()))
134 }
135
136 async fn listen_for_live_messages(
140 &self,
141 message_box: &str,
142 override_host: Option<&str>,
143 on_message: Arc<dyn Fn(PeerMessage) + Send + Sync>,
144 ) -> Result<(), RemittanceError> {
145 self.inner
146 .listen_for_live_messages(message_box, on_message, override_host)
147 .await
148 .map_err(|e| RemittanceError::Protocol(e.to_string()))
149 }
150}
151
152#[cfg(test)]
157mod tests {
158 use super::*;
159 use crate::types::ServerPeerMessage;
160 use bsv::primitives::private_key::PrivateKey;
161 use bsv::wallet::error::WalletError;
162 use bsv::wallet::interfaces::*;
163 use bsv::wallet::proto_wallet::ProtoWallet;
164
165 #[derive(Clone)]
167 struct ArcWallet(Arc<ProtoWallet>);
168
169 impl ArcWallet {
170 fn new() -> Self {
171 let key = PrivateKey::from_random().expect("random key");
172 ArcWallet(Arc::new(ProtoWallet::new(key)))
173 }
174 }
175
176 #[async_trait::async_trait]
177 impl WalletInterface for ArcWallet {
178 async fn create_action(
179 &self,
180 args: CreateActionArgs,
181 orig: Option<&str>,
182 ) -> Result<CreateActionResult, WalletError> {
183 self.0.create_action(args, orig).await
184 }
185 async fn sign_action(
186 &self,
187 args: SignActionArgs,
188 orig: Option<&str>,
189 ) -> Result<SignActionResult, WalletError> {
190 self.0.sign_action(args, orig).await
191 }
192 async fn abort_action(
193 &self,
194 args: AbortActionArgs,
195 orig: Option<&str>,
196 ) -> Result<AbortActionResult, WalletError> {
197 self.0.abort_action(args, orig).await
198 }
199 async fn list_actions(
200 &self,
201 args: ListActionsArgs,
202 orig: Option<&str>,
203 ) -> Result<ListActionsResult, WalletError> {
204 self.0.list_actions(args, orig).await
205 }
206 async fn internalize_action(
207 &self,
208 args: InternalizeActionArgs,
209 orig: Option<&str>,
210 ) -> Result<InternalizeActionResult, WalletError> {
211 self.0.internalize_action(args, orig).await
212 }
213 async fn list_outputs(
214 &self,
215 args: ListOutputsArgs,
216 orig: Option<&str>,
217 ) -> Result<ListOutputsResult, WalletError> {
218 self.0.list_outputs(args, orig).await
219 }
220 async fn relinquish_output(
221 &self,
222 args: RelinquishOutputArgs,
223 orig: Option<&str>,
224 ) -> Result<RelinquishOutputResult, WalletError> {
225 self.0.relinquish_output(args, orig).await
226 }
227 async fn get_public_key(
228 &self,
229 args: GetPublicKeyArgs,
230 orig: Option<&str>,
231 ) -> Result<GetPublicKeyResult, WalletError> {
232 self.0.get_public_key(args, orig).await
233 }
234 async fn reveal_counterparty_key_linkage(
235 &self,
236 args: RevealCounterpartyKeyLinkageArgs,
237 orig: Option<&str>,
238 ) -> Result<RevealCounterpartyKeyLinkageResult, WalletError> {
239 self.0.reveal_counterparty_key_linkage(args, orig).await
240 }
241 async fn reveal_specific_key_linkage(
242 &self,
243 args: RevealSpecificKeyLinkageArgs,
244 orig: Option<&str>,
245 ) -> Result<RevealSpecificKeyLinkageResult, WalletError> {
246 self.0.reveal_specific_key_linkage(args, orig).await
247 }
248 async fn encrypt(
249 &self,
250 args: EncryptArgs,
251 orig: Option<&str>,
252 ) -> Result<EncryptResult, WalletError> {
253 self.0.encrypt(args, orig).await
254 }
255 async fn decrypt(
256 &self,
257 args: DecryptArgs,
258 orig: Option<&str>,
259 ) -> Result<DecryptResult, WalletError> {
260 self.0.decrypt(args, orig).await
261 }
262 async fn create_hmac(
263 &self,
264 args: CreateHmacArgs,
265 orig: Option<&str>,
266 ) -> Result<CreateHmacResult, WalletError> {
267 self.0.create_hmac(args, orig).await
268 }
269 async fn verify_hmac(
270 &self,
271 args: VerifyHmacArgs,
272 orig: Option<&str>,
273 ) -> Result<VerifyHmacResult, WalletError> {
274 self.0.verify_hmac(args, orig).await
275 }
276 async fn create_signature(
277 &self,
278 args: CreateSignatureArgs,
279 orig: Option<&str>,
280 ) -> Result<CreateSignatureResult, WalletError> {
281 self.0.create_signature(args, orig).await
282 }
283 async fn verify_signature(
284 &self,
285 args: VerifySignatureArgs,
286 orig: Option<&str>,
287 ) -> Result<VerifySignatureResult, WalletError> {
288 self.0.verify_signature(args, orig).await
289 }
290 async fn acquire_certificate(
291 &self,
292 args: AcquireCertificateArgs,
293 orig: Option<&str>,
294 ) -> Result<Certificate, WalletError> {
295 self.0.acquire_certificate(args, orig).await
296 }
297 async fn list_certificates(
298 &self,
299 args: ListCertificatesArgs,
300 orig: Option<&str>,
301 ) -> Result<ListCertificatesResult, WalletError> {
302 self.0.list_certificates(args, orig).await
303 }
304 async fn prove_certificate(
305 &self,
306 args: ProveCertificateArgs,
307 orig: Option<&str>,
308 ) -> Result<ProveCertificateResult, WalletError> {
309 self.0.prove_certificate(args, orig).await
310 }
311 async fn relinquish_certificate(
312 &self,
313 args: RelinquishCertificateArgs,
314 orig: Option<&str>,
315 ) -> Result<RelinquishCertificateResult, WalletError> {
316 self.0.relinquish_certificate(args, orig).await
317 }
318 async fn discover_by_identity_key(
319 &self,
320 args: DiscoverByIdentityKeyArgs,
321 orig: Option<&str>,
322 ) -> Result<DiscoverCertificatesResult, WalletError> {
323 self.0.discover_by_identity_key(args, orig).await
324 }
325 async fn discover_by_attributes(
326 &self,
327 args: DiscoverByAttributesArgs,
328 orig: Option<&str>,
329 ) -> Result<DiscoverCertificatesResult, WalletError> {
330 self.0.discover_by_attributes(args, orig).await
331 }
332 async fn is_authenticated(
333 &self,
334 orig: Option<&str>,
335 ) -> Result<AuthenticatedResult, WalletError> {
336 self.0.is_authenticated(orig).await
337 }
338 async fn wait_for_authentication(
339 &self,
340 orig: Option<&str>,
341 ) -> Result<AuthenticatedResult, WalletError> {
342 self.0.wait_for_authentication(orig).await
343 }
344 async fn get_height(&self, orig: Option<&str>) -> Result<GetHeightResult, WalletError> {
345 self.0.get_height(orig).await
346 }
347 async fn get_header_for_height(
348 &self,
349 args: GetHeaderArgs,
350 orig: Option<&str>,
351 ) -> Result<GetHeaderResult, WalletError> {
352 self.0.get_header_for_height(args, orig).await
353 }
354 async fn get_network(&self, orig: Option<&str>) -> Result<GetNetworkResult, WalletError> {
355 self.0.get_network(orig).await
356 }
357 async fn get_version(&self, orig: Option<&str>) -> Result<GetVersionResult, WalletError> {
358 self.0.get_version(orig).await
359 }
360 }
361
362 fn make_client() -> Arc<MessageBoxClient<ArcWallet>> {
363 Arc::new(MessageBoxClient::new(
364 "https://example.com".to_string(),
365 ArcWallet::new(),
366 None,
367 bsv::services::overlay_tools::Network::Mainnet,
368 ))
369 }
370
371 #[test]
373 fn adapter_can_be_constructed() {
374 let client = make_client();
375 let _adapter = RemittanceAdapter::new(client);
376 }
377
378 #[test]
383 fn adapter_is_comms_layer() {
384 let client = make_client();
385 let adapter = Arc::new(RemittanceAdapter::new(client));
386 let _: Arc<dyn CommsLayer + Send + Sync> = adapter;
387 }
388
389 #[test]
394 fn map_server_message_all_five_fields() {
395 let server_msg = ServerPeerMessage {
396 message_id: "msg-001".to_string(),
397 body: "hello body".to_string(),
398 sender: "03senderkey".to_string(),
399 created_at: "2024-01-01T00:00:00Z".to_string(),
400 updated_at: "2024-01-01T00:01:00Z".to_string(),
401 acknowledged: None,
402 authenticated_decrypt: false,
403 };
404 let identity_key = "03myidentitykey".to_string();
405 let message_box = "payment_inbox";
406
407 let peer_msg = PeerMessage {
409 message_id: server_msg.message_id.clone(),
410 sender: server_msg.sender.clone(),
411 recipient: identity_key.clone(),
412 message_box: message_box.to_string(),
413 body: server_msg.body.clone(),
414 };
415
416 assert_eq!(peer_msg.message_id, "msg-001");
417 assert_eq!(peer_msg.sender, "03senderkey");
418 assert_eq!(
419 peer_msg.recipient, "03myidentitykey",
420 "recipient from identity key"
421 );
422 assert_eq!(
423 peer_msg.message_box, "payment_inbox",
424 "message_box from parameter"
425 );
426 assert_eq!(peer_msg.body, "hello body");
427 }
428
429 #[tokio::test]
434 async fn recipient_from_identity_key() {
435 let client = make_client();
436 let identity_key = client.get_identity_key().await.expect("get_identity_key");
437
438 assert!(!identity_key.is_empty(), "identity key must not be empty");
439
440 let peer_msg = PeerMessage {
442 message_id: "x".to_string(),
443 sender: "03other".to_string(),
444 recipient: identity_key.clone(),
445 message_box: "inbox".to_string(),
446 body: "body".to_string(),
447 };
448
449 assert_eq!(peer_msg.recipient, identity_key);
450 assert_ne!(peer_msg.recipient, "", "recipient must not be empty string");
451 }
452
453 #[test]
457 fn acknowledge_message_accepts_slice() {
458 let ids: &[String] = &["id1".to_string(), "id2".to_string()];
462 let converted: Vec<String> = ids.to_vec();
463 assert_eq!(converted, vec!["id1", "id2"]);
464 }
465
466 #[allow(dead_code)]
471 fn send_live_message_compiles(adapter: &RemittanceAdapter<ArcWallet>) {
472 let _fut = adapter.send_live_message("03abc", "inbox", "hello", None);
473 }
474
475 #[allow(dead_code)]
479 fn listen_for_live_messages_compiles(adapter: &RemittanceAdapter<ArcWallet>) {
480 let cb: Arc<dyn Fn(PeerMessage) + Send + Sync> = Arc::new(|_msg| {});
481 let _fut = adapter.listen_for_live_messages("inbox", None, cb);
482 }
483
484 #[allow(dead_code)]
488 fn test_adapter_send_message_with_host_override_compiles(
489 adapter: &RemittanceAdapter<ArcWallet>,
490 ) {
491 let _fut = adapter.send_message("03recipient", "inbox", "body", Some("https://other.host"));
492 }
493
494 #[allow(dead_code)]
496 fn test_adapter_send_message_without_override_compiles(adapter: &RemittanceAdapter<ArcWallet>) {
497 let _fut = adapter.send_message("03recipient", "inbox", "body", None);
498 }
499}