mirror of
https://github.com/JKorf/CryptoExchange.Net
synced 2025-06-09 08:56:13 +00:00
Merge pull request #4 from Zaliro/master
Added support for DEX and "Array" parameters
This commit is contained in:
commit
7a4cabffb5
@ -1,27 +1,88 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Security;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Authentication
|
namespace CryptoExchange.Net.Authentication
|
||||||
{
|
{
|
||||||
public class ApiCredentials
|
public class ApiCredentials: IDisposable
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The api key
|
/// The api key to authenticate requests
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Key { get; }
|
public SecureString Key { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The api secret
|
/// The api secret to authenticate requests
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Secret { get; }
|
public SecureString Secret { get; }
|
||||||
|
|
||||||
public ApiCredentials() { }
|
/// <summary>
|
||||||
|
/// The private key to authenticate requests
|
||||||
|
/// </summary>
|
||||||
|
public SecureString PrivateKey { get; }
|
||||||
|
|
||||||
public ApiCredentials(string key, string secret)
|
/// <summary>
|
||||||
|
/// Create Api credentials providing a private key for authenication
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="privateKey">The private key used for signing</param>
|
||||||
|
public ApiCredentials(SecureString privateKey)
|
||||||
{
|
{
|
||||||
if(string.IsNullOrEmpty(key) || string.IsNullOrEmpty(secret))
|
PrivateKey = Key;
|
||||||
throw new ArgumentException("Apikey or apisecret not provided");
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create Api credentials providing a private key for authenication
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="privateKey">The private key used for signing</param>
|
||||||
|
public ApiCredentials(string privateKey)
|
||||||
|
{
|
||||||
|
if(string.IsNullOrEmpty(privateKey))
|
||||||
|
throw new ArgumentException("Private key can't be null/empty");
|
||||||
|
|
||||||
|
var securePrivateKey = new SecureString();
|
||||||
|
foreach (var c in privateKey)
|
||||||
|
securePrivateKey.AppendChar(c);
|
||||||
|
securePrivateKey.MakeReadOnly();
|
||||||
|
PrivateKey = securePrivateKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create Api credentials providing a api key and secret for authenciation
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">The api key used for identification</param>
|
||||||
|
/// <param name="secret">The api secret used for signing</param>
|
||||||
|
public ApiCredentials(SecureString key, SecureString secret)
|
||||||
|
{
|
||||||
Key = key;
|
Key = key;
|
||||||
Secret = secret;
|
Secret = secret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create Api credentials providing a private key for authenication
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="privateKey">The private key used for signing</param>
|
||||||
|
public ApiCredentials(string key, string secret)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(key) || string.IsNullOrEmpty(secret))
|
||||||
|
throw new ArgumentException("Key and secret can't be null/empty");
|
||||||
|
|
||||||
|
var secureApiKey = new SecureString();
|
||||||
|
foreach (var c in key)
|
||||||
|
secureApiKey.AppendChar(c);
|
||||||
|
secureApiKey.MakeReadOnly();
|
||||||
|
Key = secureApiKey;
|
||||||
|
|
||||||
|
var secureApiSecret = new SecureString();
|
||||||
|
foreach (var c in secret)
|
||||||
|
secureApiSecret.AppendChar(c);
|
||||||
|
secureApiSecret.MakeReadOnly();
|
||||||
|
Secret = secureApiSecret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Key?.Dispose();
|
||||||
|
Secret?.Dispose();
|
||||||
|
PrivateKey?.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ using Newtonsoft.Json.Linq;
|
|||||||
|
|
||||||
namespace CryptoExchange.Net
|
namespace CryptoExchange.Net
|
||||||
{
|
{
|
||||||
public abstract class ExchangeClient: IDisposable
|
public abstract class ExchangeClient : IDisposable
|
||||||
{
|
{
|
||||||
public IRequestFactory RequestFactory { get; set; } = new RequestFactory();
|
public IRequestFactory RequestFactory { get; set; } = new RequestFactory();
|
||||||
|
|
||||||
@ -47,7 +47,7 @@ namespace CryptoExchange.Net
|
|||||||
log.Level = exchangeOptions.LogVerbosity;
|
log.Level = exchangeOptions.LogVerbosity;
|
||||||
|
|
||||||
apiProxy = exchangeOptions.Proxy;
|
apiProxy = exchangeOptions.Proxy;
|
||||||
if(apiProxy != null)
|
if (apiProxy != null)
|
||||||
log.Write(LogVerbosity.Info, $"Setting api proxy to {exchangeOptions.Proxy.Host}:{exchangeOptions.Proxy.Port}");
|
log.Write(LogVerbosity.Info, $"Setting api proxy to {exchangeOptions.Proxy.Host}:{exchangeOptions.Proxy.Port}");
|
||||||
|
|
||||||
rateLimiters = new List<IRateLimiter>();
|
rateLimiters = new List<IRateLimiter>();
|
||||||
@ -104,12 +104,17 @@ namespace CryptoExchange.Net
|
|||||||
}
|
}
|
||||||
|
|
||||||
string paramString = null;
|
string paramString = null;
|
||||||
if (parameters != null) {
|
if (parameters != null)
|
||||||
paramString = "with parameters ";
|
{
|
||||||
|
paramString = "with parameters";
|
||||||
|
|
||||||
foreach (var param in parameters)
|
foreach (var param in parameters)
|
||||||
paramString += $"{param.Key}={param.Value}, ";
|
paramString += $" {param.Key}={(param.Value.GetType().IsArray ? $"[{string.Join(", ", ((object[])param.Value).Select(p => p.ToString()))}]": param.Value )},";
|
||||||
|
|
||||||
|
paramString = paramString.Trim(',');
|
||||||
}
|
}
|
||||||
log.Write(LogVerbosity.Debug, $"Sending {(signed ? "signed": "")} request to {request.Uri} {(paramString ?? "")}");
|
|
||||||
|
log.Write(LogVerbosity.Debug, $"Sending {(signed ? "signed" : "")} request to {request.Uri} {(paramString ?? "")}");
|
||||||
var result = await ExecuteRequest(request).ConfigureAwait(false);
|
var result = await ExecuteRequest(request).ConfigureAwait(false);
|
||||||
return result.Error != null ? new CallResult<T>(null, result.Error) : Deserialize<T>(result.Data);
|
return result.Error != null ? new CallResult<T>(null, result.Error) : Deserialize<T>(result.Data);
|
||||||
}
|
}
|
||||||
@ -123,7 +128,14 @@ namespace CryptoExchange.Net
|
|||||||
if (!uriString.EndsWith("?"))
|
if (!uriString.EndsWith("?"))
|
||||||
uriString += "?";
|
uriString += "?";
|
||||||
|
|
||||||
uriString += $"{string.Join("&", parameters.Select(s => $"{s.Key}={s.Value}"))}";
|
var arraysParameters = parameters.Where(p => p.Value.GetType().IsArray).ToList();
|
||||||
|
foreach(var arrayEntry in arraysParameters)
|
||||||
|
{
|
||||||
|
uriString += $"{string.Join("&", ((object[])arrayEntry.Value).Select(v => $"{arrayEntry.Key}[]={v}"))}&";
|
||||||
|
}
|
||||||
|
|
||||||
|
uriString += $"{string.Join("&", parameters.Where(p => !p.Value.GetType().IsArray).Select(s => $"{s.Key}={s.Value}"))}";
|
||||||
|
uriString = uriString.TrimEnd('&');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (authProvider != null)
|
if (authProvider != null)
|
||||||
@ -189,7 +201,7 @@ namespace CryptoExchange.Net
|
|||||||
return new ServerError(error);
|
return new ServerError(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected CallResult<T> Deserialize<T>(string data, bool checkObject = true) where T: class
|
protected CallResult<T> Deserialize<T>(string data, bool checkObject = true) where T : class
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -202,7 +214,7 @@ namespace CryptoExchange.Net
|
|||||||
CheckObject(typeof(T), o);
|
CheckObject(typeof(T), o);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var ary = (JArray) obj;
|
var ary = (JArray)obj;
|
||||||
if (ary.HasValues && ary[0] is JObject jObject)
|
if (ary.HasValues && ary[0] is JObject jObject)
|
||||||
CheckObject(typeof(T).GetElementType(), jObject);
|
CheckObject(typeof(T).GetElementType(), jObject);
|
||||||
}
|
}
|
||||||
@ -227,7 +239,7 @@ namespace CryptoExchange.Net
|
|||||||
log.Write(LogVerbosity.Error, info);
|
log.Write(LogVerbosity.Error, info);
|
||||||
return new CallResult<T>(null, new DeserializeError(info));
|
return new CallResult<T>(null, new DeserializeError(info));
|
||||||
}
|
}
|
||||||
catch(Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
var info = $"Deserialize Unknown Exception: {ex.Message}. Received data: {data}";
|
var info = $"Deserialize Unknown Exception: {ex.Message}. Received data: {data}";
|
||||||
log.Write(LogVerbosity.Error, info);
|
log.Write(LogVerbosity.Error, info);
|
||||||
@ -237,6 +249,10 @@ namespace CryptoExchange.Net
|
|||||||
|
|
||||||
private void CheckObject(Type type, JObject obj)
|
private void CheckObject(Type type, JObject obj)
|
||||||
{
|
{
|
||||||
|
if (type.GetCustomAttribute<JsonConverterAttribute>(true) != null)
|
||||||
|
// If type has a custom JsonConverter we assume this will handle property mapping
|
||||||
|
return;
|
||||||
|
|
||||||
bool isDif = false;
|
bool isDif = false;
|
||||||
var properties = new List<string>();
|
var properties = new List<string>();
|
||||||
var props = type.GetProperties();
|
var props = type.GetProperties();
|
||||||
@ -247,7 +263,7 @@ namespace CryptoExchange.Net
|
|||||||
if (ignore != null)
|
if (ignore != null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
properties.Add(attr == null ? prop.Name : ((JsonPropertyAttribute) attr).PropertyName);
|
properties.Add(attr == null ? prop.Name : ((JsonPropertyAttribute)attr).PropertyName);
|
||||||
}
|
}
|
||||||
foreach (var token in obj)
|
foreach (var token in obj)
|
||||||
{
|
{
|
||||||
@ -269,9 +285,9 @@ namespace CryptoExchange.Net
|
|||||||
continue;
|
continue;
|
||||||
if (!IsSimple(propType) && propType != typeof(DateTime))
|
if (!IsSimple(propType) && propType != typeof(DateTime))
|
||||||
{
|
{
|
||||||
if(propType.IsArray && token.Value.HasValues && ((JArray)token.Value).Any() && ((JArray)token.Value)[0] is JObject)
|
if (propType.IsArray && token.Value.HasValues && ((JArray)token.Value).Any() && ((JArray)token.Value)[0] is JObject)
|
||||||
CheckObject(propType.GetElementType(), (JObject)token.Value[0]);
|
CheckObject(propType.GetElementType(), (JObject)token.Value[0]);
|
||||||
else if(token.Value is JObject)
|
else if (token.Value is JObject)
|
||||||
CheckObject(propType, (JObject)token.Value);
|
CheckObject(propType, (JObject)token.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -282,7 +298,7 @@ namespace CryptoExchange.Net
|
|||||||
log.Write(LogVerbosity.Warning, $"Didn't find key `{prop}` in returned data object of type `{type.Name}`");
|
log.Write(LogVerbosity.Warning, $"Didn't find key `{prop}` in returned data object of type `{type.Name}`");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isDif)
|
if (isDif)
|
||||||
log.Write(LogVerbosity.Debug, "Returned data: " + obj);
|
log.Write(LogVerbosity.Debug, "Returned data: " + obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -298,7 +314,7 @@ namespace CryptoExchange.Net
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (((JsonPropertyAttribute) attr).PropertyName == name)
|
if (((JsonPropertyAttribute)attr).PropertyName == name)
|
||||||
return prop;
|
return prop;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -320,6 +336,7 @@ namespace CryptoExchange.Net
|
|||||||
|
|
||||||
public virtual void Dispose()
|
public virtual void Dispose()
|
||||||
{
|
{
|
||||||
|
authProvider?.Credentials?.Dispose();
|
||||||
log.Write(LogVerbosity.Debug, "Disposing exchange client");
|
log.Write(LogVerbosity.Debug, "Disposing exchange client");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Security;
|
||||||
|
|
||||||
namespace CryptoExchange.Net
|
namespace CryptoExchange.Net
|
||||||
{
|
{
|
||||||
@ -25,5 +28,30 @@ namespace CryptoExchange.Net
|
|||||||
if (value != null)
|
if (value != null)
|
||||||
parameters.Add(key, value);
|
parameters.Add(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string GetString(this SecureString source)
|
||||||
|
{
|
||||||
|
string result = null;
|
||||||
|
int length = source.Length;
|
||||||
|
IntPtr pointer = IntPtr.Zero;
|
||||||
|
char[] chars = new char[length];
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
pointer = Marshal.SecureStringToBSTR(source);
|
||||||
|
Marshal.Copy(pointer, chars, 0, length);
|
||||||
|
|
||||||
|
result = string.Join("", chars);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (pointer != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
Marshal.ZeroFreeBSTR(pointer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user