memberlist_core/
options.rs

1use std::time::Duration;
2
3use memberlist_proto::Label;
4
5use super::proto::{DelegateVersion, ProtocolVersion};
6
7#[cfg(any(
8  feature = "crc32",
9  feature = "xxhash32",
10  feature = "xxhash64",
11  feature = "xxhash3",
12  feature = "murmur3"
13))]
14use super::proto::ChecksumAlgorithm;
15
16#[cfg(any(
17  feature = "zstd",
18  feature = "snappy",
19  feature = "brotli",
20  feature = "lz4",
21))]
22use super::proto::CompressAlgorithm;
23
24#[cfg(feature = "encryption")]
25use super::proto::{EncryptionAlgorithm, SecretKey, SecretKeys};
26
27#[cfg(feature = "metrics")]
28pub use super::proto::MetricLabels;
29
30/// Options used to configure the memberlist.
31#[viewit::viewit(getters(vis_all = "pub"), setters(vis_all = "pub", prefix = "with"))]
32#[derive(Debug, Clone)]
33#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
34pub struct Options {
35  /// Label is an optional set of bytes to include on the outside of each
36  /// packet and stream.
37  ///
38  /// If gossip encryption is enabled and this is set it is treated as GCM
39  /// authenticated data.
40  #[viewit(
41    getter(const, style = "ref", attrs(doc = "Get the label of the node."),),
42    setter(attrs(doc = "Set the label of the node. (Builder pattern)"),)
43  )]
44  #[cfg_attr(
45    feature = "serde",
46    serde(default, skip_serializing_if = "Label::is_empty")
47  )]
48  label: Label,
49
50  /// Skips the check that inbound packets and gossip
51  /// streams need to be label prefixed.
52  #[viewit(
53    getter(
54      const,
55      attrs(
56        doc = "Get if the check that inbound packets and gossip streams need to be label prefixed."
57      ),
58    ),
59    setter(attrs(
60      doc = "Set if the check that inbound packets and gossip streams need to be label prefixed. (Builder pattern)"
61    ),)
62  )]
63  skip_inbound_label_check: bool,
64
65  /// The timeout for establishing a stream connection with
66  /// a remote node for a full state sync, and for stream read and write
67  /// operations.
68  #[cfg_attr(feature = "serde", serde(with = "humantime_serde"))]
69  #[viewit(
70    getter(
71      const,
72      attrs(
73        doc = "Returns the timeout for establishing a stream connection with a remote node for a full state sync, and for stream read and write operations."
74      )
75    ),
76    setter(
77      const,
78      attrs(
79        doc = "Sets the timeout for establishing a stream connection with a remote node for a full state sync, and for stream read and write operations (Builder pattern)."
80      )
81    )
82  )]
83  timeout: Duration,
84
85  /// The number of nodes that will be asked to perform
86  /// an indirect probe of a node in the case a direct probe fails. [`Memberlist`](crate::Memberlist)
87  /// waits for an ack from any single indirect node, so increasing this
88  /// number will increase the likelihood that an indirect probe will succeed
89  /// at the expense of bandwidth.
90  #[viewit(
91    getter(
92      const,
93      attrs(
94        doc = "Returns the number of nodes that will be asked to perform an indirect probe of a node in the case a direct probe fails."
95      )
96    ),
97    setter(
98      const,
99      attrs(
100        doc = "Sets the number of nodes that will be asked to perform an indirect probe of a node in the case a direct probe fails (Builder pattern)."
101      )
102    )
103  )]
104  indirect_checks: usize,
105
106  /// The multiplier for the number of retransmissions
107  /// that are attempted for messages broadcasted over gossip. The actual
108  /// count of retransmissions is calculated using the formula:
109  ///
110  ///   `retransmits = retransmit_mult * log(N+1)`
111  ///
112  /// This allows the retransmits to scale properly with cluster size. The
113  /// higher the multiplier, the more likely a failed broadcast is to converge
114  /// at the expense of increased bandwidth.
115  #[viewit(
116    getter(const, attrs(doc = "Returns the retransmit mult")),
117    setter(const, attrs(doc = "Sets the retransmit mult (Builder pattern)."))
118  )]
119  retransmit_mult: usize,
120
121  /// The multiplier for determining the time an
122  /// inaccessible node is considered suspect before declaring it dead.
123  /// The actual timeout is calculated using the formula:
124  ///
125  ///   `suspicion_timeout = suspicion_mult * log(N+1) * probe_interval`
126  ///
127  /// This allows the timeout to scale properly with expected propagation
128  /// delay with a larger cluster size. The higher the multiplier, the longer
129  /// an inaccessible node is considered part of the cluster before declaring
130  /// it dead, giving that suspect node more time to refute if it is indeed
131  /// still alive.
132  #[viewit(
133    getter(const, attrs(doc = "Returns the suspicion mult")),
134    setter(const, attrs(doc = "Sets the suspicion mult (Builder pattern)."))
135  )]
136  suspicion_mult: usize,
137
138  /// The multiplier applied to the
139  /// `suspicion_timeout` used as an upper bound on detection time. This max
140  /// timeout is calculated using the formula:
141  ///
142  /// `suspicion_max_timeout = suspicion_max_timeout_mult * suspicion_timeout`
143  ///
144  /// If everything is working properly, confirmations from other nodes will
145  /// accelerate suspicion timers in a manner which will cause the timeout
146  /// to reach the base SuspicionTimeout before that elapses, so this value
147  /// will typically only come into play if a node is experiencing issues
148  /// communicating with other nodes. It should be set to a something fairly
149  /// large so that a node having problems will have a lot of chances to
150  /// recover before falsely declaring other nodes as failed, but short
151  /// enough for a legitimately isolated node to still make progress marking
152  /// nodes failed in a reasonable amount of time.
153  #[viewit(
154    getter(const, attrs(doc = "Returns the suspicion max timeout mult")),
155    setter(
156      const,
157      attrs(doc = "Sets the suspicion max timeout mult (Builder pattern).")
158    )
159  )]
160  suspicion_max_timeout_mult: usize,
161
162  /// The interval between complete state syncs.
163  /// Complete state syncs are done with a single node over TCP and are
164  /// quite expensive relative to standard gossiped messages. Setting this
165  /// to zero will disable state push/pull syncs completely.
166  ///
167  /// Setting this interval lower (more frequent) will increase convergence
168  /// speeds across larger clusters at the expense of increased bandwidth
169  /// usage.
170  #[cfg_attr(feature = "serde", serde(with = "humantime_serde"))]
171  #[viewit(
172    getter(const, attrs(doc = "Returns the push pull interval")),
173    setter(const, attrs(doc = "Sets the push pull interval (Builder pattern)."))
174  )]
175  push_pull_interval: Duration,
176
177  /// The interval between random node probes. Setting
178  /// this lower (more frequent) will cause the memberlist cluster to detect
179  /// failed nodes more quickly at the expense of increased bandwidth usage
180  #[cfg_attr(feature = "serde", serde(with = "humantime_serde"))]
181  #[viewit(
182    getter(const, attrs(doc = "Returns the probe interval")),
183    setter(const, attrs(doc = "Sets the probe interval (Builder pattern)."))
184  )]
185  probe_interval: Duration,
186  /// The timeout to wait for an ack from a probed node
187  /// before assuming it is unhealthy. This should be set to 99-percentile
188  /// of RTT (round-trip time) on your network.
189  #[cfg_attr(feature = "serde", serde(with = "humantime_serde"))]
190  #[viewit(
191    getter(const, attrs(doc = "Returns the probe timeout")),
192    setter(const, attrs(doc = "Sets the probe timeout (Builder pattern)."))
193  )]
194  probe_timeout: Duration,
195
196  /// Set this field will turn off the fallback promised pings that are attempted
197  /// if the direct unreliable ping fails. These get pipelined along with the
198  /// indirect unreliable pings.
199  #[viewit(
200    getter(const, attrs(doc = "Returns whether disable promised pings or not")),
201    setter(
202      const,
203      attrs(doc = "Sets whether disable promised pings or not (Builder pattern).")
204    )
205  )]
206  disable_reliable_pings: bool,
207
208  /// Increase the probe interval if the node
209  /// becomes aware that it might be degraded and not meeting the soft real
210  /// time requirements to reliably probe other nodes.
211  #[viewit(
212    getter(const, attrs(doc = "Returns the awareness max multiplier")),
213    setter(
214      const,
215      attrs(doc = "Sets the awareness max multiplier (Builder pattern).")
216    )
217  )]
218  awareness_max_multiplier: usize,
219
220  /// The interval between sending messages that need
221  /// to be gossiped that haven't been able to piggyback on probing messages.
222  /// If this is set to zero, non-piggyback gossip is disabled. By lowering
223  /// this value (more frequent) gossip messages are propagated across
224  /// the cluster more quickly at the expense of increased bandwidth.
225  #[cfg_attr(feature = "serde", serde(with = "humantime_serde"))]
226  #[viewit(
227    getter(const, attrs(doc = "Returns the gossip interval")),
228    setter(const, attrs(doc = "Sets the gossip interval (Builder pattern)."))
229  )]
230  gossip_interval: Duration,
231
232  /// The number of random nodes to send gossip messages to
233  /// per `gossip_interval`. Increasing this number causes the gossip messages
234  /// to propagate across the cluster more quickly at the expense of
235  /// increased bandwidth.
236  #[viewit(
237    getter(const, attrs(doc = "Returns the gossip nodes")),
238    setter(const, attrs(doc = "Sets the gossip nodes (Builder pattern)."))
239  )]
240  gossip_nodes: usize,
241  /// The interval after which a node has died that
242  /// we will still try to gossip to it. This gives it a chance to refute.
243  #[cfg_attr(feature = "serde", serde(with = "humantime_serde"))]
244  #[viewit(
245    getter(const, attrs(doc = "Returns the gossip to the dead timeout")),
246    setter(
247      const,
248      attrs(doc = "Sets the gossip to the dead timeout (Builder pattern).")
249    )
250  )]
251  gossip_to_the_dead_time: Duration,
252
253  /// Used to guarantee protocol-compatibility
254  #[viewit(
255    getter(
256      const,
257      attrs(doc = "Returns the protocol version this node is speaking")
258    ),
259    setter(
260      const,
261      attrs(doc = "Sets the protocol version this node is speaking (Builder pattern).")
262    )
263  )]
264  protocol_version: ProtocolVersion,
265
266  /// Used to guarantee protocol-compatibility
267  /// for any custom messages that the delegate might do (broadcasts,
268  /// local/remote state, etc.). If you don't set these, then the protocol
269  /// versions will just be zero, and version compliance won't be done.
270  #[viewit(
271    getter(
272      const,
273      attrs(doc = "Returns the delegate version this node is speaking")
274    ),
275    setter(
276      const,
277      attrs(doc = "Sets the delegate version this node is speaking (Builder pattern).")
278    )
279  )]
280  delegate_version: DelegateVersion,
281
282  /// Size of Memberlist's internal channel which handles UDP messages. The
283  /// size of this determines the size of the queue which Memberlist will keep
284  /// while UDP messages are handled.
285  #[viewit(
286    getter(const, attrs(doc = "Returns the handoff queue depth")),
287    setter(const, attrs(doc = "Sets the handoff queue depth (Builder pattern)."))
288  )]
289  handoff_queue_depth: usize,
290
291  /// Controls the time before a dead node's name can be
292  /// reclaimed by one with a different address or port. By default, this is 0,
293  /// meaning nodes cannot be reclaimed this way.
294  #[cfg_attr(feature = "serde", serde(with = "humantime_serde"))]
295  #[viewit(
296    getter(const, attrs(doc = "Returns the dead node reclaim time")),
297    setter(
298      const,
299      attrs(doc = "Sets the dead node reclaim time (Builder pattern).")
300    )
301  )]
302  dead_node_reclaim_time: Duration,
303
304  /// The interval at which we check the message
305  /// queue to apply the warning and max depth.
306  #[cfg_attr(feature = "serde", serde(with = "humantime_serde"))]
307  #[viewit(
308    getter(const, attrs(doc = "Returns the queue check interval")),
309    setter(const, attrs(doc = "Sets the queue check interval (Builder pattern)."))
310  )]
311  queue_check_interval: Duration,
312
313  /// Indicates that should the messages sent as packets through transport will be appended a checksum.
314  ///
315  /// Default is `None`.
316  ///
317  /// ## Note
318  /// If the [`Transport::packet_reliable`](crate::transport::Transport::packet_reliable) is return `true`,
319  /// then the checksum will not be appended to the packets, even if this field is set to `Some`.
320  #[cfg(any(
321    feature = "crc32",
322    feature = "xxhash32",
323    feature = "xxhash64",
324    feature = "xxhash3",
325    feature = "murmur3",
326  ))]
327  #[cfg_attr(
328    feature = "serde",
329    serde(skip_serializing_if = "Option::is_none", default)
330  )]
331  #[viewit(
332    getter(
333      const,
334      attrs(
335        doc = "Returns the checksum algorithm for the packets sent through transport.",
336        cfg(any(
337          feature = "crc32",
338          feature = "xxhash32",
339          feature = "xxhash64",
340          feature = "xxhash3",
341          feature = "murmur3",
342        )),
343        cfg_attr(
344          docsrs,
345          doc(cfg(any(
346            feature = "crc32",
347            feature = "xxhash32",
348            feature = "xxhash64",
349            feature = "xxhash3",
350            feature = "murmur3",
351          )))
352        )
353      )
354    ),
355    setter(
356      const,
357      rename = "maybe_checksum_algo",
358      attrs(
359        doc = "Sets the checksum algorithm for the packets sent through transport.",
360        cfg(any(
361          feature = "crc32",
362          feature = "xxhash32",
363          feature = "xxhash64",
364          feature = "xxhash3",
365          feature = "murmur3",
366        )),
367        cfg_attr(
368          docsrs,
369          doc(cfg(any(
370            feature = "crc32",
371            feature = "xxhash32",
372            feature = "xxhash64",
373            feature = "xxhash3",
374            feature = "murmur3",
375          )))
376        )
377      )
378    )
379  )]
380  checksum_algo: Option<ChecksumAlgorithm>,
381
382  /// The size of a message that should be offload to [`rayon`] thread pool
383  /// for checksuming, encryption or compression.
384  ///
385  /// The default value is 1KB, which means that any message larger than 1KB
386  /// will be offloaded to [`rayon`] thread pool for encryption or compression.
387  #[cfg(any(
388    feature = "encryption",
389    feature = "lz4",
390    feature = "zstd",
391    feature = "brotli",
392    feature = "snappy",
393  ))]
394  #[cfg_attr(
395    docsrs,
396    doc(cfg(any(
397      feature = "encryption",
398      feature = "lz4",
399      feature = "zstd",
400      feature = "brotli",
401      feature = "snappy",
402    )))
403  )]
404  #[viewit(
405    getter(
406      const,
407      attrs(
408        doc = "Get the size of a message that should be offload to [`rayon`] thread pool for encryption or compression.",
409        cfg(any(
410          feature = "encryption",
411          feature = "lz4",
412          feature = "zstd",
413          feature = "brotli",
414          feature = "snappy",
415        )),
416        cfg_attr(docsrs, doc(cfg(any(feature = "compression", feature = "encryption"))))
417      ),
418    ),
419    setter(attrs(
420      doc = "Set the size of a message that should be offload to [`rayon`] thread pool for encryption or compression. (Builder pattern)",
421      cfg(any(
422        feature = "encryption",
423        feature = "lz4",
424        feature = "zstd",
425        feature = "brotli",
426        feature = "snappy",
427      )),
428      cfg_attr(
429        docsrs,
430        doc(cfg(any(
431          feature = "encryption",
432          feature = "lz4",
433          feature = "zstd",
434          feature = "brotli",
435          feature = "snappy",
436        )))
437      )
438    ),)
439  )]
440  offload_size: usize,
441
442  /// Indicates that should the messages sent as packet or stream through transport will be encrypted or not.
443  ///
444  /// Default is `None`.
445  ///
446  /// ## Note
447  /// - If the [`Transport::packet_secure`](crate::transport::Transport::packet_secure) returns `true`,
448  ///   then the encryption will not be applied to the messages when sending as packet, even if this field is set to `Some`.
449  /// - If the [`Transport::stream_secure`](crate::transport::Transport::stream_secure) returns `true`,
450  ///   then the encryption will not be applied to the messages when sending as stream, even if this field is set to `Some`.
451  #[cfg(feature = "encryption")]
452  #[cfg_attr(
453    feature = "serde",
454    serde(skip_serializing_if = "Option::is_none", default)
455  )]
456  #[viewit(
457    getter(
458      const,
459      attrs(
460        doc = "Returns the encryption algorithm for the messages sent through transport.",
461        cfg(feature = "encryption"),
462        cfg_attr(docsrs, doc(cfg(feature = "encryption")))
463      )
464    ),
465    setter(
466      const,
467      rename = "maybe_encryption_algo",
468      attrs(
469        doc = "Sets the encryption algorithm for the messages sent through transport.",
470        cfg(feature = "encryption"),
471        cfg_attr(docsrs, doc(cfg(feature = "encryption")))
472      )
473    )
474  )]
475  encryption_algo: Option<EncryptionAlgorithm>,
476
477  /// Controls whether to enforce encryption for outgoing
478  /// gossip. It is used for upshifting from unencrypted to encrypted gossip on
479  /// a running cluster.
480  #[cfg_attr(feature = "serde", serde(default))]
481  #[cfg(feature = "encryption")]
482  #[cfg_attr(docsrs, doc(cfg(feature = "encryption")))]
483  #[viewit(
484    getter(
485      const,
486      attrs(
487        doc = "Get whether to enforce encryption for outgoing gossip. It is used for upshifting from unencrypted to encrypted gossip on a running cluster.",
488        cfg(feature = "encryption"),
489        cfg_attr(docsrs, doc(cfg(feature = "encryption")))
490      ),
491    ),
492    setter(attrs(
493      doc = "Set whether to enforce encryption for outgoing gossip. It is used for upshifting from unencrypted to encrypted gossip on a running cluster. (Builder pattern)",
494      cfg(feature = "encryption"),
495      cfg_attr(docsrs, doc(cfg(feature = "encryption")))
496    ),)
497  )]
498  gossip_verify_outgoing: bool,
499
500  /// Controls whether to enforce encryption for incoming
501  /// gossip. It is used for upshifting from unencrypted to encrypted gossip on
502  /// a running cluster.
503  #[cfg_attr(feature = "serde", serde(default))]
504  #[cfg(feature = "encryption")]
505  #[cfg_attr(docsrs, doc(cfg(feature = "encryption")))]
506  #[viewit(
507    getter(
508      const,
509      attrs(
510        doc = "Get whether to enforce encryption for incoming gossip. It is used for upshifting from unencrypted to encrypted gossip on a running cluster.",
511        cfg(feature = "encryption"),
512        cfg_attr(docsrs, doc(cfg(feature = "encryption")))
513      ),
514    ),
515    setter(attrs(
516      doc = "Set whether to enforce encryption for incoming gossip. It is used for upshifting from unencrypted to encrypted gossip on a running cluster. (Builder pattern)",
517      cfg(feature = "encryption"),
518      cfg_attr(docsrs, doc(cfg(feature = "encryption")))
519    ),)
520  )]
521  gossip_verify_incoming: bool,
522
523  /// Used to initialize the primary encryption key in a keyring.
524  ///
525  /// The primary encryption key is the only key used to encrypt messages and
526  /// the first key used while attempting to decrypt messages. Providing a
527  /// value for this primary key will enable message-level encryption and
528  /// verification, and automatically install the key onto the keyring.
529  #[cfg(feature = "encryption")]
530  #[cfg_attr(docsrs, doc(cfg(feature = "encryption")))]
531  #[viewit(
532    getter(
533      const,
534      style = "ref",
535      result(converter(fn = "Option::as_ref"), type = "Option<&SecretKey>"),
536      attrs(
537        doc = "Get the primary encryption key in a keyring.",
538        cfg(feature = "encryption"),
539        cfg_attr(docsrs, doc(cfg(feature = "encryption")))
540      ),
541    ),
542    setter(
543      rename = "maybe_primary_key",
544      attrs(
545        doc = "Set the primary encryption key in a keyring. (Builder pattern)",
546        cfg(feature = "encryption"),
547        cfg_attr(docsrs, doc(cfg(feature = "encryption")))
548      ),
549    )
550  )]
551  #[cfg_attr(
552    feature = "serde",
553    serde(skip_serializing_if = "Option::is_none", default)
554  )]
555  primary_key: Option<SecretKey>,
556
557  /// Holds all of the encryption keys used internally.
558  #[viewit(
559    getter(
560      style = "ref",
561      result(converter(fn = "AsRef::as_ref"), type = "&[SecretKey]"),
562      attrs(
563        doc = "Get all of the encryption keys used internally.",
564        cfg(feature = "encryption"),
565        cfg_attr(docsrs, doc(cfg(feature = "encryption")))
566      ),
567    ),
568    setter(attrs(
569      doc = "Set all of the encryption keys used internally. (Builder pattern)",
570      cfg(feature = "encryption"),
571      cfg_attr(docsrs, doc(cfg(feature = "encryption")))
572    ))
573  )]
574  #[cfg(feature = "encryption")]
575  #[cfg_attr(docsrs, doc(cfg(feature = "encryption")))]
576  #[cfg_attr(
577    feature = "serde",
578    serde(skip_serializing_if = "SecretKeys::is_empty", default)
579  )]
580  secret_keys: SecretKeys,
581
582  /// Indicates that should the messages sent through transport will be compressed or not.
583  ///
584  /// Default is `None`.
585  #[cfg(any(
586    feature = "zstd",
587    feature = "lz4",
588    feature = "brotli",
589    feature = "snappy",
590  ))]
591  #[cfg_attr(
592    feature = "serde",
593    serde(skip_serializing_if = "Option::is_none", default)
594  )]
595  #[viewit(
596    getter(
597      const,
598      attrs(
599        doc = "Returns the compress algorithm for the messages sent through transport.",
600        cfg(any(
601          feature = "zstd",
602          feature = "lz4",
603          feature = "brotli",
604          feature = "snappy",
605        )),
606        cfg_attr(
607          docsrs,
608          doc(cfg(any(
609            feature = "zstd",
610            feature = "lz4",
611            feature = "brotli",
612            feature = "snappy",
613          )))
614        )
615      )
616    ),
617    setter(
618      const,
619      rename = "maybe_compress_algo",
620      attrs(
621        doc = "Sets the compress algorithm for the messages sent through transport.",
622        cfg(any(
623          feature = "zstd",
624          feature = "lz4",
625          feature = "brotli",
626          feature = "snappy",
627        )),
628        cfg_attr(
629          docsrs,
630          doc(cfg(any(
631            feature = "zstd",
632            feature = "lz4",
633            feature = "brotli",
634            feature = "snappy",
635          )))
636        )
637      )
638    )
639  )]
640  compress_algo: Option<CompressAlgorithm>,
641
642  /// The metric labels for the memberlist.
643  #[viewit(
644    getter(
645      style = "ref",
646      const,
647      attrs(
648        doc = "Get the metric labels for the memberlist.",
649        cfg(feature = "metrics"),
650        cfg_attr(docsrs, doc(cfg(feature = "metrics")))
651      )
652    ),
653    setter(attrs(
654      doc = "Sets the metric labels for the memberlist.",
655      cfg(feature = "metrics"),
656      cfg_attr(docsrs, doc(cfg(feature = "metrics")))
657    ))
658  )]
659  #[cfg(feature = "metrics")]
660  metric_labels: std::sync::Arc<MetricLabels>,
661}
662
663impl Default for Options {
664  #[inline]
665  fn default() -> Self {
666    Self::lan()
667  }
668}
669
670impl Options {
671  /// Returns a sane set of configurations for Memberlist.
672  /// Sets very conservative
673  /// values that are sane for most LAN environments. The default configuration
674  /// errs on the side of caution, choosing values that are optimized
675  /// for higher convergence at the cost of higher bandwidth usage. Regardless,
676  /// these values are a good starting point when getting started with memberlist.
677  #[inline]
678  pub fn lan() -> Self {
679    Self {
680      label: Label::empty(),
681      timeout: Duration::from_secs(10), // Timeout after 10 seconds
682      indirect_checks: 3,               // Use 3 nodes for the indirect ping
683      retransmit_mult: 4,               // Retransmit a message 4 * log(N+1) nodes
684      suspicion_mult: 4,                // Suspect a node for 4 * log(N+1) * Interval
685      suspicion_max_timeout_mult: 6,    // For 10k nodes this will give a max timeout of 120 seconds
686      push_pull_interval: Duration::from_secs(30), // Low frequency
687      probe_interval: Duration::from_millis(500), // Failure check every second
688      probe_timeout: Duration::from_secs(1), // Reasonable RTT time for LAN
689      disable_reliable_pings: false,    // TCP pings are safe, even with mixed versions
690      awareness_max_multiplier: 8,      // Probe interval backs off to 8 seconds
691      gossip_interval: Duration::from_millis(200), // Gossip every 200ms
692      gossip_nodes: 3,                  // Gossip to 3 nodes
693      gossip_to_the_dead_time: Duration::from_secs(30), // same as push/pull
694      delegate_version: DelegateVersion::V1,
695      protocol_version: ProtocolVersion::V1,
696      handoff_queue_depth: 1024,
697      dead_node_reclaim_time: Duration::ZERO,
698      queue_check_interval: Duration::from_secs(30),
699      skip_inbound_label_check: false,
700      #[cfg(any(
701        feature = "crc32",
702        feature = "xxhash32",
703        feature = "xxhash64",
704        feature = "xxhash3",
705        feature = "murmur3"
706      ))]
707      checksum_algo: None,
708      #[cfg(any(
709        feature = "encryption",
710        feature = "lz4",
711        feature = "zstd",
712        feature = "brotli",
713        feature = "snappy",
714      ))]
715      offload_size: 1024 * 1024,
716      #[cfg(feature = "encryption")]
717      encryption_algo: None,
718      #[cfg(feature = "encryption")]
719      gossip_verify_incoming: false,
720      #[cfg(feature = "encryption")]
721      gossip_verify_outgoing: false,
722      #[cfg(feature = "encryption")]
723      primary_key: None,
724      #[cfg(feature = "encryption")]
725      secret_keys: SecretKeys::new(),
726      #[cfg(any(
727        feature = "zstd",
728        feature = "lz4",
729        feature = "brotli",
730        feature = "snappy",
731      ))]
732      compress_algo: None,
733      #[cfg(feature = "metrics")]
734      metric_labels: std::sync::Arc::new(MetricLabels::new()),
735    }
736  }
737
738  /// Returns a configuration
739  /// that is optimized for most WAN environments. The default configuration is
740  /// still very conservative and errs on the side of caution.
741  #[inline]
742  pub fn wan() -> Self {
743    Self::lan()
744      .with_timeout(Duration::from_secs(30))
745      .with_suspicion_mult(6)
746      .with_push_pull_interval(Duration::from_secs(60))
747      .with_probe_timeout(Duration::from_secs(3))
748      .with_probe_interval(Duration::from_secs(5))
749      .with_gossip_nodes(4)
750      .with_gossip_interval(Duration::from_millis(500))
751      .with_gossip_to_the_dead_time(Duration::from_secs(60))
752  }
753
754  /// Returns a configuration
755  /// that is optimized for a local loopback environments. The default configuration is
756  /// still very conservative and errs on the side of caution.
757  #[inline]
758  pub fn local() -> Self {
759    Self::lan()
760      .with_timeout(Duration::from_secs(1))
761      .with_indirect_checks(1)
762      .with_retransmit_mult(2)
763      .with_suspicion_mult(3)
764      .with_push_pull_interval(Duration::from_secs(15))
765      .with_probe_timeout(Duration::from_millis(200))
766      .with_probe_interval(Duration::from_secs(1))
767      .with_gossip_interval(Duration::from_millis(100))
768      .with_gossip_to_the_dead_time(Duration::from_secs(15))
769  }
770
771  /// Set the compression algorithm for the messages
772  /// sent through transport.
773  #[cfg(any(
774    feature = "zstd",
775    feature = "lz4",
776    feature = "brotli",
777    feature = "snappy",
778  ))]
779  #[cfg_attr(
780    docsrs,
781    doc(cfg(any(
782      feature = "zstd",
783      feature = "lz4",
784      feature = "brotli",
785      feature = "snappy",
786    )))
787  )]
788  #[inline]
789  pub fn with_compress_algo(mut self, compress_algo: CompressAlgorithm) -> Self {
790    self.compress_algo = Some(compress_algo);
791    self
792  }
793
794  /// Set the checksum algorithm for the packets
795  /// sent through transport.
796  #[cfg(any(
797    feature = "crc32",
798    feature = "xxhash32",
799    feature = "xxhash64",
800    feature = "xxhash3",
801    feature = "murmur3",
802  ))]
803  #[cfg_attr(
804    docsrs,
805    doc(cfg(any(
806      feature = "crc32",
807      feature = "xxhash32",
808      feature = "xxhash64",
809      feature = "xxhash3",
810      feature = "murmur3",
811    )))
812  )]
813  #[inline]
814  pub fn with_checksum_algo(mut self, checksum_algo: ChecksumAlgorithm) -> Self {
815    self.checksum_algo = Some(checksum_algo);
816    self
817  }
818
819  /// Set the encryption algorithm for the messages
820  /// sent through transport.
821  #[cfg(feature = "encryption")]
822  #[cfg_attr(docsrs, doc(cfg(feature = "encryption")))]
823  #[inline]
824  pub fn with_encryption_algo(mut self, encryption_algo: EncryptionAlgorithm) -> Self {
825    self.encryption_algo = Some(encryption_algo);
826    self
827  }
828
829  /// Set the primary encryption key in a keyring.
830  #[cfg(feature = "encryption")]
831  #[cfg_attr(docsrs, doc(cfg(feature = "encryption")))]
832  #[inline]
833  pub fn with_primary_key(mut self, primary_key: SecretKey) -> Self {
834    self.primary_key = Some(primary_key);
835    self
836  }
837}
838
839#[cfg(test)]
840mod tests {
841  use super::*;
842
843  #[test]
844  fn test_constructor() {
845    let _ = Options::wan();
846    let _ = Options::lan();
847    let _ = Options::local();
848  }
849}