コード例 #1
0
        /// <inheritdoc />
        public async Task <CallResult <UpdateSubscription> > SubscribeToOrderUpdatesAsync(IEnumerable <string> symbols, Action <DataEvent <CoinExSocketOrderUpdate> > onMessage, CancellationToken ct = default)
        {
            var internalHandler = new Action <DataEvent <JToken[]> >(data =>
            {
                if (data.Data.Length != 2)
                {
                    _log.Write(LogLevel.Warning, $"Received unexpected data format for order update. Expected 2 objects, received {data.Data.Length}. Data: [{string.Join(",", data.Data.Select(s => s.ToString()))}]");
                    return;
                }

                var updateResult = JsonConvert.DeserializeObject <UpdateType>(data.Data[0].ToString(), new UpdateTypeConverter(false));
                var desResult    = _baseClient.DeserializeInternal <CoinExSocketOrder>(data.Data[1]);
                if (!desResult)
                {
                    _log.Write(LogLevel.Warning, "Received invalid order update: " + desResult.Error);
                    return;
                }

                var result = new CoinExSocketOrderUpdate()
                {
                    UpdateType = updateResult,
                    Order      = desResult.Data
                };
                onMessage(data.As(result, result.Order.Symbol));
            });

            var request = new CoinExSocketRequest(_baseClient.NextIdInternal(), OrderSubject, SubscribeAction, symbols.ToArray());

            return(await _baseClient.SubscribeInternalAsync(this, request, null, true, internalHandler, ct).ConfigureAwait(false));
        }
コード例 #2
0
        private async Task <CallResult <T> > QueryNewSocket <T>(CoinExSocketRequest request, bool authenticated)
        {
            var con = ConnectNewSocket();

            if (!con.Success)
            {
                return(new CallResult <T>(default(T), con.Error));
            }

            if (authenticated)
            {
                var auth = await Authenticate(con.Data).ConfigureAwait(false);

                if (!auth.Success)
                {
                    return(new CallResult <T>(default(T), auth.Error));
                }
            }

            var result = await Query <T>(con.Data, request).ConfigureAwait(false);

            var closeTask = con.Data.Close().ConfigureAwait(false); // let it close in background

            return(result);
        }
コード例 #3
0
        public void SubscribingToAuthenticatedStream_Should_SendAuthentication()
        {
            // arrange
            var client = TestHelpers.PrepareSocketClient(() => Construct(new CoinExSocketClientOptions()
            {
                ApiCredentials = new ApiCredentials("TestKey", "test"),
                SubscriptionResponseTimeout = TimeSpan.FromMilliseconds(100)
            }));
            var expected = new CoinExSocketRequest("server", "sign", "TestKey", "", 1);
            CoinExSocketRequest actual = null;

            // act
            var sendWait = TestHelpers.WaitForSend(client);
            var sub      = client.SubscribeToBalanceUpdates(data => { });
            var result   = sendWait.Result;

            var invocations = Mock.Get(client.sockets[0].Socket).Invocations.Where(s => s.Method == typeof(IWebsocket).GetMethod("Send"));

            foreach (var invocation in invocations)
            {
                var msg = (string)invocation.Arguments[0];
                if (msg.Contains("sign"))
                {
                    actual = JsonConvert.DeserializeObject <CoinExSocketRequest>(msg);
                }
            }

            // assert
            Assert.IsTrue(result);
            Assert.IsTrue(actual != null);
            Assert.IsTrue(expected.Method == actual.Method);
            Assert.IsTrue((string)expected.Parameters[0] == (string)actual.Parameters[0]);;
        }
