/// <inheritdoc /> protected override async Task <CallResult <UpdateSubscription> > Subscribe <T>(string url, object?request, string?identifier, bool authenticated, Action <T> dataHandler) { SocketConnection? socket; SocketSubscription handler; var released = false; await semaphoreSlim.WaitAsync().ConfigureAwait(false); try { socket = GetWebsocket(url, authenticated); if (socket == null) { KucoinToken token; var clientOptions = KucoinClient.DefaultOptions.Copy(); KucoinApiCredentials?thisCredentials = (KucoinApiCredentials?)authProvider?.Credentials; if (thisCredentials != null) { clientOptions.ApiCredentials = new KucoinApiCredentials(thisCredentials.Key !.GetString(), thisCredentials.Secret !.GetString(), thisCredentials.PassPhrase.GetString()); } using (var restClient = new KucoinClient(clientOptions)) { var tokenResult = restClient.GetWebsocketToken(authenticated).Result; if (!tokenResult) { return(new CallResult <UpdateSubscription>(null, tokenResult.Error)); } token = tokenResult.Data; } // Create new socket var s = CreateSocket(token.Servers.First().Endpoint + "?token=" + token.Token); socket = new SocketConnection(this, s); foreach (var kvp in genericHandlers) { socket.AddHandler(SocketSubscription.CreateForIdentifier(kvp.Key, false, kvp.Value)); } } handler = AddHandler(request, identifier, true, socket, dataHandler); if (SocketCombineTarget == 1) { // Can release early when only a single sub per connection semaphoreSlim.Release(); released = true; } var connectResult = await ConnectIfNeeded(socket, authenticated).ConfigureAwait(false); if (!connectResult) { return(new CallResult <UpdateSubscription>(null, connectResult.Error)); } } finally { //When the task is ready, release the semaphore. It is vital to ALWAYS release the semaphore when we are ready, or else we will end up with a Semaphore that is forever locked. //This is why it is important to do the Release within a try...finally clause; program execution may crash or take a different path, this way you are guaranteed execution if (!released) { semaphoreSlim.Release(); } } if (request != null) { var subResult = await SubscribeAndWait(socket, request, handler).ConfigureAwait(false); if (!subResult) { await socket.Close(handler).ConfigureAwait(false); return(new CallResult <UpdateSubscription>(null, subResult.Error)); } } else { handler.Confirmed = true; } socket.ShouldReconnect = true; return(new CallResult <UpdateSubscription>(new UpdateSubscription(socket, handler), null)); }
/// <summary> /// Create a new order book instance /// </summary> /// <param name="symbol">The symbol the order book is for</param> /// <param name="options">The options for the order book</param> public KucoinSymbolOrderBook(string symbol, KucoinOrderBookOptions?options = null) : base(symbol, options ?? new KucoinOrderBookOptions()) { restClient = new KucoinClient(); socketClient = new KucoinSocketClient(); }