Skip to content

Commit

Permalink
fix: use HttpClient for requests. fixes #36 and #39
Browse files Browse the repository at this point in the history
  • Loading branch information
ajinasokan committed Jul 3, 2024
1 parent 5a6f38b commit 3d580fe
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 85 deletions.
151 changes: 67 additions & 84 deletions KiteConnect/Kite.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Collections;
using System.Reflection;
using System.Net.Http;
using System.Text;
using System.Net.Mime;
using System.Net;

namespace KiteConnect
{
Expand All @@ -21,12 +23,12 @@ public class Kite
private string _apiKey;
private string _accessToken;
private bool _enableLogging;
private WebProxy _proxy;

private int _timeout;

private Action _sessionHook;

//private Cache cache = new Cache();
private HttpClient httpClient;

private readonly Dictionary<string, string> _routes = new Dictionary<string, string>
{
Expand Down Expand Up @@ -98,15 +100,24 @@ public class Kite
/// <param name="Timeout">Time in milliseconds for which the API client will wait for a request to complete before it fails</param>
/// <param name="Proxy">To set proxy for http request. Should be an object of WebProxy.</param>
/// <param name="Pool">Number of connections to server. Client will reuse the connections if they are alive.</param>
public Kite(string APIKey, string AccessToken = null, string Root = null, bool Debug = false, int Timeout = 7000, WebProxy Proxy = null, int Pool = 2)
public Kite(string APIKey, string AccessToken = null, string Root = null, bool Debug = false, int Timeout = 7000, IWebProxy Proxy = null, int Pool = 2)
{
_accessToken = AccessToken;
_apiKey = APIKey;
if (!String.IsNullOrEmpty(Root)) this._root = Root;
_enableLogging = Debug;

_timeout = Timeout;
_proxy = Proxy;

HttpClientHandler httpClientHandler = new HttpClientHandler()
{
Proxy = Proxy,
};
httpClient = new(httpClientHandler)
{
BaseAddress = new Uri(_root),
Timeout = TimeSpan.FromMilliseconds(Timeout),
};

ServicePointManager.DefaultConnectionLimit = Pool;
}
Expand Down Expand Up @@ -166,7 +177,7 @@ public string GetLoginURL()
/// <returns>User structure with tokens and profile data</returns>
public User GenerateSession(string RequestToken, string AppSecret)
{
string checksum = Utils.SHA256(_apiKey + RequestToken + AppSecret);
string checksum = Utils.SHA256Hash(_apiKey + RequestToken + AppSecret);

var param = new Dictionary<string, dynamic>
{
Expand Down Expand Up @@ -220,7 +231,7 @@ public TokenSet RenewAccessToken(string RefreshToken, string AppSecret)
{
var param = new Dictionary<string, dynamic>();

string checksum = Utils.SHA256(_apiKey + RefreshToken + AppSecret);
string checksum = Utils.SHA256Hash(_apiKey + RefreshToken + AppSecret);

Utils.AddIfNotNull(param, "api_key", _apiKey);
Utils.AddIfNotNull(param, "refresh_token", RefreshToken);
Expand Down Expand Up @@ -1213,28 +1224,22 @@ private dynamic Delete(string Route, dynamic Params = null)
/// Adds extra headers to request
/// </summary>
/// <param name="Req">Request object to add headers</param>
private void AddExtraHeaders(ref HttpWebRequest Req)
private void AddExtraHeaders(ref HttpRequestMessage Req)
{
var KiteAssembly = System.Reflection.Assembly.GetAssembly(typeof(Kite));
var KiteAssembly = Assembly.GetAssembly(typeof(Kite));
if (KiteAssembly != null)
Req.UserAgent = "KiteConnect.Net/" + KiteAssembly.GetName().Version;
{
Req.Headers.UserAgent.TryParseAdd("KiteConnect.Net/" + KiteAssembly.GetName().Version);
}

Req.Headers.Add("X-Kite-Version", "3");
Req.Headers.Add("Authorization", "token " + _apiKey + ":" + _accessToken);

//if(Req.Method == "GET" && cache.IsCached(Req.RequestUri.AbsoluteUri))
//{
// Req.Headers.Add("If-None-Match: " + cache.GetETag(Req.RequestUri.AbsoluteUri));
//}

Req.Timeout = _timeout;
if (_proxy != null) Req.Proxy = _proxy;

if (_enableLogging)
{
foreach (string header in Req.Headers.Keys)
foreach (var header in Req.Headers)
{
Console.WriteLine("DEBUG: " + header + ": " + Req.Headers.GetValues(header)[0]);
Console.WriteLine("DEBUG: " + header.Key + ": " + String.Join(",", header.Value.ToArray()));
}
}
}
Expand Down Expand Up @@ -1268,7 +1273,7 @@ private dynamic Request(string Route, string Method, dynamic Params = null, Dict
}
}

HttpWebRequest request;
HttpRequestMessage request = new();

if (Method == "POST" || Method == "PUT")
{
Expand All @@ -1284,17 +1289,13 @@ private dynamic Request(string Route, string Method, dynamic Params = null, Dict
else
requestBody = String.Join("&", (Params as Dictionary<string, dynamic>).Select(x => Utils.BuildParam(x.Key, x.Value)));

request = (HttpWebRequest)WebRequest.Create(url);
request.AllowAutoRedirect = true;
request.Method = Method;
request.ContentType = json ? "application/json" : "application/x-www-form-urlencoded";
request.ContentLength = requestBody.Length;
if (_enableLogging) Console.WriteLine("DEBUG: " + Method + " " + url + "\n" + requestBody);
request.RequestUri = new Uri(url);
request.Method = new HttpMethod(Method);
AddExtraHeaders(ref request);

using (Stream webStream = request.GetRequestStream())
using (StreamWriter requestWriter = new StreamWriter(webStream))
requestWriter.Write(requestBody);
if (_enableLogging) Console.WriteLine("DEBUG: " + Method + " " + url + "\n" + requestBody);

request.Content = new StringContent(requestBody, Encoding.UTF8, json ? "application/json" : "application/x-www-form-urlencoded");
}
else
{
Expand All @@ -1315,75 +1316,57 @@ private dynamic Request(string Route, string Method, dynamic Params = null, Dict
url += "?" + String.Join("&", allParams.Select(x => Utils.BuildParam(x.Key, x.Value)));
}

request = (HttpWebRequest)WebRequest.Create(url);
request.AllowAutoRedirect = true;
request.Method = Method;
request.RequestUri = new Uri(url);
request.Method = new HttpMethod(Method);
if (_enableLogging) Console.WriteLine("DEBUG: " + Method + " " + url);
AddExtraHeaders(ref request);
}

WebResponse webResponse;
try
{
webResponse = request.GetResponse();
}
catch (WebException e)
{
if (e.Response is null)
throw e;
HttpResponseMessage response = httpClient.Send(request);
HttpStatusCode status = response.StatusCode;

webResponse = e.Response;
}
string responseBody = response.Content.ReadAsStringAsync().Result;
if (_enableLogging) Console.WriteLine("DEBUG: " + ((int)status) + " " + responseBody + "\n");

using (Stream webStream = webResponse.GetResponseStream())
if (response.Content.Headers.ContentType.MediaType == MediaTypeNames.Application.Json)
{
using (StreamReader responseReader = new StreamReader(webStream))
{
string response = responseReader.ReadToEnd();
if (_enableLogging) Console.WriteLine("DEBUG: " + (int)((HttpWebResponse)webResponse).StatusCode + " " + response + "\n");

HttpStatusCode status = ((HttpWebResponse)webResponse).StatusCode;

if (webResponse.ContentType == "application/json")
{
Dictionary<string, dynamic> responseDictionary = Utils.JsonDeserialize(response);
Dictionary<string, dynamic> responseDictionary = Utils.JsonDeserialize(responseBody);

if (status != HttpStatusCode.OK)
{
string errorType = "GeneralException";
string message = "";
if (status != HttpStatusCode.OK)
{
string errorType = "GeneralException";
string message = "";

if (responseDictionary.ContainsKey("error_type"))
errorType = responseDictionary["error_type"];
if (responseDictionary.ContainsKey("error_type"))
errorType = responseDictionary["error_type"];

if (responseDictionary.ContainsKey("message"))
message = responseDictionary["message"];
if (responseDictionary.ContainsKey("message"))
message = responseDictionary["message"];

switch (errorType)
switch (errorType)
{
case "GeneralException": throw new GeneralException(message, status);
case "TokenException":
{
case "GeneralException": throw new GeneralException(message, status);
case "TokenException":
{
_sessionHook?.Invoke();
throw new TokenException(message, status);
}
case "PermissionException": throw new PermissionException(message, status);
case "OrderException": throw new OrderException(message, status);
case "InputException": throw new InputException(message, status);
case "DataException": throw new DataException(message, status);
case "NetworkException": throw new NetworkException(message, status);
default: throw new GeneralException(message, status);
_sessionHook?.Invoke();
throw new TokenException(message, status);
}
}

return responseDictionary;
case "PermissionException": throw new PermissionException(message, status);
case "OrderException": throw new OrderException(message, status);
case "InputException": throw new InputException(message, status);
case "DataException": throw new DataException(message, status);
case "NetworkException": throw new NetworkException(message, status);
default: throw new GeneralException(message, status);
}
else if (webResponse.ContentType == "text/csv")
return Utils.ParseCSV(response);
else
throw new DataException("Unexpected content type " + webResponse.ContentType + " " + response);
}

return responseDictionary;
}
else if (response.Content.Headers.ContentType.MediaType == "text/csv")
return Utils.ParseCSV(responseBody);
else
throw new DataException("Unexpected content type " + response.Content.Headers.ContentType.MediaType + " " + response);

}

#endregion
Expand Down
2 changes: 1 addition & 1 deletion KiteConnect/Utils.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
Expand Down

0 comments on commit 3d580fe

Please sign in to comment.