コード例 #4
0
        /// <inheritdoc />
        protected override async Task <CallResult <bool> > AuthenticateSocketAsync(SocketConnection s)
        {
            if (s.ApiClient.AuthenticationProvider == null)
            {
                return(new CallResult <bool>(new NoApiCredentialsError()));
            }

            var request = new CoinExSocketRequest(NextId(), ServerSubject, AuthenticateAction, GetAuthParameters(s.ApiClient));
            var result  = new CallResult <bool>(new ServerError("No response from server"));
            await s.SendAndWaitAsync(request, ClientOptions.SocketResponseTimeout, data =>
            {
                var idField = data["id"];
                if (idField == null)
                {
                    return(false);
                }

                if ((int)idField != request.Id)
                {
                    return(false); // Not for this request
                }
                var authResponse = Deserialize <CoinExSocketRequestResponse <CoinExSocketRequestResponseMessage> >(data);
                if (!authResponse)
                {
                    log.Write(LogLevel.Warning, "Authorization failed: " + authResponse.Error);
                    result = new CallResult <bool>(authResponse.Error !);
                    return(true);
                }
コード例 #5
0
        private async Task <CallResult <bool> > Authenticate(SocketSubscription subscription)
        {
            if (authProvider == null)
            {
                return(new CallResult <bool>(false, new NoApiCredentialsError()));
            }

            var request = new CoinExSocketRequest(ServerSubject, AuthenticateAction, true, GetAuthParameters())
            {
                Id = NextId()
            };

            var waitTask = subscription.WaitForEvent(AuthenticationEvent, request.Id.ToString(), subResponseTimeout);

            Send(subscription.Socket, request);
            var authResult = await waitTask.ConfigureAwait(false);

            if (!authResult.Success)
            {
                var closeTask = subscription.Close();
                return(new CallResult <bool>(false, authResult.Error));
            }

            return(new CallResult <bool>(true, null));
        }
コード例 #6
0
        private async Task <CallResult <UpdateSubscription> > Subscribe(CoinExSocketRequest request, Action <JToken[]> onData)
        {
            var connectResult = await CreateAndConnectSocket(request.Signed, true, onData).ConfigureAwait(false);

            if (!connectResult.Success)
            {
                return(new CallResult <UpdateSubscription>(null, connectResult.Error));
            }

            return(await Subscribe(connectResult.Data, request).ConfigureAwait(false));
        }
コード例 #7
0
        protected override async Task <CallResult <bool> > AuthenticateSocket(SocketConnection s)
        {
            if (authProvider == null)
            {
                return(new CallResult <bool>(false, new NoApiCredentialsError()));
            }

            var request = new CoinExSocketRequest(NextId(), ServerSubject, AuthenticateAction, GetAuthParameters());
            CallResult <bool> result = new CallResult <bool>(false, new ServerError("No response from server"));
            await s.SendAndWait(request, ResponseTimeout, data =>
            {
                var idField = data["id"];
                if (idField == null)
                {
                    return(false);
                }

                if ((int)idField != request.Id)
                {
                    return(false); // Not for this request
                }
                var authResponse = Deserialize <CoinExSocketRequestResponse <CoinExSocketRequestResponseMessage> >(data, false);
                if (!authResponse.Success)
                {
                    log.Write(LogVerbosity.Warning, "Authorization failed: " + authResponse.Error);
                    result = new CallResult <bool>(false, authResponse.Error);
                    return(true);
                }

                if (authResponse.Data.Error != null)
                {
                    var error = new ServerError(authResponse.Data.Error.Code, authResponse.Data.Error.Message);
                    log.Write(LogVerbosity.Debug, "Failed to authenticate: " + error);
                    result = new CallResult <bool>(false, error);
                    return(true);
                }

                if (authResponse.Data.Result.Status != SuccessString)
                {
                    log.Write(LogVerbosity.Debug, "Failed to authenticate: " + authResponse.Data.Result.Status);
                    result = new CallResult <bool>(false, new ServerError(authResponse.Data.Result.Status));
                    return(true);
                }

                log.Write(LogVerbosity.Debug, "Authorization completed");
                result = new CallResult <bool>(true, null);
                return(true);
            });

            return(result);
        }
コード例 #8
0
        private async Task <CallResult <T> > Query <T>(CoinExSocketRequest request)
        {
            CallResult <T> result          = null;
            var            internalHandler = new Action <JToken[]>(data => result = Deserialize <T>(data[0]));

            var subscription = GetBackgroundSocket(request.Signed);

            if (subscription == null)
            {
                // We don't have a background socket to query, create a new one
                var connectResult = await CreateAndConnectSocket(request.Signed, false, internalHandler).ConfigureAwait(false);

                if (!connectResult.Success)
                {
                    return(new CallResult <T>(default(T), connectResult.Error));
                }

                subscription      = connectResult.Data;
                subscription.Type = request.Signed ? SocketType.BackgroundAuthenticated : SocketType.Background;
            }
            else
            {
                // Use earlier created background socket to query without having to connect again
                subscription.Events.Single(s => s.Name == DataEvent).Reset();
                subscription.MessageHandlers[DataHandlerName] = (subs, data) => DataHandlerQuery(subs, data, internalHandler);
            }

            request.Id = NextId();

            var waitTask = subscription.WaitForEvent(DataEvent, request.Id.ToString(), subResponseTimeout);

            Send(subscription.Socket, request);
            var dataResult = await waitTask.ConfigureAwait(false);

            return(!dataResult.Success ? new CallResult <T>(default(T), dataResult.Error) : result);
        }
コード例 #9
0
        private async Task <CallResult <CoinExStreamSubscription> > Subscribe(CoinExStream stream, CoinExSocketRequest request, bool resubscribing)
        {
            if (stream.Authenticated)
            {
                var auth = await Authenticate(stream).ConfigureAwait(false);

                if (!auth.Success)
                {
                    return(new CallResult <CoinExStreamSubscription>(null, auth.Error));
                }
            }

            if (!resubscribing) // Only add the message handler once, is already done if resubscribing
            {
                stream.Socket.OnMessage += (msg) => OnMessage(stream.StreamResult.StreamId, msg);
            }

            var subConfirm = await Query <CoinExSocketRequestResponseMessage>(stream, request).ConfigureAwait(false);

            if (subConfirm.Success)
            {
                stream.Request = request;
                stream.Subscription.StreamId = stream.StreamResult.StreamId;
                stream.TryReconnect          = true;
                lock (subscriptions)
                    if (!subscriptions.Contains(stream.Subscription))
                    {
                        subscriptions.Add(stream.Subscription);
                    }
                log.Write(LogVerbosity.Info, $"Subscription {stream.Subscription.StreamId} successful");
            }
            else
            {
                log.Write(LogVerbosity.Info, $"Failed to subscribe {stream.Subscription.StreamId}: {subConfirm.Error}");
                if (!resubscribing) // If we're just trying to initialy subscribe we dont need to reconnect if we failed subbing, so close it here
                {
                    await stream.Close().ConfigureAwait(false);
                }
            }

            return(new CallResult <CoinExStreamSubscription>(stream.StreamResult, subConfirm.Error));
        }
コード例 #10
0
        private async Task <CallResult <CoinExStreamSubscription> > Subscribe(CoinExSubscription subscription, CoinExSocketRequest request, bool authenticated = false)
        {
            log.Write(LogVerbosity.Debug, $"Starting new subscription for {request.Method}");
            var con = ConnectNewSocket();

            if (!con.Success)
            {
                return(new CallResult <CoinExStreamSubscription>(null, con.Error));
            }

            con.Data.Authenticated = authenticated;
            con.Data.Subscription  = subscription;
            return(await Subscribe(con.Data, request, false).ConfigureAwait(false));
        }
コード例 #11
0
        private async Task <CallResult <T> > Query <T>(CoinExStream stream, CoinExSocketRequest request)
        {
            return(await Task.Run(() =>
            {
                log.Write(LogVerbosity.Debug, $"Querying socket {stream.Subscription.StreamId} for {request.Method}");
                ManualResetEvent evnt = new ManualResetEvent(false);
                CallResult <CoinExSocketRequestResponse <T> > result = null;
                request.Id = NextRequestId();
                var onMessageAction = new Action <string>((msg) =>
                {
                    log.Write(LogVerbosity.Debug, "Socket received query response: " + msg);

                    var token = JToken.Parse(msg);
                    if ((int?)token["id"] != request.Id)
                    {
                        return;
                    }

                    if (token["error"].Type == JTokenType.Null)
                    {
                        result = Deserialize <CoinExSocketRequestResponse <T> >(msg);
                    }
                    else
                    {
                        var errorResult = Deserialize <CoinExSocketError>(token["error"].ToString());
                        if (!errorResult.Success)
                        {
                            result = new CallResult <CoinExSocketRequestResponse <T> >(null, new ServerError("Unknown error: " + token["error"]));
                        }
                        else
                        {
                            result = new CallResult <CoinExSocketRequestResponse <T> >(null, new ServerError(errorResult.Data.Code, errorResult.Data.Message));
                        }
                    }

                    evnt?.Set();
                });

                stream.Socket.OnMessage += onMessageAction;
                var data = JsonConvert.SerializeObject(request);
                log.Write(LogVerbosity.Debug, "Sending data: " + data);
                stream.Socket.Send(data);
                evnt.WaitOne(subResponseTimeout);
                stream.Socket.OnMessage -= onMessageAction;
                evnt.Dispose();
                evnt = null;
                if (result == null)
                {
                    return new CallResult <T>(default(T), new ServerError("No response from server"));
                }
                if (!result.Success)
                {
                    return new CallResult <T>(default(T), result.Error);
                }
                if (result.Data.Error != null)
                {
                    return new CallResult <T>(default(T), new ServerError(result.Data.Error.Code, result.Data.Error.Message));
                }

                return new CallResult <T>(result.Data.Result, null);
            }).ConfigureAwait(false));
        }
コード例 #12
0
        private async Task <CallResult <UpdateSubscription> > Subscribe(SocketSubscription subscription, CoinExSocketRequest request)
        {
            request.Id = NextId();
            var waitTask = subscription.WaitForEvent(SubscriptionEvent, request.Id.ToString(), subResponseTimeout);

            Send(subscription.Socket, request);

            var subResult = await waitTask.ConfigureAwait(false);

            if (!subResult.Success)
            {
                await subscription.Close().ConfigureAwait(false);

                return(new CallResult <UpdateSubscription>(null, subResult.Error));
            }

            subscription.Request = request;
            subscription.Socket.ShouldReconnect = true;
            return(new CallResult <UpdateSubscription>(new UpdateSubscription(subscription), null));
        }