/// <summary> /// Constructor. /// </summary> /// <param name="api">The Binance API.</param> /// <param name="client">The WebSocket client.</param> /// <param name="options">The options.</param> /// <param name="logger">The logger.</param> public UserDataWebSocketClient(IBinanceApi api, IWebSocketStream webSocket, IOptions <UserDataWebSocketClientOptions> options = null, ILogger <UserDataWebSocketClient> logger = null) : base(webSocket, logger) { Throw.IfNull(api, nameof(api)); Throw.IfNull(webSocket, nameof(webSocket)); _api = api; _options = options?.Value; webSocket.Client.Open += (s, e) => { var period = _options?.KeepAliveTimerPeriod ?? KeepAliveTimerPeriodDefault; period = Math.Min(Math.Max(period, KeepAliveTimerPeriodMin), KeepAliveTimerPeriodMax); _keepAliveTimer = new Timer(OnKeepAliveTimer, CancellationToken.None, period, period); }; webSocket.Client.Close += async(s, e) => { _keepAliveTimer.Dispose(); foreach (var _ in _listenKeys) { await _api.UserStreamCloseAsync(_.Key, _.Value, CancellationToken.None) .ConfigureAwait(false); } }; }
public virtual async Task SubscribeAsync(IBinanceApiUser user, Action <UserDataEventArgs> callback, CancellationToken token) { Throw.IfNull(user, nameof(user)); if (!token.CanBeCanceled) { throw new ArgumentException("Token must be capable of being in the canceled state.", nameof(token)); } token.ThrowIfCancellationRequested(); User = user; if (IsSubscribed) { throw new InvalidOperationException($"{nameof(UserDataWebSocketClient)} is already subscribed to a user."); } try { _listenKey = await _api.UserStreamStartAsync(user, token) .ConfigureAwait(false); if (string.IsNullOrWhiteSpace(_listenKey)) { throw new Exception($"{nameof(IUserDataWebSocketClient)}: Failed to get listen key from API."); } var period = _options?.KeepAliveTimerPeriod ?? KeepAliveTimerPeriodDefault; period = Math.Min(Math.Max(period, KeepAliveTimerPeriodMin), KeepAliveTimerPeriodMax); _keepAliveTimer = new Timer(OnKeepAliveTimer, token, period, period); try { await SubscribeToAsync(_listenKey, callback, token) .ConfigureAwait(false); } finally { _keepAliveTimer.Dispose(); await _api.UserStreamCloseAsync(User, _listenKey, CancellationToken.None) .ConfigureAwait(false); } } catch (OperationCanceledException) { } catch (Exception e) { if (!token.IsCancellationRequested) { Logger?.LogError(e, $"{nameof(UserDataWebSocketClient)}.{nameof(SubscribeAsync)}"); throw; } } }