1use std::collections::HashMap;
2
3use url::Url;
4
5#[allow(unused_imports)]
7use crate::config::{
8 ForwarderBuilder,
9 TunnelBuilder,
10};
11use crate::{
12 config::common::{
13 default_forwards_to,
14 CommonOpts,
15 TunnelConfig,
16 },
17 internals::proto::{
18 BindExtra,
19 BindOpts,
20 },
21 tunnel::LabeledTunnel,
22 Session,
23};
24
25#[derive(Default, Clone)]
27struct LabeledOptions {
28 pub(crate) common_opts: CommonOpts,
29 pub(crate) labels: HashMap<String, String>,
30}
31
32impl TunnelConfig for LabeledOptions {
33 fn forwards_to(&self) -> String {
34 self.common_opts
35 .forwards_to
36 .clone()
37 .unwrap_or(default_forwards_to().into())
38 }
39
40 fn forwards_proto(&self) -> String {
41 self.common_opts.forwards_proto.clone().unwrap_or_default()
42 }
43
44 fn verify_upstream_tls(&self) -> bool {
45 self.common_opts.verify_upstream_tls()
46 }
47
48 fn extra(&self) -> BindExtra {
49 BindExtra {
50 token: Default::default(),
51 ip_policy_ref: Default::default(),
52 metadata: self.common_opts.metadata.clone().unwrap_or_default(),
53 bindings: Vec::new(),
54 pooling_enabled: self.common_opts.pooling_enabled.unwrap_or(false),
55 }
56 }
57 fn proto(&self) -> String {
58 "".into()
59 }
60 fn opts(&self) -> Option<BindOpts> {
61 None
62 }
63 fn labels(&self) -> HashMap<String, String> {
64 self.labels.clone()
65 }
66}
67
68impl_builder! {
69 LabeledTunnelBuilder, LabeledOptions, LabeledTunnel, edge
71}
72
73impl LabeledTunnelBuilder {
74 pub fn metadata(&mut self, metadata: impl Into<String>) -> &mut Self {
79 self.options.common_opts.metadata = Some(metadata.into());
80 self
81 }
82
83 pub fn label(&mut self, label: impl Into<String>, value: impl Into<String>) -> &mut Self {
87 self.options.labels.insert(label.into(), value.into());
88 self
89 }
90
91 pub fn forwards_to(&mut self, forwards_to: impl Into<String>) -> &mut Self {
100 self.options.common_opts.forwards_to = forwards_to.into().into();
101 self
102 }
103
104 pub fn app_protocol(&mut self, app_protocol: impl Into<String>) -> &mut Self {
106 self.options.common_opts.forwards_proto = Some(app_protocol.into());
107 self
108 }
109
110 pub fn verify_upstream_tls(&mut self, verify_upstream_tls: bool) -> &mut Self {
112 self.options
113 .common_opts
114 .set_verify_upstream_tls(verify_upstream_tls);
115 self
116 }
117
118 pub(crate) async fn for_forwarding_to(&mut self, to_url: &Url) -> &mut Self {
119 self.options.common_opts.for_forwarding_to(to_url);
120 self
121 }
122}
123
124#[cfg(test)]
125mod test {
126 use super::*;
127
128 const METADATA: &str = "testmeta";
129 const LABEL_KEY: &str = "edge";
130 const LABEL_VAL: &str = "edghts_2IC6RJ6CQnuh7waciWyaGKc50Nt";
131
132 #[test]
133 fn test_interface_to_proto() {
134 tunnel_test(
137 &LabeledTunnelBuilder {
138 session: None,
139 options: Default::default(),
140 }
141 .metadata(METADATA)
142 .label(LABEL_KEY, LABEL_VAL)
143 .options,
144 );
145 }
146
147 fn tunnel_test<C>(tunnel_cfg: &C)
148 where
149 C: TunnelConfig,
150 {
151 assert_eq!(default_forwards_to(), tunnel_cfg.forwards_to());
152
153 let extra = tunnel_cfg.extra();
154 assert_eq!(String::default(), *extra.token);
155 assert_eq!(METADATA, extra.metadata);
156 assert_eq!(String::default(), extra.ip_policy_ref);
157
158 assert_eq!("", tunnel_cfg.proto());
159
160 assert!(tunnel_cfg.opts().is_none());
161
162 let mut labels: HashMap<String, String> = HashMap::new();
163 labels.insert(LABEL_KEY.into(), LABEL_VAL.into());
164 assert_eq!(labels, tunnel_cfg.labels());
165 }
166}