1#[cfg(feature = "starttls")]
8use crate::tokio_xmpp::connect::{DnsConfig, StartTlsServerConnector};
9
10use crate::{
11 Agent, ClientFeature, ClientType, Config, RoomNick,
12 jid::{BareJid, Jid, ResourceRef},
13 parsers::{
14 disco::{DiscoInfoResult, Feature, Identity},
15 ns,
16 },
17 tokio_xmpp::{Client as TokioXmppClient, connect::ServerConnector, xmlstream::Timeouts},
18};
19
20pub struct ClientBuilder<'a, C: ServerConnector> {
21 jid: BareJid,
22 password: &'a str,
23 server_connector: C,
24 config: Config,
25 features: Vec<ClientFeature>,
26 resource: Option<String>,
27 timeouts: Timeouts,
28}
29
30#[cfg(feature = "starttls")]
31impl ClientBuilder<'_, StartTlsServerConnector> {
32 pub fn new<'a>(jid: BareJid, password: &'a str) -> ClientBuilder<'a, StartTlsServerConnector> {
33 Self::new_with_connector(
34 jid.clone(),
35 password,
36 StartTlsServerConnector(DnsConfig::srv_default_client(jid.domain())),
37 )
38 }
39}
40
41impl<C: ServerConnector> ClientBuilder<'_, C> {
42 pub fn new_with_connector<'a>(
43 jid: BareJid,
44 password: &'a str,
45 server_connector: C,
46 ) -> ClientBuilder<'a, C> {
47 ClientBuilder {
48 jid,
49 password,
50 server_connector,
51 config: Config::default(),
52 features: vec![],
53 resource: None,
54 timeouts: Timeouts::default(),
55 }
56 }
57
58 pub fn set_resource(mut self, resource: &str) -> Self {
60 self.resource = Some(resource.to_string());
61 self
62 }
63
64 pub fn set_config(mut self, config: Config) -> Self {
65 self.config = config;
66 self
67 }
68
69 pub fn set_client(mut self, type_: ClientType, name: &str) -> Self {
70 self.config.disco = (type_, String::from(name));
71 self
72 }
73
74 pub fn set_website(mut self, url: &str) -> Self {
75 self.config.website = String::from(url);
76 self
77 }
78
79 pub fn set_default_nick(mut self, nick: impl AsRef<ResourceRef>) -> Self {
80 self.config.default_nick = RoomNick::from_resource_ref(nick.as_ref());
81 self
82 }
83
84 pub fn set_lang(mut self, lang: Vec<String>) -> Self {
85 self.config.lang = lang;
86 self
87 }
88
89 pub fn set_timeouts(mut self, timeouts: Timeouts) -> Self {
94 self.timeouts = timeouts;
95 self
96 }
97
98 pub fn enable_feature(mut self, feature: ClientFeature) -> Self {
99 self.features.push(feature);
100 self
101 }
102
103 fn make_disco(&self) -> DiscoInfoResult {
104 let identities = vec![Identity::new(
105 "client",
106 self.config.disco.0.to_string(),
107 "en",
108 self.config.disco.1.to_string(),
109 )];
110 let mut features = vec![Feature::new(ns::DISCO_INFO)];
111 #[cfg(feature = "avatars")]
112 {
113 if self.features.contains(&ClientFeature::Avatars) {
114 features.push(Feature::new(format!("{}+notify", ns::AVATAR_METADATA)));
115 }
116 }
117 if self.features.contains(&ClientFeature::JoinRooms) {
118 features.push(Feature::new(format!("{}+notify", ns::BOOKMARKS2)));
119 }
120 DiscoInfoResult {
121 node: None,
122 identities,
123 features,
124 extensions: vec![],
125 }
126 }
127
128 pub fn build(self) -> Agent {
129 let jid: Jid = if let Some(resource) = &self.resource {
130 self.jid.with_resource_str(resource).unwrap().into()
131 } else {
132 self.jid.clone().into()
133 };
134
135 let client = TokioXmppClient::new_with_connector(
136 jid,
137 self.password,
138 self.server_connector.clone(),
139 self.timeouts,
140 );
141 self.build_impl(client)
142 }
143
144 pub(crate) fn build_impl(self, client: TokioXmppClient) -> Agent {
146 let disco = self.make_disco();
147
148 Agent::new(client, self.config, disco)
149 }
150}