1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
use crate::login::{LoginCredentials, StaticLoginCredentials};
#[cfg(feature = "metrics-collection")]
use std::borrow::Cow;
use std::sync::Arc;
use std::time::Duration;
use tokio::sync::Semaphore;

/// Configures settings for a `TwitchIRCClient`.
#[derive(Debug)]
pub struct ClientConfig<L: LoginCredentials> {
    /// Gets a set of credentials every time the client needs to log in on a new connection.
    /// See [`LoginCredentials`](../login/trait.LoginCredentials.html) for details.
    pub login_credentials: L,

    /// A new connection will automatically be created if a channel is joined and all
    /// currently established connections have joined at least this many channels.
    pub max_channels_per_connection: usize,

    /// A new connection will automatically be created if any message is to be sent
    /// and all currently established connections have recently sent more than this many
    /// messages (time interval is defined by `max_waiting_messages_duration_window`)
    pub max_waiting_messages_per_connection: usize,

    /// We assume messages to be "waiting" for this amount of time after sending them out, e.g.
    /// typically 100 or 150 milliseconds (purely a value that has been measured/observed,
    /// not documented or fixed in any way)
    pub time_per_message: Duration,

    /// rate-limits the opening of new connections. By default this is constructed with 1 permit
    /// only, which means connections cannot be opened in parallel. If this is set to more than 1
    /// permit, then that many connections can be opened in parallel.
    ///
    /// This is designed to be wrapped in an Arc to allow it to be shared between multiple
    /// TwitchIRCClient instances.
    pub connection_rate_limiter: Arc<Semaphore>,

    /// Allow a new connection to be made after this period has elapsed. By default this is set
    /// to 2 seconds, and combined with the permits=1 of the semaphore, allows one connection
    /// to be made every 2 seconds.
    ///
    /// More specifically, after taking the permit from the semaphore, the permit will be put
    /// back after this period has elapsed.
    pub new_connection_every: Duration,

    /// Imposes a general timeout for new connections. This is in place in addition to possible
    /// operating system timeouts (E.g. for new TCP connections), since additional "connect" work
    /// takes place after the TCP connection is opened, e.g. to set up TLS or perform a WebSocket
    /// handshake. Default value: 20 seconds.
    pub connect_timeout: Duration,

    /// Set this to `None` to disable metrics collection for this client.
    ///
    /// If this is set to `Some(value)`, then metrics are collected from this client using
    /// the `metrics` crate under the `twitch_irc_` prefix. Because multiple clients
    /// may coexist at the same time, this string should be picked to be unique in your application.
    /// The client will label all metrics it publishes using this identifier string.
    /// The specific client is then identified using the `client` label on all metrics below.
    ///
    /// Currently exported metrics:
    /// * `twitch_irc_messages_received` with label `command` counts all incoming messages. (Counter)
    ///
    /// * `twitch_irc_messages_sent` counts messages sent out, with a `command` label. (Counter)
    ///
    /// * `twitch_irc_channels` with `type=allocated/confirmed` counts how many channels
    ///   you are joined to (Gauge). Allocated channels are joins that passed through the `TwitchIRCClient`
    ///   but may be waiting e.g. for the connection to finish connecting. Once a
    ///   confirmation response is received by Twitch that the channel was joined successfully,
    ///   that channel is additionally `confirmed`.
    ///
    /// * `twitch_irc_connections` counts how many connections this client has in use (Gauge).
    ///    The label `state=initializing/open` identifies how many connections are
    ///    in the process of connecting (`initializing`) vs how many connections are already established (`open`).
    ///
    /// * `twitch_irc_reconnects` counts every time a connection fails (Counter). Note however, depending
    ///   on conditions e.g. how many channels were joined on that channel, the connection may not
    ///   actually have been reconnected (despite the name `twitch_irc_reconnects`).
    ///   If other connections have enough capacity left to join the channels from the failed
    ///   connection, then no new connection will be made.
    #[cfg(feature = "metrics-collection")]
    pub metrics_identifier: Option<Cow<'static, str>>,
}

impl<L: LoginCredentials> ClientConfig<L> {
    /// Create a new configuration from the given login credentials, with all other configuration
    /// options being default.
    pub fn new_simple(login_credentials: L) -> ClientConfig<L> {
        ClientConfig {
            login_credentials,
            max_channels_per_connection: 90,

            max_waiting_messages_per_connection: 5,
            time_per_message: Duration::from_millis(150),

            // 1 connection every 2 seconds seems to work well
            connection_rate_limiter: Arc::new(Semaphore::new(1)),
            new_connection_every: Duration::from_secs(2),
            connect_timeout: Duration::from_secs(20),

            #[cfg(feature = "metrics-collection")]
            metrics_identifier: None,
        }
    }
}

impl Default for ClientConfig<StaticLoginCredentials> {
    fn default() -> ClientConfig<StaticLoginCredentials> {
        ClientConfig::new_simple(StaticLoginCredentials::anonymous())
    }
}