1use std::collections::HashMap;
4use std::sync::Arc;
5use std::time::Duration;
6use tokio::sync::mpsc;
7
8use crate::events::*;
9use crate::packets::BinaryReqType;
10use crate::parsing::{hex_decode, hex_encode, to_microdegrees};
11use crate::reader::MessageReader;
12use crate::{Error, Result, CHANNEL_NAME_LEN, CHANNEL_SECRET_LEN};
13
14pub const DEFAULT_TIMEOUT: Duration = Duration::from_secs(5);
16
17const CMD_APP_START: u8 = 1;
19const CMD_SEND_TXT_MSG: u8 = 2;
20const CMD_SEND_CHANNEL_TXT_MSG: u8 = 3;
21const CMD_GET_CONTACTS: u8 = 4;
22const CMD_GET_DEVICE_TIME: u8 = 5;
23const CMD_SET_DEVICE_TIME: u8 = 6;
24const CMD_SEND_SELF_ADVERT: u8 = 7;
25const CMD_SET_ADVERT_NAME: u8 = 8;
26const CMD_ADD_UPDATE_CONTACT: u8 = 9;
27const CMD_SYNC_NEXT_MESSAGE: u8 = 10;
28#[allow(dead_code)]
29const CMD_SET_RADIO_PARAMS: u8 = 11;
30const CMD_SET_RADIO_TX_POWER: u8 = 12;
31#[allow(dead_code)]
32const CMD_RESET_PATH: u8 = 13;
33const CMD_SET_ADVERT_LATLON: u8 = 14;
34const CMD_REMOVE_CONTACT: u8 = 15;
35#[allow(dead_code)]
36const CMD_SHARE_CONTACT: u8 = 16;
37const CMD_EXPORT_CONTACT: u8 = 17;
38const CMD_IMPORT_CONTACT: u8 = 18;
39const CMD_REBOOT: u8 = 19;
40const CMD_GET_BATT_AND_STORAGE: u8 = 20;
41#[allow(dead_code)]
42const CMD_SET_TUNING_PARAMS: u8 = 21;
43const CMD_DEVICE_QUERY: u8 = 22;
44const CMD_EXPORT_PRIVATE_KEY: u8 = 23;
45const CMD_IMPORT_PRIVATE_KEY: u8 = 24;
46#[allow(dead_code)]
47const CMD_SEND_RAW_DATA: u8 = 25;
48const CMD_SEND_LOGIN: u8 = 26;
49#[allow(dead_code)]
50const CMD_SEND_STATUS_REQ: u8 = 27;
51#[allow(dead_code)]
52const CMD_HAS_CONNECTION: u8 = 28;
53const CMD_LOGOUT: u8 = 29;
54#[allow(dead_code)]
55const CMD_GET_CONTACT_BY_KEY: u8 = 30;
56const CMD_GET_CHANNEL: u8 = 31;
57const CMD_SET_CHANNEL: u8 = 32;
58const CMD_SIGN_START: u8 = 33;
59const CMD_SIGN_DATA: u8 = 34;
60const CMD_SIGN_FINISH: u8 = 35;
61const CMD_GET_CUSTOM_VARS: u8 = 40;
62const CMD_SET_CUSTOM_VAR: u8 = 41;
63const CMD_SEND_BINARY_REQ: u8 = 50;
64const CMD_SET_FLOOD_SCOPE: u8 = 54;
65
66#[derive(Debug, Clone)]
68pub enum Destination {
69 Bytes(Vec<u8>),
71 Hex(String),
73 Contact(Contact),
75}
76
77impl Destination {
78 pub fn prefix(&self) -> Result<[u8; 6]> {
80 match self {
81 Destination::Bytes(b) => {
82 if b.len() >= 6 {
83 let mut prefix = [0u8; 6];
84 prefix.copy_from_slice(&b[..6]);
85 Ok(prefix)
86 } else {
87 Err(Error::invalid_param("Destination too short"))
88 }
89 }
90 Destination::Hex(s) => {
91 let bytes = hex_decode(s)?;
92 if bytes.len() >= 6 {
93 let mut prefix = [0u8; 6];
94 prefix.copy_from_slice(&bytes[..6]);
95 Ok(prefix)
96 } else {
97 Err(Error::invalid_param("Destination too short"))
98 }
99 }
100 Destination::Contact(c) => Ok(c.prefix()),
101 }
102 }
103
104 pub fn public_key(&self) -> Option<[u8; 32]> {
106 match self {
107 Destination::Bytes(b) if b.len() >= 32 => {
108 let mut key = [0u8; 32];
109 key.copy_from_slice(&b[..32]);
110 Some(key)
111 }
112 Destination::Hex(s) => {
113 let bytes = hex_decode(s).ok()?;
114 if bytes.len() >= 32 {
115 let mut key = [0u8; 32];
116 key.copy_from_slice(&bytes[..32]);
117 Some(key)
118 } else {
119 None
120 }
121 }
122 Destination::Contact(c) => Some(c.public_key),
123 _ => None,
124 }
125 }
126}
127
128impl From<&[u8]> for Destination {
129 fn from(bytes: &[u8]) -> Self {
130 Destination::Bytes(bytes.to_vec())
131 }
132}
133
134impl From<Vec<u8>> for Destination {
135 fn from(bytes: Vec<u8>) -> Self {
136 Destination::Bytes(bytes)
137 }
138}
139
140impl From<&str> for Destination {
141 fn from(s: &str) -> Self {
142 Destination::Hex(s.to_string())
143 }
144}
145
146impl From<String> for Destination {
147 fn from(s: String) -> Self {
148 Destination::Hex(s)
149 }
150}
151
152impl From<Contact> for Destination {
153 fn from(c: Contact) -> Self {
154 Destination::Contact(c)
155 }
156}
157
158impl From<&Contact> for Destination {
159 fn from(c: &Contact) -> Self {
160 Destination::Contact(c.clone())
161 }
162}
163
164pub struct CommandHandler {
166 sender: mpsc::Sender<Vec<u8>>,
168 dispatcher: Arc<EventDispatcher>,
170 reader: Arc<MessageReader>,
172 default_timeout: Duration,
174}
175
176impl CommandHandler {
177 pub fn new(
179 sender: mpsc::Sender<Vec<u8>>,
180 dispatcher: Arc<EventDispatcher>,
181 reader: Arc<MessageReader>,
182 ) -> Self {
183 Self {
184 sender,
185 dispatcher,
186 reader,
187 default_timeout: DEFAULT_TIMEOUT,
188 }
189 }
190
191 pub fn set_default_timeout(&mut self, timeout: Duration) {
193 self.default_timeout = timeout;
194 }
195
196 pub async fn send(
198 &self,
199 data: &[u8],
200 expected_event: Option<EventType>,
201 ) -> Result<MeshCoreEvent> {
202 self.send_with_timeout(data, expected_event, self.default_timeout)
203 .await
204 }
205
206 pub async fn send_with_timeout(
208 &self,
209 data: &[u8],
210 expected_event: Option<EventType>,
211 timeout: Duration,
212 ) -> Result<MeshCoreEvent> {
213 self.sender
215 .send(data.to_vec())
216 .await
217 .map_err(|e| Error::Channel(e.to_string()))?;
218
219 self.wait_for_event(expected_event, HashMap::new(), timeout)
221 .await
222 }
223
224 pub async fn send_multi(
226 &self,
227 data: &[u8],
228 expected_events: &[EventType],
229 timeout: Duration,
230 ) -> Result<MeshCoreEvent> {
231 self.sender
233 .send(data.to_vec())
234 .await
235 .map_err(|e| Error::Channel(e.to_string()))?;
236
237 self.wait_for_any_event(expected_events, timeout).await
239 }
240
241 pub async fn wait_for_event(
243 &self,
244 event_type: Option<EventType>,
245 filters: HashMap<String, String>,
246 timeout: Duration,
247 ) -> Result<MeshCoreEvent> {
248 self.dispatcher
249 .wait_for_event(event_type, filters, timeout)
250 .await
251 .ok_or_else(|| Error::timeout(format!("{:?}", event_type)))
252 }
253
254 pub async fn wait_for_any_event(
256 &self,
257 event_types: &[EventType],
258 timeout: Duration,
259 ) -> Result<MeshCoreEvent> {
260 let mut rx = self.dispatcher.receiver();
261
262 tokio::select! {
263 _ = tokio::time::sleep(timeout) => {
264 Err(Error::timeout("response"))
265 }
266 result = async {
267 loop {
268 match rx.recv().await {
269 Ok(event) => {
270 if event_types.contains(&event.event_type) {
271 return Ok(event);
272 }
273 }
274 Err(_) => return Err(Error::Channel("Receiver closed".to_string())),
275 }
276 }
277 } => result,
278 }
279 }
280
281 pub async fn send_appstart(&self) -> Result<SelfInfo> {
287 let data = [
291 CMD_APP_START,
292 0x00,
293 0x00,
294 0x00,
295 0x00,
296 0x00,
297 0x00,
298 0x00, b'm',
300 b'c',
301 b'c',
302 b'l',
303 b'i', ];
305 let event = self.send(&data, Some(EventType::SelfInfo)).await?;
306
307 match event.payload {
308 EventPayload::SelfInfo(info) => Ok(info),
309 _ => Err(Error::protocol("Unexpected response to APPSTART")),
310 }
311 }
312
313 pub async fn send_device_query(&self) -> Result<DeviceInfoData> {
317 let data = [CMD_DEVICE_QUERY, 8];
319 let event = self.send(&data, Some(EventType::DeviceInfo)).await?;
320
321 match event.payload {
322 EventPayload::DeviceInfo(info) => Ok(info),
323 _ => Err(Error::protocol("Unexpected response to device query")),
324 }
325 }
326
327 pub async fn get_bat(&self) -> Result<BatteryInfo> {
331 let data = [CMD_GET_BATT_AND_STORAGE];
332 let event = self.send(&data, Some(EventType::Battery)).await?;
333
334 match event.payload {
335 EventPayload::Battery(info) => Ok(info),
336 _ => Err(Error::protocol("Unexpected response to battery query")),
337 }
338 }
339
340 pub async fn get_time(&self) -> Result<u32> {
344 let data = [CMD_GET_DEVICE_TIME];
345 let event = self.send(&data, Some(EventType::CurrentTime)).await?;
346
347 match event.payload {
348 EventPayload::Time(t) => Ok(t),
349 _ => Err(Error::protocol("Unexpected response to time query")),
350 }
351 }
352
353 pub async fn set_time(&self, timestamp: u32) -> Result<MeshCoreEvent> {
357 let mut data = vec![CMD_SET_DEVICE_TIME];
358 data.extend_from_slice(×tamp.to_le_bytes());
359 self.send(&data, Some(EventType::Ok)).await
360 }
361
362 pub async fn set_name(&self, name: &str) -> Result<MeshCoreEvent> {
366 let mut data = vec![CMD_SET_ADVERT_NAME];
367 data.extend_from_slice(name.as_bytes());
368 self.send(&data, Some(EventType::Ok)).await
369 }
370
371 pub async fn set_coords(&self, lat: f64, lon: f64) -> Result<MeshCoreEvent> {
375 let lat_micro = to_microdegrees(lat);
376 let lon_micro = to_microdegrees(lon);
377
378 let mut data = vec![CMD_SET_ADVERT_LATLON];
379 data.extend_from_slice(&lat_micro.to_le_bytes());
380 data.extend_from_slice(&lon_micro.to_le_bytes());
381 self.send(&data, Some(EventType::Ok)).await
383 }
384
385 pub async fn set_tx_power(&self, power: u8) -> Result<MeshCoreEvent> {
389 let data = [CMD_SET_RADIO_TX_POWER, power];
390 self.send(&data, Some(EventType::Ok)).await
391 }
392
393 pub async fn send_advert(&self, flood: bool) -> Result<MeshCoreEvent> {
397 let data = if flood {
398 vec![CMD_SEND_SELF_ADVERT, 0x01]
399 } else {
400 vec![CMD_SEND_SELF_ADVERT]
401 };
402 self.send(&data, Some(EventType::Ok)).await
403 }
404
405 pub async fn reboot(&self) -> Result<()> {
409 let data = [CMD_REBOOT, b'r', b'e', b'b', b'o', b'o', b't'];
410 self.sender
411 .send(data.to_vec())
412 .await
413 .map_err(|e| Error::Channel(e.to_string()))
414 }
415
416 pub async fn get_custom_vars(&self) -> Result<HashMap<String, String>> {
420 let data = [CMD_GET_CUSTOM_VARS];
421 let event = self.send(&data, Some(EventType::CustomVars)).await?;
422
423 match event.payload {
424 EventPayload::CustomVars(vars) => Ok(vars),
425 _ => Err(Error::protocol("Unexpected response to custom vars query")),
426 }
427 }
428
429 pub async fn set_custom_var(&self, key: &str, value: &str) -> Result<()> {
433 let mut data = vec![CMD_SET_CUSTOM_VAR];
434 data.extend_from_slice(key.as_bytes());
435 data.push(b'=');
436 data.extend_from_slice(value.as_bytes());
437 self.send(&data, Some(EventType::Ok)).await?;
438 Ok(())
439 }
440
441 pub async fn get_channel(&self, channel_idx: u8) -> Result<ChannelInfoData> {
445 let data = [CMD_GET_CHANNEL, channel_idx];
446 let event = self.send(&data, Some(EventType::ChannelInfo)).await?;
447
448 match event.payload {
449 EventPayload::ChannelInfo(info) => Ok(info),
450 _ => Err(Error::protocol("Unexpected response to channel query")),
451 }
452 }
453
454 pub async fn set_channel(
459 &self,
460 channel_idx: u8,
461 name: &str,
462 secret: &[u8; CHANNEL_SECRET_LEN],
463 ) -> Result<()> {
464 let mut data = vec![CMD_SET_CHANNEL, channel_idx];
465 let mut name_bytes = [0u8; CHANNEL_NAME_LEN];
467 let name_len = name.len().min(CHANNEL_NAME_LEN - 1);
469 name_bytes[..name_len].copy_from_slice(&name.as_bytes()[..name_len]);
470 data.extend_from_slice(&name_bytes);
472 data.extend_from_slice(secret);
473 self.send(&data, Some(EventType::Ok)).await?;
474 Ok(())
475 }
476
477 pub async fn set_flood_scope(&self, scope: Option<&str>) -> Result<()> {
482 let mut data = vec![CMD_SET_FLOOD_SCOPE, 0];
483 if let Some(scope) = scope {
484 data.extend_from_slice(scope.as_bytes());
485 data.resize(18, 0u8);
486 }
487 self.send(&data, Some(EventType::Ok)).await?;
488 Ok(())
489 }
490
491 pub async fn export_private_key(&self) -> Result<[u8; 64]> {
495 let data = [CMD_EXPORT_PRIVATE_KEY];
496 let event = self
497 .send_multi(
498 &data,
499 &[EventType::PrivateKey, EventType::Disabled],
500 self.default_timeout,
501 )
502 .await?;
503
504 match event.payload {
505 EventPayload::PrivateKey(key) => Ok(key),
506 EventPayload::String(msg) => Err(Error::Disabled(msg)),
507 _ => Err(Error::protocol("Unexpected response to export private key")),
508 }
509 }
510
511 pub async fn import_private_key(&self, key: &[u8; 64]) -> Result<()> {
515 let mut data = vec![CMD_IMPORT_PRIVATE_KEY];
516 data.extend_from_slice(key);
517 self.send(&data, Some(EventType::Ok)).await?;
518 Ok(())
519 }
520
521 pub async fn get_contacts(&self, last_modification_timestamp: u32) -> Result<Vec<Contact>> {
525 self.get_contacts_with_timeout(last_modification_timestamp, self.default_timeout)
526 .await
527 }
528
529 pub async fn get_contacts_with_timeout(
533 &self,
534 last_modification_timestamp: u32,
535 timeout: Duration,
536 ) -> Result<Vec<Contact>> {
537 let mut data = vec![CMD_GET_CONTACTS];
538 data.extend_from_slice(&last_modification_timestamp.to_le_bytes());
539 let event = self
540 .send_with_timeout(&data, Some(EventType::Contacts), timeout)
541 .await?;
542
543 match event.payload {
544 EventPayload::Contacts(contacts) => Ok(contacts),
545 _ => Err(Error::protocol("Unexpected response to get contacts")),
546 }
547 }
548
549 pub async fn add_contact(&self, contact: &Contact) -> Result<()> {
553 let mut data = vec![CMD_ADD_UPDATE_CONTACT];
554 data.extend_from_slice(&contact.public_key);
555 data.push(contact.contact_type);
556 data.push(contact.flags);
557 data.push(contact.path_len as u8);
558
559 let mut path = [0u8; 64];
561 let path_len = contact.out_path.len().min(64);
562 path[..path_len].copy_from_slice(&contact.out_path[..path_len]);
563 data.extend_from_slice(&path);
564
565 let mut name = [0u8; 32];
567 let name_len = contact.adv_name.len().min(32);
568 name[..name_len].copy_from_slice(&contact.adv_name.as_bytes()[..name_len]);
569 data.extend_from_slice(&name);
570
571 data.extend_from_slice(&contact.last_advert.to_le_bytes());
572 data.extend_from_slice(&contact.adv_lat.to_le_bytes());
573 data.extend_from_slice(&contact.adv_lon.to_le_bytes());
574
575 self.send(&data, Some(EventType::Ok)).await?;
576 Ok(())
577 }
578
579 pub async fn remove_contact(&self, key: impl Into<Destination>) -> Result<()> {
583 let dest: Destination = key.into();
584 let prefix = dest.prefix()?;
585
586 let mut data = vec![CMD_REMOVE_CONTACT];
587 data.extend_from_slice(&prefix);
588 self.send(&data, Some(EventType::Ok)).await?;
589 Ok(())
590 }
591
592 pub async fn export_contact(&self, key: Option<impl Into<Destination>>) -> Result<String> {
596 let data = if let Some(k) = key {
597 let dest: Destination = k.into();
598 let prefix = dest.prefix()?;
599 let mut d = vec![CMD_EXPORT_CONTACT];
600 d.extend_from_slice(&prefix);
601 d
602 } else {
603 vec![CMD_EXPORT_CONTACT]
604 };
605
606 let event = self.send(&data, Some(EventType::ContactUri)).await?;
607
608 match event.payload {
609 EventPayload::String(uri) => Ok(uri),
610 _ => Err(Error::protocol("Unexpected response to export contact")),
611 }
612 }
613
614 pub async fn import_contact(&self, card_data: &[u8]) -> Result<()> {
618 let mut data = vec![CMD_IMPORT_CONTACT];
619 data.extend_from_slice(card_data);
620 self.send(&data, Some(EventType::Ok)).await?;
621 Ok(())
622 }
623
624 pub async fn get_msg(&self) -> Result<Option<MeshCoreEvent>> {
635 self.get_msg_with_timeout(self.default_timeout).await
636 }
637
638 pub async fn get_msg_with_timeout(&self, timeout: Duration) -> Result<Option<MeshCoreEvent>> {
642 let data = [CMD_SYNC_NEXT_MESSAGE];
643 let event = self
644 .send_multi(
645 &data,
646 &[
647 EventType::ContactMsgRecv,
648 EventType::ChannelMsgRecv,
649 EventType::NoMoreMessages,
650 EventType::Error,
651 ],
652 timeout,
653 )
654 .await?;
655
656 match event.event_type {
657 EventType::ContactMsgRecv | EventType::ChannelMsgRecv => Ok(Some(event)),
658 EventType::NoMoreMessages => Ok(None),
659 EventType::Error => match event.payload {
660 EventPayload::String(msg) => Err(Error::device(msg)),
661 _ => Err(Error::device("Unknown error")),
662 },
663 _ => Err(Error::protocol("Unexpected event type")),
664 }
665 }
666
667 pub async fn send_msg(
671 &self,
672 dest: impl Into<Destination>,
673 msg: &str,
674 timestamp: Option<u32>,
675 ) -> Result<MsgSentInfo> {
676 let dest: Destination = dest.into();
677 let prefix = dest.prefix()?;
678 let ts = timestamp.unwrap_or_else(|| {
679 std::time::SystemTime::now()
680 .duration_since(std::time::UNIX_EPOCH)
681 .unwrap()
682 .as_secs() as u32
683 });
684
685 let mut data = vec![CMD_SEND_TXT_MSG, 0x00, 0x00]; data.extend_from_slice(&ts.to_le_bytes());
688 data.extend_from_slice(&prefix);
689 data.extend_from_slice(msg.as_bytes());
690
691 let event = self
692 .send_with_timeout(&data, Some(EventType::MsgSent), Duration::from_secs(10))
693 .await?;
694
695 if event.event_type == EventType::Error {
696 return match event.payload {
697 EventPayload::String(error_message) => Err(Error::protocol(error_message)),
698 _ => Err(Error::protocol("Unexpected response to send_msg")),
699 };
700 }
701
702 match event.payload {
703 EventPayload::MsgSent(info) => Ok(info),
704 _ => Err(Error::protocol("Unexpected response to send_msg")),
705 }
706 }
707
708 pub async fn send_channel_msg(
712 &self,
713 channel: u8,
714 msg: &str,
715 timestamp: Option<u32>,
716 ) -> Result<()> {
717 let ts = timestamp.unwrap_or_else(|| {
718 std::time::SystemTime::now()
719 .duration_since(std::time::UNIX_EPOCH)
720 .unwrap()
721 .as_secs() as u32
722 });
723
724 let mut data = vec![CMD_SEND_CHANNEL_TXT_MSG, 0x00, channel];
726 data.extend_from_slice(&ts.to_le_bytes());
727 data.extend_from_slice(msg.as_bytes());
728
729 let _ = self.send(&data, Some(EventType::Ok)).await?;
730
731 Ok(())
732 }
733
734 pub async fn send_login(
738 &self,
739 dest: impl Into<Destination>,
740 password: &str,
741 ) -> Result<MsgSentInfo> {
742 let dest: Destination = dest.into();
743 let pubkey = dest
744 .public_key()
745 .ok_or_else(|| Error::invalid_param("Login requires full 32-byte public key"))?;
746
747 let mut data = vec![CMD_SEND_LOGIN];
748 data.extend_from_slice(&pubkey);
749 data.extend_from_slice(password.as_bytes());
750
751 let event = self.send(&data, Some(EventType::MsgSent)).await?;
752
753 match event.payload {
754 EventPayload::MsgSent(info) => Ok(info),
755 _ => Err(Error::protocol("Unexpected response to send_login")),
756 }
757 }
758
759 pub async fn send_logout(&self, dest: impl Into<Destination>) -> Result<()> {
763 let dest: Destination = dest.into();
764 let pubkey = dest
765 .public_key()
766 .ok_or_else(|| Error::invalid_param("Logout requires full 32-byte public key"))?;
767
768 let mut data = vec![CMD_LOGOUT];
769 data.extend_from_slice(&pubkey);
770
771 self.send(&data, Some(EventType::Ok)).await?;
772 Ok(())
773 }
774
775 pub async fn send_binary_req(
781 &self,
782 dest: impl Into<Destination>,
783 req_type: BinaryReqType,
784 ) -> Result<MsgSentInfo> {
785 let dest: Destination = dest.into();
786 let pubkey = dest.public_key().ok_or_else(|| {
787 Error::invalid_param("Binary request requires full 32-byte public key")
788 })?;
789
790 let mut data = vec![CMD_SEND_BINARY_REQ];
791 data.push(req_type as u8);
792 data.extend_from_slice(&pubkey);
793
794 let event = self.send(&data, Some(EventType::MsgSent)).await?;
795
796 match event.payload {
797 EventPayload::MsgSent(info) => {
798 self.reader
800 .register_binary_request(
801 &info.expected_ack,
802 req_type,
803 pubkey.to_vec(),
804 Duration::from_millis(info.suggested_timeout as u64),
805 HashMap::new(),
806 false,
807 )
808 .await;
809 Ok(info)
810 }
811 _ => Err(Error::protocol("Unexpected response to binary request")),
812 }
813 }
814
815 pub async fn request_status(&self, dest: impl Into<Destination>) -> Result<StatusData> {
817 self.request_status_with_timeout(dest, self.default_timeout)
818 .await
819 }
820
821 pub async fn request_status_with_timeout(
823 &self,
824 dest: impl Into<Destination>,
825 timeout: Duration,
826 ) -> Result<StatusData> {
827 let sent = self.send_binary_req(dest, BinaryReqType::Status).await?;
828
829 let mut filters = HashMap::new();
830 filters.insert("tag".to_string(), hex_encode(&sent.expected_ack));
831
832 let event = self
833 .wait_for_event(Some(EventType::StatusResponse), filters, timeout)
834 .await?;
835
836 match event.payload {
837 EventPayload::Status(status) => Ok(status),
838 _ => Err(Error::protocol("Unexpected response to status request")),
839 }
840 }
841
842 pub async fn request_telemetry(&self, dest: impl Into<Destination>) -> Result<Vec<u8>> {
844 self.request_telemetry_with_timeout(dest, self.default_timeout)
845 .await
846 }
847
848 pub async fn request_telemetry_with_timeout(
850 &self,
851 dest: impl Into<Destination>,
852 timeout: Duration,
853 ) -> Result<Vec<u8>> {
854 let sent = self.send_binary_req(dest, BinaryReqType::Telemetry).await?;
855
856 let mut filters = HashMap::new();
857 filters.insert("tag".to_string(), hex_encode(&sent.expected_ack));
858
859 let event = self
860 .wait_for_event(Some(EventType::TelemetryResponse), filters, timeout)
861 .await?;
862
863 match event.payload {
864 EventPayload::Telemetry(data) => Ok(data),
865 _ => Err(Error::protocol("Unexpected response to telemetry request")),
866 }
867 }
868
869 pub async fn request_acl(&self, dest: impl Into<Destination>) -> Result<Vec<AclEntry>> {
871 self.request_acl_with_timeout(dest, self.default_timeout)
872 .await
873 }
874
875 pub async fn request_acl_with_timeout(
877 &self,
878 dest: impl Into<Destination>,
879 timeout: Duration,
880 ) -> Result<Vec<AclEntry>> {
881 let sent = self.send_binary_req(dest, BinaryReqType::Acl).await?;
882
883 let mut filters = HashMap::new();
884 filters.insert("tag".to_string(), hex_encode(&sent.expected_ack));
885
886 let event = self
887 .wait_for_event(Some(EventType::AclResponse), filters, timeout)
888 .await?;
889
890 match event.payload {
891 EventPayload::Acl(entries) => Ok(entries),
892 _ => Err(Error::protocol("Unexpected response to ACL request")),
893 }
894 }
895
896 pub async fn request_neighbours(
898 &self,
899 dest: impl Into<Destination>,
900 count: u16,
901 offset: u16,
902 ) -> Result<NeighboursData> {
903 self.request_neighbours_with_timeout(dest, count, offset, self.default_timeout)
904 .await
905 }
906
907 pub async fn request_neighbours_with_timeout(
911 &self,
912 dest: impl Into<Destination>,
913 count: u16,
914 offset: u16,
915 timeout: Duration,
916 ) -> Result<NeighboursData> {
917 let dest: Destination = dest.into();
918 let pubkey = dest.public_key().ok_or_else(|| {
919 Error::invalid_param("Neighbours request requires full 32-byte public key")
920 })?;
921
922 let mut data = vec![CMD_SEND_BINARY_REQ];
923 data.push(BinaryReqType::Neighbours as u8);
924 data.extend_from_slice(&pubkey);
925 data.extend_from_slice(&count.to_le_bytes());
926 data.extend_from_slice(&offset.to_le_bytes());
927
928 let event = self.send(&data, Some(EventType::MsgSent)).await?;
929 let sent = match event.payload {
930 EventPayload::MsgSent(info) => info,
931 _ => return Err(Error::protocol("Unexpected response to neighbours request")),
932 };
933
934 self.reader
936 .register_binary_request(
937 &sent.expected_ack,
938 BinaryReqType::Neighbours,
939 pubkey.to_vec(),
940 timeout,
941 HashMap::new(),
942 false,
943 )
944 .await;
945
946 let mut filters = HashMap::new();
947 filters.insert("tag".to_string(), hex_encode(&sent.expected_ack));
948
949 let event = self
950 .wait_for_event(Some(EventType::NeighboursResponse), filters, timeout)
951 .await?;
952
953 match event.payload {
954 EventPayload::Neighbours(data) => Ok(data),
955 _ => Err(Error::protocol("Unexpected response to neighbours request")),
956 }
957 }
958
959 pub async fn sign_start(&self) -> Result<u32> {
965 let data = [CMD_SIGN_START];
966 let event = self.send(&data, Some(EventType::SignStart)).await?;
967
968 match event.payload {
969 EventPayload::SignStart { max_length } => Ok(max_length),
970 _ => Err(Error::protocol("Unexpected response to sign_start")),
971 }
972 }
973
974 pub async fn sign_data(&self, chunk: &[u8]) -> Result<()> {
978 let mut data = vec![CMD_SIGN_DATA];
979 data.extend_from_slice(chunk);
980 self.send(&data, Some(EventType::Ok)).await?;
981 Ok(())
982 }
983
984 pub async fn sign_finish(&self, timeout: Duration) -> Result<Vec<u8>> {
988 let data = [CMD_SIGN_FINISH];
989 let event = self
990 .send_with_timeout(&data, Some(EventType::Signature), timeout)
991 .await?;
992
993 match event.payload {
994 EventPayload::Signature(sig) => Ok(sig),
995 _ => Err(Error::protocol("Unexpected response to sign_finish")),
996 }
997 }
998
999 pub async fn sign(&self, data_to_sign: &[u8], chunk_size: usize) -> Result<Vec<u8>> {
1001 let max_length = self.sign_start().await?;
1002
1003 if data_to_sign.len() > max_length as usize {
1004 return Err(Error::invalid_param(format!(
1005 "Data too large: {} > {}",
1006 data_to_sign.len(),
1007 max_length
1008 )));
1009 }
1010
1011 for chunk in data_to_sign.chunks(chunk_size) {
1013 self.sign_data(chunk).await?;
1014 }
1015
1016 let timeout = Duration::from_secs(30);
1018 self.sign_finish(timeout).await
1019 }
1020}
1021
1022#[cfg(test)]
1023mod tests {
1024 use super::*;
1025
1026 #[test]
1029 fn test_destination_from_bytes_slice() {
1030 let bytes: &[u8] = &[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
1031 let dest: Destination = bytes.into();
1032 assert!(matches!(dest, Destination::Bytes(_)));
1033 }
1034
1035 #[test]
1036 fn test_destination_from_vec() {
1037 let bytes = vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06];
1038 let dest: Destination = bytes.into();
1039 assert!(matches!(dest, Destination::Bytes(_)));
1040 }
1041
1042 #[test]
1043 fn test_destination_from_str() {
1044 let dest: Destination = "0102030405060708".into();
1045 assert!(matches!(dest, Destination::Hex(_)));
1046 }
1047
1048 #[test]
1049 fn test_destination_from_string() {
1050 let dest: Destination = String::from("0102030405060708").into();
1051 assert!(matches!(dest, Destination::Hex(_)));
1052 }
1053
1054 #[test]
1055 fn test_destination_from_contact() {
1056 let contact = Contact {
1057 public_key: [0xAA; 32],
1058 contact_type: 1,
1059 flags: 0,
1060 path_len: -1,
1061 out_path: vec![],
1062 adv_name: "Test".to_string(),
1063 last_advert: 0,
1064 adv_lat: 0,
1065 adv_lon: 0,
1066 last_modification_timestamp: 0,
1067 };
1068 let dest: Destination = contact.into();
1069 assert!(matches!(dest, Destination::Contact(_)));
1070 }
1071
1072 #[test]
1073 fn test_destination_from_contact_ref() {
1074 let contact = Contact {
1075 public_key: [0xBB; 32],
1076 contact_type: 1,
1077 flags: 0,
1078 path_len: -1,
1079 out_path: vec![],
1080 adv_name: "Test".to_string(),
1081 last_advert: 0,
1082 adv_lat: 0,
1083 adv_lon: 0,
1084 last_modification_timestamp: 0,
1085 };
1086 let dest: Destination = (&contact).into();
1087 assert!(matches!(dest, Destination::Contact(_)));
1088 }
1089
1090 #[test]
1091 fn test_destination_prefix_from_bytes() {
1092 let bytes = vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
1093 let dest: Destination = bytes.into();
1094 let prefix = dest.prefix().unwrap();
1095 assert_eq!(prefix, [0x01, 0x02, 0x03, 0x04, 0x05, 0x06]);
1096 }
1097
1098 #[test]
1099 fn test_destination_prefix_from_bytes_too_short() {
1100 let bytes = vec![0x01, 0x02, 0x03];
1101 let dest: Destination = bytes.into();
1102 assert!(dest.prefix().is_err());
1103 }
1104
1105 #[test]
1106 fn test_destination_prefix_from_hex() {
1107 let dest: Destination = "010203040506".into();
1108 let prefix = dest.prefix().unwrap();
1109 assert_eq!(prefix, [0x01, 0x02, 0x03, 0x04, 0x05, 0x06]);
1110 }
1111
1112 #[test]
1113 fn test_destination_prefix_from_hex_too_short() {
1114 let dest: Destination = "0102".into();
1115 assert!(dest.prefix().is_err());
1116 }
1117
1118 #[test]
1119 fn test_destination_prefix_from_contact() {
1120 let mut public_key = [0u8; 32];
1121 public_key[0..6].copy_from_slice(&[0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF]);
1122 let contact = Contact {
1123 public_key,
1124 contact_type: 1,
1125 flags: 0,
1126 path_len: -1,
1127 out_path: vec![],
1128 adv_name: "Test".to_string(),
1129 last_advert: 0,
1130 adv_lat: 0,
1131 adv_lon: 0,
1132 last_modification_timestamp: 0,
1133 };
1134 let dest: Destination = contact.into();
1135 let prefix = dest.prefix().unwrap();
1136 assert_eq!(prefix, [0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF]);
1137 }
1138
1139 #[test]
1140 fn test_destination_public_key_from_bytes_32() {
1141 let bytes = vec![0xAA; 32];
1142 let dest: Destination = bytes.into();
1143 let key = dest.public_key().unwrap();
1144 assert_eq!(key, [0xAA; 32]);
1145 }
1146
1147 #[test]
1148 fn test_destination_public_key_from_bytes_short() {
1149 let bytes = vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06];
1150 let dest: Destination = bytes.into();
1151 assert!(dest.public_key().is_none());
1152 }
1153
1154 #[test]
1155 fn test_destination_public_key_from_hex_32() {
1156 let hex = "aa".repeat(32);
1158 let dest: Destination = hex.into();
1159 let key = dest.public_key().unwrap();
1160 assert_eq!(key, [0xAA; 32]);
1161 }
1162
1163 #[test]
1164 fn test_destination_public_key_from_hex_short() {
1165 let dest: Destination = "010203040506".into();
1166 assert!(dest.public_key().is_none());
1167 }
1168
1169 #[test]
1170 fn test_destination_public_key_from_contact() {
1171 let contact = Contact {
1172 public_key: [0xCC; 32],
1173 contact_type: 1,
1174 flags: 0,
1175 path_len: -1,
1176 out_path: vec![],
1177 adv_name: "Test".to_string(),
1178 last_advert: 0,
1179 adv_lat: 0,
1180 adv_lon: 0,
1181 last_modification_timestamp: 0,
1182 };
1183 let dest: Destination = contact.into();
1184 let key = dest.public_key().unwrap();
1185 assert_eq!(key, [0xCC; 32]);
1186 }
1187
1188 #[test]
1189 fn test_destination_clone() {
1190 let dest = Destination::Hex("0102030405060708".to_string());
1191 let cloned = dest.clone();
1192 assert!(matches!(cloned, Destination::Hex(_)));
1193 }
1194
1195 #[test]
1196 fn test_destination_debug() {
1197 let dest = Destination::Bytes(vec![1, 2, 3]);
1198 let debug_str = format!("{:?}", dest);
1199 assert!(debug_str.contains("Bytes"));
1200 }
1201
1202 #[test]
1205 fn test_default_timeout() {
1206 assert_eq!(DEFAULT_TIMEOUT, Duration::from_secs(5));
1207 }
1208
1209 #[test]
1210 fn test_command_constants() {
1211 assert_eq!(CMD_APP_START, 1);
1212 assert_eq!(CMD_SEND_TXT_MSG, 2);
1213 assert_eq!(CMD_SEND_CHANNEL_TXT_MSG, 3);
1214 assert_eq!(CMD_GET_CONTACTS, 4);
1215 assert_eq!(CMD_GET_DEVICE_TIME, 5);
1216 assert_eq!(CMD_SET_DEVICE_TIME, 6);
1217 assert_eq!(CMD_SEND_SELF_ADVERT, 7);
1218 assert_eq!(CMD_SET_ADVERT_NAME, 8);
1219 assert_eq!(CMD_ADD_UPDATE_CONTACT, 9);
1220 assert_eq!(CMD_SYNC_NEXT_MESSAGE, 10);
1221 assert_eq!(CMD_SET_RADIO_TX_POWER, 12);
1222 assert_eq!(CMD_SET_ADVERT_LATLON, 14);
1223 assert_eq!(CMD_REMOVE_CONTACT, 15);
1224 assert_eq!(CMD_EXPORT_CONTACT, 17);
1225 assert_eq!(CMD_IMPORT_CONTACT, 18);
1226 assert_eq!(CMD_REBOOT, 19);
1227 assert_eq!(CMD_GET_BATT_AND_STORAGE, 20);
1228 assert_eq!(CMD_DEVICE_QUERY, 22);
1229 assert_eq!(CMD_EXPORT_PRIVATE_KEY, 23);
1230 assert_eq!(CMD_IMPORT_PRIVATE_KEY, 24);
1231 assert_eq!(CMD_SEND_LOGIN, 26);
1232 assert_eq!(CMD_LOGOUT, 29);
1233 assert_eq!(CMD_GET_CHANNEL, 31);
1234 assert_eq!(CMD_SET_CHANNEL, 32);
1235 assert_eq!(CMD_SIGN_START, 33);
1236 assert_eq!(CMD_SIGN_DATA, 34);
1237 assert_eq!(CMD_SIGN_FINISH, 35);
1238 assert_eq!(CMD_GET_CUSTOM_VARS, 40);
1239 assert_eq!(CMD_SET_CUSTOM_VAR, 41);
1240 assert_eq!(CMD_SEND_BINARY_REQ, 50);
1241 }
1242
1243 fn create_test_handler() -> (
1246 CommandHandler,
1247 mpsc::Receiver<Vec<u8>>,
1248 Arc<EventDispatcher>,
1249 ) {
1250 let (sender, receiver) = mpsc::channel(16);
1251 let dispatcher = Arc::new(EventDispatcher::new());
1252 let reader = Arc::new(MessageReader::new(dispatcher.clone()));
1253 let handler = CommandHandler::new(sender, dispatcher.clone(), reader);
1254 (handler, receiver, dispatcher)
1255 }
1256
1257 #[tokio::test]
1258 async fn test_command_handler_new() {
1259 let (handler, _rx, _dispatcher) = create_test_handler();
1260 assert_eq!(handler.default_timeout, DEFAULT_TIMEOUT);
1261 }
1262
1263 #[tokio::test]
1264 async fn test_command_handler_set_default_timeout() {
1265 let (mut handler, _rx, _dispatcher) = create_test_handler();
1266 handler.set_default_timeout(Duration::from_secs(10));
1267 assert_eq!(handler.default_timeout, Duration::from_secs(10));
1268 }
1269
1270 #[tokio::test]
1271 async fn test_command_handler_send_timeout() {
1272 let (handler, mut rx, _dispatcher) = create_test_handler();
1273
1274 let recv_task = tokio::spawn(async move { rx.recv().await });
1276
1277 let result = handler
1279 .send_with_timeout(&[0x01], Some(EventType::Ok), Duration::from_millis(10))
1280 .await;
1281
1282 assert!(result.is_err());
1283
1284 let sent = recv_task.await.unwrap();
1286 assert_eq!(sent, Some(vec![0x01]));
1287 }
1288
1289 #[tokio::test]
1290 async fn test_command_handler_send_with_response() {
1291 let (handler, mut rx, dispatcher) = create_test_handler();
1292
1293 let dispatcher_clone = dispatcher.clone();
1295 tokio::spawn(async move {
1296 let _sent = rx.recv().await;
1298 dispatcher_clone.emit(MeshCoreEvent::ok()).await;
1300 });
1301
1302 let result = handler
1303 .send_with_timeout(&[0x01], Some(EventType::Ok), Duration::from_millis(100))
1304 .await;
1305
1306 assert!(result.is_ok());
1307 assert_eq!(result.unwrap().event_type, EventType::Ok);
1308 }
1309
1310 #[tokio::test]
1311 async fn test_command_handler_wait_for_event_timeout() {
1312 let (handler, _rx, _dispatcher) = create_test_handler();
1313
1314 let result = handler
1315 .wait_for_event(
1316 Some(EventType::Ok),
1317 HashMap::new(),
1318 Duration::from_millis(10),
1319 )
1320 .await;
1321
1322 assert!(result.is_err());
1323 }
1324
1325 #[tokio::test]
1326 async fn test_command_handler_wait_for_event_success() {
1327 let (handler, _rx, dispatcher) = create_test_handler();
1328
1329 tokio::spawn(async move {
1331 tokio::time::sleep(Duration::from_millis(5)).await;
1332 dispatcher.emit(MeshCoreEvent::ok()).await;
1333 });
1334
1335 let result = handler
1336 .wait_for_event(
1337 Some(EventType::Ok),
1338 HashMap::new(),
1339 Duration::from_millis(100),
1340 )
1341 .await;
1342
1343 assert!(result.is_ok());
1344 }
1345
1346 #[tokio::test]
1347 async fn test_command_handler_wait_for_any_event() {
1348 let (handler, _rx, dispatcher) = create_test_handler();
1349
1350 tokio::spawn(async move {
1352 tokio::time::sleep(Duration::from_millis(5)).await;
1353 dispatcher.emit(MeshCoreEvent::error("test")).await;
1354 });
1355
1356 let result = handler
1357 .wait_for_any_event(
1358 &[EventType::Ok, EventType::Error],
1359 Duration::from_millis(100),
1360 )
1361 .await;
1362
1363 assert!(result.is_ok());
1364 assert_eq!(result.unwrap().event_type, EventType::Error);
1365 }
1366
1367 #[tokio::test]
1368 async fn test_command_handler_wait_for_any_event_timeout() {
1369 let (handler, _rx, _dispatcher) = create_test_handler();
1370
1371 let result = handler
1372 .wait_for_any_event(
1373 &[EventType::Ok, EventType::Error],
1374 Duration::from_millis(10),
1375 )
1376 .await;
1377
1378 assert!(result.is_err());
1379 }
1380
1381 #[tokio::test]
1382 async fn test_command_handler_send_multi() {
1383 let (handler, mut rx, dispatcher) = create_test_handler();
1384
1385 let dispatcher_clone = dispatcher.clone();
1387 tokio::spawn(async move {
1388 let _sent = rx.recv().await;
1389 dispatcher_clone
1390 .emit(MeshCoreEvent::error("device busy"))
1391 .await;
1392 });
1393
1394 let result = handler
1395 .send_multi(
1396 &[0x01],
1397 &[EventType::Ok, EventType::Error],
1398 Duration::from_millis(100),
1399 )
1400 .await;
1401
1402 assert!(result.is_ok());
1403 assert_eq!(result.unwrap().event_type, EventType::Error);
1404 }
1405
1406 #[tokio::test]
1407 async fn test_send_appstart_success() {
1408 let (handler, mut rx, dispatcher) = create_test_handler();
1409
1410 let dispatcher_clone = dispatcher.clone();
1411 tokio::spawn(async move {
1412 let sent = rx.recv().await.unwrap();
1413 assert_eq!(sent[0], CMD_APP_START);
1415 assert_eq!(&sent[8..13], b"mccli");
1416
1417 let info = SelfInfo {
1419 adv_type: 1,
1420 tx_power: 20,
1421 max_tx_power: 30,
1422 public_key: [0; 32],
1423 adv_lat: 0,
1424 adv_lon: 0,
1425 multi_acks: 0,
1426 adv_loc_policy: 0,
1427 telemetry_mode_base: 0,
1428 telemetry_mode_loc: 0,
1429 telemetry_mode_env: 0,
1430 manual_add_contacts: false,
1431 radio_freq: 915000000,
1432 radio_bw: 125000,
1433 sf: 7,
1434 cr: 5,
1435 name: "TestDevice".to_string(),
1436 };
1437 dispatcher_clone
1438 .emit(MeshCoreEvent::new(
1439 EventType::SelfInfo,
1440 EventPayload::SelfInfo(info),
1441 ))
1442 .await;
1443 });
1444
1445 let result = handler.send_appstart().await;
1446 assert!(result.is_ok());
1447 let info = result.unwrap();
1448 assert_eq!(info.name, "TestDevice");
1449 assert_eq!(info.tx_power, 20);
1450 }
1451
1452 #[tokio::test]
1453 async fn test_get_bat_success() {
1454 let (handler, mut rx, dispatcher) = create_test_handler();
1455
1456 let dispatcher_clone = dispatcher.clone();
1457 tokio::spawn(async move {
1458 let sent = rx.recv().await.unwrap();
1459 assert_eq!(sent[0], CMD_GET_BATT_AND_STORAGE);
1460
1461 let info = BatteryInfo {
1462 battery_mv: 4200,
1463 used_kb: Some(512),
1464 total_kb: Some(4096),
1465 };
1466 dispatcher_clone
1467 .emit(MeshCoreEvent::new(
1468 EventType::Battery,
1469 EventPayload::Battery(info),
1470 ))
1471 .await;
1472 });
1473
1474 let result = handler.get_bat().await;
1475 assert!(result.is_ok());
1476 let info = result.unwrap();
1477 assert_eq!(info.battery_mv, 4200);
1478 assert!((info.voltage() - 4.2).abs() < 0.001);
1479 }
1480
1481 #[tokio::test]
1482 async fn test_get_time_success() {
1483 let (handler, mut rx, dispatcher) = create_test_handler();
1484
1485 let dispatcher_clone = dispatcher.clone();
1486 tokio::spawn(async move {
1487 let sent = rx.recv().await.unwrap();
1488 assert_eq!(sent[0], CMD_GET_DEVICE_TIME);
1489
1490 dispatcher_clone
1491 .emit(MeshCoreEvent::new(
1492 EventType::CurrentTime,
1493 EventPayload::Time(1234567890),
1494 ))
1495 .await;
1496 });
1497
1498 let result = handler.get_time().await;
1499 assert!(result.is_ok());
1500 assert_eq!(result.unwrap(), 1234567890);
1501 }
1502
1503 #[tokio::test]
1504 async fn test_set_time_success() {
1505 let (handler, mut rx, dispatcher) = create_test_handler();
1506
1507 let dispatcher_clone = dispatcher.clone();
1508 tokio::spawn(async move {
1509 let sent = rx.recv().await.unwrap();
1510 assert_eq!(sent[0], CMD_SET_DEVICE_TIME);
1511 let ts = u32::from_le_bytes([sent[1], sent[2], sent[3], sent[4]]);
1513 assert_eq!(ts, 1234567890);
1514
1515 dispatcher_clone.emit(MeshCoreEvent::ok()).await;
1516 });
1517
1518 let result = handler.set_time(1234567890).await;
1519 assert!(result.is_ok());
1520 }
1521
1522 #[tokio::test]
1523 async fn test_set_name_success() {
1524 let (handler, mut rx, dispatcher) = create_test_handler();
1525
1526 let dispatcher_clone = dispatcher.clone();
1527 tokio::spawn(async move {
1528 let sent = rx.recv().await.unwrap();
1529 assert_eq!(sent[0], CMD_SET_ADVERT_NAME);
1530 assert_eq!(&sent[1..], b"MyNode");
1531
1532 dispatcher_clone.emit(MeshCoreEvent::ok()).await;
1533 });
1534
1535 let result = handler.set_name("MyNode").await;
1536 assert!(result.is_ok());
1537 }
1538
1539 #[tokio::test]
1540 async fn test_set_coords_success() {
1541 let (handler, mut rx, dispatcher) = create_test_handler();
1542
1543 let dispatcher_clone = dispatcher.clone();
1544 tokio::spawn(async move {
1545 let sent = rx.recv().await.unwrap();
1546 assert_eq!(sent[0], CMD_SET_ADVERT_LATLON);
1547 assert!(sent.len() >= 9);
1549
1550 dispatcher_clone.emit(MeshCoreEvent::ok()).await;
1551 });
1552
1553 let result = handler.set_coords(37.7749, -122.4194).await;
1554 assert!(result.is_ok());
1555 }
1556
1557 #[tokio::test]
1558 async fn test_set_tx_power_success() {
1559 let (handler, mut rx, dispatcher) = create_test_handler();
1560
1561 let dispatcher_clone = dispatcher.clone();
1562 tokio::spawn(async move {
1563 let sent = rx.recv().await.unwrap();
1564 assert_eq!(sent[0], CMD_SET_RADIO_TX_POWER);
1565 assert_eq!(sent[1], 20);
1566
1567 dispatcher_clone.emit(MeshCoreEvent::ok()).await;
1568 });
1569
1570 let result = handler.set_tx_power(20).await;
1571 assert!(result.is_ok());
1572 }
1573
1574 #[tokio::test]
1575 async fn test_send_advert_flood() {
1576 let (handler, mut rx, dispatcher) = create_test_handler();
1577
1578 let dispatcher_clone = dispatcher.clone();
1579 tokio::spawn(async move {
1580 let sent = rx.recv().await.unwrap();
1581 assert_eq!(sent[0], CMD_SEND_SELF_ADVERT);
1582 assert_eq!(sent[1], 0x01); dispatcher_clone.emit(MeshCoreEvent::ok()).await;
1585 });
1586
1587 let result = handler.send_advert(true).await;
1588 assert!(result.is_ok());
1589 }
1590
1591 #[tokio::test]
1592 async fn test_send_advert_no_flood() {
1593 let (handler, mut rx, dispatcher) = create_test_handler();
1594
1595 let dispatcher_clone = dispatcher.clone();
1596 tokio::spawn(async move {
1597 let sent = rx.recv().await.unwrap();
1598 assert_eq!(sent[0], CMD_SEND_SELF_ADVERT);
1599 assert_eq!(sent.len(), 1); dispatcher_clone.emit(MeshCoreEvent::ok()).await;
1602 });
1603
1604 let result = handler.send_advert(false).await;
1605 assert!(result.is_ok());
1606 }
1607
1608 #[tokio::test]
1609 async fn test_reboot() {
1610 let (handler, mut rx, _dispatcher) = create_test_handler();
1611
1612 let recv_task = tokio::spawn(async move { rx.recv().await });
1613
1614 let result = handler.reboot().await;
1615 assert!(result.is_ok());
1616
1617 let sent = recv_task.await.unwrap().unwrap();
1618 assert_eq!(sent[0], CMD_REBOOT);
1619 assert_eq!(&sent[1..], b"reboot");
1620 }
1621
1622 #[tokio::test]
1623 async fn test_get_contacts_success() {
1624 let (handler, mut rx, dispatcher) = create_test_handler();
1625
1626 let dispatcher_clone = dispatcher.clone();
1627 tokio::spawn(async move {
1628 let sent = rx.recv().await.unwrap();
1629 assert_eq!(sent[0], CMD_GET_CONTACTS);
1630
1631 let contacts = vec![Contact {
1632 public_key: [0xAA; 32],
1633 contact_type: 1,
1634 flags: 0,
1635 path_len: 2,
1636 out_path: vec![],
1637 adv_name: "Contact1".to_string(),
1638 last_advert: 0,
1639 adv_lat: 0,
1640 adv_lon: 0,
1641 last_modification_timestamp: 0,
1642 }];
1643 dispatcher_clone
1644 .emit(MeshCoreEvent::new(
1645 EventType::Contacts,
1646 EventPayload::Contacts(contacts),
1647 ))
1648 .await;
1649 });
1650
1651 let result = handler.get_contacts(0).await;
1652 assert!(result.is_ok());
1653 let contacts = result.unwrap();
1654 assert_eq!(contacts.len(), 1);
1655 assert_eq!(contacts[0].adv_name, "Contact1");
1656 }
1657
1658 #[tokio::test]
1659 async fn test_export_contact_self() {
1660 let (handler, mut rx, dispatcher) = create_test_handler();
1661
1662 let dispatcher_clone = dispatcher.clone();
1663 tokio::spawn(async move {
1664 let sent = rx.recv().await.unwrap();
1665 assert_eq!(sent[0], CMD_EXPORT_CONTACT);
1666 assert_eq!(sent.len(), 1); dispatcher_clone
1669 .emit(MeshCoreEvent::new(
1670 EventType::ContactUri,
1671 EventPayload::String("mod.rs://...".to_string()),
1672 ))
1673 .await;
1674 });
1675
1676 let result: Result<String> = handler.export_contact(None::<&str>).await;
1677 assert!(result.is_ok());
1678 assert!(result.unwrap().starts_with("mod.rs://"));
1679 }
1680
1681 #[tokio::test]
1682 async fn test_get_channel_success() {
1683 let (handler, mut rx, dispatcher) = create_test_handler();
1684
1685 let dispatcher_clone = dispatcher.clone();
1686 tokio::spawn(async move {
1687 let sent = rx.recv().await.unwrap();
1688 assert_eq!(sent[0], CMD_GET_CHANNEL);
1689 assert_eq!(sent[1], 0); let info = ChannelInfoData {
1692 channel_idx: 0,
1693 name: "General".to_string(),
1694 secret: [0; 16],
1695 };
1696 dispatcher_clone
1697 .emit(MeshCoreEvent::new(
1698 EventType::ChannelInfo,
1699 EventPayload::ChannelInfo(info),
1700 ))
1701 .await;
1702 });
1703
1704 let result = handler.get_channel(0).await;
1705 assert!(result.is_ok());
1706 assert_eq!(result.unwrap().name, "General");
1707 }
1708
1709 #[tokio::test]
1710 async fn test_set_channel_success() {
1711 let (handler, mut rx, dispatcher) = create_test_handler();
1712
1713 let dispatcher_clone = dispatcher.clone();
1714 tokio::spawn(async move {
1715 let sent = rx.recv().await.unwrap();
1716 assert_eq!(sent[0], CMD_SET_CHANNEL);
1717 assert_eq!(sent[1], 1); assert_eq!(sent.len(), 1 + 1 + CHANNEL_NAME_LEN + CHANNEL_SECRET_LEN);
1720 assert_eq!(&sent[2..6], b"Test");
1722 assert!(sent[6..2 + CHANNEL_NAME_LEN].iter().all(|&b| b == 0));
1724 assert_eq!(&sent[2 + CHANNEL_NAME_LEN..], &[0xAA; CHANNEL_SECRET_LEN]);
1726
1727 dispatcher_clone
1728 .emit(MeshCoreEvent::new(EventType::Ok, EventPayload::None))
1729 .await;
1730 });
1731
1732 let secret = [0xAA; CHANNEL_SECRET_LEN];
1733 let result = handler.set_channel(1, "Test", &secret).await;
1734 assert!(result.is_ok());
1735 }
1736
1737 #[tokio::test]
1738 async fn test_set_channel_name_truncation_with_null_terminator() {
1739 let (handler, mut rx, dispatcher) = create_test_handler();
1740
1741 let dispatcher_clone = dispatcher.clone();
1742 tokio::spawn(async move {
1743 let sent = rx.recv().await.unwrap();
1744 assert_eq!(sent[0], CMD_SET_CHANNEL);
1745 assert_eq!(sent.len(), 1 + 1 + CHANNEL_NAME_LEN + CHANNEL_SECRET_LEN);
1747 let expected_name = b"This is a very long channel nam"; assert_eq!(
1750 &sent[2..2 + CHANNEL_NAME_LEN - 1],
1751 &expected_name[..CHANNEL_NAME_LEN - 1]
1752 );
1753 assert_eq!(
1755 sent[2 + CHANNEL_NAME_LEN - 1],
1756 0,
1757 "Last byte of name field must be null terminator"
1758 );
1759
1760 dispatcher_clone
1761 .emit(MeshCoreEvent::new(EventType::Ok, EventPayload::None))
1762 .await;
1763 });
1764
1765 let secret = [0xBB; CHANNEL_SECRET_LEN];
1766 let long_name = "This is a very long channel name that exceeds the limit";
1768 let result = handler.set_channel(2, long_name, &secret).await;
1769 assert!(result.is_ok());
1770 }
1771
1772 #[tokio::test]
1773 async fn test_sign_start_success() {
1774 let (handler, mut rx, dispatcher) = create_test_handler();
1775
1776 let dispatcher_clone = dispatcher.clone();
1777 tokio::spawn(async move {
1778 let sent = rx.recv().await.unwrap();
1779 assert_eq!(sent[0], CMD_SIGN_START);
1780
1781 dispatcher_clone
1782 .emit(MeshCoreEvent::new(
1783 EventType::SignStart,
1784 EventPayload::SignStart { max_length: 4096 },
1785 ))
1786 .await;
1787 });
1788
1789 let result = handler.sign_start().await;
1790 assert!(result.is_ok());
1791 assert_eq!(result.unwrap(), 4096);
1792 }
1793
1794 #[tokio::test]
1795 async fn test_get_custom_vars_success() {
1796 let (handler, mut rx, dispatcher) = create_test_handler();
1797
1798 let dispatcher_clone = dispatcher.clone();
1799 tokio::spawn(async move {
1800 let sent = rx.recv().await.unwrap();
1801 assert_eq!(sent[0], CMD_GET_CUSTOM_VARS);
1802
1803 let mut vars = HashMap::new();
1804 vars.insert("key1".to_string(), "value1".to_string());
1805 dispatcher_clone
1806 .emit(MeshCoreEvent::new(
1807 EventType::CustomVars,
1808 EventPayload::CustomVars(vars),
1809 ))
1810 .await;
1811 });
1812
1813 let result = handler.get_custom_vars().await;
1814 assert!(result.is_ok());
1815 let vars = result.unwrap();
1816 assert_eq!(vars.get("key1"), Some(&"value1".to_string()));
1817 }
1818
1819 #[tokio::test]
1820 async fn test_set_custom_var_success() {
1821 let (handler, mut rx, dispatcher) = create_test_handler();
1822
1823 let dispatcher_clone = dispatcher.clone();
1824 tokio::spawn(async move {
1825 let sent = rx.recv().await.unwrap();
1826 assert_eq!(sent[0], CMD_SET_CUSTOM_VAR);
1827 let payload = String::from_utf8_lossy(&sent[1..]);
1829 assert!(payload.contains("mykey=myvalue"));
1830
1831 dispatcher_clone.emit(MeshCoreEvent::ok()).await;
1832 });
1833
1834 let result = handler.set_custom_var("mykey", "myvalue").await;
1835 assert!(result.is_ok());
1836 }
1837
1838 #[tokio::test]
1839 async fn test_get_msg_no_more() {
1840 let (handler, mut rx, dispatcher) = create_test_handler();
1841
1842 let dispatcher_clone = dispatcher.clone();
1843 tokio::spawn(async move {
1844 let sent = rx.recv().await.unwrap();
1845 assert_eq!(sent[0], CMD_SYNC_NEXT_MESSAGE);
1846
1847 dispatcher_clone
1848 .emit(MeshCoreEvent::new(
1849 EventType::NoMoreMessages,
1850 EventPayload::None,
1851 ))
1852 .await;
1853 });
1854
1855 let result = handler.get_msg().await;
1856 assert!(result.is_ok());
1857 assert!(result.unwrap().is_none());
1858 }
1859
1860 #[tokio::test]
1861 async fn test_get_msg_with_message() {
1862 let (handler, mut rx, dispatcher) = create_test_handler();
1863
1864 let dispatcher_clone = dispatcher.clone();
1865 tokio::spawn(async move {
1866 let _sent = rx.recv().await.unwrap();
1867
1868 let msg = ContactMessage {
1869 sender_prefix: [0x01, 0x02, 0x03, 0x04, 0x05, 0x06],
1870 path_len: 2,
1871 txt_type: 1,
1872 sender_timestamp: 1234567890,
1873 text: "Hello!".to_string(),
1874 snr: None,
1875 signature: None,
1876 };
1877 dispatcher_clone
1878 .emit(MeshCoreEvent::new(
1879 EventType::ContactMsgRecv,
1880 EventPayload::ContactMessage(msg),
1881 ))
1882 .await;
1883 });
1884
1885 let result = handler.get_msg().await;
1886 assert!(result.is_ok());
1887 let event = result.unwrap().unwrap();
1888 assert_eq!(event.event_type, EventType::ContactMsgRecv);
1889 match event.payload {
1890 EventPayload::ContactMessage(msg) => {
1891 assert_eq!(msg.text, "Hello!");
1892 }
1893 _ => panic!("Expected ContactMessage payload"),
1894 }
1895 }
1896}