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 Newtonsoft.Json; using SpotifyAPI.Web.Models; 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\": \"{0}\" }}"; public SpotifyWebClient(ProxyConfig proxyConfig = null) { HttpClientHandler clientHandler = ProxyConfig.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 error) { return new Tuple(response.Item1, JsonConvert.DeserializeObject(string.Format(UnknownErrorJson, error.Message), 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 error) { return new Tuple(response.Item1, JsonConvert.DeserializeObject(string.Format(UnknownErrorJson, error.Message), 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 error) { return new Tuple(response.Item1, JsonConvert.DeserializeObject(string.Format(UnknownErrorJson, error.Message), 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 error) { return new Tuple(response.Item1, JsonConvert.DeserializeObject(string.Format(UnknownErrorJson, error.Message), 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); } } } }