mirror of
https://github.com/JKorf/CryptoExchange.Net
synced 2025-06-11 18:06:27 +00:00
3.0 wip
This commit is contained in:
parent
715fe378d5
commit
8ec902951d
@ -14,17 +14,17 @@ namespace CryptoExchange.Net.Authentication
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The api key to authenticate requests
|
/// The api key to authenticate requests
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public SecureString Key { get; }
|
public SecureString? Key { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The api secret to authenticate requests
|
/// The api secret to authenticate requests
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public SecureString Secret { get; }
|
public SecureString? Secret { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The private key to authenticate requests
|
/// The private key to authenticate requests
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public PrivateKey PrivateKey { get; }
|
public PrivateKey? PrivateKey { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create Api credentials providing a private key for authentication
|
/// Create Api credentials providing a private key for authentication
|
||||||
@ -56,8 +56,20 @@ namespace CryptoExchange.Net.Authentication
|
|||||||
if (string.IsNullOrEmpty(key) || string.IsNullOrEmpty(secret))
|
if (string.IsNullOrEmpty(key) || string.IsNullOrEmpty(secret))
|
||||||
throw new ArgumentException("Key and secret can't be null/empty");
|
throw new ArgumentException("Key and secret can't be null/empty");
|
||||||
|
|
||||||
Key = CreateSecureString(key);
|
Key = key.ToSecureString();
|
||||||
Secret = CreateSecureString(secret);
|
Secret = secret.ToSecureString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Copy the credentials
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public ApiCredentials Copy()
|
||||||
|
{
|
||||||
|
if (PrivateKey == null)
|
||||||
|
return new ApiCredentials(Key!.GetString(), Secret!.GetString());
|
||||||
|
else
|
||||||
|
return new ApiCredentials(PrivateKey!.Copy());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -66,24 +78,23 @@ namespace CryptoExchange.Net.Authentication
|
|||||||
/// <param name="inputStream">The stream containing the json data</param>
|
/// <param name="inputStream">The stream containing the json data</param>
|
||||||
/// <param name="identifierKey">A key to identify the credentials for the API. For example, when set to `binanceKey` the json data should contain a value for the property `binanceKey`. Defaults to 'apiKey'.</param>
|
/// <param name="identifierKey">A key to identify the credentials for the API. For example, when set to `binanceKey` the json data should contain a value for the property `binanceKey`. Defaults to 'apiKey'.</param>
|
||||||
/// <param name="identifierSecret">A key to identify the credentials for the API. For example, when set to `binanceSecret` the json data should contain a value for the property `binanceSecret`. Defaults to 'apiSecret'.</param>
|
/// <param name="identifierSecret">A key to identify the credentials for the API. For example, when set to `binanceSecret` the json data should contain a value for the property `binanceSecret`. Defaults to 'apiSecret'.</param>
|
||||||
public ApiCredentials(Stream inputStream, string identifierKey = null, string identifierSecret = null)
|
public ApiCredentials(Stream inputStream, string? identifierKey = null, string? identifierSecret = null)
|
||||||
{
|
{
|
||||||
using (var reader = new StreamReader(inputStream, Encoding.ASCII, false, 512, true))
|
using var reader = new StreamReader(inputStream, Encoding.ASCII, false, 512, true);
|
||||||
{
|
|
||||||
var stringData = reader.ReadToEnd();
|
var stringData = reader.ReadToEnd();
|
||||||
var jsonData = stringData.ToJToken();
|
var jsonData = stringData.ToJToken();
|
||||||
if(jsonData == null)
|
if(jsonData == null)
|
||||||
throw new ArgumentException("Input stream not valid json data");
|
throw new ArgumentException("Input stream not valid json data");
|
||||||
|
|
||||||
var key = TryGetValue(jsonData, identifierKey ?? "apiKey");
|
var key = TryGetValue(jsonData, identifierKey ?? "apiKey");
|
||||||
var secret = TryGetValue(jsonData, identifierSecret ?? "apiSecret");
|
var secret = TryGetValue(jsonData, identifierSecret ?? "apiSecret");
|
||||||
|
|
||||||
if (key == null || secret == null)
|
if (key == null || secret == null)
|
||||||
throw new ArgumentException("apiKey or apiSecret value not found in Json credential file");
|
throw new ArgumentException("apiKey or apiSecret value not found in Json credential file");
|
||||||
|
|
||||||
Key = CreateSecureString(key);
|
Key = key.ToSecureString();
|
||||||
Secret = CreateSecureString(secret);
|
Secret = secret.ToSecureString();
|
||||||
}
|
|
||||||
|
|
||||||
inputStream.Seek(0, SeekOrigin.Begin);
|
inputStream.Seek(0, SeekOrigin.Begin);
|
||||||
}
|
}
|
||||||
@ -94,26 +105,12 @@ namespace CryptoExchange.Net.Authentication
|
|||||||
/// <param name="data"></param>
|
/// <param name="data"></param>
|
||||||
/// <param name="key"></param>
|
/// <param name="key"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
protected string TryGetValue(JToken data, string key)
|
protected string? TryGetValue(JToken data, string key)
|
||||||
{
|
{
|
||||||
if (data[key] == null)
|
if (data[key] == null)
|
||||||
return null;
|
return null;
|
||||||
return (string) data[key];
|
return (string) data[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a secure string from a string
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="source"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
protected SecureString CreateSecureString(string source)
|
|
||||||
{
|
|
||||||
var secureString = new SecureString();
|
|
||||||
foreach (var c in source)
|
|
||||||
secureString.AppendChar(c);
|
|
||||||
secureString.MakeReadOnly();
|
|
||||||
return secureString;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Dispose
|
/// Dispose
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Net.Http;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Authentication
|
namespace CryptoExchange.Net.Authentication
|
||||||
{
|
{
|
||||||
@ -29,7 +30,7 @@ namespace CryptoExchange.Net.Authentication
|
|||||||
/// <param name="parameters"></param>
|
/// <param name="parameters"></param>
|
||||||
/// <param name="signed"></param>
|
/// <param name="signed"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public virtual Dictionary<string, object> AddAuthenticationToParameters(string uri, string method, Dictionary<string, object> parameters, bool signed)
|
public virtual Dictionary<string, object> AddAuthenticationToParameters(string uri, HttpMethod method, Dictionary<string, object> parameters, bool signed)
|
||||||
{
|
{
|
||||||
return parameters;
|
return parameters;
|
||||||
}
|
}
|
||||||
@ -42,7 +43,7 @@ namespace CryptoExchange.Net.Authentication
|
|||||||
/// <param name="parameters"></param>
|
/// <param name="parameters"></param>
|
||||||
/// <param name="signed"></param>
|
/// <param name="signed"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public virtual Dictionary<string, string> AddAuthenticationToHeaders(string uri, string method, Dictionary<string, object> parameters, bool signed)
|
public virtual Dictionary<string, string> AddAuthenticationToHeaders(string uri, HttpMethod method, Dictionary<string, object> parameters, bool signed)
|
||||||
{
|
{
|
||||||
return new Dictionary<string, string>();
|
return new Dictionary<string, string>();
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ namespace CryptoExchange.Net.Authentication
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The private key's pass phrase
|
/// The private key's pass phrase
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public SecureString Passphrase { get; }
|
public SecureString? Passphrase { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates if the private key is encrypted or not
|
/// Indicates if the private key is encrypted or not
|
||||||
@ -81,15 +81,23 @@ namespace CryptoExchange.Net.Authentication
|
|||||||
if (string.IsNullOrEmpty(key))
|
if (string.IsNullOrEmpty(key))
|
||||||
throw new ArgumentException("Key can't be null/empty");
|
throw new ArgumentException("Key can't be null/empty");
|
||||||
|
|
||||||
var secureKey = new SecureString();
|
Key = key.ToSecureString();
|
||||||
foreach (var c in key)
|
|
||||||
secureKey.AppendChar(c);
|
|
||||||
secureKey.MakeReadOnly();
|
|
||||||
Key = secureKey;
|
|
||||||
|
|
||||||
IsEncrypted = false;
|
IsEncrypted = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Copy the private key
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public PrivateKey Copy()
|
||||||
|
{
|
||||||
|
if (Passphrase == null)
|
||||||
|
return new PrivateKey(Key.GetString());
|
||||||
|
else
|
||||||
|
return new PrivateKey(Key.GetString(), Passphrase.GetString());
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Dispose
|
/// Dispose
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -7,15 +7,17 @@ using Newtonsoft.Json.Linq;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace CryptoExchange.Net
|
namespace CryptoExchange.Net
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The base for all clients
|
/// The base for all clients
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class BaseClient: IDisposable
|
public abstract class BaseClient : IDisposable
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The address of the client
|
/// The address of the client
|
||||||
@ -28,11 +30,11 @@ namespace CryptoExchange.Net
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The api proxy
|
/// The api proxy
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected ApiProxy apiProxy;
|
protected ApiProxy? apiProxy;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The auth provider
|
/// The auth provider
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected internal AuthenticationProvider authProvider;
|
protected internal AuthenticationProvider? authProvider;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The last used id
|
/// The last used id
|
||||||
@ -59,26 +61,17 @@ namespace CryptoExchange.Net
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="options"></param>
|
/// <param name="options"></param>
|
||||||
/// <param name="authenticationProvider"></param>
|
/// <param name="authenticationProvider"></param>
|
||||||
protected BaseClient(ClientOptions options, AuthenticationProvider authenticationProvider)
|
protected BaseClient(ClientOptions options, AuthenticationProvider? authenticationProvider)
|
||||||
{
|
{
|
||||||
log = new Log();
|
log = new Log();
|
||||||
authProvider = authenticationProvider;
|
authProvider = authenticationProvider;
|
||||||
Configure(options);
|
log.UpdateWriters(options.LogWriters);
|
||||||
}
|
log.Level = options.LogVerbosity;
|
||||||
|
|
||||||
/// <summary>
|
BaseAddress = options.BaseAddress;
|
||||||
/// Configure the client using the provided options
|
apiProxy = options.Proxy;
|
||||||
/// </summary>
|
|
||||||
/// <param name="clientOptions">Options</param>
|
|
||||||
protected void Configure(ClientOptions clientOptions)
|
|
||||||
{
|
|
||||||
log.UpdateWriters(clientOptions.LogWriters);
|
|
||||||
log.Level = clientOptions.LogVerbosity;
|
|
||||||
|
|
||||||
BaseAddress = clientOptions.BaseAddress;
|
log.Write(LogVerbosity.Debug, $"Client configuration: {options}");
|
||||||
apiProxy = clientOptions.Proxy;
|
|
||||||
if (apiProxy != null)
|
|
||||||
log.Write(LogVerbosity.Info, $"Setting api proxy to {clientOptions.Proxy.Host}:{clientOptions.Proxy.Port}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -137,10 +130,10 @@ namespace CryptoExchange.Net
|
|||||||
/// <param name="checkObject">Whether or not the parsing should be checked for missing properties (will output data to the logging if log verbosity is Debug)</param>
|
/// <param name="checkObject">Whether or not the parsing should be checked for missing properties (will output data to the logging if log verbosity is Debug)</param>
|
||||||
/// <param name="serializer">A specific serializer to use</param>
|
/// <param name="serializer">A specific serializer to use</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
protected CallResult<T> Deserialize<T>(string data, bool checkObject = true, JsonSerializer serializer = null)
|
protected CallResult<T> Deserialize<T>(string data, bool checkObject = true, JsonSerializer? serializer = null)
|
||||||
{
|
{
|
||||||
var tokenResult = ValidateJson(data);
|
var tokenResult = ValidateJson(data);
|
||||||
return !tokenResult.Success ? new CallResult<T>(default, tokenResult.Error) : Deserialize<T>(tokenResult.Data, checkObject, serializer);
|
return !tokenResult ? new CallResult<T>(default, tokenResult.Error) : Deserialize<T>(tokenResult.Data, checkObject, serializer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -151,7 +144,7 @@ namespace CryptoExchange.Net
|
|||||||
/// <param name="checkObject">Whether or not the parsing should be checked for missing properties (will output data to the logging if log verbosity is Debug)</param>
|
/// <param name="checkObject">Whether or not the parsing should be checked for missing properties (will output data to the logging if log verbosity is Debug)</param>
|
||||||
/// <param name="serializer">A specific serializer to use</param>
|
/// <param name="serializer">A specific serializer to use</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
protected CallResult<T> Deserialize<T>(JToken obj, bool checkObject = true, JsonSerializer serializer = null)
|
protected CallResult<T> Deserialize<T>(JToken obj, bool checkObject = true, JsonSerializer? serializer = null)
|
||||||
{
|
{
|
||||||
if (serializer == null)
|
if (serializer == null)
|
||||||
serializer = defaultSerializer;
|
serializer = defaultSerializer;
|
||||||
@ -200,6 +193,53 @@ namespace CryptoExchange.Net
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Deserialize a stream into an object
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type to deserialize into</typeparam>
|
||||||
|
/// <param name="stream">The stream to deserialize</param>
|
||||||
|
/// <param name="serializer">A specific serializer to use</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
protected async Task<CallResult<T>> Deserialize<T>(Stream stream, JsonSerializer? serializer = null)
|
||||||
|
{
|
||||||
|
if (serializer == null)
|
||||||
|
serializer = defaultSerializer;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var reader = new StreamReader(stream);
|
||||||
|
using var jsonReader = new JsonTextReader(reader);
|
||||||
|
return new CallResult<T>(serializer.Deserialize<T>(jsonReader), null);
|
||||||
|
}
|
||||||
|
catch (JsonReaderException jre)
|
||||||
|
{
|
||||||
|
var data = await ReadStream(stream).ConfigureAwait(false);
|
||||||
|
var info = $"Deserialize JsonReaderException: {jre.Message}, Path: {jre.Path}, LineNumber: {jre.LineNumber}, LinePosition: {jre.LinePosition}, data: {data}";
|
||||||
|
log.Write(LogVerbosity.Error, info);
|
||||||
|
return new CallResult<T>(default, new DeserializeError(info));
|
||||||
|
}
|
||||||
|
catch (JsonSerializationException jse)
|
||||||
|
{
|
||||||
|
var data = await ReadStream(stream).ConfigureAwait(false);
|
||||||
|
var info = $"Deserialize JsonSerializationException: {jse.Message}, data: {data}";
|
||||||
|
log.Write(LogVerbosity.Error, info);
|
||||||
|
return new CallResult<T>(default, new DeserializeError(info));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var data = await ReadStream(stream).ConfigureAwait(false);
|
||||||
|
var info = $"Deserialize Unknown Exception: {ex.Message}, data: {data}";
|
||||||
|
log.Write(LogVerbosity.Error, info);
|
||||||
|
return new CallResult<T>(default, new DeserializeError(info));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<string> ReadStream(Stream stream)
|
||||||
|
{
|
||||||
|
using var reader = new StreamReader(stream);
|
||||||
|
return await reader.ReadToEndAsync().ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
private void CheckObject(Type type, JObject obj)
|
private void CheckObject(Type type, JObject obj)
|
||||||
{
|
{
|
||||||
if (type.GetCustomAttribute<JsonConverterAttribute>(true) != null)
|
if (type.GetCustomAttribute<JsonConverterAttribute>(true) != null)
|
||||||
@ -233,13 +273,17 @@ namespace CryptoExchange.Net
|
|||||||
if (d == null)
|
if (d == null)
|
||||||
{
|
{
|
||||||
d = properties.SingleOrDefault(p => string.Equals(p, token.Key, StringComparison.CurrentCultureIgnoreCase));
|
d = properties.SingleOrDefault(p => string.Equals(p, token.Key, StringComparison.CurrentCultureIgnoreCase));
|
||||||
if (d == null && !(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>)))
|
if (d == null)
|
||||||
{
|
{
|
||||||
log.Write(LogVerbosity.Warning, $"Local object doesn't have property `{token.Key}` expected in type `{type.Name}`");
|
if (!(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>)))
|
||||||
isDif = true;
|
{
|
||||||
|
log.Write(LogVerbosity.Warning, $"Local object doesn't have property `{token.Key}` expected in type `{type.Name}`");
|
||||||
|
isDif = true;
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
properties.Remove(d);
|
properties.Remove(d);
|
||||||
|
|
||||||
var propType = GetProperty(d, props)?.PropertyType;
|
var propType = GetProperty(d, props)?.PropertyType;
|
||||||
@ -270,7 +314,7 @@ namespace CryptoExchange.Net
|
|||||||
log.Write(LogVerbosity.Debug, "Returned data: " + obj);
|
log.Write(LogVerbosity.Debug, "Returned data: " + obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static PropertyInfo GetProperty(string name, IEnumerable<PropertyInfo> props)
|
private static PropertyInfo? GetProperty(string name, IEnumerable<PropertyInfo> props)
|
||||||
{
|
{
|
||||||
foreach (var prop in props)
|
foreach (var prop in props)
|
||||||
{
|
{
|
||||||
|
@ -21,7 +21,7 @@ namespace CryptoExchange.Net.Converters
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
public override object? ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||||
{
|
{
|
||||||
if (objectType == typeof(JToken))
|
if (objectType == typeof(JToken))
|
||||||
return JToken.Load(reader);
|
return JToken.Load(reader);
|
||||||
@ -31,7 +31,7 @@ namespace CryptoExchange.Net.Converters
|
|||||||
return ParseObject(arr, result, objectType);
|
return ParseObject(arr, result, objectType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static object ParseObject(JArray arr, object result, Type objectType)
|
private static object? ParseObject(JArray arr, object result, Type objectType)
|
||||||
{
|
{
|
||||||
foreach (var property in objectType.GetProperties())
|
foreach (var property in objectType.GetProperties())
|
||||||
{
|
{
|
||||||
@ -76,7 +76,7 @@ namespace CryptoExchange.Net.Converters
|
|||||||
|
|
||||||
var converterAttribute = (JsonConverterAttribute)property.GetCustomAttribute(typeof(JsonConverterAttribute)) ?? (JsonConverterAttribute)property.PropertyType.GetCustomAttribute(typeof(JsonConverterAttribute));
|
var converterAttribute = (JsonConverterAttribute)property.GetCustomAttribute(typeof(JsonConverterAttribute)) ?? (JsonConverterAttribute)property.PropertyType.GetCustomAttribute(typeof(JsonConverterAttribute));
|
||||||
var conversionAttribute = (JsonConversionAttribute)property.GetCustomAttribute(typeof(JsonConversionAttribute)) ?? (JsonConversionAttribute)property.PropertyType.GetCustomAttribute(typeof(JsonConversionAttribute));
|
var conversionAttribute = (JsonConversionAttribute)property.GetCustomAttribute(typeof(JsonConversionAttribute)) ?? (JsonConversionAttribute)property.PropertyType.GetCustomAttribute(typeof(JsonConversionAttribute));
|
||||||
object value;
|
object? value;
|
||||||
if (converterAttribute != null)
|
if (converterAttribute != null)
|
||||||
{
|
{
|
||||||
value = arr[attribute.Index].ToObject(property.PropertyType, new JsonSerializer {Converters = {(JsonConverter) Activator.CreateInstance(converterAttribute.ConverterType)}});
|
value = arr[attribute.Index].ToObject(property.PropertyType, new JsonSerializer {Converters = {(JsonConverter) Activator.CreateInstance(converterAttribute.ConverterType)}});
|
||||||
@ -133,7 +133,7 @@ namespace CryptoExchange.Net.Converters
|
|||||||
|
|
||||||
while (arrayProp.Index != last + 1)
|
while (arrayProp.Index != last + 1)
|
||||||
{
|
{
|
||||||
writer.WriteValue((string)null);
|
writer.WriteValue((string?)null);
|
||||||
last += 1;
|
last += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
@ -10,7 +11,7 @@ namespace CryptoExchange.Net.Converters
|
|||||||
/// Base class for enum converters
|
/// Base class for enum converters
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">Type of enum to convert</typeparam>
|
/// <typeparam name="T">Type of enum to convert</typeparam>
|
||||||
public abstract class BaseConverter<T>: JsonConverter
|
public abstract class BaseConverter<T>: JsonConverter where T: struct
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The enum->string mapping
|
/// The enum->string mapping
|
||||||
@ -38,7 +39,7 @@ namespace CryptoExchange.Net.Converters
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
public override object? ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||||
{
|
{
|
||||||
if (reader.Value == null)
|
if (reader.Value == null)
|
||||||
return null;
|
return null;
|
||||||
@ -69,7 +70,7 @@ namespace CryptoExchange.Net.Converters
|
|||||||
return objectType == typeof(T) || Nullable.GetUnderlyingType(objectType) == typeof(T);
|
return objectType == typeof(T) || Nullable.GetUnderlyingType(objectType) == typeof(T);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool GetValue(string value, out T result)
|
private bool GetValue(string value, [NotNullWhen(false)]out T result)
|
||||||
{
|
{
|
||||||
var mapping = Mapping.FirstOrDefault(kv => kv.Value.Equals(value, StringComparison.InvariantCultureIgnoreCase));
|
var mapping = Mapping.FirstOrDefault(kv => kv.Value.Equals(value, StringComparison.InvariantCultureIgnoreCase));
|
||||||
if (!mapping.Equals(default(KeyValuePair<T, string>)))
|
if (!mapping.Equals(default(KeyValuePair<T, string>)))
|
||||||
|
@ -15,7 +15,7 @@ namespace CryptoExchange.Net.Converters
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
public override object? ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||||
{
|
{
|
||||||
if (reader.Value == null)
|
if (reader.Value == null)
|
||||||
return null;
|
return null;
|
||||||
|
@ -17,7 +17,7 @@ namespace CryptoExchange.Net.Converters
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
public override object? ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||||
{
|
{
|
||||||
if (reader.Value == null)
|
if (reader.Value == null)
|
||||||
return null;
|
return null;
|
||||||
|
@ -16,8 +16,11 @@ namespace CryptoExchange.Net.Converters
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
public override object? ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||||
{
|
{
|
||||||
|
if (reader.Value == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
if (reader.Value is double d)
|
if (reader.Value is double d)
|
||||||
return new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(d);
|
return new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(d);
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ namespace CryptoExchange.Net.Converters
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
public override object? ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||||
{
|
{
|
||||||
if (reader.Value == null)
|
if (reader.Value == null)
|
||||||
return null;
|
return null;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netstandard2.1</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<PackageId>CryptoExchange.Net</PackageId>
|
<PackageId>CryptoExchange.Net</PackageId>
|
||||||
<Authors>JKorf</Authors>
|
<Authors>JKorf</Authors>
|
||||||
@ -12,7 +12,8 @@
|
|||||||
<NeutralLanguage>en</NeutralLanguage>
|
<NeutralLanguage>en</NeutralLanguage>
|
||||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||||
<PackageReleaseNotes>2.1.8 - Added array serialization options for implementations</PackageReleaseNotes>
|
<PackageReleaseNotes>2.1.8 - Added array serialization options for implementations</PackageReleaseNotes>
|
||||||
<LangVersion>7.1</LangVersion>
|
<Nullable>enable</Nullable>
|
||||||
|
<LangVersion>8.0</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
<DocumentationFile>CryptoExchange.Net.xml</DocumentationFile>
|
<DocumentationFile>CryptoExchange.Net.xml</DocumentationFile>
|
||||||
|
@ -54,6 +54,12 @@
|
|||||||
<param name="key">The api key used for identification</param>
|
<param name="key">The api key used for identification</param>
|
||||||
<param name="secret">The api secret used for signing</param>
|
<param name="secret">The api secret used for signing</param>
|
||||||
</member>
|
</member>
|
||||||
|
<member name="M:CryptoExchange.Net.Authentication.ApiCredentials.Copy">
|
||||||
|
<summary>
|
||||||
|
Copy the credentials
|
||||||
|
</summary>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.Authentication.ApiCredentials.#ctor(System.IO.Stream,System.String,System.String)">
|
<member name="M:CryptoExchange.Net.Authentication.ApiCredentials.#ctor(System.IO.Stream,System.String,System.String)">
|
||||||
<summary>
|
<summary>
|
||||||
Create Api credentials providing a stream containing json data. The json data should include two values: apiKey and apiSecret
|
Create Api credentials providing a stream containing json data. The json data should include two values: apiKey and apiSecret
|
||||||
@ -70,13 +76,6 @@
|
|||||||
<param name="key"></param>
|
<param name="key"></param>
|
||||||
<returns></returns>
|
<returns></returns>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.Authentication.ApiCredentials.CreateSecureString(System.String)">
|
|
||||||
<summary>
|
|
||||||
Create a secure string from a string
|
|
||||||
</summary>
|
|
||||||
<param name="source"></param>
|
|
||||||
<returns></returns>
|
|
||||||
</member>
|
|
||||||
<member name="M:CryptoExchange.Net.Authentication.ApiCredentials.Dispose">
|
<member name="M:CryptoExchange.Net.Authentication.ApiCredentials.Dispose">
|
||||||
<summary>
|
<summary>
|
||||||
Dispose
|
Dispose
|
||||||
@ -98,7 +97,7 @@
|
|||||||
</summary>
|
</summary>
|
||||||
<param name="credentials"></param>
|
<param name="credentials"></param>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.Authentication.AuthenticationProvider.AddAuthenticationToParameters(System.String,System.String,System.Collections.Generic.Dictionary{System.String,System.Object},System.Boolean)">
|
<member name="M:CryptoExchange.Net.Authentication.AuthenticationProvider.AddAuthenticationToParameters(System.String,System.Net.Http.HttpMethod,System.Collections.Generic.Dictionary{System.String,System.Object},System.Boolean)">
|
||||||
<summary>
|
<summary>
|
||||||
Add authentication to the parameter list
|
Add authentication to the parameter list
|
||||||
</summary>
|
</summary>
|
||||||
@ -108,7 +107,7 @@
|
|||||||
<param name="signed"></param>
|
<param name="signed"></param>
|
||||||
<returns></returns>
|
<returns></returns>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.Authentication.AuthenticationProvider.AddAuthenticationToHeaders(System.String,System.String,System.Collections.Generic.Dictionary{System.String,System.Object},System.Boolean)">
|
<member name="M:CryptoExchange.Net.Authentication.AuthenticationProvider.AddAuthenticationToHeaders(System.String,System.Net.Http.HttpMethod,System.Collections.Generic.Dictionary{System.String,System.Object},System.Boolean)">
|
||||||
<summary>
|
<summary>
|
||||||
Add authentication to the header dictionary
|
Add authentication to the header dictionary
|
||||||
</summary>
|
</summary>
|
||||||
@ -185,6 +184,12 @@
|
|||||||
</summary>
|
</summary>
|
||||||
<param name="key">The private key used for signing</param>
|
<param name="key">The private key used for signing</param>
|
||||||
</member>
|
</member>
|
||||||
|
<member name="M:CryptoExchange.Net.Authentication.PrivateKey.Copy">
|
||||||
|
<summary>
|
||||||
|
Copy the private key
|
||||||
|
</summary>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.Authentication.PrivateKey.Dispose">
|
<member name="M:CryptoExchange.Net.Authentication.PrivateKey.Dispose">
|
||||||
<summary>
|
<summary>
|
||||||
Dispose
|
Dispose
|
||||||
@ -237,12 +242,6 @@
|
|||||||
<param name="options"></param>
|
<param name="options"></param>
|
||||||
<param name="authenticationProvider"></param>
|
<param name="authenticationProvider"></param>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.BaseClient.Configure(CryptoExchange.Net.Objects.ClientOptions)">
|
|
||||||
<summary>
|
|
||||||
Configure the client using the provided options
|
|
||||||
</summary>
|
|
||||||
<param name="clientOptions">Options</param>
|
|
||||||
</member>
|
|
||||||
<member name="M:CryptoExchange.Net.BaseClient.SetAuthenticationProvider(CryptoExchange.Net.Authentication.AuthenticationProvider)">
|
<member name="M:CryptoExchange.Net.BaseClient.SetAuthenticationProvider(CryptoExchange.Net.Authentication.AuthenticationProvider)">
|
||||||
<summary>
|
<summary>
|
||||||
Set the authentication provider
|
Set the authentication provider
|
||||||
@ -276,6 +275,15 @@
|
|||||||
<param name="serializer">A specific serializer to use</param>
|
<param name="serializer">A specific serializer to use</param>
|
||||||
<returns></returns>
|
<returns></returns>
|
||||||
</member>
|
</member>
|
||||||
|
<member name="M:CryptoExchange.Net.BaseClient.Deserialize``1(System.IO.Stream,Newtonsoft.Json.JsonSerializer)">
|
||||||
|
<summary>
|
||||||
|
Deserialize a stream into an object
|
||||||
|
</summary>
|
||||||
|
<typeparam name="T">The type to deserialize into</typeparam>
|
||||||
|
<param name="stream">The stream to deserialize</param>
|
||||||
|
<param name="serializer">A specific serializer to use</param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.BaseClient.NextId">
|
<member name="M:CryptoExchange.Net.BaseClient.NextId">
|
||||||
<summary>
|
<summary>
|
||||||
Generate a unique id
|
Generate a unique id
|
||||||
@ -467,11 +475,11 @@
|
|||||||
<param name="source">The source secure string</param>
|
<param name="source">The source secure string</param>
|
||||||
<returns></returns>
|
<returns></returns>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.ExtensionMethods.ToIEnumerable(System.Net.WebHeaderCollection)">
|
<member name="M:CryptoExchange.Net.ExtensionMethods.ToSecureString(System.String)">
|
||||||
<summary>
|
<summary>
|
||||||
Header collection to IEnumerable
|
Create a secure string from a string
|
||||||
</summary>
|
</summary>
|
||||||
<param name="headers"></param>
|
<param name="source"></param>
|
||||||
<returns></returns>
|
<returns></returns>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.ExtensionMethods.WaitOneAsync(System.Threading.WaitHandle,System.Int32,System.Threading.CancellationToken)">
|
<member name="M:CryptoExchange.Net.ExtensionMethods.WaitOneAsync(System.Threading.WaitHandle,System.Int32,System.Threading.CancellationToken)">
|
||||||
@ -518,65 +526,49 @@
|
|||||||
Request interface
|
Request interface
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
<member name="P:CryptoExchange.Net.Interfaces.IRequest.Uri">
|
<member name="P:CryptoExchange.Net.Interfaces.IRequest.Accept">
|
||||||
<summary>
|
<summary>
|
||||||
The uri of the request
|
Accept header
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:CryptoExchange.Net.Interfaces.IRequest.Headers">
|
|
||||||
<summary>
|
|
||||||
The headers of the request
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:CryptoExchange.Net.Interfaces.IRequest.Method">
|
|
||||||
<summary>
|
|
||||||
The method of the request
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:CryptoExchange.Net.Interfaces.IRequest.Timeout">
|
|
||||||
<summary>
|
|
||||||
The timeout of the request
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="M:CryptoExchange.Net.Interfaces.IRequest.SetProxy(System.String,System.Int32,System.String,System.String)">
|
|
||||||
<summary>
|
|
||||||
Set a proxy
|
|
||||||
</summary>
|
|
||||||
<param name="host"></param>
|
|
||||||
<param name="port"></param>
|
|
||||||
<param name="login"></param>
|
|
||||||
<param name="password"></param>
|
|
||||||
</member>
|
|
||||||
<member name="P:CryptoExchange.Net.Interfaces.IRequest.ContentType">
|
|
||||||
<summary>
|
|
||||||
Content type
|
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
<member name="P:CryptoExchange.Net.Interfaces.IRequest.Content">
|
<member name="P:CryptoExchange.Net.Interfaces.IRequest.Content">
|
||||||
<summary>
|
<summary>
|
||||||
String content
|
Content
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
<member name="P:CryptoExchange.Net.Interfaces.IRequest.Accept">
|
<member name="P:CryptoExchange.Net.Interfaces.IRequest.Headers">
|
||||||
<summary>
|
<summary>
|
||||||
Accept
|
Headers
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
<member name="P:CryptoExchange.Net.Interfaces.IRequest.ContentLength">
|
<member name="P:CryptoExchange.Net.Interfaces.IRequest.Method">
|
||||||
<summary>
|
<summary>
|
||||||
Content length
|
Method
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.Interfaces.IRequest.GetRequestStream">
|
<member name="P:CryptoExchange.Net.Interfaces.IRequest.Uri">
|
||||||
<summary>
|
<summary>
|
||||||
Get the request stream
|
Uri
|
||||||
</summary>
|
</summary>
|
||||||
<returns></returns>
|
|
||||||
</member>
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.Interfaces.IRequest.GetResponse">
|
<member name="M:CryptoExchange.Net.Interfaces.IRequest.SetContent(System.Byte[])">
|
||||||
<summary>
|
<summary>
|
||||||
Get the response object
|
Set byte content
|
||||||
</summary>
|
</summary>
|
||||||
|
<param name="data"></param>
|
||||||
|
</member>
|
||||||
|
<member name="M:CryptoExchange.Net.Interfaces.IRequest.SetContent(System.String,System.String)">
|
||||||
|
<summary>
|
||||||
|
Set string content
|
||||||
|
</summary>
|
||||||
|
<param name="data"></param>
|
||||||
|
<param name="contentType"></param>
|
||||||
|
</member>
|
||||||
|
<member name="M:CryptoExchange.Net.Interfaces.IRequest.GetResponse(System.Threading.CancellationToken)">
|
||||||
|
<summary>
|
||||||
|
Get the response
|
||||||
|
</summary>
|
||||||
|
<param name="cancellationToken"></param>
|
||||||
<returns></returns>
|
<returns></returns>
|
||||||
</member>
|
</member>
|
||||||
<member name="T:CryptoExchange.Net.Interfaces.IRequestFactory">
|
<member name="T:CryptoExchange.Net.Interfaces.IRequestFactory">
|
||||||
@ -584,13 +576,21 @@
|
|||||||
Request factory interface
|
Request factory interface
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.Interfaces.IRequestFactory.Create(System.String)">
|
<member name="M:CryptoExchange.Net.Interfaces.IRequestFactory.Create(System.Net.Http.HttpMethod,System.String)">
|
||||||
<summary>
|
<summary>
|
||||||
Create a request for an uri
|
Create a request for an uri
|
||||||
</summary>
|
</summary>
|
||||||
|
<param name="method"></param>
|
||||||
<param name="uri"></param>
|
<param name="uri"></param>
|
||||||
<returns></returns>
|
<returns></returns>
|
||||||
</member>
|
</member>
|
||||||
|
<member name="M:CryptoExchange.Net.Interfaces.IRequestFactory.Configure(System.TimeSpan,CryptoExchange.Net.Objects.ApiProxy)">
|
||||||
|
<summary>
|
||||||
|
Configure the requests created by this factory
|
||||||
|
</summary>
|
||||||
|
<param name="requestTimeout">Request timeout to use</param>
|
||||||
|
<param name="proxy">Proxy settings to use</param>
|
||||||
|
</member>
|
||||||
<member name="T:CryptoExchange.Net.Interfaces.IResponse">
|
<member name="T:CryptoExchange.Net.Interfaces.IResponse">
|
||||||
<summary>
|
<summary>
|
||||||
Response object interface
|
Response object interface
|
||||||
@ -601,18 +601,22 @@
|
|||||||
The response status code
|
The response status code
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
|
<member name="P:CryptoExchange.Net.Interfaces.IResponse.IsSuccessStatusCode">
|
||||||
|
<summary>
|
||||||
|
Whether the status code indicates a success status
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:CryptoExchange.Net.Interfaces.IResponse.ResponseHeaders">
|
||||||
|
<summary>
|
||||||
|
The response headers
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.Interfaces.IResponse.GetResponseStream">
|
<member name="M:CryptoExchange.Net.Interfaces.IResponse.GetResponseStream">
|
||||||
<summary>
|
<summary>
|
||||||
Get the response stream
|
Get the response stream
|
||||||
</summary>
|
</summary>
|
||||||
<returns></returns>
|
<returns></returns>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.Interfaces.IResponse.GetResponseHeaders">
|
|
||||||
<summary>
|
|
||||||
Get the response headers
|
|
||||||
</summary>
|
|
||||||
<returns></returns>
|
|
||||||
</member>
|
|
||||||
<member name="M:CryptoExchange.Net.Interfaces.IResponse.Close">
|
<member name="M:CryptoExchange.Net.Interfaces.IResponse.Close">
|
||||||
<summary>
|
<summary>
|
||||||
Close the response
|
Close the response
|
||||||
@ -883,16 +887,6 @@
|
|||||||
Is open
|
Is open
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
<member name="P:CryptoExchange.Net.Interfaces.IWebsocket.PingConnection">
|
|
||||||
<summary>
|
|
||||||
Should ping connecting
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:CryptoExchange.Net.Interfaces.IWebsocket.PingInterval">
|
|
||||||
<summary>
|
|
||||||
Interval of pinging
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:CryptoExchange.Net.Interfaces.IWebsocket.SSLProtocols">
|
<member name="P:CryptoExchange.Net.Interfaces.IWebsocket.SSLProtocols">
|
||||||
<summary>
|
<summary>
|
||||||
Supported ssl protocols
|
Supported ssl protocols
|
||||||
@ -1090,6 +1084,16 @@
|
|||||||
<param name="login">The proxy login</param>
|
<param name="login">The proxy login</param>
|
||||||
<param name="password">The proxy password</param>
|
<param name="password">The proxy password</param>
|
||||||
</member>
|
</member>
|
||||||
|
<member name="M:CryptoExchange.Net.Objects.ApiProxy.#ctor(System.String,System.Int32,System.String,System.Security.SecureString)">
|
||||||
|
<inheritdoc />
|
||||||
|
<summary>
|
||||||
|
Create new settings for a proxy
|
||||||
|
</summary>
|
||||||
|
<param name="host">The proxy hostname/ip</param>
|
||||||
|
<param name="port">The proxy port</param>
|
||||||
|
<param name="login">The proxy login</param>
|
||||||
|
<param name="password">The proxy password</param>
|
||||||
|
</member>
|
||||||
<member name="T:CryptoExchange.Net.Objects.ByteOrderComparer">
|
<member name="T:CryptoExchange.Net.Objects.ByteOrderComparer">
|
||||||
<summary>
|
<summary>
|
||||||
Comparer for byte order
|
Comparer for byte order
|
||||||
@ -1147,7 +1151,7 @@
|
|||||||
The response headers
|
The response headers
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.Objects.WebCallResult`1.#ctor(System.Nullable{System.Net.HttpStatusCode},System.Collections.Generic.IEnumerable{System.Tuple{System.String,System.String}},`0,CryptoExchange.Net.Objects.Error)">
|
<member name="M:CryptoExchange.Net.Objects.WebCallResult`1.#ctor(System.Nullable{System.Net.HttpStatusCode},System.Collections.Generic.IEnumerable{System.Collections.Generic.KeyValuePair{System.String,System.Collections.Generic.IEnumerable{System.String}}},`0,CryptoExchange.Net.Objects.Error)">
|
||||||
<summary>
|
<summary>
|
||||||
ctor
|
ctor
|
||||||
</summary>
|
</summary>
|
||||||
@ -1163,7 +1167,7 @@
|
|||||||
<param name="error"></param>
|
<param name="error"></param>
|
||||||
<returns></returns>
|
<returns></returns>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.Objects.WebCallResult`1.CreateErrorResult(System.Nullable{System.Net.HttpStatusCode},System.Collections.Generic.IEnumerable{System.Tuple{System.String,System.String}},CryptoExchange.Net.Objects.Error)">
|
<member name="M:CryptoExchange.Net.Objects.WebCallResult`1.CreateErrorResult(System.Nullable{System.Net.HttpStatusCode},System.Collections.Generic.IEnumerable{System.Collections.Generic.KeyValuePair{System.String,System.Collections.Generic.IEnumerable{System.String}}},CryptoExchange.Net.Objects.Error)">
|
||||||
<summary>
|
<summary>
|
||||||
Create an error result
|
Create an error result
|
||||||
</summary>
|
</summary>
|
||||||
@ -1177,26 +1181,6 @@
|
|||||||
Constants
|
Constants
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
<member name="F:CryptoExchange.Net.Objects.Constants.GetMethod">
|
|
||||||
<summary>
|
|
||||||
GET Http method
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="F:CryptoExchange.Net.Objects.Constants.PostMethod">
|
|
||||||
<summary>
|
|
||||||
POST Http method
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="F:CryptoExchange.Net.Objects.Constants.DeleteMethod">
|
|
||||||
<summary>
|
|
||||||
DELETE Http method
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="F:CryptoExchange.Net.Objects.Constants.PutMethod">
|
|
||||||
<summary>
|
|
||||||
PUT Http method
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="F:CryptoExchange.Net.Objects.Constants.JsonContentHeader">
|
<member name="F:CryptoExchange.Net.Objects.Constants.JsonContentHeader">
|
||||||
<summary>
|
<summary>
|
||||||
Json content type header
|
Json content type header
|
||||||
@ -1428,6 +1412,16 @@
|
|||||||
</summary>
|
</summary>
|
||||||
<param name="message"></param>
|
<param name="message"></param>
|
||||||
</member>
|
</member>
|
||||||
|
<member name="T:CryptoExchange.Net.Objects.CancellationRequestedError">
|
||||||
|
<summary>
|
||||||
|
Cancellation requested
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:CryptoExchange.Net.Objects.CancellationRequestedError.#ctor">
|
||||||
|
<summary>
|
||||||
|
ctor
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
<member name="T:CryptoExchange.Net.Objects.BaseOptions">
|
<member name="T:CryptoExchange.Net.Objects.BaseOptions">
|
||||||
<summary>
|
<summary>
|
||||||
Base options
|
Base options
|
||||||
@ -1443,6 +1437,9 @@
|
|||||||
The log writers
|
The log writers
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
|
<member name="M:CryptoExchange.Net.Objects.BaseOptions.ToString">
|
||||||
|
<inheritdoc />
|
||||||
|
</member>
|
||||||
<member name="T:CryptoExchange.Net.Objects.OrderBookOptions">
|
<member name="T:CryptoExchange.Net.Objects.OrderBookOptions">
|
||||||
<summary>
|
<summary>
|
||||||
Base for order book options
|
Base for order book options
|
||||||
@ -1464,26 +1461,38 @@
|
|||||||
<param name="name">The name of the order book implementation</param>
|
<param name="name">The name of the order book implementation</param>
|
||||||
<param name="sequencesAreConsecutive">Whether each update should have a consecutive id number. Used to identify and reconnect when numbers are skipped.</param>
|
<param name="sequencesAreConsecutive">Whether each update should have a consecutive id number. Used to identify and reconnect when numbers are skipped.</param>
|
||||||
</member>
|
</member>
|
||||||
|
<member name="M:CryptoExchange.Net.Objects.OrderBookOptions.ToString">
|
||||||
|
<inheritdoc />
|
||||||
|
</member>
|
||||||
<member name="T:CryptoExchange.Net.Objects.ClientOptions">
|
<member name="T:CryptoExchange.Net.Objects.ClientOptions">
|
||||||
<summary>
|
<summary>
|
||||||
Base client options
|
Base client options
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
<member name="P:CryptoExchange.Net.Objects.ClientOptions.ApiCredentials">
|
|
||||||
<summary>
|
|
||||||
The api credentials
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:CryptoExchange.Net.Objects.ClientOptions.BaseAddress">
|
<member name="P:CryptoExchange.Net.Objects.ClientOptions.BaseAddress">
|
||||||
<summary>
|
<summary>
|
||||||
The base address of the client
|
The base address of the client
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
|
<member name="P:CryptoExchange.Net.Objects.ClientOptions.ApiCredentials">
|
||||||
|
<summary>
|
||||||
|
The api credentials
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
<member name="P:CryptoExchange.Net.Objects.ClientOptions.Proxy">
|
<member name="P:CryptoExchange.Net.Objects.ClientOptions.Proxy">
|
||||||
<summary>
|
<summary>
|
||||||
Proxy to use
|
Proxy to use
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
|
<member name="M:CryptoExchange.Net.Objects.ClientOptions.#ctor(System.String)">
|
||||||
|
<summary>
|
||||||
|
ctor
|
||||||
|
</summary>
|
||||||
|
<param name="baseAddress"></param>
|
||||||
|
</member>
|
||||||
|
<member name="M:CryptoExchange.Net.Objects.ClientOptions.ToString">
|
||||||
|
<inheritdoc />
|
||||||
|
</member>
|
||||||
<member name="T:CryptoExchange.Net.Objects.RestClientOptions">
|
<member name="T:CryptoExchange.Net.Objects.RestClientOptions">
|
||||||
<summary>
|
<summary>
|
||||||
Base for rest client options
|
Base for rest client options
|
||||||
@ -1504,6 +1513,12 @@
|
|||||||
The time the server has to respond to a request before timing out
|
The time the server has to respond to a request before timing out
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
|
<member name="M:CryptoExchange.Net.Objects.RestClientOptions.#ctor(System.String)">
|
||||||
|
<summary>
|
||||||
|
ctor
|
||||||
|
</summary>
|
||||||
|
<param name="baseAddress"></param>
|
||||||
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.Objects.RestClientOptions.Copy``1">
|
<member name="M:CryptoExchange.Net.Objects.RestClientOptions.Copy``1">
|
||||||
<summary>
|
<summary>
|
||||||
Create a copy of the options
|
Create a copy of the options
|
||||||
@ -1511,6 +1526,9 @@
|
|||||||
<typeparam name="T"></typeparam>
|
<typeparam name="T"></typeparam>
|
||||||
<returns></returns>
|
<returns></returns>
|
||||||
</member>
|
</member>
|
||||||
|
<member name="M:CryptoExchange.Net.Objects.RestClientOptions.ToString">
|
||||||
|
<inheritdoc />
|
||||||
|
</member>
|
||||||
<member name="T:CryptoExchange.Net.Objects.SocketClientOptions">
|
<member name="T:CryptoExchange.Net.Objects.SocketClientOptions">
|
||||||
<summary>
|
<summary>
|
||||||
Base for socket client options
|
Base for socket client options
|
||||||
@ -1542,6 +1560,12 @@
|
|||||||
Setting this to a higher number increases subscription speed, but having more subscriptions on a single connection will also increase the amount of traffic on that single connection.
|
Setting this to a higher number increases subscription speed, but having more subscriptions on a single connection will also increase the amount of traffic on that single connection.
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
|
<member name="M:CryptoExchange.Net.Objects.SocketClientOptions.#ctor(System.String)">
|
||||||
|
<summary>
|
||||||
|
ctor
|
||||||
|
</summary>
|
||||||
|
<param name="baseAddress"></param>
|
||||||
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.Objects.SocketClientOptions.Copy``1">
|
<member name="M:CryptoExchange.Net.Objects.SocketClientOptions.Copy``1">
|
||||||
<summary>
|
<summary>
|
||||||
Create a copy of the options
|
Create a copy of the options
|
||||||
@ -1549,6 +1573,9 @@
|
|||||||
<typeparam name="T"></typeparam>
|
<typeparam name="T"></typeparam>
|
||||||
<returns></returns>
|
<returns></returns>
|
||||||
</member>
|
</member>
|
||||||
|
<member name="M:CryptoExchange.Net.Objects.SocketClientOptions.ToString">
|
||||||
|
<inheritdoc />
|
||||||
|
</member>
|
||||||
<member name="T:CryptoExchange.Net.OrderBook.OrderBookEntry">
|
<member name="T:CryptoExchange.Net.OrderBook.OrderBookEntry">
|
||||||
<summary>
|
<summary>
|
||||||
Order book entry
|
Order book entry
|
||||||
@ -1876,43 +1903,35 @@
|
|||||||
Request object
|
Request object
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.Requests.Request.#ctor(System.Net.WebRequest)">
|
<member name="M:CryptoExchange.Net.Requests.Request.#ctor(System.Net.Http.HttpRequestMessage,System.Net.Http.HttpClient)">
|
||||||
<summary>
|
<summary>
|
||||||
Create request object for web request
|
Create request object for web request
|
||||||
</summary>
|
</summary>
|
||||||
<param name="request"></param>
|
<param name="request"></param>
|
||||||
|
<param name="client"></param>
|
||||||
</member>
|
</member>
|
||||||
<member name="P:CryptoExchange.Net.Requests.Request.Headers">
|
<member name="P:CryptoExchange.Net.Requests.Request.Headers">
|
||||||
<inheritdoc />
|
<inheritdoc />
|
||||||
</member>
|
</member>
|
||||||
<member name="P:CryptoExchange.Net.Requests.Request.ContentType">
|
|
||||||
<inheritdoc />
|
|
||||||
</member>
|
|
||||||
<member name="P:CryptoExchange.Net.Requests.Request.Content">
|
<member name="P:CryptoExchange.Net.Requests.Request.Content">
|
||||||
<inheritdoc />
|
<inheritdoc />
|
||||||
</member>
|
</member>
|
||||||
<member name="P:CryptoExchange.Net.Requests.Request.Accept">
|
<member name="P:CryptoExchange.Net.Requests.Request.Accept">
|
||||||
<inheritdoc />
|
<inheritdoc />
|
||||||
</member>
|
</member>
|
||||||
<member name="P:CryptoExchange.Net.Requests.Request.ContentLength">
|
|
||||||
<inheritdoc />
|
|
||||||
</member>
|
|
||||||
<member name="P:CryptoExchange.Net.Requests.Request.Method">
|
<member name="P:CryptoExchange.Net.Requests.Request.Method">
|
||||||
<inheritdoc />
|
<inheritdoc />
|
||||||
</member>
|
</member>
|
||||||
<member name="P:CryptoExchange.Net.Requests.Request.Timeout">
|
|
||||||
<inheritdoc />
|
|
||||||
</member>
|
|
||||||
<member name="P:CryptoExchange.Net.Requests.Request.Uri">
|
<member name="P:CryptoExchange.Net.Requests.Request.Uri">
|
||||||
<inheritdoc />
|
<inheritdoc />
|
||||||
</member>
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.Requests.Request.SetProxy(System.String,System.Int32,System.String,System.String)">
|
<member name="M:CryptoExchange.Net.Requests.Request.SetContent(System.String,System.String)">
|
||||||
<inheritdoc />
|
<inheritdoc />
|
||||||
</member>
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.Requests.Request.GetRequestStream">
|
<member name="M:CryptoExchange.Net.Requests.Request.SetContent(System.Byte[])">
|
||||||
<inheritdoc />
|
<inheritdoc />
|
||||||
</member>
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.Requests.Request.GetResponse">
|
<member name="M:CryptoExchange.Net.Requests.Request.GetResponse(System.Threading.CancellationToken)">
|
||||||
<inheritdoc />
|
<inheritdoc />
|
||||||
</member>
|
</member>
|
||||||
<member name="T:CryptoExchange.Net.Requests.RequestFactory">
|
<member name="T:CryptoExchange.Net.Requests.RequestFactory">
|
||||||
@ -1920,7 +1939,10 @@
|
|||||||
WebRequest factory
|
WebRequest factory
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.Requests.RequestFactory.Create(System.String)">
|
<member name="M:CryptoExchange.Net.Requests.RequestFactory.Configure(System.TimeSpan,CryptoExchange.Net.Objects.ApiProxy)">
|
||||||
|
<inheritdoc />
|
||||||
|
</member>
|
||||||
|
<member name="M:CryptoExchange.Net.Requests.RequestFactory.Create(System.Net.Http.HttpMethod,System.String)">
|
||||||
<inheritdoc />
|
<inheritdoc />
|
||||||
</member>
|
</member>
|
||||||
<member name="T:CryptoExchange.Net.Requests.Response">
|
<member name="T:CryptoExchange.Net.Requests.Response">
|
||||||
@ -1931,16 +1953,19 @@
|
|||||||
<member name="P:CryptoExchange.Net.Requests.Response.StatusCode">
|
<member name="P:CryptoExchange.Net.Requests.Response.StatusCode">
|
||||||
<inheritdoc />
|
<inheritdoc />
|
||||||
</member>
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.Requests.Response.#ctor(System.Net.HttpWebResponse)">
|
<member name="P:CryptoExchange.Net.Requests.Response.IsSuccessStatusCode">
|
||||||
<summary>
|
|
||||||
Create response for http web response
|
|
||||||
</summary>
|
|
||||||
<param name="response"></param>
|
|
||||||
</member>
|
|
||||||
<member name="M:CryptoExchange.Net.Requests.Response.GetResponseStream">
|
|
||||||
<inheritdoc />
|
<inheritdoc />
|
||||||
</member>
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.Requests.Response.GetResponseHeaders">
|
<member name="P:CryptoExchange.Net.Requests.Response.ResponseHeaders">
|
||||||
|
<inheritdoc />
|
||||||
|
</member>
|
||||||
|
<member name="M:CryptoExchange.Net.Requests.Response.#ctor(System.Net.Http.HttpResponseMessage)">
|
||||||
|
<summary>
|
||||||
|
Create response for a http response message
|
||||||
|
</summary>
|
||||||
|
<param name="response">The actual response</param>
|
||||||
|
</member>
|
||||||
|
<member name="M:CryptoExchange.Net.Requests.Response.GetResponseStream">
|
||||||
<inheritdoc />
|
<inheritdoc />
|
||||||
</member>
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.Requests.Response.Close">
|
<member name="M:CryptoExchange.Net.Requests.Response.Close">
|
||||||
@ -1998,12 +2023,6 @@
|
|||||||
<param name="exchangeOptions"></param>
|
<param name="exchangeOptions"></param>
|
||||||
<param name="authenticationProvider"></param>
|
<param name="authenticationProvider"></param>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.RestClient.Configure(CryptoExchange.Net.Objects.RestClientOptions)">
|
|
||||||
<summary>
|
|
||||||
Configure the client using the provided options
|
|
||||||
</summary>
|
|
||||||
<param name="exchangeOptions">Options</param>
|
|
||||||
</member>
|
|
||||||
<member name="M:CryptoExchange.Net.RestClient.AddRateLimiter(CryptoExchange.Net.Interfaces.IRateLimiter)">
|
<member name="M:CryptoExchange.Net.RestClient.AddRateLimiter(CryptoExchange.Net.Interfaces.IRateLimiter)">
|
||||||
<summary>
|
<summary>
|
||||||
Adds a rate limiter to the client. There are 2 choices, the <see cref="T:CryptoExchange.Net.RateLimiter.RateLimiterTotal"/> and the <see cref="T:CryptoExchange.Net.RateLimiter.RateLimiterPerEndpoint"/>.
|
Adds a rate limiter to the client. There are 2 choices, the <see cref="T:CryptoExchange.Net.RateLimiter.RateLimiterTotal"/> and the <see cref="T:CryptoExchange.Net.RateLimiter.RateLimiterPerEndpoint"/>.
|
||||||
@ -2027,26 +2046,28 @@
|
|||||||
</summary>
|
</summary>
|
||||||
<returns>The roundtrip time of the ping request</returns>
|
<returns>The roundtrip time of the ping request</returns>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.RestClient.ExecuteRequest``1(System.Uri,System.String,System.Collections.Generic.Dictionary{System.String,System.Object},System.Boolean,System.Boolean)">
|
<member name="M:CryptoExchange.Net.RestClient.SendRequest``1(System.Uri,System.Net.Http.HttpMethod,System.Threading.CancellationToken,System.Collections.Generic.Dictionary{System.String,System.Object},System.Boolean,System.Boolean)">
|
||||||
<summary>
|
<summary>
|
||||||
Execute a request
|
Execute a request
|
||||||
</summary>
|
</summary>
|
||||||
<typeparam name="T">The expected result type</typeparam>
|
<typeparam name="T">The expected result type</typeparam>
|
||||||
<param name="uri">The uri to send the request to</param>
|
<param name="uri">The uri to send the request to</param>
|
||||||
<param name="method">The method of the request</param>
|
<param name="method">The method of the request</param>
|
||||||
|
<param name="cancellationToken">Cancellation token</param>
|
||||||
<param name="parameters">The parameters of the request</param>
|
<param name="parameters">The parameters of the request</param>
|
||||||
<param name="signed">Whether or not the request should be authenticated</param>
|
<param name="signed">Whether or not the request should be authenticated</param>
|
||||||
<param name="checkResult">Whether or not the resulting object should be checked for missing properties in the mapping (only outputs if log verbosity is Debug)</param>
|
<param name="checkResult">Whether or not the resulting object should be checked for missing properties in the mapping (only outputs if log verbosity is Debug)</param>
|
||||||
<returns></returns>
|
<returns></returns>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.RestClient.IsErrorResponse(Newtonsoft.Json.Linq.JToken)">
|
<member name="M:CryptoExchange.Net.RestClient.GetResponse``1(CryptoExchange.Net.Interfaces.IRequest,System.Threading.CancellationToken)">
|
||||||
<summary>
|
<summary>
|
||||||
Can be overridden to indicate if a response is an error response
|
Executes the request and returns the string result
|
||||||
</summary>
|
</summary>
|
||||||
<param name="data">The received data</param>
|
<param name="request">The request object to execute</param>
|
||||||
<returns>True if error response</returns>
|
<param name="cancellationToken">Cancellation token</param>
|
||||||
|
<returns></returns>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.RestClient.ConstructRequest(System.Uri,System.String,System.Collections.Generic.Dictionary{System.String,System.Object},System.Boolean)">
|
<member name="M:CryptoExchange.Net.RestClient.ConstructRequest(System.Uri,System.Net.Http.HttpMethod,System.Collections.Generic.Dictionary{System.String,System.Object},System.Boolean)">
|
||||||
<summary>
|
<summary>
|
||||||
Creates a request object
|
Creates a request object
|
||||||
</summary>
|
</summary>
|
||||||
@ -2056,26 +2077,13 @@
|
|||||||
<param name="signed">Whether or not the request should be authenticated</param>
|
<param name="signed">Whether or not the request should be authenticated</param>
|
||||||
<returns></returns>
|
<returns></returns>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.RestClient.WriteParamBody(CryptoExchange.Net.Interfaces.IRequest,System.String)">
|
<member name="M:CryptoExchange.Net.RestClient.WriteParamBody(CryptoExchange.Net.Interfaces.IRequest,System.Collections.Generic.Dictionary{System.String,System.Object},System.String)">
|
||||||
<summary>
|
|
||||||
Writes the string data of the parameters to the request body stream
|
|
||||||
</summary>
|
|
||||||
<param name="request"></param>
|
|
||||||
<param name="stringData"></param>
|
|
||||||
</member>
|
|
||||||
<member name="M:CryptoExchange.Net.RestClient.WriteParamBody(CryptoExchange.Net.Interfaces.IRequest,System.Collections.Generic.Dictionary{System.String,System.Object})">
|
|
||||||
<summary>
|
<summary>
|
||||||
Writes the parameters of the request to the request object, either in the query string or the request body
|
Writes the parameters of the request to the request object, either in the query string or the request body
|
||||||
</summary>
|
</summary>
|
||||||
<param name="request"></param>
|
<param name="request"></param>
|
||||||
<param name="parameters"></param>
|
<param name="parameters"></param>
|
||||||
</member>
|
<param name="contentType"></param>
|
||||||
<member name="M:CryptoExchange.Net.RestClient.ExecuteRequest(CryptoExchange.Net.Interfaces.IRequest)">
|
|
||||||
<summary>
|
|
||||||
Executes the request and returns the string result
|
|
||||||
</summary>
|
|
||||||
<param name="request">The request object to execute</param>
|
|
||||||
<returns></returns>
|
|
||||||
</member>
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.RestClient.ParseErrorResponse(Newtonsoft.Json.Linq.JToken)">
|
<member name="M:CryptoExchange.Net.RestClient.ParseErrorResponse(Newtonsoft.Json.Linq.JToken)">
|
||||||
<summary>
|
<summary>
|
||||||
@ -2166,12 +2174,6 @@
|
|||||||
<param name="exchangeOptions">Client options</param>
|
<param name="exchangeOptions">Client options</param>
|
||||||
<param name="authenticationProvider">Authentication provider</param>
|
<param name="authenticationProvider">Authentication provider</param>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.SocketClient.Configure(CryptoExchange.Net.Objects.SocketClientOptions)">
|
|
||||||
<summary>
|
|
||||||
Configure the client using the provided options
|
|
||||||
</summary>
|
|
||||||
<param name="exchangeOptions">Options</param>
|
|
||||||
</member>
|
|
||||||
<member name="M:CryptoExchange.Net.SocketClient.SetDataInterpreter(System.Func{System.Byte[],System.String},System.Func{System.String,System.String})">
|
<member name="M:CryptoExchange.Net.SocketClient.SetDataInterpreter(System.Func{System.Byte[],System.String},System.Func{System.String,System.String})">
|
||||||
<summary>
|
<summary>
|
||||||
Set a function to interpret the data, used when the data is received as bytes instead of a string
|
Set a function to interpret the data, used when the data is received as bytes instead of a string
|
||||||
@ -2536,12 +2538,19 @@
|
|||||||
If the subscription has been confirmed
|
If the subscription has been confirmed
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.Sockets.SocketSubscription.#ctor(System.String,System.Object,System.Boolean,System.Action{CryptoExchange.Net.Sockets.SocketConnection,Newtonsoft.Json.Linq.JToken})">
|
<member name="M:CryptoExchange.Net.Sockets.SocketSubscription.#ctor(System.Object,System.Boolean,System.Action{CryptoExchange.Net.Sockets.SocketConnection,Newtonsoft.Json.Linq.JToken})">
|
||||||
|
<summary>
|
||||||
|
ctor
|
||||||
|
</summary>
|
||||||
|
<param name="request"></param>
|
||||||
|
<param name="userSubscription"></param>
|
||||||
|
<param name="dataHandler"></param>
|
||||||
|
</member>
|
||||||
|
<member name="M:CryptoExchange.Net.Sockets.SocketSubscription.#ctor(System.String,System.Boolean,System.Action{CryptoExchange.Net.Sockets.SocketConnection,Newtonsoft.Json.Linq.JToken})">
|
||||||
<summary>
|
<summary>
|
||||||
ctor
|
ctor
|
||||||
</summary>
|
</summary>
|
||||||
<param name="identifier"></param>
|
<param name="identifier"></param>
|
||||||
<param name="request"></param>
|
|
||||||
<param name="userSubscription"></param>
|
<param name="userSubscription"></param>
|
||||||
<param name="dataHandler"></param>
|
<param name="dataHandler"></param>
|
||||||
</member>
|
</member>
|
||||||
|
@ -47,7 +47,7 @@ namespace CryptoExchange.Net
|
|||||||
/// <param name="parameters"></param>
|
/// <param name="parameters"></param>
|
||||||
/// <param name="key"></param>
|
/// <param name="key"></param>
|
||||||
/// <param name="value"></param>
|
/// <param name="value"></param>
|
||||||
public static void AddOptionalParameter(this Dictionary<string, object> parameters, string key, object value)
|
public static void AddOptionalParameter(this Dictionary<string, object> parameters, string key, object? value)
|
||||||
{
|
{
|
||||||
if(value != null)
|
if(value != null)
|
||||||
parameters.Add(key, value);
|
parameters.Add(key, value);
|
||||||
@ -59,7 +59,7 @@ namespace CryptoExchange.Net
|
|||||||
/// <param name="parameters"></param>
|
/// <param name="parameters"></param>
|
||||||
/// <param name="key"></param>
|
/// <param name="key"></param>
|
||||||
/// <param name="value"></param>
|
/// <param name="value"></param>
|
||||||
public static void AddOptionalParameter(this Dictionary<string, string> parameters, string key, string value)
|
public static void AddOptionalParameter(this Dictionary<string, string> parameters, string key, string? value)
|
||||||
{
|
{
|
||||||
if (value != null)
|
if (value != null)
|
||||||
parameters.Add(key, value);
|
parameters.Add(key, value);
|
||||||
@ -127,20 +127,17 @@ namespace CryptoExchange.Net
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Header collection to IEnumerable
|
/// Create a secure string from a string
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="headers"></param>
|
/// <param name="source"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static IEnumerable<Tuple<string, string>> ToIEnumerable(this WebHeaderCollection headers)
|
internal static SecureString ToSecureString(this string source)
|
||||||
{
|
{
|
||||||
if (headers == null)
|
var secureString = new SecureString();
|
||||||
return null;
|
foreach (var c in source)
|
||||||
|
secureString.AppendChar(c);
|
||||||
return Enumerable
|
secureString.MakeReadOnly();
|
||||||
.Range(0, headers.Count)
|
return secureString;
|
||||||
.SelectMany(i => headers.GetValues(i)
|
|
||||||
.Select(v => Tuple.Create(headers.GetKey(i), v))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -152,7 +149,7 @@ namespace CryptoExchange.Net
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static async Task<bool> WaitOneAsync(this WaitHandle handle, int millisecondsTimeout, CancellationToken cancellationToken)
|
public static async Task<bool> WaitOneAsync(this WaitHandle handle, int millisecondsTimeout, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
RegisteredWaitHandle registeredHandle = null;
|
RegisteredWaitHandle? registeredHandle = null;
|
||||||
CancellationTokenRegistration tokenRegistration = default;
|
CancellationTokenRegistration tokenRegistration = default;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -192,7 +189,7 @@ namespace CryptoExchange.Net
|
|||||||
/// <param name="stringData"></param>
|
/// <param name="stringData"></param>
|
||||||
/// <param name="log"></param>
|
/// <param name="log"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static JToken ToJToken(this string stringData, Log log = null)
|
public static JToken? ToJToken(this string stringData, Log? log = null)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(stringData))
|
if (string.IsNullOrEmpty(stringData))
|
||||||
return null;
|
return null;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.Net.Http;
|
||||||
using System.Net;
|
using System.Net.Http.Headers;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Interfaces
|
namespace CryptoExchange.Net.Interfaces
|
||||||
@ -11,56 +12,41 @@ namespace CryptoExchange.Net.Interfaces
|
|||||||
public interface IRequest
|
public interface IRequest
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The uri of the request
|
/// Accept header
|
||||||
|
/// </summary>
|
||||||
|
string Accept { set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Content
|
||||||
|
/// </summary>
|
||||||
|
string? Content { get; }
|
||||||
|
/// <summary>
|
||||||
|
/// Headers
|
||||||
|
/// </summary>
|
||||||
|
HttpRequestHeaders Headers { get; }
|
||||||
|
/// <summary>
|
||||||
|
/// Method
|
||||||
|
/// </summary>
|
||||||
|
HttpMethod Method { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Uri
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Uri Uri { get; }
|
Uri Uri { get; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The headers of the request
|
/// Set byte content
|
||||||
/// </summary>
|
/// </summary>
|
||||||
WebHeaderCollection Headers { get; set; }
|
/// <param name="data"></param>
|
||||||
|
void SetContent(byte[] data);
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The method of the request
|
/// Set string content
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string Method { get; set; }
|
/// <param name="data"></param>
|
||||||
|
/// <param name="contentType"></param>
|
||||||
|
void SetContent(string data, string contentType);
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The timeout of the request
|
/// Get the response
|
||||||
/// </summary>
|
|
||||||
TimeSpan Timeout { get; set; }
|
|
||||||
/// <summary>
|
|
||||||
/// Set a proxy
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="host"></param>
|
|
||||||
/// <param name="port"></param>
|
|
||||||
/// <param name="login"></param>
|
|
||||||
/// <param name="password"></param>
|
|
||||||
void SetProxy(string host, int port, string login, string password);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Content type
|
|
||||||
/// </summary>
|
|
||||||
string ContentType { get; set; }
|
|
||||||
/// <summary>
|
|
||||||
/// String content
|
|
||||||
/// </summary>
|
|
||||||
string Content { get; set; }
|
|
||||||
/// <summary>
|
|
||||||
/// Accept
|
|
||||||
/// </summary>
|
|
||||||
string Accept { get; set; }
|
|
||||||
/// <summary>
|
|
||||||
/// Content length
|
|
||||||
/// </summary>
|
|
||||||
long ContentLength { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get the request stream
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<Stream> GetRequestStream();
|
Task<IResponse> GetResponse(CancellationToken cancellationToken);
|
||||||
/// <summary>
|
|
||||||
/// Get the response object
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task<IResponse> GetResponse();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,8 @@
|
|||||||
namespace CryptoExchange.Net.Interfaces
|
using CryptoExchange.Net.Objects;
|
||||||
|
using System;
|
||||||
|
using System.Net.Http;
|
||||||
|
|
||||||
|
namespace CryptoExchange.Net.Interfaces
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Request factory interface
|
/// Request factory interface
|
||||||
@ -8,8 +12,16 @@
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a request for an uri
|
/// Create a request for an uri
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="method"></param>
|
||||||
/// <param name="uri"></param>
|
/// <param name="uri"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
IRequest Create(string uri);
|
IRequest Create(HttpMethod method, string uri);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Configure the requests created by this factory
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="requestTimeout">Request timeout to use</param>
|
||||||
|
/// <param name="proxy">Proxy settings to use</param>
|
||||||
|
void Configure(TimeSpan requestTimeout, ApiProxy? proxy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
using System;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Interfaces
|
namespace CryptoExchange.Net.Interfaces
|
||||||
{
|
{
|
||||||
@ -14,16 +14,23 @@ namespace CryptoExchange.Net.Interfaces
|
|||||||
/// The response status code
|
/// The response status code
|
||||||
/// </summary>
|
/// </summary>
|
||||||
HttpStatusCode StatusCode { get; }
|
HttpStatusCode StatusCode { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the status code indicates a success status
|
||||||
|
/// </summary>
|
||||||
|
bool IsSuccessStatusCode { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The response headers
|
||||||
|
/// </summary>
|
||||||
|
IEnumerable<KeyValuePair<string, IEnumerable<string>>> ResponseHeaders { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get the response stream
|
/// Get the response stream
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Stream GetResponseStream();
|
Task<Stream> GetResponseStream();
|
||||||
/// <summary>
|
|
||||||
/// Get the response headers
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
IEnumerable<Tuple<string, string>> GetResponseHeaders();
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Close the response
|
/// Close the response
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -34,7 +34,7 @@ namespace CryptoExchange.Net.Interfaces
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Origin
|
/// Origin
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string Origin { get; set; }
|
string? Origin { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reconnecting
|
/// Reconnecting
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -42,11 +42,11 @@ namespace CryptoExchange.Net.Interfaces
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handler for byte data
|
/// Handler for byte data
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Func<byte[], string> DataInterpreterBytes { get; set; }
|
Func<byte[], string>? DataInterpreterBytes { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handler for string data
|
/// Handler for string data
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Func<string, string> DataInterpreterString { get; set; }
|
Func<string, string>? DataInterpreterString { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Socket url
|
/// Socket url
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -64,14 +64,6 @@ namespace CryptoExchange.Net.Interfaces
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
bool IsOpen { get; }
|
bool IsOpen { get; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Should ping connecting
|
|
||||||
/// </summary>
|
|
||||||
bool PingConnection { get; set; }
|
|
||||||
/// <summary>
|
|
||||||
/// Interval of pinging
|
|
||||||
/// </summary>
|
|
||||||
TimeSpan PingInterval { get; set; }
|
|
||||||
/// <summary>
|
|
||||||
/// Supported ssl protocols
|
/// Supported ssl protocols
|
||||||
/// </summary>
|
/// </summary>
|
||||||
SslProtocols SSLProtocols { get; set; }
|
SslProtocols SSLProtocols { get; set; }
|
||||||
|
@ -49,11 +49,8 @@ namespace CryptoExchange.Net.Logging
|
|||||||
/// <param name="disposing"></param>
|
/// <param name="disposing"></param>
|
||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
lock (writeLock)
|
lock (writeLock)
|
||||||
{
|
logWriter.Close();
|
||||||
logWriter.Close();
|
|
||||||
logWriter = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Security;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Objects
|
namespace CryptoExchange.Net.Objects
|
||||||
{
|
{
|
||||||
@ -19,25 +20,20 @@ namespace CryptoExchange.Net.Objects
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The login of the proxy
|
/// The login of the proxy
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Login { get; }
|
public string? Login { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The password of the proxy
|
/// The password of the proxy
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Password { get; }
|
public SecureString? Password { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create new settings for a proxy
|
/// Create new settings for a proxy
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="host">The proxy hostname/ip</param>
|
/// <param name="host">The proxy hostname/ip</param>
|
||||||
/// <param name="port">The proxy port</param>
|
/// <param name="port">The proxy port</param>
|
||||||
public ApiProxy(string host, int port)
|
public ApiProxy(string host, int port): this(host, port, null, (SecureString?)null)
|
||||||
{
|
{
|
||||||
if(string.IsNullOrEmpty(host) || port <= 0)
|
|
||||||
throw new ArgumentException("Proxy host or port not filled");
|
|
||||||
|
|
||||||
Host = host;
|
|
||||||
Port = port;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -48,11 +44,28 @@ namespace CryptoExchange.Net.Objects
|
|||||||
/// <param name="port">The proxy port</param>
|
/// <param name="port">The proxy port</param>
|
||||||
/// <param name="login">The proxy login</param>
|
/// <param name="login">The proxy login</param>
|
||||||
/// <param name="password">The proxy password</param>
|
/// <param name="password">The proxy password</param>
|
||||||
public ApiProxy(string host, int port, string login, string password) : this(host, port)
|
public ApiProxy(string host, int port, string? login, string? password) : this(host, port, login, password?.ToSecureString())
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(login) || string.IsNullOrEmpty(password))
|
}
|
||||||
throw new ArgumentException("Proxy login or password not filled");
|
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
/// <summary>
|
||||||
|
/// Create new settings for a proxy
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="host">The proxy hostname/ip</param>
|
||||||
|
/// <param name="port">The proxy port</param>
|
||||||
|
/// <param name="login">The proxy login</param>
|
||||||
|
/// <param name="password">The proxy password</param>
|
||||||
|
public ApiProxy(string host, int port, string? login, SecureString? password)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(login))
|
||||||
|
throw new ArgumentException("Proxy login not provided");
|
||||||
|
|
||||||
|
if (!host.StartsWith("http"))
|
||||||
|
throw new ArgumentException("Proxy host should start with either http:// or https://");
|
||||||
|
|
||||||
|
Host = host;
|
||||||
|
Port = port;
|
||||||
Login = login;
|
Login = login;
|
||||||
Password = password;
|
Password = password;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
using System;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Generic;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Objects
|
namespace CryptoExchange.Net.Objects
|
||||||
@ -17,7 +17,7 @@ namespace CryptoExchange.Net.Objects
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// An error if the call didn't succeed
|
/// An error if the call didn't succeed
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Error Error { get; internal set; }
|
public Error? Error { get; internal set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether the call was successful
|
/// Whether the call was successful
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -28,11 +28,20 @@ namespace CryptoExchange.Net.Objects
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="data"></param>
|
/// <param name="data"></param>
|
||||||
/// <param name="error"></param>
|
/// <param name="error"></param>
|
||||||
public CallResult(T data, Error error)
|
public CallResult([AllowNull]T data, Error? error)
|
||||||
{
|
{
|
||||||
Data = data;
|
Data = data;
|
||||||
Error = error;
|
Error = error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Overwrite bool check so we can use if(callResult) instead of if(callResult.Success)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj"></param>
|
||||||
|
public static implicit operator bool(CallResult<T> obj)
|
||||||
|
{
|
||||||
|
return !ReferenceEquals(obj, null) && obj.Success;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -49,7 +58,7 @@ namespace CryptoExchange.Net.Objects
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The response headers
|
/// The response headers
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IEnumerable<Tuple<string, string>> ResponseHeaders { get; set; }
|
public IEnumerable<KeyValuePair<string, IEnumerable<string>>>? ResponseHeaders { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ctor
|
/// ctor
|
||||||
@ -58,7 +67,7 @@ namespace CryptoExchange.Net.Objects
|
|||||||
/// <param name="responseHeaders"></param>
|
/// <param name="responseHeaders"></param>
|
||||||
/// <param name="data"></param>
|
/// <param name="data"></param>
|
||||||
/// <param name="error"></param>
|
/// <param name="error"></param>
|
||||||
public WebCallResult(HttpStatusCode? code, IEnumerable<Tuple<string, string>> responseHeaders, T data, Error error): base(data, error)
|
public WebCallResult(HttpStatusCode? code, IEnumerable<KeyValuePair<string, IEnumerable<string>>>? responseHeaders, [AllowNull] T data, Error? error): base(data, error)
|
||||||
{
|
{
|
||||||
ResponseHeaders = responseHeaders;
|
ResponseHeaders = responseHeaders;
|
||||||
ResponseStatusCode = code;
|
ResponseStatusCode = code;
|
||||||
@ -81,7 +90,7 @@ namespace CryptoExchange.Net.Objects
|
|||||||
/// <param name="responseHeaders"></param>
|
/// <param name="responseHeaders"></param>
|
||||||
/// <param name="error"></param>
|
/// <param name="error"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static WebCallResult<T> CreateErrorResult(HttpStatusCode? code, IEnumerable<Tuple<string, string>> responseHeaders, Error error)
|
public static WebCallResult<T> CreateErrorResult(HttpStatusCode? code, IEnumerable<KeyValuePair<string, IEnumerable<string>>> responseHeaders, Error error)
|
||||||
{
|
{
|
||||||
return new WebCallResult<T>(code, responseHeaders, default, error);
|
return new WebCallResult<T>(code, responseHeaders, default, error);
|
||||||
}
|
}
|
||||||
|
@ -5,23 +5,6 @@
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class Constants
|
public class Constants
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// GET Http method
|
|
||||||
/// </summary>
|
|
||||||
public const string GetMethod = "GET";
|
|
||||||
/// <summary>
|
|
||||||
/// POST Http method
|
|
||||||
/// </summary>
|
|
||||||
public const string PostMethod = "POST";
|
|
||||||
/// <summary>
|
|
||||||
/// DELETE Http method
|
|
||||||
/// </summary>
|
|
||||||
public const string DeleteMethod = "DELETE";
|
|
||||||
/// <summary>
|
|
||||||
/// PUT Http method
|
|
||||||
/// </summary>
|
|
||||||
public const string PutMethod = "PUT";
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Json content type header
|
/// Json content type header
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -137,4 +137,15 @@
|
|||||||
/// <param name="message"></param>
|
/// <param name="message"></param>
|
||||||
public RateLimitError(string message) : base(8, "Rate limit exceeded: " + message) { }
|
public RateLimitError(string message) : base(8, "Rate limit exceeded: " + message) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cancellation requested
|
||||||
|
/// </summary>
|
||||||
|
public class CancellationRequestedError : Error
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// ctor
|
||||||
|
/// </summary>
|
||||||
|
public CancellationRequestedError() : base(9, "Cancellation requested") { }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,12 @@ namespace CryptoExchange.Net.Objects
|
|||||||
/// The log writers
|
/// The log writers
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<TextWriter> LogWriters { get; set; } = new List<TextWriter> { new DebugTextWriter() };
|
public List<TextWriter> LogWriters { get; set; } = new List<TextWriter> { new DebugTextWriter() };
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"LogVerbosity: {LogVerbosity}, Writers: {LogWriters.Count}";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -47,6 +53,12 @@ namespace CryptoExchange.Net.Objects
|
|||||||
OrderBookName = name;
|
OrderBookName = name;
|
||||||
SequenceNumbersAreConsecutive = sequencesAreConsecutive;
|
SequenceNumbersAreConsecutive = sequencesAreConsecutive;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"{base.ToString()}, OrderBookName: {OrderBookName}, SequenceNumbersAreConsequtive: {SequenceNumbersAreConsecutive}";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -54,21 +66,36 @@ namespace CryptoExchange.Net.Objects
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class ClientOptions : BaseOptions
|
public class ClientOptions : BaseOptions
|
||||||
{
|
{
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The api credentials
|
|
||||||
/// </summary>
|
|
||||||
public ApiCredentials ApiCredentials { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The base address of the client
|
/// The base address of the client
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string BaseAddress { get; set; }
|
public string BaseAddress { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The api credentials
|
||||||
|
/// </summary>
|
||||||
|
public ApiCredentials? ApiCredentials { get; set; }
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Proxy to use
|
/// Proxy to use
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ApiProxy Proxy { get; set; }
|
public ApiProxy? Proxy { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ctor
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="baseAddress"></param>
|
||||||
|
public ClientOptions(string baseAddress)
|
||||||
|
{
|
||||||
|
BaseAddress = baseAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"{base.ToString()}, Credentials: {(ApiCredentials == null ? "-": "Set")}, BaseAddress: {BaseAddress}, Proxy: {(Proxy == null? "-": Proxy.Host)}";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -91,6 +118,14 @@ namespace CryptoExchange.Net.Objects
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public TimeSpan RequestTimeout { get; set; } = TimeSpan.FromSeconds(30);
|
public TimeSpan RequestTimeout { get; set; } = TimeSpan.FromSeconds(30);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ctor
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="baseAddress"></param>
|
||||||
|
public RestClientOptions(string baseAddress): base(baseAddress)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a copy of the options
|
/// Create a copy of the options
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -110,10 +145,16 @@ namespace CryptoExchange.Net.Objects
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (ApiCredentials != null)
|
if (ApiCredentials != null)
|
||||||
copy.ApiCredentials = new ApiCredentials(ApiCredentials.Key.GetString(), ApiCredentials.Secret.GetString());
|
copy.ApiCredentials = ApiCredentials.Copy();
|
||||||
|
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"{base.ToString()}, RateLimitters: {RateLimiters.Count}, RateLimitBehaviour: {RateLimitingBehaviour}, RequestTimeout: {RequestTimeout.ToString("c")}";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -146,6 +187,14 @@ namespace CryptoExchange.Net.Objects
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public int? SocketSubscriptionsCombineTarget { get; set; }
|
public int? SocketSubscriptionsCombineTarget { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ctor
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="baseAddress"></param>
|
||||||
|
public SocketClientOptions(string baseAddress) : base(baseAddress)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a copy of the options
|
/// Create a copy of the options
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -166,9 +215,15 @@ namespace CryptoExchange.Net.Objects
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (ApiCredentials != null)
|
if (ApiCredentials != null)
|
||||||
copy.ApiCredentials = new ApiCredentials(ApiCredentials.Key.GetString(), ApiCredentials.Secret.GetString());
|
copy.ApiCredentials = ApiCredentials.Copy();
|
||||||
|
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"{base.ToString()}, AutoReconnect: {AutoReconnect}, ReconnectInterval: {ReconnectInterval}, SocketResponseTimeout: {SocketResponseTimeout.ToString("c")}, SocketSubscriptionsCombineTarget: {SocketSubscriptionsCombineTarget}";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ namespace CryptoExchange.Net.OrderBook
|
|||||||
|
|
||||||
protected SortedList<decimal, ISymbolOrderBookEntry> bids;
|
protected SortedList<decimal, ISymbolOrderBookEntry> bids;
|
||||||
private OrderBookStatus status;
|
private OrderBookStatus status;
|
||||||
private UpdateSubscription subscription;
|
private UpdateSubscription? subscription;
|
||||||
private readonly bool sequencesAreConsecutive;
|
private readonly bool sequencesAreConsecutive;
|
||||||
private readonly string id;
|
private readonly string id;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -71,11 +71,11 @@ namespace CryptoExchange.Net.OrderBook
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Event when the state changes
|
/// Event when the state changes
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event Action<OrderBookStatus, OrderBookStatus> OnStatusChange;
|
public event Action<OrderBookStatus, OrderBookStatus>? OnStatusChange;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Event when order book was updated. Be careful! It can generate a lot of events at high-liquidity markets
|
/// Event when order book was updated. Be careful! It can generate a lot of events at high-liquidity markets
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event Action OnOrderBookUpdate;
|
public event Action? OnOrderBookUpdate;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Timestamp of the last update
|
/// Timestamp of the last update
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -145,6 +145,12 @@ namespace CryptoExchange.Net.OrderBook
|
|||||||
/// <param name="options"></param>
|
/// <param name="options"></param>
|
||||||
protected SymbolOrderBook(string symbol, OrderBookOptions options)
|
protected SymbolOrderBook(string symbol, OrderBookOptions options)
|
||||||
{
|
{
|
||||||
|
if (symbol == null)
|
||||||
|
throw new ArgumentNullException("symbol");
|
||||||
|
|
||||||
|
if (options == null)
|
||||||
|
throw new ArgumentNullException("options");
|
||||||
|
|
||||||
id = options.OrderBookName;
|
id = options.OrderBookName;
|
||||||
processBuffer = new List<ProcessBufferEntry>();
|
processBuffer = new List<ProcessBufferEntry>();
|
||||||
sequencesAreConsecutive = options.SequenceNumbersAreConsecutive;
|
sequencesAreConsecutive = options.SequenceNumbersAreConsecutive;
|
||||||
@ -173,7 +179,7 @@ namespace CryptoExchange.Net.OrderBook
|
|||||||
{
|
{
|
||||||
Status = OrderBookStatus.Connecting;
|
Status = OrderBookStatus.Connecting;
|
||||||
var startResult = await DoStart().ConfigureAwait(false);
|
var startResult = await DoStart().ConfigureAwait(false);
|
||||||
if (!startResult.Success)
|
if (!startResult)
|
||||||
return new CallResult<bool>(false, startResult.Error);
|
return new CallResult<bool>(false, startResult.Error);
|
||||||
|
|
||||||
subscription = startResult.Data;
|
subscription = startResult.Data;
|
||||||
@ -202,7 +208,7 @@ namespace CryptoExchange.Net.OrderBook
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var resyncResult = DoResync().Result;
|
var resyncResult = DoResync().Result;
|
||||||
success = resyncResult.Success;
|
success = resyncResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Write(LogVerbosity.Info, $"{id} order book {Symbol} successfully resynchronized");
|
log.Write(LogVerbosity.Info, $"{id} order book {Symbol} successfully resynchronized");
|
||||||
@ -222,7 +228,8 @@ namespace CryptoExchange.Net.OrderBook
|
|||||||
public async Task StopAsync()
|
public async Task StopAsync()
|
||||||
{
|
{
|
||||||
Status = OrderBookStatus.Disconnected;
|
Status = OrderBookStatus.Disconnected;
|
||||||
await subscription.Close().ConfigureAwait(false);
|
if(subscription != null)
|
||||||
|
await subscription.Close().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -303,7 +310,7 @@ namespace CryptoExchange.Net.OrderBook
|
|||||||
{
|
{
|
||||||
// Out of sync
|
// Out of sync
|
||||||
log.Write(LogVerbosity.Warning, $"{id} order book {Symbol} out of sync, reconnecting");
|
log.Write(LogVerbosity.Warning, $"{id} order book {Symbol} out of sync, reconnecting");
|
||||||
subscription.Reconnect().Wait();
|
subscription!.Reconnect().Wait();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -32,7 +32,7 @@ namespace CryptoExchange.Net.RateLimiter
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public CallResult<double> LimitRequest(RestClient client, string url, RateLimitingBehaviour limitBehaviour)
|
public CallResult<double> LimitRequest(RestClient client, string url, RateLimitingBehaviour limitBehaviour)
|
||||||
{
|
{
|
||||||
if(client.authProvider?.Credentials == null)
|
if(client.authProvider?.Credentials?.Key == null)
|
||||||
return new CallResult<double>(0, null);
|
return new CallResult<double>(0, null);
|
||||||
|
|
||||||
var key = client.authProvider.Credentials.Key.GetString();
|
var key = client.authProvider.Credentials.Key.GetString();
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.Net.Http;
|
||||||
using System.Net;
|
using System.Net.Http.Headers;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using CryptoExchange.Net.Interfaces;
|
using CryptoExchange.Net.Interfaces;
|
||||||
|
|
||||||
@ -9,84 +11,61 @@ namespace CryptoExchange.Net.Requests
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Request object
|
/// Request object
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Request : IRequest
|
internal class Request : IRequest
|
||||||
{
|
{
|
||||||
private readonly WebRequest request;
|
private readonly HttpRequestMessage request;
|
||||||
|
private readonly HttpClient httpClient;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create request object for web request
|
/// Create request object for web request
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="request"></param>
|
/// <param name="request"></param>
|
||||||
public Request(WebRequest request)
|
/// <param name="client"></param>
|
||||||
|
public Request(HttpRequestMessage request, HttpClient client)
|
||||||
{
|
{
|
||||||
|
httpClient = client;
|
||||||
this.request = request;
|
this.request = request;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public WebHeaderCollection Headers
|
public HttpRequestHeaders Headers => request.Headers;
|
||||||
{
|
|
||||||
get => request.Headers;
|
|
||||||
set => request.Headers = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string ContentType
|
public string? Content { get; private set; }
|
||||||
{
|
|
||||||
get => request.ContentType;
|
|
||||||
set => request.ContentType = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public string Content { get; set; }
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string Accept
|
public string Accept
|
||||||
{
|
{
|
||||||
get => ((HttpWebRequest)request).Accept;
|
set => request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(value));
|
||||||
set => ((HttpWebRequest)request).Accept = value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public long ContentLength
|
public HttpMethod Method
|
||||||
{
|
|
||||||
get => ((HttpWebRequest)request).ContentLength;
|
|
||||||
set => ((HttpWebRequest)request).ContentLength = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public string Method
|
|
||||||
{
|
{
|
||||||
get => request.Method;
|
get => request.Method;
|
||||||
set => request.Method = value;
|
set => request.Method = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public TimeSpan Timeout
|
|
||||||
{
|
|
||||||
get => TimeSpan.FromMilliseconds(request.Timeout);
|
|
||||||
set => request.Timeout = (int)Math.Round(value.TotalMilliseconds);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Uri Uri => request.RequestUri;
|
public Uri Uri => request.RequestUri;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void SetProxy(string host, int port, string login, string password)
|
public void SetContent(string data, string contentType)
|
||||||
{
|
{
|
||||||
request.Proxy = new WebProxy(host, port);
|
Content = data;
|
||||||
if(!string.IsNullOrEmpty(login) && !string.IsNullOrEmpty(password)) request.Proxy.Credentials = new NetworkCredential(login, password);
|
request.Content = new StringContent(data, Encoding.UTF8, contentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public async Task<Stream> GetRequestStream()
|
public void SetContent(byte[] data)
|
||||||
{
|
{
|
||||||
return await request.GetRequestStreamAsync().ConfigureAwait(false);
|
request.Content = new ByteArrayContent(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public async Task<IResponse> GetResponse()
|
public async Task<IResponse> GetResponse(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return new Response((HttpWebResponse)await request.GetResponseAsync().ConfigureAwait(false));
|
return new Response(await httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
using System.Net;
|
using System;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Http;
|
||||||
using CryptoExchange.Net.Interfaces;
|
using CryptoExchange.Net.Interfaces;
|
||||||
|
using CryptoExchange.Net.Objects;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Requests
|
namespace CryptoExchange.Net.Requests
|
||||||
{
|
{
|
||||||
@ -8,10 +11,31 @@ namespace CryptoExchange.Net.Requests
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class RequestFactory : IRequestFactory
|
public class RequestFactory : IRequestFactory
|
||||||
{
|
{
|
||||||
|
private HttpClient? httpClient;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IRequest Create(string uri)
|
public void Configure(TimeSpan requestTimeout, ApiProxy? proxy)
|
||||||
{
|
{
|
||||||
return new Request(WebRequest.Create(uri));
|
HttpMessageHandler handler = new HttpClientHandler()
|
||||||
|
{
|
||||||
|
Proxy = proxy == null ? null : new WebProxy
|
||||||
|
{
|
||||||
|
Address = new Uri($"{proxy.Host}:{proxy.Port}"),
|
||||||
|
Credentials = proxy.Password == null ? null : new NetworkCredential(proxy.Login, proxy.Password)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
httpClient = new HttpClient(handler);
|
||||||
|
httpClient.Timeout = requestTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public IRequest Create(HttpMethod method, string uri)
|
||||||
|
{
|
||||||
|
if (httpClient == null)
|
||||||
|
throw new InvalidOperationException("Cant create request before configuring http client");
|
||||||
|
|
||||||
|
return new Request(new HttpRequestMessage(method, uri), httpClient);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
using System;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using CryptoExchange.Net.Interfaces;
|
using CryptoExchange.Net.Interfaces;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Requests
|
namespace CryptoExchange.Net.Requests
|
||||||
@ -9,38 +10,38 @@ namespace CryptoExchange.Net.Requests
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// HttpWebResponse response object
|
/// HttpWebResponse response object
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Response : IResponse
|
internal class Response : IResponse
|
||||||
{
|
{
|
||||||
private readonly HttpWebResponse response;
|
private readonly HttpResponseMessage response;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public HttpStatusCode StatusCode => response.StatusCode;
|
public HttpStatusCode StatusCode => response.StatusCode;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public bool IsSuccessStatusCode => response.IsSuccessStatusCode;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public IEnumerable<KeyValuePair<string, IEnumerable<string>>> ResponseHeaders => response.Headers;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create response for http web response
|
/// Create response for a http response message
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="response"></param>
|
/// <param name="response">The actual response</param>
|
||||||
public Response(HttpWebResponse response)
|
public Response(HttpResponseMessage response)
|
||||||
{
|
{
|
||||||
this.response = response;
|
this.response = response;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Stream GetResponseStream()
|
public async Task<Stream> GetResponseStream()
|
||||||
{
|
{
|
||||||
return response.GetResponseStream();
|
return await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public IEnumerable<Tuple<string, string>> GetResponseHeaders()
|
|
||||||
{
|
|
||||||
return response.Headers.ToIEnumerable();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void Close()
|
public void Close()
|
||||||
{
|
{
|
||||||
response.Close();
|
response.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,10 +2,10 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net.Http;
|
||||||
using System.Net.NetworkInformation;
|
using System.Net.NetworkInformation;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Text;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Web;
|
using System.Web;
|
||||||
using CryptoExchange.Net.Authentication;
|
using CryptoExchange.Net.Authentication;
|
||||||
@ -29,7 +29,6 @@ namespace CryptoExchange.Net
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public IRequestFactory RequestFactory { get; set; } = new RequestFactory();
|
public IRequestFactory RequestFactory { get; set; } = new RequestFactory();
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Where to place post parameters
|
/// Where to place post parameters
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -66,18 +65,13 @@ namespace CryptoExchange.Net
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="exchangeOptions"></param>
|
/// <param name="exchangeOptions"></param>
|
||||||
/// <param name="authenticationProvider"></param>
|
/// <param name="authenticationProvider"></param>
|
||||||
protected RestClient(RestClientOptions exchangeOptions, AuthenticationProvider authenticationProvider): base(exchangeOptions, authenticationProvider)
|
protected RestClient(RestClientOptions exchangeOptions, AuthenticationProvider? authenticationProvider): base(exchangeOptions, authenticationProvider)
|
||||||
{
|
{
|
||||||
Configure(exchangeOptions);
|
if (exchangeOptions == null)
|
||||||
}
|
throw new ArgumentNullException("Options");
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Configure the client using the provided options
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="exchangeOptions">Options</param>
|
|
||||||
protected void Configure(RestClientOptions exchangeOptions)
|
|
||||||
{
|
|
||||||
RequestTimeout = exchangeOptions.RequestTimeout;
|
RequestTimeout = exchangeOptions.RequestTimeout;
|
||||||
|
RequestFactory.Configure(exchangeOptions.RequestTimeout, exchangeOptions.Proxy);
|
||||||
RateLimitBehaviour = exchangeOptions.RateLimitingBehaviour;
|
RateLimitBehaviour = exchangeOptions.RateLimitingBehaviour;
|
||||||
var rateLimiters = new List<IRateLimiter>();
|
var rateLimiters = new List<IRateLimiter>();
|
||||||
foreach (var rateLimiter in exchangeOptions.RateLimiters)
|
foreach (var rateLimiter in exchangeOptions.RateLimiters)
|
||||||
@ -91,6 +85,9 @@ namespace CryptoExchange.Net
|
|||||||
/// <param name="limiter">The limiter to add</param>
|
/// <param name="limiter">The limiter to add</param>
|
||||||
public void AddRateLimiter(IRateLimiter limiter)
|
public void AddRateLimiter(IRateLimiter limiter)
|
||||||
{
|
{
|
||||||
|
if (limiter == null)
|
||||||
|
throw new ArgumentNullException("limiter");
|
||||||
|
|
||||||
var rateLimiters = RateLimiters.ToList();
|
var rateLimiters = RateLimiters.ToList();
|
||||||
rateLimiters.Add(limiter);
|
rateLimiters.Add(limiter);
|
||||||
RateLimiters = rateLimiters;
|
RateLimiters = rateLimiters;
|
||||||
@ -132,6 +129,10 @@ namespace CryptoExchange.Net
|
|||||||
return new CallResult<long>(0, new CantConnectError { Message = "Ping failed: " + exception.SocketErrorCode });
|
return new CallResult<long>(0, new CantConnectError { Message = "Ping failed: " + exception.SocketErrorCode });
|
||||||
return new CallResult<long>(0, new CantConnectError { Message = "Ping failed: " + e.InnerException.Message });
|
return new CallResult<long>(0, new CantConnectError { Message = "Ping failed: " + e.InnerException.Message });
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
ping.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
return reply.Status == IPStatus.Success ? new CallResult<long>(reply.RoundtripTime, null) : new CallResult<long>(0, new CantConnectError { Message = "Ping failed: " + reply.Status });
|
return reply.Status == IPStatus.Success ? new CallResult<long>(reply.RoundtripTime, null) : new CallResult<long>(0, new CantConnectError { Message = "Ping failed: " + reply.Status });
|
||||||
}
|
}
|
||||||
@ -142,11 +143,13 @@ namespace CryptoExchange.Net
|
|||||||
/// <typeparam name="T">The expected result type</typeparam>
|
/// <typeparam name="T">The expected result type</typeparam>
|
||||||
/// <param name="uri">The uri to send the request to</param>
|
/// <param name="uri">The uri to send the request to</param>
|
||||||
/// <param name="method">The method of the request</param>
|
/// <param name="method">The method of the request</param>
|
||||||
|
/// <param name="cancellationToken">Cancellation token</param>
|
||||||
/// <param name="parameters">The parameters of the request</param>
|
/// <param name="parameters">The parameters of the request</param>
|
||||||
/// <param name="signed">Whether or not the request should be authenticated</param>
|
/// <param name="signed">Whether or not the request should be authenticated</param>
|
||||||
/// <param name="checkResult">Whether or not the resulting object should be checked for missing properties in the mapping (only outputs if log verbosity is Debug)</param>
|
/// <param name="checkResult">Whether or not the resulting object should be checked for missing properties in the mapping (only outputs if log verbosity is Debug)</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
protected virtual async Task<WebCallResult<T>> ExecuteRequest<T>(Uri uri, string method = Constants.GetMethod, Dictionary<string, object> parameters = null, bool signed = false, bool checkResult = true) where T : class
|
protected virtual async Task<WebCallResult<T>> SendRequest<T>(Uri uri, HttpMethod method, CancellationToken cancellationToken,
|
||||||
|
Dictionary<string, object>? parameters = null, bool signed = false, bool checkResult = true) where T : class
|
||||||
{
|
{
|
||||||
log.Write(LogVerbosity.Debug, "Creating request for " + uri);
|
log.Write(LogVerbosity.Debug, "Creating request for " + uri);
|
||||||
if (signed && authProvider == null)
|
if (signed && authProvider == null)
|
||||||
@ -156,13 +159,6 @@ namespace CryptoExchange.Net
|
|||||||
}
|
}
|
||||||
|
|
||||||
var request = ConstructRequest(uri, method, parameters, signed);
|
var request = ConstructRequest(uri, method, parameters, signed);
|
||||||
|
|
||||||
if (apiProxy != null)
|
|
||||||
{
|
|
||||||
log.Write(LogVerbosity.Debug, "Setting proxy");
|
|
||||||
request.SetProxy(apiProxy.Host, apiProxy.Port, apiProxy.Login, apiProxy.Password);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var limiter in RateLimiters)
|
foreach (var limiter in RateLimiters)
|
||||||
{
|
{
|
||||||
var limitResult = limiter.LimitRequest(this, uri.AbsolutePath, RateLimitBehaviour);
|
var limitResult = limiter.LimitRequest(this, uri.AbsolutePath, RateLimitBehaviour);
|
||||||
@ -176,37 +172,64 @@ namespace CryptoExchange.Net
|
|||||||
log.Write(LogVerbosity.Debug, $"Request {uri.AbsolutePath} was limited by {limitResult.Data}ms by {limiter.GetType().Name}");
|
log.Write(LogVerbosity.Debug, $"Request {uri.AbsolutePath} was limited by {limitResult.Data}ms by {limiter.GetType().Name}");
|
||||||
}
|
}
|
||||||
|
|
||||||
string paramString = null;
|
string? paramString = null;
|
||||||
if (parameters != null && method == Constants.PostMethod)
|
if (parameters != null && method == HttpMethod.Post)
|
||||||
paramString = "with request body " + request.Content;
|
paramString = " with request body " + request.Content;
|
||||||
|
|
||||||
log.Write(LogVerbosity.Debug, $"Sending {method}{(signed ? " signed" : "")} request to {request.Uri} {paramString ?? ""}");
|
log.Write(LogVerbosity.Debug, $"Sending {method}{(signed ? " signed" : "")} request to {request.Uri}{paramString ?? " "}{(apiProxy == null? "": $" via proxy {apiProxy.Host}")}");
|
||||||
var result = await ExecuteRequest(request).ConfigureAwait(false);
|
return await GetResponse<T>(request, cancellationToken).ConfigureAwait(false);
|
||||||
if(!result.Success)
|
|
||||||
return new WebCallResult<T>(result.ResponseStatusCode, result.ResponseHeaders, null, result.Error);
|
|
||||||
|
|
||||||
var jsonResult = ValidateJson(result.Data);
|
|
||||||
if(!jsonResult.Success)
|
|
||||||
return new WebCallResult<T>(result.ResponseStatusCode, result.ResponseHeaders, null, jsonResult.Error);
|
|
||||||
|
|
||||||
if (IsErrorResponse(jsonResult.Data))
|
|
||||||
return new WebCallResult<T>(result.ResponseStatusCode, result.ResponseHeaders, null, ParseErrorResponse(jsonResult.Data));
|
|
||||||
|
|
||||||
var desResult = Deserialize<T>(jsonResult.Data, checkResult);
|
|
||||||
if (!desResult.Success)
|
|
||||||
return new WebCallResult<T>(result.ResponseStatusCode, result.ResponseHeaders, null, desResult.Error);
|
|
||||||
|
|
||||||
return new WebCallResult<T>(result.ResponseStatusCode, result.ResponseHeaders, desResult.Data, null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Can be overridden to indicate if a response is an error response
|
/// Executes the request and returns the string result
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="data">The received data</param>
|
/// <param name="request">The request object to execute</param>
|
||||||
/// <returns>True if error response</returns>
|
/// <param name="cancellationToken">Cancellation token</param>
|
||||||
protected virtual bool IsErrorResponse(JToken data)
|
/// <returns></returns>
|
||||||
|
private async Task<WebCallResult<T>> GetResponse<T>(IRequest request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return false;
|
try
|
||||||
|
{
|
||||||
|
TotalRequestsMade++;
|
||||||
|
var response = await request.GetResponse(cancellationToken).ConfigureAwait(false);
|
||||||
|
var statusCode = response.StatusCode;
|
||||||
|
var headers = response.ResponseHeaders;
|
||||||
|
var responseStream = await response.GetResponseStream().ConfigureAwait(false);
|
||||||
|
if (response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
var desResult = await Deserialize<T>(responseStream).ConfigureAwait(false);
|
||||||
|
response.Close();
|
||||||
|
return new WebCallResult<T>(statusCode, headers, desResult.Data, desResult.Error);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
using var reader = new StreamReader(responseStream);
|
||||||
|
var data = await reader.ReadToEndAsync().ConfigureAwait(false);
|
||||||
|
response.Close();
|
||||||
|
var parseResult = ValidateJson(data);
|
||||||
|
return new WebCallResult<T>(statusCode, headers, default, parseResult.Success ? ParseErrorResponse(parseResult.Data) :new ServerError(data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (HttpRequestException requestException)
|
||||||
|
{
|
||||||
|
log.Write(LogVerbosity.Warning, "Request exception: " + requestException.Message);
|
||||||
|
return new WebCallResult<T>(null, null, default, new ServerError(requestException.Message));
|
||||||
|
}
|
||||||
|
catch (TaskCanceledException canceledException)
|
||||||
|
{
|
||||||
|
if(canceledException.CancellationToken == cancellationToken)
|
||||||
|
{
|
||||||
|
// Cancellation token cancelled
|
||||||
|
log.Write(LogVerbosity.Warning, "Request cancel requested");
|
||||||
|
return new WebCallResult<T>(null, null, default, new CancellationRequestedError());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Request timed out
|
||||||
|
log.Write(LogVerbosity.Warning, "Request timed out");
|
||||||
|
return new WebCallResult<T>(null, null, default, new WebError("Request timed out"));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -217,7 +240,7 @@ namespace CryptoExchange.Net
|
|||||||
/// <param name="parameters">The parameters of the request</param>
|
/// <param name="parameters">The parameters of the request</param>
|
||||||
/// <param name="signed">Whether or not the request should be authenticated</param>
|
/// <param name="signed">Whether or not the request should be authenticated</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
protected virtual IRequest ConstructRequest(Uri uri, string method, Dictionary<string, object> parameters, bool signed)
|
protected virtual IRequest ConstructRequest(Uri uri, HttpMethod method, Dictionary<string, object>? parameters, bool signed)
|
||||||
{
|
{
|
||||||
if (parameters == null)
|
if (parameters == null)
|
||||||
parameters = new Dictionary<string, object>();
|
parameters = new Dictionary<string, object>();
|
||||||
@ -226,57 +249,44 @@ namespace CryptoExchange.Net
|
|||||||
if(authProvider != null)
|
if(authProvider != null)
|
||||||
parameters = authProvider.AddAuthenticationToParameters(uriString, method, parameters, signed);
|
parameters = authProvider.AddAuthenticationToParameters(uriString, method, parameters, signed);
|
||||||
|
|
||||||
if((method == Constants.GetMethod || method == Constants.DeleteMethod || postParametersPosition == PostParameters.InUri) && parameters?.Any() == true)
|
if((method == HttpMethod.Get || method == HttpMethod.Delete || postParametersPosition == PostParameters.InUri) && parameters?.Any() == true)
|
||||||
uriString += "?" + parameters.CreateParamString(true, arraySerialization);
|
uriString += "?" + parameters.CreateParamString(true, arraySerialization);
|
||||||
|
|
||||||
var request = RequestFactory.Create(uriString);
|
var contentType = requestBodyFormat == RequestBodyFormat.Json ? Constants.JsonContentHeader : Constants.FormContentHeader;
|
||||||
request.ContentType = requestBodyFormat == RequestBodyFormat.Json ? Constants.JsonContentHeader : Constants.FormContentHeader;
|
var request = RequestFactory.Create(method, uriString);
|
||||||
request.Accept = Constants.JsonContentHeader;
|
request.Accept = Constants.JsonContentHeader;
|
||||||
request.Method = method;
|
|
||||||
|
|
||||||
var headers = new Dictionary<string, string>();
|
var headers = new Dictionary<string, string>();
|
||||||
if (authProvider != null)
|
if (authProvider != null)
|
||||||
headers = authProvider.AddAuthenticationToHeaders(uriString, method, parameters, signed);
|
headers = authProvider.AddAuthenticationToHeaders(uriString, method, parameters!, signed);
|
||||||
|
|
||||||
foreach (var header in headers)
|
foreach (var header in headers)
|
||||||
request.Headers.Add(header.Key, header.Value);
|
request.Headers.Add(header.Key, header.Value);
|
||||||
|
|
||||||
if ((method == Constants.PostMethod || method == Constants.PutMethod) && postParametersPosition != PostParameters.InUri)
|
if ((method == HttpMethod.Post || method == HttpMethod.Put) && postParametersPosition != PostParameters.InUri)
|
||||||
{
|
{
|
||||||
if(parameters?.Any() == true)
|
if(parameters?.Any() == true)
|
||||||
WriteParamBody(request, parameters);
|
WriteParamBody(request, parameters, contentType);
|
||||||
else
|
else
|
||||||
WriteParamBody(request, "{}");
|
request.SetContent("{}", contentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Writes the string data of the parameters to the request body stream
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="request"></param>
|
|
||||||
/// <param name="stringData"></param>
|
|
||||||
protected virtual void WriteParamBody(IRequest request, string stringData)
|
|
||||||
{
|
|
||||||
var data = Encoding.UTF8.GetBytes(stringData);
|
|
||||||
request.ContentLength = data.Length;
|
|
||||||
request.Content = stringData;
|
|
||||||
using (var stream = request.GetRequestStream().Result)
|
|
||||||
stream.Write(data, 0, data.Length);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Writes the parameters of the request to the request object, either in the query string or the request body
|
/// Writes the parameters of the request to the request object, either in the query string or the request body
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="request"></param>
|
/// <param name="request"></param>
|
||||||
/// <param name="parameters"></param>
|
/// <param name="parameters"></param>
|
||||||
protected virtual void WriteParamBody(IRequest request, Dictionary<string, object> parameters)
|
/// <param name="contentType"></param>
|
||||||
|
protected virtual void WriteParamBody(IRequest request, Dictionary<string, object> parameters, string contentType)
|
||||||
{
|
{
|
||||||
if (requestBodyFormat == RequestBodyFormat.Json)
|
if (requestBodyFormat == RequestBodyFormat.Json)
|
||||||
{
|
{
|
||||||
var stringData = JsonConvert.SerializeObject(parameters.OrderBy(p => p.Key).ToDictionary(p => p.Key, p => p.Value));
|
var stringData = JsonConvert.SerializeObject(parameters.OrderBy(p => p.Key).ToDictionary(p => p.Key, p => p.Value));
|
||||||
WriteParamBody(request, stringData);
|
request.SetContent(stringData, contentType);
|
||||||
|
|
||||||
}
|
}
|
||||||
else if(requestBodyFormat == RequestBodyFormat.FormData)
|
else if(requestBodyFormat == RequestBodyFormat.FormData)
|
||||||
{
|
{
|
||||||
@ -284,81 +294,9 @@ namespace CryptoExchange.Net
|
|||||||
foreach (var kvp in parameters.OrderBy(p => p.Key))
|
foreach (var kvp in parameters.OrderBy(p => p.Key))
|
||||||
formData.Add(kvp.Key, kvp.Value.ToString());
|
formData.Add(kvp.Key, kvp.Value.ToString());
|
||||||
var stringData = formData.ToString();
|
var stringData = formData.ToString();
|
||||||
WriteParamBody(request, stringData);
|
request.SetContent(stringData, contentType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Executes the request and returns the string result
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="request">The request object to execute</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private async Task<WebCallResult<string>> ExecuteRequest(IRequest request)
|
|
||||||
{
|
|
||||||
var returnedData = "";
|
|
||||||
try
|
|
||||||
{
|
|
||||||
request.Timeout = RequestTimeout;
|
|
||||||
TotalRequestsMade++;
|
|
||||||
var response = await request.GetResponse().ConfigureAwait(false);
|
|
||||||
using (var reader = new StreamReader(response.GetResponseStream()))
|
|
||||||
{
|
|
||||||
returnedData = await reader.ReadToEndAsync().ConfigureAwait(false);
|
|
||||||
log.Write(LogVerbosity.Debug, "Data returned: " + returnedData);
|
|
||||||
}
|
|
||||||
|
|
||||||
var statusCode = response.StatusCode;
|
|
||||||
var returnHeaders = response.GetResponseHeaders();
|
|
||||||
response.Close();
|
|
||||||
return new WebCallResult<string>(statusCode, returnHeaders, returnedData, null);
|
|
||||||
}
|
|
||||||
catch (WebException we)
|
|
||||||
{
|
|
||||||
var response = (HttpWebResponse)we.Response;
|
|
||||||
var statusCode = response?.StatusCode;
|
|
||||||
var returnHeaders = response?.Headers.ToIEnumerable();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var responseStream = response?.GetResponseStream();
|
|
||||||
if (response != null && responseStream != null)
|
|
||||||
{
|
|
||||||
using (var reader = new StreamReader(responseStream))
|
|
||||||
{
|
|
||||||
returnedData = await reader.ReadToEndAsync().ConfigureAwait(false);
|
|
||||||
log.Write(LogVerbosity.Warning, "Server returned an error: " + returnedData);
|
|
||||||
}
|
|
||||||
|
|
||||||
response.Close();
|
|
||||||
|
|
||||||
var jsonResult = ValidateJson(returnedData);
|
|
||||||
return !jsonResult.Success ? new WebCallResult<string>(statusCode, returnHeaders, null, jsonResult.Error) : new WebCallResult<string>(statusCode, returnHeaders, null, ParseErrorResponse(jsonResult.Data));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
log.Write(LogVerbosity.Debug, "Not able to read server response: " + e.Message);
|
|
||||||
}
|
|
||||||
|
|
||||||
var infoMessage = "No response from server";
|
|
||||||
if (response == null)
|
|
||||||
{
|
|
||||||
infoMessage += $" | {we.Status} - {we.Message}";
|
|
||||||
log.Write(LogVerbosity.Warning, infoMessage);
|
|
||||||
return new WebCallResult<string>(0, null, null, new WebError(infoMessage));
|
|
||||||
}
|
|
||||||
|
|
||||||
infoMessage = $"Status: {response.StatusCode}-{response.StatusDescription}, Message: {we.Message}";
|
|
||||||
log.Write(LogVerbosity.Warning, infoMessage);
|
|
||||||
response.Close();
|
|
||||||
return new WebCallResult<string>(statusCode, returnHeaders, null, new ServerError(infoMessage));
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
log.Write(LogVerbosity.Error, $"Unknown error occured: {e.GetType()}, {e.Message}, {e.StackTrace}");
|
|
||||||
return new WebCallResult<string>(null, null, null, new UnknownError(e.Message + ", data: " + returnedData));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Parse an error response from the server. Only used when server returns a status other than Success(200)
|
/// Parse an error response from the server. Only used when server returns a status other than Success(200)
|
||||||
|
@ -50,11 +50,11 @@ namespace CryptoExchange.Net
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handler for byte data
|
/// Handler for byte data
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected Func<byte[], string> dataInterpreterBytes;
|
protected Func<byte[], string>? dataInterpreterBytes;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handler for string data
|
/// Handler for string data
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected Func<string, string> dataInterpreterString;
|
protected Func<string, string>? dataInterpreterString;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generic handlers
|
/// Generic handlers
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -62,11 +62,11 @@ namespace CryptoExchange.Net
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Periodic task
|
/// Periodic task
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected Task periodicTask;
|
protected Task? periodicTask;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Periodic task event
|
/// Periodic task event
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected AutoResetEvent periodicEvent;
|
protected AutoResetEvent? periodicEvent;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Is disposing
|
/// Is disposing
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -84,17 +84,11 @@ namespace CryptoExchange.Net
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="exchangeOptions">Client options</param>
|
/// <param name="exchangeOptions">Client options</param>
|
||||||
/// <param name="authenticationProvider">Authentication provider</param>
|
/// <param name="authenticationProvider">Authentication provider</param>
|
||||||
protected SocketClient(SocketClientOptions exchangeOptions, AuthenticationProvider authenticationProvider): base(exchangeOptions, authenticationProvider)
|
protected SocketClient(SocketClientOptions exchangeOptions, AuthenticationProvider? authenticationProvider): base(exchangeOptions, authenticationProvider)
|
||||||
{
|
{
|
||||||
Configure(exchangeOptions);
|
if (exchangeOptions == null)
|
||||||
}
|
throw new ArgumentNullException("Options");
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Configure the client using the provided options
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="exchangeOptions">Options</param>
|
|
||||||
protected void Configure(SocketClientOptions exchangeOptions)
|
|
||||||
{
|
|
||||||
AutoReconnect = exchangeOptions.AutoReconnect;
|
AutoReconnect = exchangeOptions.AutoReconnect;
|
||||||
ReconnectInterval = exchangeOptions.ReconnectInterval;
|
ReconnectInterval = exchangeOptions.ReconnectInterval;
|
||||||
ResponseTimeout = exchangeOptions.SocketResponseTimeout;
|
ResponseTimeout = exchangeOptions.SocketResponseTimeout;
|
||||||
@ -137,7 +131,7 @@ namespace CryptoExchange.Net
|
|||||||
/// <param name="authenticated">If the subscription should be authenticated</param>
|
/// <param name="authenticated">If the subscription should be authenticated</param>
|
||||||
/// <param name="dataHandler">The handler of update data</param>
|
/// <param name="dataHandler">The handler of update data</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
protected virtual async Task<CallResult<UpdateSubscription>> Subscribe<T>(string url, object request, string identifier, bool authenticated, Action<T> dataHandler)
|
protected virtual async Task<CallResult<UpdateSubscription>> Subscribe<T>(string url, object? request, string? identifier, bool authenticated, Action<T> dataHandler)
|
||||||
{
|
{
|
||||||
SocketConnection socket;
|
SocketConnection socket;
|
||||||
SocketSubscription handler;
|
SocketSubscription handler;
|
||||||
@ -155,7 +149,7 @@ namespace CryptoExchange.Net
|
|||||||
}
|
}
|
||||||
|
|
||||||
var connectResult = await ConnectIfNeeded(socket, authenticated).ConfigureAwait(false);
|
var connectResult = await ConnectIfNeeded(socket, authenticated).ConfigureAwait(false);
|
||||||
if (!connectResult.Success)
|
if (!connectResult)
|
||||||
return new CallResult<UpdateSubscription>(null, connectResult.Error);
|
return new CallResult<UpdateSubscription>(null, connectResult.Error);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
@ -170,7 +164,7 @@ namespace CryptoExchange.Net
|
|||||||
if (request != null)
|
if (request != null)
|
||||||
{
|
{
|
||||||
var subResult = await SubscribeAndWait(socket, request, handler).ConfigureAwait(false);
|
var subResult = await SubscribeAndWait(socket, request, handler).ConfigureAwait(false);
|
||||||
if (!subResult.Success)
|
if (!subResult)
|
||||||
{
|
{
|
||||||
await socket.Close(handler).ConfigureAwait(false);
|
await socket.Close(handler).ConfigureAwait(false);
|
||||||
return new CallResult<UpdateSubscription>(null, subResult.Error);
|
return new CallResult<UpdateSubscription>(null, subResult.Error);
|
||||||
@ -192,8 +186,8 @@ namespace CryptoExchange.Net
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
protected internal virtual async Task<CallResult<bool>> SubscribeAndWait(SocketConnection socket, object request, SocketSubscription subscription)
|
protected internal virtual async Task<CallResult<bool>> SubscribeAndWait(SocketConnection socket, object request, SocketSubscription subscription)
|
||||||
{
|
{
|
||||||
CallResult<object> callResult = null;
|
CallResult<object>? callResult = null;
|
||||||
await socket.SendAndWait(request, ResponseTimeout, data => HandleSubscriptionResponse(socket, subscription, request, data, out callResult)).ConfigureAwait(false);
|
await socket.SendAndWait(request, ResponseTimeout, data => HandleSubscriptionResponse(socket, subscription, request, data, out var callResult)).ConfigureAwait(false);
|
||||||
|
|
||||||
if (callResult?.Success == true)
|
if (callResult?.Success == true)
|
||||||
subscription.Confirmed = true;
|
subscription.Confirmed = true;
|
||||||
@ -237,7 +231,7 @@ namespace CryptoExchange.Net
|
|||||||
}
|
}
|
||||||
|
|
||||||
var connectResult = await ConnectIfNeeded(socket, authenticated).ConfigureAwait(false);
|
var connectResult = await ConnectIfNeeded(socket, authenticated).ConfigureAwait(false);
|
||||||
if (!connectResult.Success)
|
if (!connectResult)
|
||||||
return new CallResult<T>(default, connectResult.Error);
|
return new CallResult<T>(default, connectResult.Error);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
@ -291,17 +285,17 @@ namespace CryptoExchange.Net
|
|||||||
return new CallResult<bool>(true, null);
|
return new CallResult<bool>(true, null);
|
||||||
|
|
||||||
var connectResult = await ConnectSocket(socket).ConfigureAwait(false);
|
var connectResult = await ConnectSocket(socket).ConfigureAwait(false);
|
||||||
if (!connectResult.Success)
|
if (!connectResult)
|
||||||
return new CallResult<bool>(false, new CantConnectError());
|
return new CallResult<bool>(false, new CantConnectError());
|
||||||
|
|
||||||
if (!authenticated || socket.Authenticated)
|
if (!authenticated || socket.Authenticated)
|
||||||
return new CallResult<bool>(true, null);
|
return new CallResult<bool>(true, null);
|
||||||
|
|
||||||
var result = await AuthenticateSocket(socket).ConfigureAwait(false);
|
var result = await AuthenticateSocket(socket).ConfigureAwait(false);
|
||||||
if (!result.Success)
|
if (!result)
|
||||||
{
|
{
|
||||||
log.Write(LogVerbosity.Warning, "Socket authentication failed");
|
log.Write(LogVerbosity.Warning, "Socket authentication failed");
|
||||||
result.Error.Message = "Authentication failed: " + result.Error.Message;
|
result.Error!.Message = "Authentication failed: " + result.Error.Message;
|
||||||
return new CallResult<bool>(false, result.Error);
|
return new CallResult<bool>(false, result.Error);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -377,7 +371,7 @@ namespace CryptoExchange.Net
|
|||||||
/// <param name="connection">The socket connection the handler is on</param>
|
/// <param name="connection">The socket connection the handler is on</param>
|
||||||
/// <param name="dataHandler">The handler of the data received</param>
|
/// <param name="dataHandler">The handler of the data received</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
protected virtual SocketSubscription AddHandler<T>(object request, string identifier, bool userSubscription, SocketConnection connection, Action<T> dataHandler)
|
protected virtual SocketSubscription AddHandler<T>(object? request, string? identifier, bool userSubscription, SocketConnection connection, Action<T> dataHandler)
|
||||||
{
|
{
|
||||||
void InternalHandler(SocketConnection socketWrapper, JToken data)
|
void InternalHandler(SocketConnection socketWrapper, JToken data)
|
||||||
{
|
{
|
||||||
@ -388,7 +382,7 @@ namespace CryptoExchange.Net
|
|||||||
}
|
}
|
||||||
|
|
||||||
var desResult = Deserialize<T>(data, false);
|
var desResult = Deserialize<T>(data, false);
|
||||||
if (!desResult.Success)
|
if (!desResult)
|
||||||
{
|
{
|
||||||
log.Write(LogVerbosity.Warning, $"Failed to deserialize data into type {typeof(T)}: {desResult.Error}");
|
log.Write(LogVerbosity.Warning, $"Failed to deserialize data into type {typeof(T)}: {desResult.Error}");
|
||||||
return;
|
return;
|
||||||
@ -397,7 +391,7 @@ namespace CryptoExchange.Net
|
|||||||
dataHandler(desResult.Data);
|
dataHandler(desResult.Data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return connection.AddHandler(request ?? identifier, userSubscription, InternalHandler);
|
return connection.AddHandler(request ?? identifier!, userSubscription, InternalHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -486,6 +480,9 @@ namespace CryptoExchange.Net
|
|||||||
/// <param name="objGetter">Method returning the object to send</param>
|
/// <param name="objGetter">Method returning the object to send</param>
|
||||||
public virtual void SendPeriodic(TimeSpan interval, Func<SocketConnection, object> objGetter)
|
public virtual void SendPeriodic(TimeSpan interval, Func<SocketConnection, object> objGetter)
|
||||||
{
|
{
|
||||||
|
if (objGetter == null)
|
||||||
|
throw new ArgumentNullException("objGetter");
|
||||||
|
|
||||||
periodicEvent = new AutoResetEvent(false);
|
periodicEvent = new AutoResetEvent(false);
|
||||||
periodicTask = Task.Run(async () =>
|
periodicTask = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
@ -517,7 +514,6 @@ namespace CryptoExchange.Net
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -530,7 +526,7 @@ namespace CryptoExchange.Net
|
|||||||
public virtual async Task Unsubscribe(UpdateSubscription subscription)
|
public virtual async Task Unsubscribe(UpdateSubscription subscription)
|
||||||
{
|
{
|
||||||
if (subscription == null)
|
if (subscription == null)
|
||||||
return;
|
throw new ArgumentNullException("subscription");
|
||||||
|
|
||||||
log.Write(LogVerbosity.Info, "Closing subscription");
|
log.Write(LogVerbosity.Info, "Closing subscription");
|
||||||
await subscription.Close().ConfigureAwait(false);
|
await subscription.Close().ConfigureAwait(false);
|
||||||
@ -564,9 +560,10 @@ namespace CryptoExchange.Net
|
|||||||
{
|
{
|
||||||
disposing = true;
|
disposing = true;
|
||||||
periodicEvent?.Set();
|
periodicEvent?.Set();
|
||||||
|
periodicEvent?.Dispose();
|
||||||
log.Write(LogVerbosity.Debug, "Disposing socket client, closing all subscriptions");
|
log.Write(LogVerbosity.Debug, "Disposing socket client, closing all subscriptions");
|
||||||
UnsubscribeAll().Wait();
|
UnsubscribeAll().Wait();
|
||||||
|
semaphoreSlim?.Dispose();
|
||||||
base.Dispose();
|
base.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
internal static int lastStreamId;
|
internal static int lastStreamId;
|
||||||
private static readonly object streamIdLock = new object();
|
private static readonly object streamIdLock = new object();
|
||||||
|
|
||||||
protected WebSocket socket;
|
protected WebSocket? socket;
|
||||||
protected Log log;
|
protected Log log;
|
||||||
protected object socketLock = new object();
|
protected object socketLock = new object();
|
||||||
|
|
||||||
@ -32,34 +32,22 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
|
|
||||||
protected IDictionary<string, string> cookies;
|
protected IDictionary<string, string> cookies;
|
||||||
protected IDictionary<string, string> headers;
|
protected IDictionary<string, string> headers;
|
||||||
protected HttpConnectProxy proxy;
|
protected HttpConnectProxy? proxy;
|
||||||
|
|
||||||
public int Id { get; }
|
public int Id { get; }
|
||||||
public bool Reconnecting { get; set; }
|
public bool Reconnecting { get; set; }
|
||||||
public string Origin { get; set; }
|
public string? Origin { get; set; }
|
||||||
|
|
||||||
public string Url { get; }
|
public string Url { get; }
|
||||||
public bool IsClosed => socket.State == WebSocketState.Closed;
|
public bool IsClosed => socket?.State == null ? true: socket.State == WebSocketState.Closed;
|
||||||
public bool IsOpen => socket.State == WebSocketState.Open;
|
public bool IsOpen => socket?.State == WebSocketState.Open;
|
||||||
public SslProtocols SSLProtocols { get; set; } = SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls;
|
public SslProtocols SSLProtocols { get; set; } = SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls;
|
||||||
public Func<byte[], string> DataInterpreterBytes { get; set; }
|
public Func<byte[], string>? DataInterpreterBytes { get; set; }
|
||||||
public Func<string, string> DataInterpreterString { get; set; }
|
public Func<string, string>? DataInterpreterString { get; set; }
|
||||||
|
|
||||||
public DateTime LastActionTime { get; private set; }
|
public DateTime LastActionTime { get; private set; }
|
||||||
public TimeSpan Timeout { get; set; }
|
public TimeSpan Timeout { get; set; }
|
||||||
private Task timeoutTask;
|
private Task? timeoutTask;
|
||||||
|
|
||||||
public bool PingConnection
|
|
||||||
{
|
|
||||||
get => socket.EnableAutoSendPing;
|
|
||||||
set => socket.EnableAutoSendPing = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TimeSpan PingInterval
|
|
||||||
{
|
|
||||||
get => TimeSpan.FromSeconds(socket.AutoSendPingInterval);
|
|
||||||
set => socket.AutoSendPingInterval = (int) Math.Round(value.TotalSeconds);
|
|
||||||
}
|
|
||||||
|
|
||||||
public WebSocketState SocketState => socket?.State ?? WebSocketState.None;
|
public WebSocketState SocketState => socket?.State ?? WebSocketState.None;
|
||||||
|
|
||||||
@ -176,7 +164,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
|
|
||||||
var waitLock = new object();
|
var waitLock = new object();
|
||||||
log?.Write(LogVerbosity.Debug, $"Socket {Id} closing");
|
log?.Write(LogVerbosity.Debug, $"Socket {Id} closing");
|
||||||
var evnt = new ManualResetEvent(false);
|
ManualResetEvent? evnt = new ManualResetEvent(false);
|
||||||
var handler = new EventHandler((o, a) =>
|
var handler = new EventHandler((o, a) =>
|
||||||
{
|
{
|
||||||
lock(waitLock)
|
lock(waitLock)
|
||||||
@ -208,7 +196,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
|
|
||||||
public virtual void Send(string data)
|
public virtual void Send(string data)
|
||||||
{
|
{
|
||||||
socket.Send(data);
|
socket?.Send(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual Task<bool> Connect()
|
public virtual Task<bool> Connect()
|
||||||
@ -239,7 +227,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
{
|
{
|
||||||
log?.Write(LogVerbosity.Debug, $"Socket {Id} connecting");
|
log?.Write(LogVerbosity.Debug, $"Socket {Id} connecting");
|
||||||
var waitLock = new object();
|
var waitLock = new object();
|
||||||
var evnt = new ManualResetEvent(false);
|
ManualResetEvent? evnt = new ManualResetEvent(false);
|
||||||
var handler = new EventHandler((o, a) =>
|
var handler = new EventHandler((o, a) =>
|
||||||
{
|
{
|
||||||
lock (waitLock)
|
lock (waitLock)
|
||||||
|
@ -19,15 +19,15 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Connection lost event
|
/// Connection lost event
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event Action ConnectionLost;
|
public event Action? ConnectionLost;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Connecting restored event
|
/// Connecting restored event
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event Action<TimeSpan> ConnectionRestored;
|
public event Action<TimeSpan>? ConnectionRestored;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Connecting closed event
|
/// Connecting closed event
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event Action Closed;
|
public event Action? Closed;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The amount of handlers
|
/// The amount of handlers
|
||||||
@ -119,7 +119,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public SocketSubscription AddHandler(object request, bool userSubscription, Action<SocketConnection, JToken> dataHandler)
|
public SocketSubscription AddHandler(object request, bool userSubscription, Action<SocketConnection, JToken> dataHandler)
|
||||||
{
|
{
|
||||||
var handler = new SocketSubscription(null, request, userSubscription, dataHandler);
|
var handler = new SocketSubscription(request, userSubscription, dataHandler);
|
||||||
lock (handlersLock)
|
lock (handlersLock)
|
||||||
handlers.Add(handler);
|
handlers.Add(handler);
|
||||||
return handler;
|
return handler;
|
||||||
@ -135,7 +135,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public SocketSubscription AddHandler(string identifier, bool userSubscription, Action<SocketConnection, JToken> dataHandler)
|
public SocketSubscription AddHandler(string identifier, bool userSubscription, Action<SocketConnection, JToken> dataHandler)
|
||||||
{
|
{
|
||||||
var handler = new SocketSubscription(identifier, null, userSubscription, dataHandler);
|
var handler = new SocketSubscription(identifier, userSubscription, dataHandler);
|
||||||
lock (handlersLock)
|
lock (handlersLock)
|
||||||
handlers.Add(handler);
|
handlers.Add(handler);
|
||||||
return handler;
|
return handler;
|
||||||
@ -169,7 +169,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
|
|
||||||
private bool HandleData(JToken tokenData)
|
private bool HandleData(JToken tokenData)
|
||||||
{
|
{
|
||||||
SocketSubscription currentSubscription = null;
|
SocketSubscription? currentSubscription = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var handled = false;
|
var handled = false;
|
||||||
@ -181,7 +181,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
currentSubscription = handler;
|
currentSubscription = handler;
|
||||||
if (handler.Request == null)
|
if (handler.Request == null)
|
||||||
{
|
{
|
||||||
if (socketClient.MessageMatchesHandler(tokenData, handler.Identifier))
|
if (socketClient.MessageMatchesHandler(tokenData, handler.Identifier!))
|
||||||
{
|
{
|
||||||
handled = true;
|
handled = true;
|
||||||
handler.MessageHandler(this, tokenData);
|
handler.MessageHandler(this, tokenData);
|
||||||
@ -326,7 +326,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
if (Authenticated)
|
if (Authenticated)
|
||||||
{
|
{
|
||||||
var authResult = await socketClient.AuthenticateSocket(this).ConfigureAwait(false);
|
var authResult = await socketClient.AuthenticateSocket(this).ConfigureAwait(false);
|
||||||
if (!authResult.Success)
|
if (!authResult)
|
||||||
{
|
{
|
||||||
log.Write(LogVerbosity.Info, "Authentication failed on reconnected socket. Disconnecting and reconnecting.");
|
log.Write(LogVerbosity.Info, "Authentication failed on reconnected socket. Disconnecting and reconnecting.");
|
||||||
return false;
|
return false;
|
||||||
@ -343,9 +343,9 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
var taskList = new List<Task>();
|
var taskList = new List<Task>();
|
||||||
foreach (var handler in handlerList)
|
foreach (var handler in handlerList)
|
||||||
{
|
{
|
||||||
var task = socketClient.SubscribeAndWait(this, handler.Request, handler).ContinueWith(t =>
|
var task = socketClient.SubscribeAndWait(this, handler.Request!, handler).ContinueWith(t =>
|
||||||
{
|
{
|
||||||
if (!t.Result.Success)
|
if (!t.Result)
|
||||||
success = false;
|
success = false;
|
||||||
});
|
});
|
||||||
taskList.Add(task);
|
taskList.Add(task);
|
||||||
@ -403,7 +403,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
internal class PendingRequest
|
internal class PendingRequest
|
||||||
{
|
{
|
||||||
public Func<JToken, bool> Handler { get; }
|
public Func<JToken, bool> Handler { get; }
|
||||||
public JToken Result { get; private set; }
|
public JToken? Result { get; private set; }
|
||||||
public ManualResetEvent Event { get; }
|
public ManualResetEvent Event { get; }
|
||||||
public TimeSpan Timeout { get; }
|
public TimeSpan Timeout { get; }
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Exception event
|
/// Exception event
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event Action<Exception> Exception;
|
public event Action<Exception>? Exception;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Message handlers for this subscription. Should return true if the message is handled and should not be distributed to the other handlers
|
/// Message handlers for this subscription. Should return true if the message is handled and should not be distributed to the other handlers
|
||||||
@ -21,11 +21,11 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Request object
|
/// Request object
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public object Request { get; set; }
|
public object? Request { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Subscription identifier
|
/// Subscription identifier
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Identifier { get; set; }
|
public string? Identifier { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Is user subscription or generic
|
/// Is user subscription or generic
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -36,22 +36,32 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool Confirmed { get; set; }
|
public bool Confirmed { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ctor
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request"></param>
|
||||||
|
/// <param name="userSubscription"></param>
|
||||||
|
/// <param name="dataHandler"></param>
|
||||||
|
public SocketSubscription(object request, bool userSubscription, Action<SocketConnection, JToken> dataHandler)
|
||||||
|
{
|
||||||
|
UserSubscription = userSubscription;
|
||||||
|
MessageHandler = dataHandler;
|
||||||
|
Request = request;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ctor
|
/// ctor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="identifier"></param>
|
/// <param name="identifier"></param>
|
||||||
/// <param name="request"></param>
|
|
||||||
/// <param name="userSubscription"></param>
|
/// <param name="userSubscription"></param>
|
||||||
/// <param name="dataHandler"></param>
|
/// <param name="dataHandler"></param>
|
||||||
public SocketSubscription(string identifier, object request, bool userSubscription, Action<SocketConnection, JToken> dataHandler)
|
public SocketSubscription(string identifier, bool userSubscription, Action<SocketConnection, JToken> dataHandler)
|
||||||
{
|
{
|
||||||
UserSubscription = userSubscription;
|
UserSubscription = userSubscription;
|
||||||
MessageHandler = dataHandler;
|
MessageHandler = dataHandler;
|
||||||
Identifier = identifier;
|
Identifier = identifier;
|
||||||
Request = request;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invoke the exception event
|
/// Invoke the exception event
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user