Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(#2): add messy implementation for futures ws #3

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 23 additions & 6 deletions src/Huobi.Client.Websocket/Authentication/HuobiSignature.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,21 @@ public class HuobiSignature : IHuobiSignature
{
private const string METHOD = "GET";
private const string NEW_LINE_CHAR = "\n";
private const string ACCESS_KEY_NAME = "accessKey";
private const string TIMESTAMP_NAME = "timestamp";
private const string ACCESS_KEY_NAME = "AccessKeyId";
private const string TIMESTAMP_NAME = "Timestamp";

private const string SIGNATURE_METHOD_NAME = "signatureMethod";
private const string SIGNATURE_METHOD_NAME = "SignatureMethod";
internal const string SIGNATURE_METHOD_VALUE = "HmacSHA256";

private const string SIGNATURE_VERSION_NAME = "signatureVersion";
internal const string SIGNATURE_VERSION_VERSION = "2.1";
private const string SIGNATURE_VERSION_NAME = "SignatureVersion";
internal const string SIGNATURE_VERSION_VERSION = "2";

public string Create(string accessKey, string secretKey, string host, string uri, DateTimeOffset timestamp)
{
var secretKeyBytes = Encoding.UTF8.GetBytes(secretKey);
using var hmacSha256 = new HMACSHA256(secretKeyBytes);

var requestString = CreateRequestString(accessKey, host, uri, timestamp);
var requestString = CreateRequestStringFutures(accessKey, host, uri, timestamp);
var requestStringBytes = Encoding.UTF8.GetBytes(requestString);
var requestStringHash = hmacSha256.ComputeHash(requestStringBytes);

Expand All @@ -49,6 +49,23 @@ private static string CreateRequestString(string accessKey, string host, string
return requestString;
}

private static string CreateRequestStringFutures(string accessKey, string baseurl, string path, DateTimeOffset timestamp)
{
var requestStringBuilder = new StringBuilder(METHOD);
requestStringBuilder.Append(NEW_LINE_CHAR);
requestStringBuilder.Append(baseurl);
requestStringBuilder.Append(NEW_LINE_CHAR);
requestStringBuilder.Append(path);
requestStringBuilder.Append(NEW_LINE_CHAR);

var urlParams = CreateQueryString(accessKey, timestamp);
requestStringBuilder.Append(urlParams);

var requestString = requestStringBuilder.ToString();
// Console.WriteLine($"requestString: {requestString}");
return requestString;
}

private static string CreateQueryString(string accessKey, DateTimeOffset timestamp)
{
var urlParamsDict = new Dictionary<string, string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Huobi.Client.Websocket.Messages.Account.AccountUpdates;
using Huobi.Client.Websocket.Messages.Account.OrderUpdates;
using Huobi.Client.Websocket.Messages.Account.TradeDetails;
using Huobi.Client.Websocket.Messages.Account.FuturesLiquidation;
using Huobi.Client.Websocket.Serializer;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
Expand All @@ -17,6 +18,7 @@ public class HuobiAccountWebsocketClient : HuobiWebsocketClientBase<HuobiAccount
{
private readonly IOptions<HuobiAccountWebsocketClientConfig> _config;
private readonly IHuobiAuthenticationRequestFactory _authenticationRequestFactory;
private readonly ILogger<HuobiAccountWebsocketClient> _logger;

public HuobiAccountWebsocketClient(
IOptions<HuobiAccountWebsocketClientConfig> config,
Expand All @@ -28,6 +30,7 @@ public class HuobiAccountWebsocketClient : HuobiWebsocketClientBase<HuobiAccount
{
_config = config;
_authenticationRequestFactory = authenticationRequestFactory;
_logger = logger;
}

public override async Task Start()
Expand All @@ -44,10 +47,12 @@ public void Send(AccountRequestBase request)

protected override bool TryHandleMessage(string message)
{
_logger.LogError($"tryHandleMsg: {message}");
return TryHandleTradeDetailsMessages(message)
|| TryHandleOrderUpdateMessages(message)
|| TryHandleAccountUpdateMessages(message)
|| TryHandleSubscribeResponses(message)
|| TryHandleLiquidationsMessages(message)
|| TryHandleAccountUpdateMessages(message)
|| TryHandleAuthenticationResponses(message);
}

Expand Down Expand Up @@ -117,10 +122,23 @@ private bool TryHandleAccountUpdateMessages(string message)
return false;
}

private bool TryHandleLiquidationsMessages(string message)
{
// TODO:::
if (FuturesLiquidationMessage.TryParse(Serializer, message, out var futuresLiquidationMessage))
{
Streams.FuturesLiquidationSubject.OnNext(futuresLiquidationMessage);
return true;
}

return false;
}

private bool TryHandleSubscribeResponses(string message)
{
if (AccountSubscribeResponse.TryParse(Serializer, message, out var subscribeResponse))
{
_logger.LogError($"Subscribed to topic: {message}");
Streams.SubscribeResponseSubject.OnNext(subscribeResponse);
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Huobi.Client.Websocket.Messages.Account.AccountUpdates;
using Huobi.Client.Websocket.Messages.Account.OrderUpdates;
using Huobi.Client.Websocket.Messages.Account.TradeDetails;
using Huobi.Client.Websocket.Messages.Account.FuturesLiquidation;

namespace Huobi.Client.Websocket.Clients.Streams
{
Expand All @@ -18,14 +19,15 @@ public class HuobiAccountClientStreams : HuobiClientStreamsBase
internal readonly Subject<OrderSubmittedMessage> OrderSubmittedMessageSubject = new();
internal readonly Subject<OrderTradedMessage> OrderTradedMessageSubject = new();
internal readonly Subject<OrderCanceledMessage> OrderCanceledMessageSubject = new();

internal readonly Subject<TradeDetailsMessage> TradeDetailsMessageSubject = new();

internal readonly Subject<AccountUpdateMessage> AccountUpdateMessageSubject = new();
internal readonly Subject<FuturesLiquidationMessage> FuturesLiquidationSubject = new();

public IObservable<AuthenticationResponse> AuthenticationResponseStream => AuthenticationResponseSubject.AsObservable();
public IObservable<AccountSubscribeResponse> SubscribeResponseStream => SubscribeResponseSubject.AsObservable();

public IObservable<ConditionalOrderTriggerFailureMessage> ConditionalOrderTriggerFailureMessageStream => ConditionalOrderTriggerFailureMessageSubject.AsObservable();
public IObservable<ConditionalOrderCanceledMessage> ConditionalOrderCanceledMessageStream => ConditionalOrderCanceledMessageSubject.AsObservable();
public IObservable<OrderSubmittedMessage> OrderSubmittedMessageStream => OrderSubmittedMessageSubject.AsObservable();
Expand All @@ -35,5 +37,6 @@ public class HuobiAccountClientStreams : HuobiClientStreamsBase
public IObservable<TradeDetailsMessage> TradeDetailsMessageStream => TradeDetailsMessageSubject.AsObservable();

public IObservable<AccountUpdateMessage> AccountUpdateMessageStream => AccountUpdateMessageSubject.AsObservable();
public IObservable<FuturesLiquidationMessage> FuturesLiquidationMessageStream => FuturesLiquidationSubject.AsObservable();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using System;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using Huobi.Client.Websocket.Messages.Account;
using Huobi.Client.Websocket.Messages.Account.AccountUpdates;
using Huobi.Client.Websocket.Messages.Account.OrderUpdates;
using Huobi.Client.Websocket.Messages.Account.TradeDetails;

namespace Huobi.Client.Websocket.Clients.Streams
{
public class HuobiFuturesClientStreams : HuobiClientStreamsBase
{
internal readonly Subject<AuthenticationResponse> AuthenticationResponseSubject = new();
internal readonly Subject<AccountSubscribeResponse> SubscribeResponseSubject = new();

internal readonly Subject<ConditionalOrderTriggerFailureMessage> ConditionalOrderTriggerFailureMessageSubject = new();
internal readonly Subject<ConditionalOrderCanceledMessage> ConditionalOrderCanceledMessageSubject = new();
internal readonly Subject<OrderSubmittedMessage> OrderSubmittedMessageSubject = new();
internal readonly Subject<OrderTradedMessage> OrderTradedMessageSubject = new();
internal readonly Subject<OrderCanceledMessage> OrderCanceledMessageSubject = new();

internal readonly Subject<TradeDetailsMessage> TradeDetailsMessageSubject = new();

internal readonly Subject<AccountUpdateMessage> AccountUpdateMessageSubject = new();
internal readonly Subject<AccountUpdateMessage> FuturesLiquidationSubject = new();

public IObservable<AuthenticationResponse> AuthenticationResponseStream => AuthenticationResponseSubject.AsObservable();
public IObservable<AccountSubscribeResponse> SubscribeResponseStream => SubscribeResponseSubject.AsObservable();

public IObservable<ConditionalOrderTriggerFailureMessage> ConditionalOrderTriggerFailureMessageStream => ConditionalOrderTriggerFailureMessageSubject.AsObservable();
public IObservable<ConditionalOrderCanceledMessage> ConditionalOrderCanceledMessageStream => ConditionalOrderCanceledMessageSubject.AsObservable();
public IObservable<OrderSubmittedMessage> OrderSubmittedMessageStream => OrderSubmittedMessageSubject.AsObservable();
public IObservable<OrderTradedMessage> OrderTradedMessageStream => OrderTradedMessageSubject.AsObservable();
public IObservable<OrderCanceledMessage> OrderCanceledMessageStream => OrderCanceledMessageSubject.AsObservable();

public IObservable<TradeDetailsMessage> TradeDetailsMessageStream => TradeDetailsMessageSubject.AsObservable();

public IObservable<AccountUpdateMessage> AccountUpdateMessageStream => AccountUpdateMessageSubject.AsObservable();
public IObservable<AccountUpdateMessage> FuturesLiquidationMessageStream => FuturesLiquidationSubject.AsObservable();

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Huobi.Client.Websocket.Config
{
public class HuobiFuturesAccountWebsocketClient : HuobiGenericWebsocketClientConfig
{
public string? AccessKey { get; set; }
public string? SecretKey { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Huobi.Client.Websocket.Config
{
public class HuobiPerpFuturesAccountWebsocketClient : HuobiGenericWebsocketClientConfig
{
public string? AccessKey { get; set; }
public string? SecretKey { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public AccountErrorMessage(int code, string? topic, string? message)

public int Code { get; }

[JsonProperty("ch")]
[JsonProperty("topic")]
public string Topic { get; }

public string Message { get; }
Expand All @@ -30,12 +30,12 @@ public AccountErrorMessage(int code, string? topic, string? message)
input,
new[]
{
"\"code\"",
"\"err-code\"",
"\"message\""
},
out response);

return result && response?.Code != 200;
return result && response?.Code == 0;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ internal AccountPingRequest(string? action, AccountMessageData? data)
Data = data;
}

[JsonProperty("action")]
[JsonProperty("op")]
public string Action { get; }

[JsonProperty("data")]
Expand Down
18 changes: 12 additions & 6 deletions src/Huobi.Client.Websocket/Messages/Account/AccountRequestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,25 @@ namespace Huobi.Client.Websocket.Messages.Account
{
public abstract class AccountRequestBase
{
protected AccountRequestBase(string action, string channel)
protected AccountRequestBase(string action, string? channel = null)
{
Validations.ValidateInput(action, nameof(action));
Validations.ValidateInput(channel, nameof(channel));
// Validations.ValidateInput(channel, nameof(channel));

Action = action;
Channel = channel;
if (string.IsNullOrEmpty(channel) == false) {
Channel = channel;
}

}

[JsonProperty("action")]
// [JsonProperty("op")]
// public string Op { get; }

[JsonProperty("op")]
public string Action { get; }

[JsonProperty("ch")]
public string Channel { get; }
[JsonProperty("topic")]
public string? Channel { get; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,30 +12,34 @@ public AccountRequestParams(string accessKey, string signature, DateTimeOffset t
Validations.ValidateInput(accessKey, nameof(accessKey));
Validations.ValidateInput(signature, nameof(signature));

AuthType = "api";
type = "api";
AccessKey = accessKey;
SignatureMethod = HuobiSignature.SIGNATURE_METHOD_VALUE;
SignatureVersion = HuobiSignature.SIGNATURE_VERSION_VERSION;
Timestamp = timestamp.ToHuobiUtcString();
Signature = signature;
Op = "auth";
}

[JsonProperty("authType")]
public string AuthType { get; }
[JsonProperty("type")]
public string type { get; }

[JsonProperty("accessKey")]
[JsonProperty("op")]
public string Op { get; }

[JsonProperty("AccessKeyId")]
public string AccessKey { get; }

[JsonProperty("signatureMethod")]
[JsonProperty("SignatureMethod")]
public string SignatureMethod { get; }

[JsonProperty("signatureVersion")]
[JsonProperty("SignatureVersion")]
public string SignatureVersion { get; }

[JsonProperty("timestamp")]
[JsonProperty("Timestamp")]
public string Timestamp { get; }

[JsonProperty("signature")]
[JsonProperty("Signature")]
public string Signature { get; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,18 @@ namespace Huobi.Client.Websocket.Messages.Account
public abstract class AccountResponseBase<TData>
where TData : class
{
protected AccountResponseBase(string? action, string? channel, TData? data)
protected AccountResponseBase(string? action, string? topic, TData? data)
{
Action = action ?? string.Empty;
Channel = channel ?? string.Empty;
Topic = topic ?? string.Empty;
Data = data;
}

[JsonProperty("op")]
public string Action { get; }

[JsonProperty("ch")]
public string Channel { get; }
[JsonProperty("topic")]
public string Topic { get; }

public TData? Data { get; }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ public AccountSubscribeRequest(string symbol, AccountSubscriptionType subscripti

private static string FormatChannel(string symbol, AccountSubscriptionType subscriptionType)
{
if (subscriptionType == AccountSubscriptionType.Liquidations) {
return $"public.{symbol}.liquidation_orders";
}
return $"{subscriptionType.ToTopicId()}#{symbol}";
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
using System.Diagnostics.CodeAnalysis;
using Huobi.Client.Websocket.Serializer;
using Newtonsoft.Json;
using System;

namespace Huobi.Client.Websocket.Messages.Account
{
public class AccountSubscribeResponse : AccountResponseBase<object>
{
[JsonConstructor]
public AccountSubscribeResponse(string action, int code, string channel, object data)
: base(action, channel, data)
public AccountSubscribeResponse(string op, int code, string topic, object data)
: base(op, topic, data)
{
Code = code;
}
Expand All @@ -24,15 +25,11 @@ public AccountSubscribeResponse(string action, int code, string channel, object
input,
new[]
{
"\"sub\"",
"\"code\""
},
new[]
{
"\"message\""
"\"sub\""
},
out response);

Console.WriteLine($"tryParseSubResp: {result}");
return result;
}
}
Expand Down
Loading