using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Net; using System.Net.Http; using System.Net.Http.Headers; using System.Text; using System.Threading.Tasks; using SpotifyAPI.Web.Models; using SpotifyAPI.Web.Enums; namespace SpotifyAPI.Web { internal class SpotifyWebClient : IClient { public JsonSerializerSettings JsonSettings { get; set; } private readonly Encoding _encoding = Encoding.UTF8; private readonly HttpClient _client; private const string UnknownErrorJson = "{\"error\": { \"status\": 0, \"message\": \"SpotifyAPI.Web - Unkown Spotify Error\" }}"; public SpotifyWebClient(ProxyConfig proxyConfig = null) { HttpClientHandler clientHandler = CreateClientHandler(proxyConfig); _client = new HttpClient(clientHandler); } public Tuple Download(string url, Dictionary headers = null) { Tuple raw = DownloadRaw(url, headers); return new Tuple(raw.Item1, raw.Item2.Length > 0 ? _encoding.GetString(raw.Item2) : "{}"); } public async Task> DownloadAsync(string url, Dictionary headers = null) { Tuple raw = await DownloadRawAsync(url, headers).ConfigureAwait(false); return new Tuple(raw.Item1, raw.Item2.Length > 0 ? _encoding.GetString(raw.Item2) : "{}"); } public Tuple DownloadRaw(string url, Dictionary headers = null) { if (headers != null) { AddHeaders(headers); } using (HttpResponseMessage response = Task.Run(() => _client.GetAsync(url)).Result) { return new Tuple(new ResponseInfo { StatusCode = response.StatusCode, Headers = ConvertHeaders(response.Headers) }, Task.Run(() => response.Content.ReadAsByteArrayAsync()).Result); } } public async Task> DownloadRawAsync(string url, Dictionary headers = null) { if (headers != null) { AddHeaders(headers); } using (HttpResponseMessage response = await _client.GetAsync(url).ConfigureAwait(false)) { return new Tuple(new ResponseInfo { StatusCode = response.StatusCode, Headers = ConvertHeaders(response.Headers) }, await response.Content.ReadAsByteArrayAsync()); } } public Tuple DownloadJson(string url, Dictionary headers = null) { Tuple response = Download(url, headers); try { return new Tuple(response.Item1, JsonConvert.DeserializeObject(response.Item2, JsonSettings)); } catch (JsonException) { return new Tuple(response.Item1, JsonConvert.DeserializeObject(UnknownErrorJson, JsonSettings)); } } public async Task> DownloadJsonAsync(string url, Dictionary headers = null) { Tuple response = await DownloadAsync(url, headers).ConfigureAwait(false);try { return new Tuple(response.Item1, JsonConvert.DeserializeObject(response.Item2, JsonSettings)); } catch (JsonException) { return new Tuple(response.Item1, JsonConvert.DeserializeObject(UnknownErrorJson, JsonSettings)); } } public Tuple Upload(string url, string body, string method, Dictionary headers = null) { Tuple data = UploadRaw(url, body, method, headers); return new Tuple(data.Item1, data.Item2.Length > 0 ? _encoding.GetString(data.Item2) : "{}"); } public async Task> UploadAsync(string url, string body, string method, Dictionary headers = null) { Tuple data = await UploadRawAsync(url, body, method, headers).ConfigureAwait(false); return new Tuple(data.Item1, data.Item2.Length > 0 ? _encoding.GetString(data.Item2) : "{}"); } public Tuple UploadRaw(string url, string body, string method, Dictionary headers = null) { if (headers != null) { AddHeaders(headers); } HttpRequestMessage message = new HttpRequestMessage(new HttpMethod(method), url) { Content = new StringContent(body, _encoding) }; using (HttpResponseMessage response = Task.Run(() => _client.SendAsync(message)).Result) { return new Tuple(new ResponseInfo { StatusCode = response.StatusCode, Headers = ConvertHeaders(response.Headers) }, Task.Run(() => response.Content.ReadAsByteArrayAsync()).Result); } } public async Task> UploadRawAsync(string url, string body, string method, Dictionary headers = null) { if (headers != null) { AddHeaders(headers); } HttpRequestMessage message = new HttpRequestMessage(new HttpMethod(method), url) { Content = new StringContent(body, _encoding) }; using (HttpResponseMessage response = await _client.SendAsync(message)) { return new Tuple(new ResponseInfo { StatusCode = response.StatusCode, Headers = ConvertHeaders(response.Headers) }, await response.Content.ReadAsByteArrayAsync()); } } public Tuple UploadJson(string url, string body, string method, Dictionary headers = null) { Tuple response = Upload(url, body, method, headers); try { return new Tuple(response.Item1, JsonConvert.DeserializeObject(response.Item2, JsonSettings)); } catch (JsonException) { return new Tuple(response.Item1, JsonConvert.DeserializeObject(UnknownErrorJson, JsonSettings)); } } public async Task> UploadJsonAsync(string url, string body, string method, Dictionary headers = null) { Tuple response = await UploadAsync(url, body, method, headers).ConfigureAwait(false); try { return new Tuple(response.Item1, JsonConvert.DeserializeObject(response.Item2, JsonSettings)); } catch (JsonException) { return new Tuple(response.Item1, JsonConvert.DeserializeObject(UnknownErrorJson, JsonSettings)); } } public void Dispose() { _client.Dispose(); GC.SuppressFinalize(this); } private static WebHeaderCollection ConvertHeaders(HttpResponseHeaders headers) { WebHeaderCollection newHeaders = new WebHeaderCollection(); foreach (KeyValuePair> headerPair in headers) { foreach (string headerValue in headerPair.Value) { newHeaders.Add(headerPair.Key, headerValue); } } return newHeaders; } private void AddHeaders(Dictionary headers) { _client.DefaultRequestHeaders.Clear(); foreach (KeyValuePair headerPair in headers) { _client.DefaultRequestHeaders.TryAddWithoutValidation(headerPair.Key, headerPair.Value); } } private static HttpClientHandler CreateClientHandler(ProxyConfig proxyConfig = null) { HttpClientHandler clientHandler = new HttpClientHandler { PreAuthenticate = false, UseDefaultCredentials = true, UseProxy = false }; if (!string.IsNullOrWhiteSpace(proxyConfig?.Host)) { WebProxy proxy = proxyConfig.CreateWebProxy(); clientHandler.UseProxy = true; clientHandler.Proxy = proxy; clientHandler.UseDefaultCredentials = proxy.UseDefaultCredentials; clientHandler.PreAuthenticate = proxy.UseDefaultCredentials; } return clientHandler; } } }