dfx/session/settings/
setting.rs

1#![allow(dead_code)]
2use std::{
3    net::SocketAddr,
4    path::PathBuf,
5};
6
7use derive_builder::Builder;
8
9use dfx_base::fields::converters::datetime::DateTimeFormat;
10use native_tls::{TlsAcceptor, TlsConnector};
11use crate::{
12    connection::SocketSettings,
13    session::SessionSchedule,
14};
15
16use dfx_base::session_id::SessionId;
17
18use super::{SessionSettingsError, SettingOption};
19
20#[derive(Debug, Clone, PartialEq, Eq)]
21pub(crate) enum ConnectionType {
22    Acceptor,
23    Initiator,
24}
25
26impl TryFrom<&str> for ConnectionType {
27    type Error = SessionSettingsError;
28
29    fn try_from(value: &str) -> Result<Self, Self::Error> {
30        match value {
31            "initiator" => Ok(Self::Initiator),
32            "acceptor" => Ok(Self::Acceptor),
33            e => Err(SessionSettingsError::InvalidValue {
34                setting: SettingOption::ConnectionType.into(),
35                value: e.into(),
36            }),
37        }
38    }
39}
40
41#[derive(Debug, Clone, PartialEq, Eq)]
42pub(crate) enum SettingsConnection {
43    Acceptor {
44        is_dynamic: bool,
45        session_qualifier: Option<String>,
46        accept_addr: SocketAddr,
47        logon_timeout: u32,
48        logout_timeout: u32,
49    },
50    Initiator {
51        connect_addr: SocketAddr,
52
53        // reconnect options
54        reconnect_interval: u32,
55        heart_bt_int: u32,
56        logon_timeout: u32,
57        logout_timeout: u32,
58    },
59}
60
61impl SettingsConnection {
62    /// Returns `true` if the settings connection is [`Initiator`].
63    ///
64    /// [`Initiator`]: SettingsConnection::Initiator
65    #[must_use]
66    pub(crate) fn is_initiator(&self) -> bool {
67        matches!(self, Self::Initiator { .. })
68    }
69
70    /// Returns `true` if the settings connection is [`Acceptor`].
71    ///
72    /// [`Acceptor`]: SettingsConnection::Acceptor
73    #[must_use]
74    pub(crate) fn is_acceptor(&self) -> bool {
75        matches!(self, Self::Acceptor { .. })
76    }
77
78    pub(crate) fn socket_addr(&self) -> &SocketAddr {
79        match self {
80            SettingsConnection::Acceptor { accept_addr, .. } => accept_addr,
81            SettingsConnection::Initiator { connect_addr, .. } => connect_addr,
82        }
83    }
84
85    pub(crate) fn heart_bt_int(&self) -> Option<u32> {
86        match self {
87            SettingsConnection::Acceptor { .. } => None,
88            SettingsConnection::Initiator { heart_bt_int, .. } => Some(*heart_bt_int),
89        }
90    }
91
92    pub(crate) fn logon_timeout(&self) -> u32 {
93        match self {
94            SettingsConnection::Acceptor { logon_timeout, .. } => *logon_timeout,
95            SettingsConnection::Initiator { logon_timeout, .. } => *logon_timeout,
96        }
97    }
98
99    pub(crate) fn logout_timeout(&self) -> u32 {
100        match self {
101            SettingsConnection::Acceptor { logout_timeout, .. } => *logout_timeout,
102            SettingsConnection::Initiator { logout_timeout, .. } => *logout_timeout,
103        }
104    }
105}
106
107#[derive(Builder, Clone, Debug, PartialEq, Eq)]
108pub(crate) struct SocketOptions {
109    no_delay: bool,
110    send_buffer_size: usize,
111    receive_buffer_size: usize,
112    send_timeout: u64,
113    receive_timeout: u64,
114}
115
116impl SocketOptions {
117
118    pub(crate) fn builder() -> SocketOptionsBuilder {
119        SocketOptionsBuilder::create_empty()
120    }
121
122    pub(crate) fn no_delay(&self) -> bool {
123        self.no_delay
124    }
125
126    // pub(crate) fn send_buffer_size(&self) -> usize {
127    //     self.send_buffer_size
128    // }
129
130    // pub(crate) fn receive_buffer_size(&self) -> usize {
131    //     self.receive_buffer_size
132    // }
133
134    pub(crate) fn send_timeout(&self) -> u64 {
135        self.send_timeout
136    }
137
138    pub(crate) fn receive_timeout(&self) -> u64 {
139        self.receive_timeout
140    }
141}
142
143#[derive(Clone)]
144pub(crate) enum SslOptions {
145    Acceptor { acceptor: TlsAcceptor },
146    Initiator { initiator: TlsConnector, domain: String }
147}
148
149impl std::fmt::Debug for SslOptions {
150    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
151        match self {
152            Self::Acceptor { acceptor: _ } => f.debug_struct("Acceptor").finish(),
153            Self::Initiator { initiator, domain } => f.debug_struct("Initiator").field("initiator", initiator).field("domain", domain).finish(),
154        }
155    }
156}
157
158#[derive(Builder, Clone, Debug, PartialEq, Eq)]
159pub struct LoggingOptions {
160    file_log_path: Option<String>,
161    debug_file_log_path: Option<String>,
162}
163
164impl LoggingOptions {
165    pub(crate) fn builder() -> LoggingOptionsBuilder {
166        LoggingOptionsBuilder::create_empty()
167    }
168
169    pub(crate) fn file_log_path(&self) -> Option<&String> {
170        self.file_log_path.as_ref()
171    }
172
173    pub(crate) fn debug_file_log_path(&self) -> Option<&String> {
174        self.debug_file_log_path.as_ref()
175    }
176}
177
178#[derive(Clone, Debug, PartialEq, Eq)]
179pub(crate) enum Persistence {
180    FileStore { path: PathBuf },
181    Memory,
182    None,
183}
184
185#[derive(Builder, Clone, Debug, PartialEq, Eq)]
186pub(crate) struct ValidationOptions {
187    milliseconds_in_time_stamp: bool,
188    refresh_on_logon: bool,
189    reset_on_logon: bool,
190    reset_on_logout: bool,
191    reset_on_disconnect: bool,
192    send_redundant_resend_requests: bool,
193    resend_session_level_rejects: bool,
194    time_stamp_precision: DateTimeFormat,
195    enable_last_msg_seq_num_processed: bool,
196    max_messages_in_resend_request: u32,
197    send_logout_before_disconnect_from_timeout: bool,
198    ignore_poss_dup_resend_requests: bool,
199    requires_orig_sending_time: bool,
200
201    // validation options
202    use_data_dictionary: bool,
203    data_dictionary: Option<String>,
204    transport_data_dictionary: Option<String>,
205    app_data_dictionary: Option<String>,
206    validate_fields_out_of_order: bool,
207    validate_fields_have_values: bool,
208    validate_user_defined_fields: bool,
209    validate_length_and_checksum: bool,
210    allow_unknown_msg_fields: bool,
211    check_latency: bool,
212    max_latency: u32,
213}
214
215impl ValidationOptions {
216    pub(crate) fn builder() -> ValidationOptionsBuilder {
217        ValidationOptionsBuilder::create_empty()
218    }
219
220    pub(crate) fn milliseconds_in_time_stamp(&self) -> bool {
221        self.milliseconds_in_time_stamp
222    }
223
224    pub(crate) fn refresh_on_logon(&self) -> bool {
225        self.refresh_on_logon
226    }
227
228    pub(crate) fn reset_on_logon(&self) -> bool {
229        self.reset_on_logon
230    }
231
232    pub(crate) fn reset_on_logout(&self) -> bool {
233        self.reset_on_logout
234    }
235
236    pub(crate) fn reset_on_disconnect(&self) -> bool {
237        self.reset_on_disconnect
238    }
239
240    pub(crate) fn send_redundant_resend_requests(&self) -> bool {
241        self.send_redundant_resend_requests
242    }
243
244    pub(crate) fn resend_session_level_rejects(&self) -> bool {
245        self.resend_session_level_rejects
246    }
247
248    pub(crate) fn time_stamp_precision(&self) -> &DateTimeFormat {
249        &self.time_stamp_precision
250    }
251
252    pub(crate) fn enable_last_msg_seq_num_processed(&self) -> bool {
253        self.enable_last_msg_seq_num_processed
254    }
255
256    pub(crate) fn max_messages_in_resend_request(&self) -> u32 {
257        self.max_messages_in_resend_request
258    }
259
260    pub(crate) fn send_logout_before_disconnect_from_timeout(&self) -> bool {
261        self.send_logout_before_disconnect_from_timeout
262    }
263
264    pub(crate) fn ignore_poss_dup_resend_requests(&self) -> bool {
265        self.ignore_poss_dup_resend_requests
266    }
267
268    pub(crate) fn requires_orig_sending_time(&self) -> bool {
269        self.requires_orig_sending_time
270    }
271
272    pub(crate) fn use_data_dictionary(&self) -> bool {
273        self.use_data_dictionary
274    }
275
276    pub(crate) fn data_dictionary(&self) -> Option<&String> {
277        self.data_dictionary.as_ref()
278    }
279
280    pub(crate) fn transport_data_dictionary(&self) -> Option<&String> {
281        self.transport_data_dictionary.as_ref()
282    }
283
284    pub(crate) fn app_data_dictionary(&self) -> Option<&String> {
285        self.app_data_dictionary.as_ref()
286    }
287
288    pub(crate) fn validate_fields_out_of_order(&self) -> bool {
289        self.validate_fields_out_of_order
290    }
291
292    pub(crate) fn validate_fields_have_values(&self) -> bool {
293        self.validate_fields_have_values
294    }
295
296    pub(crate) fn validate_user_defined_fields(&self) -> bool {
297        self.validate_user_defined_fields
298    }
299
300    pub(crate) fn validate_length_and_checksum(&self) -> bool {
301        self.validate_length_and_checksum
302    }
303
304    pub(crate) fn allow_unknown_msg_fields(&self) -> bool {
305        self.allow_unknown_msg_fields
306    }
307
308    pub(crate) fn check_latency(&self) -> bool {
309        self.check_latency
310    }
311
312    pub(crate) fn max_latency(&self) -> u32 {
313        self.max_latency
314    }
315}
316
317#[derive(Builder, Clone, Debug)]
318pub(crate) struct SessionSetting {
319    session_id: SessionId,
320    connection: SettingsConnection,
321    socket_options: SocketOptions,
322    ssl_options: Option<SslOptions>,
323    logging: LoggingOptions,
324    persistence: Persistence,
325    default_appl_ver_id: Option<String>,
326    schedule: SessionSchedule,
327    validation_options: ValidationOptions,
328}
329
330impl SessionSetting {
331    pub(crate) fn builder() -> SessionSettingBuilder {
332        SessionSettingBuilder::create_empty()
333    }
334
335    pub(crate) fn session_id(&self) -> &SessionId {
336        &self.session_id
337    }
338
339    pub(crate) fn connection(&self) -> &SettingsConnection {
340        &self.connection
341    }
342
343    pub(crate) fn socket_options(&self) -> &SocketOptions {
344        &self.socket_options
345    }
346
347    pub(crate) fn ssl_options(&self) -> Option<&SslOptions> {
348        self.ssl_options.as_ref()
349    }
350
351    pub(crate) fn logging(&self) -> &LoggingOptions {
352        &self.logging
353    }
354
355    pub(crate) fn persistence(&self) -> &Persistence {
356        &self.persistence
357    }
358
359    pub(crate) fn default_appl_ver_id(&self) -> Option<&String> {
360        self.default_appl_ver_id.as_ref()
361    }
362
363    pub(crate) fn schedule(&self) -> &SessionSchedule {
364        &self.schedule
365    }
366
367    pub(crate) fn validation_options(&self) -> &ValidationOptions {
368        &self.validation_options
369    }
370}
371
372#[derive(Debug, Clone, PartialEq, Eq)]
373pub(crate) struct SessionSettingOld {
374    pub(crate) connection_type: ConnectionType,
375    pub(crate) is_dynamic: bool,
376
377    pub(crate) begin_string: String,
378    pub(crate) sender_comp_id: String,
379    pub(crate) sender_sub_id: Option<String>,
380    pub(crate) sender_location_id: Option<String>,
381    pub(crate) target_comp_id: String,
382    pub(crate) target_sub_id: Option<String>,
383    pub(crate) target_location_id: Option<String>,
384
385    pub(crate) session_qualifier: Option<String>,
386    pub(crate) default_appl_ver_id: Option<String>,
387
388    pub(crate) non_stop_session: bool,
389    pub(crate) use_local_time: bool,
390    pub(crate) time_zone: Option<String>,
391    pub(crate) start_day: Option<String>,
392    pub(crate) end_day: Option<String>,
393    pub(crate) start_time: Option<String>,
394    pub(crate) end_time: Option<String>,
395
396    pub(crate) milliseconds_in_time_stamp: bool,
397    pub(crate) refresh_on_logon: bool,
398    pub(crate) reset_on_logon: bool,
399    pub(crate) reset_on_logout: bool,
400    pub(crate) reset_on_disconnect: bool,
401    pub(crate) send_redundant_resend_requests: bool,
402    pub(crate) resend_session_level_rejects: bool,
403    pub(crate) time_stamp_precision: Option<String>,
404    pub(crate) enable_last_msg_seq_num_processed: bool,
405    pub(crate) max_messages_in_resend_request: u32,
406    pub(crate) send_logout_before_disconnect_from_timeout: bool,
407    pub(crate) ignore_poss_dup_resend_requests: bool,
408    pub(crate) requires_orig_sending_time: bool,
409
410    // validation options
411    pub(crate) use_data_dictionary: bool,
412    pub(crate) data_dictionary: Option<String>,
413    pub(crate) transport_data_dictionary: Option<String>,
414    pub(crate) app_data_dictionary: Option<String>,
415    pub(crate) validate_fields_out_of_order: bool,
416    pub(crate) validate_fields_have_values: bool,
417    pub(crate) validate_user_defined_fields: bool,
418    pub(crate) validate_length_and_checksum: bool,
419    pub(crate) allow_unknown_msg_fields: bool,
420    pub(crate) check_latency: bool,
421    pub(crate) max_latency: u32,
422
423    pub(crate) reconnect_interval: u32,
424    pub(crate) heart_bt_int: Option<u32>, //initiator only
425    pub(crate) logon_timeout: u32,
426    pub(crate) logout_timeout: u32,
427
428    // TODO move this into ConnectionType
429    // initiator options
430    pub(crate) socket_connect_host: Option<String>,
431    pub(crate) socket_connect_port: Option<u32>,
432    // TODO
433    // pub(crate) socket_connect_hosts: Option<String>, // initiator<n> failover
434    // pub(crate) socket_connect_ports: Option<String>, // initiator<n> failover
435
436    // acceptor options
437    // TODO move this into ConnectionType
438    pub(crate) socket_accept_host: Option<String>,
439    pub(crate) socket_accept_port: Option<u32>,
440
441    // storage
442    pub(crate) persist_messages: bool,
443    // store path
444    pub(crate) file_store_path: Option<String>,
445
446    // logging
447    pub(crate) file_log_path: Option<String>,
448    pub(crate) debug_file_log_path: Option<String>,
449
450    // Socket options
451    pub(crate) socket_nodelay: bool,
452    pub(crate) socket_send_buffer_size: Option<String>,
453    pub(crate) socket_receive_buffer_size: Option<String>,
454    pub(crate) socket_send_timeout: Option<String>,
455    pub(crate) socket_receive_timeout: Option<String>,
456
457    // SSL options
458    pub(crate) ssl_enable: bool,
459    pub(crate) ssl_server_name: Option<String>,
460    pub(crate) ssl_protocols: Option<String>,
461    pub(crate) ssl_validate_certificates: Option<String>,
462    pub(crate) ssl_check_certificate_revocation: Option<String>,
463    pub(crate) ssl_certificate: Option<String>,
464    pub(crate) ssl_certificate_password: Option<String>,
465    pub(crate) ssl_require_client_certificate: Option<String>,
466    pub(crate) ssl_ca_certificate: Option<String>,
467}
468
469impl SessionSetting {
470    pub(crate) fn score(&self, session_id: &SessionId) -> u16 {
471        let mut score = 0;
472        score += match self.session_id().sender_comp_id() {
473            "*" => 6,
474            value if value == session_id.sender_comp_id() => 7,
475            _ => 0,
476        };
477        score += match self.session_id().sender_sub_id() {
478            value if value == session_id.sender_sub_id() => 1,
479            _ => 0,
480        };
481        score += match self.session_id().sender_location_id() {
482            value if value == session_id.sender_location_id() => 1,
483            _ => 0,
484        };
485        score += match self.session_id().target_comp_id() {
486            "*" => 6,
487            value if value == session_id.target_comp_id() => 7,
488            _ => 0,
489        };
490        score += match self.session_id().target_sub_id() {
491            value if value == session_id.target_sub_id() => 1,
492            _ => 0,
493        };
494        score += match self.session_id().target_location_id() {
495            value if value == session_id.target_location_id() => 1,
496            _ => 0,
497        };
498        if score < 12 {
499            0
500        } else {
501            score
502        }
503    }
504
505    pub(crate) fn is_dynamic(&self) -> bool {
506        match self.connection {
507            SettingsConnection::Acceptor { is_dynamic, .. } => {
508                is_dynamic
509                    && (self.session_id.sender_comp_id() == "*"
510                        || self.session_id.target_comp_id() == "*")
511            }
512            SettingsConnection::Initiator { .. } => false,
513        }
514    }
515
516    pub(crate) fn socket_settings(&self) -> SocketSettings {
517        SocketSettings::new(self.connection.socket_addr().clone(), self.socket_options.clone(), self.ssl_options.clone())
518    }
519
520    pub(crate) fn reconnect_interval(&self) -> Option<u32> {
521        match self.connection {
522            SettingsConnection::Acceptor { .. } => None,
523            SettingsConnection::Initiator { reconnect_interval, .. } => Some(reconnect_interval),
524        }
525    }
526
527    pub(crate) fn accepts(&self, session_id: &SessionId) -> bool {
528        if self.is_dynamic() {
529            let sender_comp_ok = match self.session_id.sender_comp_id() {
530                "*" => true,
531                s => s == session_id.sender_comp_id(),
532            };
533            let target_comp_ok = match self.session_id.target_comp_id() {
534                "*" => true,
535                s => s == session_id.target_comp_id(),
536            };
537            sender_comp_ok && target_comp_ok
538        } else {
539            self.session_id() == session_id
540        }
541    }
542}