1use crate::common::{Id, Node};
2use crate::errors::RustyDHTError;
3use crate::packets;
4use rand::prelude::*;
5use std::convert::TryInto;
6use std::net::SocketAddr;
7use std::time::Duration;
8
9#[derive(Clone)]
33pub struct MessageBuilder {
34 message_type: BuilderMessageType,
35
36 transaction_id: Option<Vec<u8>>,
37 version: Option<Vec<u8>>,
38 requester_ip: Option<SocketAddr>,
39 read_only: Option<bool>,
40
41 sender_id: Option<Id>,
42 target: Option<Id>,
43 port: Option<u16>,
44 implied_port: Option<bool>,
45 token: Option<Vec<u8>>,
46 nodes: Option<Vec<Node>>,
47 peers: Option<Vec<SocketAddr>>,
48 interval: Option<Duration>,
49 samples: Option<Vec<Id>>,
50 num_infohashes: Option<usize>,
51 code: Option<i32>,
52 description: Option<String>,
53}
54
55#[derive(Clone)]
57enum BuilderMessageType {
58 PingRequest,
59 PingResponse,
60 FindNodeRequest,
61 FindNodeResponse,
62 GetPeersRequest,
63 GetPeersResponse,
64 AnnouncePeerRequest,
65 AnnouncePeerResponse,
66 SampleInfoHashesRequest,
67 SampleInfoHashesResponse,
68 Error,
69}
70
71impl MessageBuilder {
72 pub fn new_ping_request() -> MessageBuilder {
74 MessageBuilder::new(BuilderMessageType::PingRequest)
75 }
76
77 pub fn new_ping_response() -> MessageBuilder {
79 MessageBuilder::new(BuilderMessageType::PingResponse)
80 }
81
82 pub fn new_find_node_request() -> MessageBuilder {
84 MessageBuilder::new(BuilderMessageType::FindNodeRequest)
85 }
86
87 pub fn new_find_node_response() -> MessageBuilder {
89 MessageBuilder::new(BuilderMessageType::FindNodeResponse)
90 }
91
92 pub fn new_get_peers_request() -> MessageBuilder {
94 MessageBuilder::new(BuilderMessageType::GetPeersRequest)
95 }
96
97 pub fn new_get_peers_response() -> MessageBuilder {
99 MessageBuilder::new(BuilderMessageType::GetPeersResponse)
100 }
101
102 pub fn new_announce_peer_request() -> MessageBuilder {
104 MessageBuilder::new(BuilderMessageType::AnnouncePeerRequest)
105 }
106
107 pub fn new_announce_peer_response() -> MessageBuilder {
109 MessageBuilder::new(BuilderMessageType::AnnouncePeerResponse)
110 }
111
112 pub fn new_sample_infohashes_request() -> MessageBuilder {
114 MessageBuilder::new(BuilderMessageType::SampleInfoHashesRequest)
115 }
116
117 pub fn new_sample_infohashes_response() -> MessageBuilder {
119 MessageBuilder::new(BuilderMessageType::SampleInfoHashesResponse)
120 }
121
122 pub fn new_error() -> MessageBuilder {
124 MessageBuilder::new(BuilderMessageType::Error)
125 }
126
127 fn new(message_type: BuilderMessageType) -> MessageBuilder {
128 MessageBuilder {
129 message_type,
130 transaction_id: None,
131 version: None,
132 requester_ip: None,
133 read_only: None,
134 sender_id: None,
135 target: None,
136 port: None,
137 implied_port: None,
138 token: None,
139 nodes: None,
140 peers: None,
141 interval: None,
142 samples: None,
143 num_infohashes: None,
144 code: None,
145 description: None,
146 }
147 }
148
149 pub fn transaction_id(mut self, transaction_id: Vec<u8>) -> Self {
153 self.transaction_id = Some(transaction_id);
154 self
155 }
156
157 pub fn version(mut self, version: Vec<u8>) -> Self {
163 self.version = Some(version);
164 self
165 }
166
167 pub fn requester_ip(mut self, remote: SocketAddr) -> Self {
175 self.requester_ip = Some(remote);
176 self
177 }
178
179 pub fn read_only(mut self, read_only: bool) -> Self {
183 self.read_only = Some(read_only);
184 self
185 }
186
187 pub fn sender_id(mut self, sender_id: Id) -> Self {
189 self.sender_id = Some(sender_id);
190 self
191 }
192
193 pub fn target(mut self, target: Id) -> Self {
196 self.target = Some(target);
197 self
198 }
199
200 pub fn port(mut self, port: u16) -> Self {
206 self.port = Some(port);
207 self
208 }
209
210 pub fn implied_port(mut self, implied_port: bool) -> Self {
212 self.implied_port = Some(implied_port);
213 self
214 }
215
216 pub fn token(mut self, token: Vec<u8>) -> Self {
219 self.token = Some(token);
220 self
221 }
222
223 pub fn nodes(mut self, nodes: Vec<Node>) -> Self {
228 self.nodes = Some(nodes);
229 self
230 }
231
232 pub fn peers(mut self, peers: Vec<SocketAddr>) -> Self {
236 self.peers = Some(peers);
237 self
238 }
239
240 pub fn interval(mut self, interval: Duration) -> Self {
242 self.interval = Some(interval);
243 self
244 }
245
246 pub fn samples(mut self, samples: Vec<Id>) -> Self {
248 self.samples = Some(samples);
249 self
250 }
251
252 pub fn num_infohashes(mut self, num: usize) -> Self {
255 self.num_infohashes = Some(num);
256 self
257 }
258
259 pub fn code(mut self, code: i32) -> Self {
261 self.code = Some(code);
262 self
263 }
264
265 pub fn description(mut self, description: String) -> Self {
267 self.description = Some(description);
268 self
269 }
270
271 pub fn build(self) -> Result<packets::Message, RustyDHTError> {
273 match self.message_type {
274 BuilderMessageType::PingRequest => self.build_ping_request(),
275 BuilderMessageType::PingResponse => self.build_ping_response(),
276 BuilderMessageType::FindNodeRequest => self.build_find_node_request(),
277 BuilderMessageType::FindNodeResponse => self.build_find_node_response(),
278 BuilderMessageType::GetPeersRequest => self.build_get_peers_request(),
279 BuilderMessageType::GetPeersResponse => self.build_get_peers_response(),
280 BuilderMessageType::AnnouncePeerRequest => self.build_announce_peer_request(),
281 BuilderMessageType::AnnouncePeerResponse => self.build_announce_peer_response(),
282 BuilderMessageType::SampleInfoHashesRequest => self.build_sample_infohashes_request(),
283 BuilderMessageType::SampleInfoHashesResponse => self.build_sample_infohashes_response(),
284 BuilderMessageType::Error => self.build_error(),
285 }
286 }
287}
288
289macro_rules! required_or_error {
290 ($self:ident, $builder_field:ident) => {
291 match $self.$builder_field {
292 None => {
293 return Err(RustyDHTError::BuilderMissingFieldError(stringify!(
294 $builder_field
295 )));
296 }
297 Some($builder_field) => $builder_field,
298 }
299 };
300}
301
302macro_rules! build_request_common {
303 ($self:ident, $x:expr) => {
304 packets::Message {
305 transaction_id: match $self.transaction_id {
306 Some(transaction_id) => transaction_id,
307 None => {
308 let mut rng = thread_rng();
309 vec![rng.gen(), rng.gen()]
310 }
311 },
312 version: $self.version,
313 requester_ip: None,
314 message_type: packets::MessageType::Request($x),
315 read_only: $self.read_only,
316 }
317 };
318}
319
320macro_rules! build_response_common {
321 ($self:ident, $x:expr) => {
322 packets::Message {
323 transaction_id: required_or_error!($self, transaction_id),
324 version: $self.version,
325 requester_ip: $self.requester_ip,
326 message_type: packets::MessageType::Response($x),
327 read_only: None,
328 }
329 };
330}
331
332impl MessageBuilder {
333 fn build_ping_request(self) -> Result<packets::Message, RustyDHTError> {
334 Ok(build_request_common!(
335 self,
336 packets::RequestSpecific::PingRequest(packets::PingRequestArguments {
337 requester_id: required_or_error!(self, sender_id),
338 },)
339 ))
340 }
341
342 fn build_ping_response(self) -> Result<packets::Message, RustyDHTError> {
343 Ok(build_response_common!(
344 self,
345 packets::ResponseSpecific::PingResponse(packets::PingResponseArguments {
346 responder_id: required_or_error!(self, sender_id),
347 },)
348 ))
349 }
350
351 fn build_find_node_request(self) -> Result<packets::Message, RustyDHTError> {
352 Ok(build_request_common!(
353 self,
354 packets::RequestSpecific::FindNodeRequest(packets::FindNodeRequestArguments {
355 requester_id: required_or_error!(self, sender_id),
356 target: required_or_error!(self, target),
357 },)
358 ))
359 }
360
361 fn build_find_node_response(self) -> Result<packets::Message, RustyDHTError> {
362 Ok(build_response_common!(
363 self,
364 packets::ResponseSpecific::FindNodeResponse(packets::FindNodeResponseArguments {
365 responder_id: required_or_error!(self, sender_id),
366 nodes: required_or_error!(self, nodes),
367 },)
368 ))
369 }
370
371 fn build_get_peers_request(self) -> Result<packets::Message, RustyDHTError> {
372 Ok(build_request_common!(
373 self,
374 packets::RequestSpecific::GetPeersRequest(packets::GetPeersRequestArguments {
375 requester_id: required_or_error!(self, sender_id),
376 info_hash: required_or_error!(self, target),
377 })
378 ))
379 }
380
381 fn build_get_peers_response(self) -> Result<packets::Message, RustyDHTError> {
382 Ok(build_response_common!(
383 self,
384 packets::ResponseSpecific::GetPeersResponse(packets::GetPeersResponseArguments {
385 responder_id: required_or_error!(self, sender_id),
386 token: required_or_error!(self, token),
387
388 values: match self.peers {
389 Some(peers) => packets::GetPeersResponseValues::Peers(peers),
390 None => match self.nodes {
391 Some(nodes) => packets::GetPeersResponseValues::Nodes(nodes),
392 None => {
393 return Err(RustyDHTError::BuilderMissingFieldError("peers or nodes"));
394 }
395 },
396 }
397 })
398 ))
399 }
400
401 fn build_announce_peer_request(self) -> Result<packets::Message, RustyDHTError> {
402 Ok(build_request_common!(
403 self,
404 packets::RequestSpecific::AnnouncePeerRequest(packets::AnnouncePeerRequestArguments {
405 requester_id: required_or_error!(self, sender_id),
406 info_hash: required_or_error!(self, target),
407 token: required_or_error!(self, token),
408 port: self.port.unwrap_or(0),
409
410 implied_port: match self.implied_port {
411 Some(implied_port) => {
412 if !implied_port && self.port.is_none() {
413 return Err(RustyDHTError::BuilderInvalidComboError(
414 "implied_port must be true or port must be specified",
415 ));
416 }
417 Some(implied_port)
418 }
419 None => {
420 match self.port {
421 Some(_) => None,
422 None => Some(true),
423 }
424 }
425 }
426 })
427 ))
428 }
429
430 fn build_announce_peer_response(self) -> Result<packets::Message, RustyDHTError> {
431 self.build_ping_response()
432 }
433
434 fn build_sample_infohashes_request(self) -> Result<packets::Message, RustyDHTError> {
435 Ok(build_request_common!(
436 self,
437 packets::RequestSpecific::SampleInfoHashesRequest(
438 packets::SampleInfoHashesRequestArguments {
439 requester_id: required_or_error!(self, sender_id),
440 target: required_or_error!(self, target),
441 }
442 )
443 ))
444 }
445
446 fn build_sample_infohashes_response(self) -> Result<packets::Message, RustyDHTError> {
447 Ok(build_response_common!(
448 self,
449 packets::ResponseSpecific::SampleInfoHashesResponse(
450 packets::SampleInfoHashesResponseArguments {
451 responder_id: required_or_error!(self, sender_id),
452 interval: required_or_error!(self, interval),
453 nodes: required_or_error!(self, nodes),
454 num: match self.num_infohashes {
455 Some(num) => num.try_into().unwrap(),
456 None => {
457 return Err(RustyDHTError::BuilderMissingFieldError("num_infohashes"));
458 }
459 },
460 samples: required_or_error!(self, samples),
461 }
462 )
463 ))
464 }
465
466 fn build_error(self) -> Result<packets::Message, RustyDHTError> {
467 Ok(packets::Message {
468 transaction_id: required_or_error!(self, transaction_id),
469 version: None,
470 requester_ip: None,
471 message_type: packets::MessageType::Error(packets::ErrorSpecific {
472 code: required_or_error!(self, code),
473 description: required_or_error!(self, description),
474 }),
475 read_only: None,
476 })
477 }
478}
479
480#[cfg(test)]
481mod test {
482 use super::*;
483
484 #[test]
485 fn test_sender_id_is_required_in_requests() {
486 let transaction_id = vec![0, 1, 2, 3];
487 let err = MessageBuilder::new_ping_request()
488 .transaction_id(transaction_id)
489 .build();
490 assert!(err.is_err());
491 assert!(matches!(
492 err.unwrap_err(),
493 RustyDHTError::BuilderMissingFieldError("sender_id")
494 ));
495 }
496
497 #[test]
498 fn test_sender_id_is_required_in_responses() {
499 let transaction_id = vec![0, 1, 2, 3];
500 let err = MessageBuilder::new_ping_response()
501 .transaction_id(transaction_id)
502 .build();
503 assert!(err.is_err());
504 assert!(matches!(
505 err.unwrap_err(),
506 RustyDHTError::BuilderMissingFieldError("sender_id")
507 ));
508 }
509
510 #[test]
511 fn test_transaction_id_optional_in_requests() {
512 let our_id = Id::from_hex("0000000000000000000011111111111111111111").unwrap();
513 let b = MessageBuilder::new_ping_request().sender_id(our_id).build();
514 assert!(b.is_ok());
515 assert!(!b.unwrap().transaction_id.is_empty());
516 }
517
518 #[test]
519 fn test_transaction_id_required_in_responses() {
520 let our_id = Id::from_hex("0000000000000000000011111111111111111111").unwrap();
521 let err = MessageBuilder::new_ping_response()
522 .sender_id(our_id)
523 .build();
524 assert!(err.is_err());
525 assert!(matches!(
526 err.unwrap_err(),
527 RustyDHTError::BuilderMissingFieldError("transaction_id")
528 ));
529 }
530
531 #[test]
532 fn test_version_field_populated() {
533 let our_id = Id::from_hex("0000000000000000000011111111111111111111").unwrap();
534 let b = MessageBuilder::new_ping_request()
535 .sender_id(our_id)
536 .version(vec![6, 6, 6])
537 .build();
538 assert!(b.is_ok());
539 assert_eq!(b.unwrap().version.unwrap_or_default(), vec!(6, 6, 6));
540 }
541
542 #[test]
543 fn test_requester_ip_pointless_on_requests() {
544 let our_id = Id::from_hex("0000000000000000000011111111111111111111").unwrap();
545 let b = MessageBuilder::new_ping_request()
546 .sender_id(our_id)
547 .requester_ip("1.0.1.0:53".parse().unwrap())
548 .build();
549 assert!(b.is_ok());
550 assert_eq!(b.unwrap().requester_ip, None);
551 }
552
553 #[test]
554 fn test_requester_ip_useful_on_responses() {
555 let our_id = Id::from_hex("0000000000000000000011111111111111111111").unwrap();
556 let b = MessageBuilder::new_ping_response()
557 .sender_id(our_id)
558 .requester_ip("1.0.1.0:53".parse().unwrap())
559 .transaction_id(vec![1])
560 .build();
561 assert!(b.is_ok());
562 assert_eq!(b.unwrap().requester_ip, Some("1.0.1.0:53".parse().unwrap()));
563 }
564
565 #[test]
566 fn test_read_only_useful_on_requests() {
567 let our_id = Id::from_hex("0000000000000000000011111111111111111111").unwrap();
568 let b = MessageBuilder::new_ping_request()
569 .sender_id(our_id)
570 .read_only(true)
571 .build();
572 assert!(b.is_ok());
573 assert_eq!(b.unwrap().read_only, Some(true));
574 }
575
576 #[test]
577 fn test_read_only_pointless_on_responses() {
578 let our_id = Id::from_hex("0000000000000000000011111111111111111111").unwrap();
579 let b = MessageBuilder::new_ping_response()
580 .sender_id(our_id)
581 .read_only(true)
582 .transaction_id(vec![1])
583 .build();
584 assert!(b.is_ok());
585 assert_eq!(b.unwrap().read_only, None);
586 }
587
588 #[test]
589 fn test_build_ping_request() {
590 let our_id = Id::from_hex("0000000000000000000011111111111111111111").unwrap();
591 let transaction_id = vec![0, 1, 2, 3];
592 assert_eq!(
593 MessageBuilder::new_ping_request()
594 .sender_id(our_id)
595 .transaction_id(transaction_id.clone())
596 .build()
597 .expect("Failed to build message"),
598 packets::Message {
599 transaction_id,
600 version: None,
601 requester_ip: None,
602 message_type: packets::MessageType::Request(packets::RequestSpecific::PingRequest(
603 packets::PingRequestArguments {
604 requester_id: our_id
605 }
606 )),
607 read_only: None,
608 }
609 );
610 }
611
612 #[test]
613 fn test_build_ping_response() {
614 let our_id = Id::from_hex("0000000000000000000011111111111111111111").unwrap();
615 let transaction_id = vec![0, 1, 2, 3];
616 assert_eq!(
617 MessageBuilder::new_ping_response()
618 .sender_id(our_id)
619 .transaction_id(transaction_id.clone())
620 .build()
621 .expect("Failed to build message"),
622 packets::Message {
623 transaction_id,
624 version: None,
625 requester_ip: None,
626 message_type: packets::MessageType::Response(
627 packets::ResponseSpecific::PingResponse(packets::PingResponseArguments {
628 responder_id: our_id
629 })
630 ),
631 read_only: None,
632 }
633 );
634 }
635
636 #[test]
637 fn test_find_node_request() {
638 let our_id = Id::from_hex("0000000000000000000011111111111111111111").unwrap();
639 let target = Id::from_hex("1111111111111111111100000000000000000000").unwrap();
640 let transaction_id = vec![0, 1, 2, 3];
641 assert_eq!(
642 MessageBuilder::new_find_node_request()
643 .sender_id(our_id)
644 .transaction_id(transaction_id.clone())
645 .target(target)
646 .build()
647 .expect("Failed to build message"),
648 packets::Message {
649 transaction_id,
650 version: None,
651 requester_ip: None,
652 message_type: packets::MessageType::Request(
653 packets::RequestSpecific::FindNodeRequest(packets::FindNodeRequestArguments {
654 requester_id: our_id,
655 target,
656 })
657 ),
658 read_only: None,
659 }
660 );
661 }
662
663 #[test]
664 fn test_find_node_response() {
665 let our_id = Id::from_hex("0000000000000000000011111111111111111111").unwrap();
666 let transaction_id = vec![0, 1, 2, 3];
667 let nodes = vec![Node::new(our_id, "1.2.3.4:53".parse().unwrap())];
668 assert_eq!(
669 MessageBuilder::new_find_node_response()
670 .sender_id(our_id)
671 .transaction_id(transaction_id.clone())
672 .nodes(nodes.clone())
673 .build()
674 .expect("Failed to build message"),
675 packets::Message {
676 transaction_id,
677 version: None,
678 requester_ip: None,
679 message_type: packets::MessageType::Response(
680 packets::ResponseSpecific::FindNodeResponse(
681 packets::FindNodeResponseArguments {
682 responder_id: our_id,
683 nodes,
684 }
685 )
686 ),
687 read_only: None,
688 }
689 );
690 }
691
692 #[test]
693 fn test_get_peers_request() {
694 let our_id = Id::from_hex("0000000000000000000011111111111111111111").unwrap();
695 let target = Id::from_hex("1111111111111111111100000000000000000000").unwrap();
696 let transaction_id = vec![0, 1, 2, 3];
697 assert_eq!(
698 MessageBuilder::new_get_peers_request()
699 .sender_id(our_id)
700 .transaction_id(transaction_id.clone())
701 .target(target)
702 .build()
703 .expect("Failed to build message"),
704 packets::Message {
705 transaction_id,
706 version: None,
707 requester_ip: None,
708 message_type: packets::MessageType::Request(
709 packets::RequestSpecific::GetPeersRequest(packets::GetPeersRequestArguments {
710 requester_id: our_id,
711 info_hash: target
712 })
713 ),
714 read_only: None,
715 }
716 );
717 }
718
719 #[test]
720 fn test_get_peers_response_nodes() {
721 let our_id = Id::from_hex("0000000000000000000011111111111111111111").unwrap();
722 let transaction_id = vec![0, 1, 2, 3];
723 let nodes = vec![Node::new(our_id, "1.2.3.4:53".parse().unwrap())];
724 let token = vec![45, 56];
725 assert_eq!(
726 MessageBuilder::new_get_peers_response()
727 .sender_id(our_id)
728 .transaction_id(transaction_id.clone())
729 .nodes(nodes.clone())
730 .token(token.clone())
731 .build()
732 .expect("Failed to build message"),
733 packets::Message {
734 transaction_id,
735 version: None,
736 requester_ip: None,
737 message_type: packets::MessageType::Response(
738 packets::ResponseSpecific::GetPeersResponse(
739 packets::GetPeersResponseArguments {
740 responder_id: our_id,
741 values: packets::GetPeersResponseValues::Nodes(nodes),
742 token
743 }
744 )
745 ),
746 read_only: None,
747 }
748 );
749 }
750
751 #[test]
752 fn test_get_peers_response_peers() {
753 let our_id = Id::from_hex("0000000000000000000011111111111111111111").unwrap();
754 let transaction_id = vec![0, 1, 2, 3];
755 let peers = vec!["1.2.3.4:53".parse().unwrap()];
756 let token = vec![45, 56];
757 assert_eq!(
758 MessageBuilder::new_get_peers_response()
759 .sender_id(our_id)
760 .transaction_id(transaction_id.clone())
761 .peers(peers.clone())
762 .token(token.clone())
763 .build()
764 .expect("Failed to build message"),
765 packets::Message {
766 transaction_id,
767 version: None,
768 requester_ip: None,
769 message_type: packets::MessageType::Response(
770 packets::ResponseSpecific::GetPeersResponse(
771 packets::GetPeersResponseArguments {
772 responder_id: our_id,
773 values: packets::GetPeersResponseValues::Peers(peers),
774 token
775 }
776 )
777 ),
778 read_only: None,
779 }
780 );
781 }
782
783 #[test]
784 fn test_get_peers_response_peers_precedent() {
785 let our_id = Id::from_hex("0000000000000000000011111111111111111111").unwrap();
786 let transaction_id = vec![0, 1, 2, 3];
787 let nodes = vec![Node::new(our_id, "1.2.3.4:53".parse().unwrap())];
788 let peers = vec!["1.2.3.4:53".parse().unwrap()];
789 let token = vec![45, 56];
790 assert_eq!(
791 MessageBuilder::new_get_peers_response()
792 .sender_id(our_id)
793 .transaction_id(transaction_id.clone())
794 .peers(peers.clone())
795 .nodes(nodes)
796 .token(token.clone())
797 .build()
798 .expect("Failed to build message"),
799 packets::Message {
800 transaction_id,
801 version: None,
802 requester_ip: None,
803 message_type: packets::MessageType::Response(
804 packets::ResponseSpecific::GetPeersResponse(
805 packets::GetPeersResponseArguments {
806 responder_id: our_id,
807 values: packets::GetPeersResponseValues::Peers(peers),
808 token
809 }
810 )
811 ),
812 read_only: None,
813 }
814 );
815 }
816
817 #[test]
818 fn test_announce_peer_request() {
819 let our_id = Id::from_hex("0000000000000000000011111111111111111111").unwrap();
820 let target = Id::from_hex("1111111111111111111100000000000000000000").unwrap();
821 let transaction_id = vec![0, 1, 2, 3];
822 let token = vec![6, 6, 6];
823 assert_eq!(
824 MessageBuilder::new_announce_peer_request()
825 .sender_id(our_id)
826 .transaction_id(transaction_id.clone())
827 .target(target)
828 .port(5050)
829 .token(token.clone())
830 .build()
831 .expect("Failed to build message"),
832 packets::Message {
833 transaction_id,
834 version: None,
835 requester_ip: None,
836 message_type: packets::MessageType::Request(
837 packets::RequestSpecific::AnnouncePeerRequest(
838 packets::AnnouncePeerRequestArguments {
839 requester_id: our_id,
840 info_hash: target,
841 port: 5050,
842 implied_port: None,
843 token
844 }
845 )
846 ),
847 read_only: None,
848 }
849 );
850 }
851
852 #[test]
853 fn test_announce_peer_request_default_implied_port() {
854 let our_id = Id::from_hex("0000000000000000000011111111111111111111").unwrap();
855 let target = Id::from_hex("1111111111111111111100000000000000000000").unwrap();
856 let transaction_id = vec![0, 1, 2, 3];
857 let token = vec![6, 6, 6];
858 assert_eq!(
859 MessageBuilder::new_announce_peer_request()
860 .sender_id(our_id)
861 .transaction_id(transaction_id.clone())
862 .target(target)
863 .token(token.clone())
864 .build()
865 .expect("Failed to build message"),
866 packets::Message {
867 transaction_id,
868 version: None,
869 requester_ip: None,
870 message_type: packets::MessageType::Request(
871 packets::RequestSpecific::AnnouncePeerRequest(
872 packets::AnnouncePeerRequestArguments {
873 requester_id: our_id,
874 info_hash: target,
875 port: 0,
876 implied_port: Some(true),
877 token
878 }
879 )
880 ),
881 read_only: None,
882 }
883 );
884 }
885
886 #[test]
887 fn test_announce_peer_request_default_implied_port_conflict() {
888 let our_id = Id::from_hex("0000000000000000000011111111111111111111").unwrap();
889 let target = Id::from_hex("1111111111111111111100000000000000000000").unwrap();
890 let transaction_id = vec![0, 1, 2, 3];
891 let token = vec![6, 6, 6];
892 assert!(matches!(
893 MessageBuilder::new_announce_peer_request()
894 .sender_id(our_id)
895 .transaction_id(transaction_id)
896 .target(target)
897 .token(token)
898 .implied_port(false)
899 .build()
900 .unwrap_err(),
901 RustyDHTError::BuilderInvalidComboError(_)
902 ));
903 }
904
905 #[test]
906 fn test_announce_peer_response() {
907 let our_id = Id::from_hex("0000000000000000000011111111111111111111").unwrap();
908 let transaction_id = vec![0, 1, 2, 3];
909 assert_eq!(
910 MessageBuilder::new_announce_peer_response()
911 .sender_id(our_id)
912 .transaction_id(transaction_id.clone())
913 .build()
914 .expect("Failed to build message"),
915 packets::Message {
916 transaction_id,
917 version: None,
918 requester_ip: None,
919 message_type: packets::MessageType::Response(
920 packets::ResponseSpecific::PingResponse(packets::PingResponseArguments {
921 responder_id: our_id
922 })
923 ),
924 read_only: None,
925 }
926 );
927 }
928
929 #[test]
930 fn test_sample_infohashes_request() {
931 let our_id = Id::from_hex("0000000000000000000011111111111111111111").unwrap();
932 let target = Id::from_hex("1111111111111111111100000000000000000000").unwrap();
933 let transaction_id = vec![0, 1, 2, 3];
934 assert_eq!(
935 MessageBuilder::new_sample_infohashes_request()
936 .sender_id(our_id)
937 .transaction_id(transaction_id.clone())
938 .target(target)
939 .build()
940 .expect("Failed to build message"),
941 packets::Message {
942 transaction_id,
943 version: None,
944 requester_ip: None,
945 message_type: packets::MessageType::Request(
946 packets::RequestSpecific::SampleInfoHashesRequest(
947 packets::SampleInfoHashesRequestArguments {
948 requester_id: our_id,
949 target
950 }
951 )
952 ),
953 read_only: None,
954 }
955 );
956 }
957
958 #[test]
959 fn test_sample_infohashes_response() {
960 let our_id = Id::from_hex("0000000000000000000011111111111111111111").unwrap();
961 let transaction_id = vec![0, 1, 2, 3];
962 let nodes = vec![Node::new(our_id, "1.2.3.4:53".parse().unwrap())];
963 let samples = vec![Id::from_hex("2222222222222222222233333333333333333333").unwrap()];
964 assert_eq!(
965 MessageBuilder::new_sample_infohashes_response()
966 .sender_id(our_id)
967 .transaction_id(transaction_id.clone())
968 .interval(Duration::from_secs(30))
969 .num_infohashes(50)
970 .nodes(nodes.clone())
971 .samples(samples.clone())
972 .build()
973 .expect("Failed to build message"),
974 packets::Message {
975 transaction_id,
976 version: None,
977 requester_ip: None,
978 message_type: packets::MessageType::Response(
979 packets::ResponseSpecific::SampleInfoHashesResponse(
980 packets::SampleInfoHashesResponseArguments {
981 responder_id: our_id,
982 interval: Duration::from_secs(30),
983 num: 50,
984 nodes,
985 samples
986 }
987 )
988 ),
989 read_only: None,
990 }
991 );
992 }
993
994 #[test]
995 fn test_error() {
996 let transaction_id = vec![0, 1, 2, 3];
997 let code = 42;
998 let description = "Oh no";
999
1000 assert_eq!(
1001 MessageBuilder::new_error()
1002 .transaction_id(transaction_id.clone())
1003 .code(code)
1004 .description(description.to_string())
1005 .build()
1006 .unwrap(),
1007 packets::Message {
1008 transaction_id,
1009 version: None,
1010 requester_ip: None,
1011 message_type: packets::MessageType::Error(packets::ErrorSpecific {
1012 code,
1013 description: description.to_string()
1014 }),
1015 read_only: None,
1016 }
1017 )
1018 }
1019}