ndaxrs 0.1.0

Rust client library for the NDAX cryptocurrency exchange API
Documentation
// Copyright (C) 2026 ndaxrs Art Morozov
// SPDX-License-Identifier: GPL-3.0-only

//! WebSocket configuration types.

use crate::config::NdaxCredentials;

/// Default NDAX WebSocket gateway URL.
pub const DEFAULT_WS_GATEWAY_URL: &str = "wss://api.ndax.io:8443/WSGateway/";

/// Configuration for private WebSocket feeds.
#[derive(Debug, Clone)]
pub struct PrivateConfig {
  /// The account ID for private feeds.
  pub account_id:               u64,
  /// Whether to subscribe to account events (positions, orders, trades).
  pub subscribe_account_events: bool,
}

impl PrivateConfig {
  /// Create a new private configuration.
  pub fn new(account_id: u64) -> Self {
    Self {
      account_id,
      subscribe_account_events: false,
    }
  }

  /// Enable account events subscription.
  pub fn with_account_events(mut self) -> Self {
    self.subscribe_account_events = true;
    self
  }
}

/// Configuration for the NDAX WebSocket connection.
#[derive(Debug, Clone)]
pub struct NdaxWsConfig {
  /// Optional credentials for authenticated connections.
  pub credentials:      Option<NdaxCredentials>,
  /// Instrument IDs to subscribe to Level1 data (best bid/ask).
  pub subscribe_level1: Vec<u64>,
  /// Instrument IDs to subscribe to Level2 data (order book).
  pub subscribe_level2: Vec<u64>,
  /// Instrument IDs to subscribe to trade data.
  pub subscribe_trades: Vec<u64>,
  /// Depth of order book to maintain.
  pub book_depth:       usize,
  /// Optional private configuration for authenticated feeds.
  pub private:          Option<PrivateConfig>,
  /// WebSocket gateway URL.
  pub ws_url:           String,
}

impl Default for NdaxWsConfig {
  fn default() -> Self {
    Self {
      credentials:      None,
      subscribe_level1: Vec::new(),
      subscribe_level2: Vec::new(),
      subscribe_trades: Vec::new(),
      book_depth:       10,
      private:          None,
      ws_url:           DEFAULT_WS_GATEWAY_URL.to_string(),
    }
  }
}

impl NdaxWsConfig {
  /// Get a builder for the NdaxWsConfig object.
  pub fn builder() -> NdaxWsConfigBuilder { NdaxWsConfigBuilder::default() }
}

/// Builder for NdaxWsConfig.
#[derive(Debug, Default)]
pub struct NdaxWsConfigBuilder {
  config: NdaxWsConfig,
}

impl NdaxWsConfigBuilder {
  /// Create a new builder.
  pub fn new() -> Self { Self::default() }

  /// Set the credentials for authenticated connections.
  pub fn credentials(mut self, credentials: NdaxCredentials) -> Self {
    self.config.credentials = Some(credentials);
    self
  }

  /// Set the instrument IDs to subscribe to Level1 data.
  pub fn subscribe_level1(mut self, instrument_ids: Vec<u64>) -> Self {
    self.config.subscribe_level1 = instrument_ids;
    self
  }

  /// Add an instrument ID to the Level1 subscription list.
  pub fn add_level1(mut self, instrument_id: u64) -> Self {
    self.config.subscribe_level1.push(instrument_id);
    self
  }

  /// Set the instrument IDs to subscribe to Level2 data (order book).
  pub fn subscribe_level2(mut self, instrument_ids: Vec<u64>) -> Self {
    self.config.subscribe_level2 = instrument_ids;
    self
  }

  /// Add an instrument ID to the Level2 subscription list.
  pub fn add_level2(mut self, instrument_id: u64) -> Self {
    self.config.subscribe_level2.push(instrument_id);
    self
  }

  /// Set the instrument IDs to subscribe to trade data.
  pub fn subscribe_trades(mut self, instrument_ids: Vec<u64>) -> Self {
    self.config.subscribe_trades = instrument_ids;
    self
  }

  /// Add an instrument ID to the trades subscription list.
  pub fn add_trades(mut self, instrument_id: u64) -> Self {
    self.config.subscribe_trades.push(instrument_id);
    self
  }

  /// Set the order book depth to maintain.
  pub fn book_depth(mut self, depth: usize) -> Self {
    self.config.book_depth = depth;
    self
  }

  /// Set the private configuration for authenticated feeds.
  pub fn private(mut self, private_config: PrivateConfig) -> Self {
    self.config.private = Some(private_config);
    self
  }

  /// Set the WebSocket gateway URL.
  pub fn ws_url(mut self, url: impl Into<String>) -> Self {
    self.config.ws_url = url.into();
    self
  }

  /// Build the configuration.
  pub fn build(self) -> NdaxWsConfig { self.config }
}

#[cfg(test)]
mod tests {
  use super::*;

  #[test]
  fn test_config_default() {
    let config = NdaxWsConfig::default();
    assert!(config.credentials.is_none());
    assert!(config.subscribe_level1.is_empty());
    assert!(config.subscribe_level2.is_empty());
    assert!(config.subscribe_trades.is_empty());
    assert_eq!(config.book_depth, 10);
    assert!(config.private.is_none());
    assert_eq!(config.ws_url, DEFAULT_WS_GATEWAY_URL);
  }

  #[test]
  fn test_config_builder() {
    let creds = NdaxCredentials::new("key", "secret", "123");
    let config = NdaxWsConfig::builder()
      .credentials(creds.clone())
      .subscribe_level1(vec![1, 2])
      .subscribe_level2(vec![3, 4])
      .subscribe_trades(vec![5])
      .book_depth(20)
      .private(PrivateConfig::new(12345).with_account_events())
      .build();

    assert!(config.credentials.is_some());
    assert_eq!(config.subscribe_level1, vec![1, 2]);
    assert_eq!(config.subscribe_level2, vec![3, 4]);
    assert_eq!(config.subscribe_trades, vec![5]);
    assert_eq!(config.book_depth, 20);
    assert!(config.private.is_some());
    let private = config.private.unwrap();
    assert_eq!(private.account_id, 12345);
    assert!(private.subscribe_account_events);
  }

  #[test]
  fn test_config_builder_add_methods() {
    let config = NdaxWsConfig::builder()
      .add_level1(1)
      .add_level1(2)
      .add_level2(3)
      .add_trades(4)
      .build();

    assert_eq!(config.subscribe_level1, vec![1, 2]);
    assert_eq!(config.subscribe_level2, vec![3]);
    assert_eq!(config.subscribe_trades, vec![4]);
  }

  #[test]
  fn test_private_config() {
    let private = PrivateConfig::new(999);
    assert_eq!(private.account_id, 999);
    assert!(!private.subscribe_account_events);

    let private = private.with_account_events();
    assert!(private.subscribe_account_events);
  }
}