diff --git a/src/Discord.Net.Net45/Discord.Net.csproj b/src/Discord.Net.Net45/Discord.Net.csproj index 157eae0e7..51f118503 100644 --- a/src/Discord.Net.Net45/Discord.Net.csproj +++ b/src/Discord.Net.Net45/Discord.Net.csproj @@ -37,6 +37,7 @@ True + diff --git a/src/Discord.Net/API/DiscordAPI.cs b/src/Discord.Net/API/DiscordAPI.cs index 7f97ce45c..d76097035 100644 --- a/src/Discord.Net/API/DiscordAPI.cs +++ b/src/Discord.Net/API/DiscordAPI.cs @@ -9,109 +9,108 @@ namespace Discord.API public const int MaxMessageSize = 2000; //Auth - public static async Task LoginAnonymous(string username, HttpOptions options) + public static async Task LoginAnonymous(string username) { - var fingerprintResponse = await Http.Post(Endpoints.AuthFingerprint, options); + var fingerprintResponse = await Http.Post(Endpoints.AuthFingerprint); var registerRequest = new APIRequests.AuthRegisterRequest { Fingerprint = fingerprintResponse.Fingerprint, Username = username }; - var registerResponse = await Http.Post(Endpoints.AuthRegister, registerRequest, options); + var registerResponse = await Http.Post(Endpoints.AuthRegister, registerRequest); return registerResponse; } - public static async Task Login(string email, string password, HttpOptions options) + public static async Task Login(string email, string password) { var request = new APIRequests.AuthLogin { Email = email, Password = password }; - var response = await Http.Post(Endpoints.AuthLogin, request, options); - options.Token = response.Token; + var response = await Http.Post(Endpoints.AuthLogin, request); return response; } - public static Task Logout(HttpOptions options) - => Http.Post(Endpoints.AuthLogout, options); + public static Task Logout() + => Http.Post(Endpoints.AuthLogout); //Servers - public static Task CreateServer(string name, string region, HttpOptions options) + public static Task CreateServer(string name, string region) { var request = new APIRequests.CreateServer { Name = name, Region = region }; - return Http.Post(Endpoints.Servers, request, options); + return Http.Post(Endpoints.Servers, request); } - public static Task LeaveServer(string id, HttpOptions options) - => Http.Delete(Endpoints.Server(id), options); + public static Task LeaveServer(string id) + => Http.Delete(Endpoints.Server(id)); //Channels - public static Task CreateChannel(string serverId, string name, string channelType, HttpOptions options) + public static Task CreateChannel(string serverId, string name, string channelType) { var request = new APIRequests.CreateChannel { Name = name, Type = channelType }; - return Http.Post(Endpoints.ServerChannels(serverId), request, options); + return Http.Post(Endpoints.ServerChannels(serverId), request); } - public static Task CreatePMChannel(string myId, string recipientId, HttpOptions options) + public static Task CreatePMChannel(string myId, string recipientId) { var request = new APIRequests.CreatePMChannel { RecipientId = recipientId }; - return Http.Post(Endpoints.UserChannels(myId), request, options); + return Http.Post(Endpoints.UserChannels(myId), request); } - public static Task DestroyChannel(string channelId, HttpOptions options) - => Http.Delete(Endpoints.Channel(channelId), options); - public static Task GetMessages(string channelId, int count, HttpOptions options) - => Http.Get(Endpoints.ChannelMessages(channelId, count), options); + public static Task DestroyChannel(string channelId) + => Http.Delete(Endpoints.Channel(channelId)); + public static Task GetMessages(string channelId, int count) + => Http.Get(Endpoints.ChannelMessages(channelId, count)); //Members - public static Task Kick(string serverId, string memberId, HttpOptions options) - => Http.Delete(Endpoints.ServerMember(serverId, memberId), options); - public static Task Ban(string serverId, string memberId, HttpOptions options) - => Http.Put(Endpoints.ServerBan(serverId, memberId), options); - public static Task Unban(string serverId, string memberId, HttpOptions options) - => Http.Delete(Endpoints.ServerBan(serverId, memberId), options); + public static Task Kick(string serverId, string memberId) + => Http.Delete(Endpoints.ServerMember(serverId, memberId)); + public static Task Ban(string serverId, string memberId) + => Http.Put(Endpoints.ServerBan(serverId, memberId)); + public static Task Unban(string serverId, string memberId) + => Http.Delete(Endpoints.ServerBan(serverId, memberId)); //Invites - public static Task CreateInvite(string channelId, int maxAge, int maxUses, bool isTemporary, bool hasXkcdPass, HttpOptions options) + public static Task CreateInvite(string channelId, int maxAge, int maxUses, bool isTemporary, bool hasXkcdPass) { var request = new APIRequests.CreateInvite { MaxAge = maxAge, MaxUses = maxUses, IsTemporary = isTemporary, HasXkcdPass = hasXkcdPass }; - return Http.Post(Endpoints.ChannelInvites(channelId), request, options); + return Http.Post(Endpoints.ChannelInvites(channelId), request); } - public static Task GetInvite(string id, HttpOptions options) - => Http.Get(Endpoints.Invite(id), options); - public static Task AcceptInvite(string id, HttpOptions options) - => Http.Post(Endpoints.Invite(id), options); - public static Task DeleteInvite(string id, HttpOptions options) - => Http.Delete(Endpoints.Invite(id), options); + public static Task GetInvite(string id) + => Http.Get(Endpoints.Invite(id)); + public static Task AcceptInvite(string id) + => Http.Post(Endpoints.Invite(id)); + public static Task DeleteInvite(string id) + => Http.Delete(Endpoints.Invite(id)); //Chat - public static Task SendMessage(string channelId, string message, string[] mentions, HttpOptions options) + public static Task SendMessage(string channelId, string message, string[] mentions) { var request = new APIRequests.SendMessage { Content = message, Mentions = mentions }; - return Http.Post(Endpoints.ChannelMessages(channelId), request, options); + return Http.Post(Endpoints.ChannelMessages(channelId), request); } - public static Task EditMessage(string channelId, string messageId, string message, string[] mentions, HttpOptions options) + public static Task EditMessage(string channelId, string messageId, string message, string[] mentions) { var request = new APIRequests.EditMessage { Content = message, Mentions = mentions }; - return Http.Patch(Endpoints.ChannelMessage(channelId, messageId), request, options); + return Http.Patch(Endpoints.ChannelMessage(channelId, messageId), request); } - public static Task SendIsTyping(string channelId, HttpOptions options) - => Http.Post(Endpoints.ChannelTyping(channelId), options); - public static Task DeleteMessage(string channelId, string msgId, HttpOptions options) - => Http.Delete(Endpoints.ChannelMessage(channelId, msgId), options); + public static Task SendIsTyping(string channelId) + => Http.Post(Endpoints.ChannelTyping(channelId)); + public static Task DeleteMessage(string channelId, string msgId) + => Http.Delete(Endpoints.ChannelMessage(channelId, msgId)); //Voice - public static Task GetVoiceRegions(HttpOptions options) - => Http.Get(Endpoints.VoiceRegions, options); - public static Task GetVoiceIce(HttpOptions options) - => Http.Get(Endpoints.VoiceIce, options); - public static Task Mute(string serverId, string memberId, HttpOptions options) + public static Task GetVoiceRegions() + => Http.Get(Endpoints.VoiceRegions); + public static Task GetVoiceIce() + => Http.Get(Endpoints.VoiceIce); + public static Task Mute(string serverId, string memberId) { var request = new APIRequests.SetMemberMute { Mute = true }; - return Http.Patch(Endpoints.ServerMember(serverId, memberId), options); + return Http.Patch(Endpoints.ServerMember(serverId, memberId)); } - public static Task Unmute(string serverId, string memberId, HttpOptions options) + public static Task Unmute(string serverId, string memberId) { var request = new APIRequests.SetMemberMute { Mute = false }; - return Http.Patch(Endpoints.ServerMember(serverId, memberId), options); + return Http.Patch(Endpoints.ServerMember(serverId, memberId)); } - public static Task Deafen(string serverId, string memberId, HttpOptions options) + public static Task Deafen(string serverId, string memberId) { var request = new APIRequests.SetMemberDeaf { Deaf = true }; - return Http.Patch(Endpoints.ServerMember(serverId, memberId), options); + return Http.Patch(Endpoints.ServerMember(serverId, memberId)); } - public static Task Undeafen(string serverId, string memberId, HttpOptions options) + public static Task Undeafen(string serverId, string memberId) { var request = new APIRequests.SetMemberDeaf { Deaf = false }; - return Http.Patch(Endpoints.ServerMember(serverId, memberId), options); + return Http.Patch(Endpoints.ServerMember(serverId, memberId)); } } } diff --git a/src/Discord.Net/DiscordClient.cs b/src/Discord.Net/DiscordClient.cs index 052fe47f7..b491664be 100644 --- a/src/Discord.Net/DiscordClient.cs +++ b/src/Discord.Net/DiscordClient.cs @@ -17,7 +17,6 @@ namespace Discord public const int FailedReconnectDelay = 10000; //Time in milliseconds to wait after a failed reconnect attempt private DiscordWebSocket _webSocket; - private HttpOptions _httpOptions; private bool _isReady; public string UserId { get; private set; } @@ -45,8 +44,6 @@ namespace Discord public DiscordClient() { _isStopping = new ManualResetEventSlim(false); - string version = typeof(DiscordClient).GetTypeInfo().Assembly.GetName().Version.ToString(2); - _httpOptions = new HttpOptions($"Discord.Net/{version} (https://github.com/RogueException/Discord.Net)"); _servers = new AsyncCache( (key, parentKey) => new Server(key, this), @@ -160,7 +157,7 @@ namespace Discord try { await Task.Delay(ReconnectDelay); - await _webSocket.ConnectAsync(Endpoints.WebSocket_Hub, true, _httpOptions); + await _webSocket.ConnectAsync(Endpoints.WebSocket_Hub, true); break; } catch (Exception) @@ -413,15 +410,26 @@ namespace Discord ) .FirstOrDefault(); } - public User FindChannelUser(Channel channel, string name) - => FindChannelUser(channel.Id, name); - public User FindChannelUser(string channelId, string name) + public Membership FindMember(string serverId, string name) + => FindMember(GetServer(serverId), name); + public Membership FindMember(Server server, string name) { + if (server == null) + return null; + + if (name.StartsWith("<@") && name.EndsWith(">")) + { + var user = GetUser(name.Substring(2, name.Length - 3)); + if (user == null) + return null; + return server.GetMembership(user.Id); + } + if (name.StartsWith("@")) name = name.Substring(1); - return _users - .Where(x => string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase)) + return server.Members + .Where(x => string.Equals(x.User.Name, name, StringComparison.OrdinalIgnoreCase)) .FirstOrDefault(); } @@ -436,9 +444,11 @@ namespace Discord public Channel GetChannel(string id) => _channels[id]; public Channel FindChannel(string name) { + if (name.StartsWith("<#") && name.EndsWith(">")) + return GetChannel(name.Substring(2, name.Length - 3)); + if (name.StartsWith("#")) name = name.Substring(1); - return _channels .Where(x => string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase)) .FirstOrDefault(); @@ -447,9 +457,11 @@ namespace Discord => FindChannel(server.Id, name); public Channel FindChannel(string serverId, string name) { + if (name.StartsWith("<#") && name.EndsWith(">")) + return GetChannel(name.Substring(2, name.Length - 3)); + if (name.StartsWith("#")) name = name.Substring(1); - return _channels .Where(x => string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase) && @@ -478,7 +490,7 @@ namespace Discord { try { - var msgs = await DiscordAPI.GetMessages(channel.Id, count, _httpOptions); + var msgs = await DiscordAPI.GetMessages(channel.Id, count); return msgs.OrderBy(x => x.Timestamp) .Select(x => { @@ -501,13 +513,13 @@ namespace Discord _isStopping.Reset(); //Open websocket while we wait for login response - Task socketTask = _webSocket.ConnectAsync(Endpoints.WebSocket_Hub, false, _httpOptions); - var response = await DiscordAPI.Login(email, password, _httpOptions); - _httpOptions.Token = response.Token; + Task socketTask = _webSocket.ConnectAsync(Endpoints.WebSocket_Hub, false); + var response = await DiscordAPI.Login(email, password); + Http.Token = response.Token; //Wait for websocket to finish connecting, then send token await socketTask; - _webSocket.Login(_httpOptions); + _webSocket.Login(); _isReady = true; } @@ -516,13 +528,13 @@ namespace Discord _isStopping.Reset(); //Open websocket while we wait for login response - Task socketTask = _webSocket.ConnectAsync(Endpoints.WebSocket_Hub, false, _httpOptions); - var response = await DiscordAPI.LoginAnonymous(username, _httpOptions); - _httpOptions.Token = response.Token; + Task socketTask = _webSocket.ConnectAsync(Endpoints.WebSocket_Hub, false); + var response = await DiscordAPI.LoginAnonymous(username); + Http.Token = response.Token; //Wait for websocket to finish connecting, then send token await socketTask; - _webSocket.Login(_httpOptions); + _webSocket.Login(); _isReady = true; } @@ -543,7 +555,7 @@ namespace Discord public async Task CreateServer(string name, string region) { CheckReady(); - var response = await DiscordAPI.CreateServer(name, region, _httpOptions); + var response = await DiscordAPI.CreateServer(name, region); return _servers.Update(response.Id, response); } public Task LeaveServer(Server server) @@ -553,7 +565,7 @@ namespace Discord CheckReady(); try { - await DiscordAPI.LeaveServer(serverId, _httpOptions); + await DiscordAPI.LeaveServer(serverId); } catch (WebException ex) when ((ex.Response as HttpWebResponse)?.StatusCode == HttpStatusCode.NotFound) {} return _servers.Remove(serverId); @@ -565,7 +577,7 @@ namespace Discord public async Task CreateChannel(string serverId, string name, string type) { CheckReady(); - var response = await DiscordAPI.CreateChannel(serverId, name, type, _httpOptions); + var response = await DiscordAPI.CreateChannel(serverId, name, type); return _channels.Update(response.Id, serverId, response); } public Task CreatePMChannel(User user) @@ -573,7 +585,7 @@ namespace Discord public async Task CreatePMChannel(string recipientId) { CheckReady(); - var response = await DiscordAPI.CreatePMChannel(UserId, recipientId, _httpOptions); + var response = await DiscordAPI.CreatePMChannel(UserId, recipientId); return _channels.Update(response.Id, response); } public Task DestroyChannel(Channel channel) @@ -583,7 +595,7 @@ namespace Discord CheckReady(); try { - var response = await DiscordAPI.DestroyChannel(channelId, _httpOptions); + var response = await DiscordAPI.DestroyChannel(channelId); } catch (WebException ex) when ((ex.Response as HttpWebResponse)?.StatusCode == HttpStatusCode.NotFound) { } return _channels.Remove(channelId); @@ -599,7 +611,7 @@ namespace Discord public Task Ban(string serverId, string userId) { CheckReady(); - return DiscordAPI.Ban(serverId, userId, _httpOptions); + return DiscordAPI.Ban(serverId, userId); } public Task Unban(Server server, User user) => Unban(server.Id, user.Id); @@ -612,7 +624,7 @@ namespace Discord CheckReady(); try { - await DiscordAPI.Unban(serverId, userId, _httpOptions); + await DiscordAPI.Unban(serverId, userId); } catch (WebException ex) when ((ex.Response as HttpWebResponse)?.StatusCode == HttpStatusCode.NotFound) { } } @@ -629,7 +641,7 @@ namespace Discord public async Task CreateInvite(string channelId, int maxAge, int maxUses, bool isTemporary, bool hasXkcdPass) { CheckReady(); - var response = await DiscordAPI.CreateInvite(channelId, maxAge, maxUses, isTemporary, hasXkcdPass, _httpOptions); + var response = await DiscordAPI.CreateInvite(channelId, maxAge, maxUses, isTemporary, hasXkcdPass); _channels.Update(response.Channel.Id, response.Server.Id, response.Channel); _servers.Update(response.Server.Id, response.Server); _users.Update(response.Inviter.Id, response.Inviter); @@ -648,7 +660,7 @@ namespace Discord public async Task GetInvite(string id) { CheckReady(); - var response = await DiscordAPI.GetInvite(id, _httpOptions); + var response = await DiscordAPI.GetInvite(id); return new Invite(response.Code, response.XkcdPass, this) { ChannelId = response.Channel.Id, @@ -659,14 +671,14 @@ namespace Discord public Task AcceptInvite(Invite invite) { CheckReady(); - return DiscordAPI.AcceptInvite(invite.Code, _httpOptions); + return DiscordAPI.AcceptInvite(invite.Code); } public async Task AcceptInvite(string id) { CheckReady(); //Check if this is a human-readable link and get its ID - var response = await DiscordAPI.GetInvite(id, _httpOptions); - await DiscordAPI.AcceptInvite(response.Code, _httpOptions); + var response = await DiscordAPI.GetInvite(id); + await DiscordAPI.AcceptInvite(response.Code); } public async Task DeleteInvite(string id) { @@ -674,8 +686,8 @@ namespace Discord try { //Check if this is a human-readable link and get its ID - var response = await DiscordAPI.GetInvite(id, _httpOptions); - await DiscordAPI.DeleteInvite(response.Code, _httpOptions); + var response = await DiscordAPI.GetInvite(id); + await DiscordAPI.DeleteInvite(response.Code); } catch (WebException ex) when ((ex.Response as HttpWebResponse)?.StatusCode == HttpStatusCode.NotFound) { } } @@ -693,7 +705,7 @@ namespace Discord if (text.Length <= 2000) { - var msg = await DiscordAPI.SendMessage(channelId, text, mentions, _httpOptions); + var msg = await DiscordAPI.SendMessage(channelId, text, mentions); return new Message[] { _messages.Update(msg.Id, channelId, msg) }; } else @@ -703,7 +715,7 @@ namespace Discord for (int i = 0; i < blockCount; i++) { int index = i * DiscordAPI.MaxMessageSize; - var msg = await DiscordAPI.SendMessage(channelId, text.Substring(index, Math.Min(2000, text.Length - index)), mentions, _httpOptions); + var msg = await DiscordAPI.SendMessage(channelId, text.Substring(index, Math.Min(2000, text.Length - index)), mentions); result[i] = _messages.Update(msg.Id, channelId, msg); await Task.Delay(1000); } @@ -727,7 +739,7 @@ namespace Discord if (text.Length > DiscordAPI.MaxMessageSize) text = text.Substring(0, DiscordAPI.MaxMessageSize); - var msg = await DiscordAPI.EditMessage(channelId, messageId, text, mentions, _httpOptions); + var msg = await DiscordAPI.EditMessage(channelId, messageId, text, mentions); _messages.Update(msg.Id, channelId, msg); } @@ -737,7 +749,7 @@ namespace Discord { try { - await DiscordAPI.DeleteMessage(channelId, msgId, _httpOptions); + await DiscordAPI.DeleteMessage(channelId, msgId); return _messages.Remove(msgId); } catch (WebException ex) when ((ex.Response as HttpWebResponse)?.StatusCode == HttpStatusCode.NotFound) { } @@ -755,7 +767,7 @@ namespace Discord public Task Mute(string serverId, string userId) { CheckReady(); - return DiscordAPI.Mute(serverId, userId, _httpOptions); + return DiscordAPI.Mute(serverId, userId); } public Task Unmute(Server server, User user) @@ -767,7 +779,7 @@ namespace Discord public Task Unmute(string serverId, string userId) { CheckReady(); - return DiscordAPI.Unmute(serverId, userId, _httpOptions); + return DiscordAPI.Unmute(serverId, userId); } public Task Deafen(Server server, User user) @@ -779,7 +791,7 @@ namespace Discord public Task Deafen(string serverId, string userId) { CheckReady(); - return DiscordAPI.Deafen(serverId, userId, _httpOptions); + return DiscordAPI.Deafen(serverId, userId); } public Task Undeafen(Server server, User user) @@ -791,7 +803,7 @@ namespace Discord public Task Undeafen(string serverId, string userId) { CheckReady(); - return DiscordAPI.Undeafen(serverId, userId, _httpOptions); + return DiscordAPI.Undeafen(serverId, userId); } private void CheckReady() diff --git a/src/Discord.Net/DiscordWebSocket.cs b/src/Discord.Net/DiscordWebSocket.cs index ff0f8f555..7dabbdabd 100644 --- a/src/Discord.Net/DiscordWebSocket.cs +++ b/src/Discord.Net/DiscordWebSocket.cs @@ -25,7 +25,7 @@ namespace Discord private DateTime _lastHeartbeat; private AutoResetEvent _connectWaitOnLogin, _connectWaitOnLogin2; - public async Task ConnectAsync(string url, bool autoLogin, HttpOptions options) + public async Task ConnectAsync(string url, bool autoLogin) { await DisconnectAsync(); @@ -58,12 +58,12 @@ namespace Discord }); if (autoLogin) - Login(options); + Login(); } - public void Login(HttpOptions options) + public void Login() { WebSocketCommands.Login msg = new WebSocketCommands.Login(); - msg.Payload.Token = options.Token; + msg.Payload.Token = Http.Token; msg.Payload.Properties["$os"] = ""; msg.Payload.Properties["$browser"] = ""; msg.Payload.Properties["$device"] = "Discord.Net"; diff --git a/src/Discord.Net/Helpers/Http.cs b/src/Discord.Net/Helpers/Http.cs index efa240e97..a3a040132 100644 --- a/src/Discord.Net/Helpers/Http.cs +++ b/src/Discord.Net/Helpers/Http.cs @@ -2,23 +2,13 @@ using System; using System.IO; using System.IO.Compression; -using System.Net; using System.Text; using System.Threading.Tasks; +using System.Net.Http; +using System.Reflection; namespace Discord.Helpers { - internal class HttpOptions - { - public readonly string UserAgent; - public string Token; - - public HttpOptions(string userAgent) - { - UserAgent = userAgent; - } - } - internal static class Http { #if DEBUG @@ -26,151 +16,120 @@ namespace Discord.Helpers #else private const bool _isDebug = false; #endif - - internal static Task Get(string path, HttpOptions options) + private static readonly HttpClient _client; + private static readonly HttpMethod _patch = new HttpMethod("PATCH"); //Not sure why this isn't a default... + + static Http() + { + _client = new HttpClient(); + _client.DefaultRequestHeaders.Add("Accept", "*/*"); + _client.DefaultRequestHeaders.Add("Accept-language", "en-US;q=0.8"); + + string version = typeof(Http).GetTypeInfo().Assembly.GetName().Version.ToString(2); + _client.DefaultRequestHeaders.Add("User-agent", $"Discord.Net/{version} (https://github.com/RogueException/Discord.Net)"); + } + + private static string _token; + public static string Token + { + get { return _token; } + set + { + _token = value; + _client.DefaultRequestHeaders.Add("Authorization", _token); + } + } + + internal static Task Get(string path) where ResponseT : class - => Send("GET", path, null, options); - internal static Task Get(string path, HttpOptions options) - => Send("GET", path, null, options); + => Send(HttpMethod.Get, path, null); + internal static Task Get(string path) + => Send(HttpMethod.Get, path, null); - internal static Task Post(string path, object data, HttpOptions options) + internal static Task Post(string path, object data) where ResponseT : class - => Send("POST", path, data, options); - internal static Task Post(string path, object data, HttpOptions options) - => Send("POST", path, data, options); - internal static Task Post(string path, HttpOptions options) + => Send(HttpMethod.Post, path, data); + internal static Task Post(string path, object data) + => Send(HttpMethod.Post, path, data); + internal static Task Post(string path) where ResponseT : class - => Send("POST", path, null, options); - internal static Task Post(string path, HttpOptions options) - => Send("POST", path, null, options); + => Send(HttpMethod.Post, path, null); + internal static Task Post(string path) + => Send(HttpMethod.Post, path, null); - internal static Task Put(string path, object data, HttpOptions options) + internal static Task Put(string path, object data) where ResponseT : class - => Send("PUT", path, data, options); - internal static Task Put(string path, object data, HttpOptions options) - => Send("PUT", path, data, options); - internal static Task Put(string path, HttpOptions options) + => Send(HttpMethod.Put, path, data); + internal static Task Put(string path, object data) + => Send(HttpMethod.Put, path, data); + internal static Task Put(string path) where ResponseT : class - => Send("PUT", path, null, options); - internal static Task Put(string path, HttpOptions options) - => Send("PUT", path, null, options); + => Send(HttpMethod.Put, path, null); + internal static Task Put(string path) + => Send(HttpMethod.Put, path, null); - internal static Task Patch(string path, object data, HttpOptions options) + internal static Task Patch(string path, object data) where ResponseT : class - => Send("PATCH", path, data, options); - internal static Task Patch(string path, object data, HttpOptions options) - => Send("PATCH", path, data, options); - internal static Task Patch(string path, HttpOptions options) + => Send(_patch, path, data); + internal static Task Patch(string path, object data) + => Send(_patch, path, data); + internal static Task Patch(string path) where ResponseT : class - => Send("PATCH", path, null, options); - internal static Task Patch(string path, HttpOptions options) - => Send("PATCH", path, null, options); + => Send(_patch, path, null); + internal static Task Patch(string path) + => Send(_patch, path, null); - internal static Task Delete(string path, object data, HttpOptions options) + internal static Task Delete(string path, object data) where ResponseT : class - => Send("DELETE", path, data, options); - internal static Task Delete(string path, object data, HttpOptions options) - => Send("DELETE", path, data, options); - internal static Task Delete(string path, HttpOptions options) + => Send(HttpMethod.Delete, path, data); + internal static Task Delete(string path, object data) + => Send(HttpMethod.Delete, path, data); + internal static Task Delete(string path) where ResponseT : class - => Send("DELETE", path, null, options); - internal static Task Delete(string path, HttpOptions options) - => Send("DELETE", path, null, options); + => Send(HttpMethod.Delete, path, null); + internal static Task Delete(string path) + => Send(HttpMethod.Delete, path, null); - internal static async Task Send(string method, string path, object data, HttpOptions options) + internal static async Task Send(HttpMethod method, string path, object data) where ResponseT : class { string requestJson = data != null ? JsonConvert.SerializeObject(data) : null; - string responseJson = await SendRequest(method, path, requestJson, options, true); + string responseJson = await SendRequest(method, path, requestJson, true); var response = JsonConvert.DeserializeObject(responseJson); #if DEBUG CheckResponse(responseJson, response); #endif return response; } - internal static async Task Send(string method, string path, object data, HttpOptions options) + internal static async Task Send(HttpMethod method, string path, object data) { string requestJson = data != null ? JsonConvert.SerializeObject(data) : null; - string responseJson = await SendRequest(method, path, requestJson, options, _isDebug); + string responseJson = await SendRequest(method, path, requestJson, _isDebug); #if DEBUG CheckEmptyResponse(responseJson); #endif return responseJson; } - private static async Task SendRequest(string method, string path, string data, HttpOptions options, bool hasResponse) + private static async Task SendRequest(HttpMethod method, string path, string data, bool hasResponse) { //Create Request - HttpWebRequest request = WebRequest.CreateHttp(path); - request.Accept = "*/*"; - request.Method = method; - request.Proxy = null; - request.Headers[HttpRequestHeader.AcceptLanguage] = "en-US;q=0.8"; - request.Headers[HttpRequestHeader.AcceptEncoding] = "gzip, deflate"; - request.Headers[HttpRequestHeader.UserAgent] = options.UserAgent; - request.Headers[HttpRequestHeader.Authorization] = options.Token; - //request.UserAgent = options.UserAgent; + HttpRequestMessage msg = new HttpRequestMessage(method, path); //Add Payload if (data != null) - { - byte[] buffer = Encoding.UTF8.GetBytes(data); - using (var payload = await request.GetRequestStreamAsync()) - payload.Write(buffer, 0, buffer.Length); - request.ContentType = "application/json"; - } + msg.Content = new StringContent(data, Encoding.UTF8, "application/json"); - //Get Response - using (var response = (HttpWebResponse)(await request.GetResponseAsync())) + if (!hasResponse) { - if (hasResponse) - { - using (var stream = response.GetResponseStream()) - using (var reader = new BinaryReader(stream)) - using (var largeBuffer = new MemoryStream()) - { - //Read the response in small chunks and add them to a larger buffer. - //ContentLength isn't always provided, so this is safer. - int bytesRead = 0; - byte[] smallBuffer = new byte[4096]; - while ((bytesRead = reader.Read(smallBuffer, 0, smallBuffer.Length)) > 0) - largeBuffer.Write(smallBuffer, 0, bytesRead); - - //Do we need to decompress? - string encoding = response.Headers[HttpResponseHeader.ContentEncoding]; - if (!string.IsNullOrEmpty(encoding)) - { - largeBuffer.Position = 0; - using (var decoder = GetDecoder(encoding, largeBuffer)) - using (var decodedStream = new MemoryStream()) - { - decoder.CopyTo(decodedStream); -#if !DOTNET - return Encoding.UTF8.GetString(decodedStream.GetBuffer(), 0, (int)decodedStream.Length); -#else - ArraySegment buffer; - if (!decodedStream.TryGetBuffer(out buffer)) - throw new InvalidOperationException("Failed to get response buffer."); - return Encoding.UTF8.GetString(buffer.Array, buffer.Offset, (int)decodedStream.Length); -#endif - } - } - else - { -#if !DOTNET - return Encoding.UTF8.GetString(largeBuffer.GetBuffer(), 0, (int)largeBuffer.Length); -#else - ArraySegment buffer; - if (!largeBuffer.TryGetBuffer(out buffer)) - throw new InvalidOperationException("Failed to get response buffer."); - return Encoding.UTF8.GetString(buffer.Array, buffer.Offset, (int)largeBuffer.Length); -#endif - } - } - } - else - return null; + await _client.SendAsync(msg, HttpCompletionOption.ResponseHeadersRead); + return null; } + else + { + var response = await _client.SendAsync(msg, HttpCompletionOption.ResponseContentRead); + return await response.Content.ReadAsStringAsync(); + } } private static Stream GetDecoder(string contentEncoding, MemoryStream encodedStream) diff --git a/src/Discord.Net/project.json b/src/Discord.Net/project.json index af79b0793..220500ef4 100644 --- a/src/Discord.Net/project.json +++ b/src/Discord.Net/project.json @@ -24,5 +24,8 @@ "Newtonsoft.Json": "7.0.1" } } + }, + "dependencies": { + "Microsoft.Net.Http": "2.2.22" } }