From d0d441c1e4fe8267e21e712755a3d43cf461fe5f Mon Sep 17 00:00:00 2001 From: Brandon Smith Date: Thu, 20 Aug 2015 16:40:39 -0300 Subject: [PATCH] Added SendFile, Message now parses attachments --- src/Discord.Net/API/DiscordAPI.cs | 4 ++- src/Discord.Net/API/Models/Common.cs | 18 ++++++++-- src/Discord.Net/DiscordClient.cs | 27 +++++++++++++- src/Discord.Net/Helpers/Http.cs | 54 ++++++++++++++++++---------- src/Discord.Net/Message.cs | 11 +++++- 5 files changed, 90 insertions(+), 24 deletions(-) diff --git a/src/Discord.Net/API/DiscordAPI.cs b/src/Discord.Net/API/DiscordAPI.cs index e3baa95ad..18773aa09 100644 --- a/src/Discord.Net/API/DiscordAPI.cs +++ b/src/Discord.Net/API/DiscordAPI.cs @@ -1,5 +1,6 @@ using Discord.API.Models; using Discord.Helpers; +using System.IO; using System.Threading.Tasks; namespace Discord.API @@ -86,6 +87,8 @@ namespace Discord.API => Http.Post(Endpoints.ChannelTyping(channelId)); public static Task DeleteMessage(string channelId, string msgId) => Http.Delete(Endpoints.ChannelMessage(channelId, msgId)); + public static Task SendFile(string channelId, Stream stream, string filename = null) + => Http.File(Endpoints.ChannelMessages(channelId), stream, filename); //Voice public static Task GetVoiceRegions() @@ -129,6 +132,5 @@ namespace Discord.API var request = new APIRequests.ChangePassword { NewPassword = newPassword, CurrentEmail = currentEmail, CurrentPassword = currentPassword }; return Http.Patch(Endpoints.UserMe, request); } - } } diff --git a/src/Discord.Net/API/Models/Common.cs b/src/Discord.Net/API/Models/Common.cs index fbbcfc062..4ec6aae0a 100644 --- a/src/Discord.Net/API/Models/Common.cs +++ b/src/Discord.Net/API/Models/Common.cs @@ -150,6 +150,20 @@ namespace Discord.API.Models } internal class Message : MessageReference { + public class Attachment + { + [JsonProperty(PropertyName = "id")] + public string Id; + [JsonProperty(PropertyName = "url")] + public string Url; + [JsonProperty(PropertyName = "proxy_url")] + public string ProxyUrl; + [JsonProperty(PropertyName = "size")] + public int Size; + [JsonProperty(PropertyName = "filename")] + public string Filename; + } + [JsonProperty(PropertyName = "tts")] public bool IsTextToSpeech; [JsonProperty(PropertyName = "mention_everyone")] @@ -159,9 +173,9 @@ namespace Discord.API.Models [JsonProperty(PropertyName = "mentions")] public UserReference[] Mentions; [JsonProperty(PropertyName = "embeds")] - public object[] Embeds; + public object[] Embeds; //TODO: Parse this [JsonProperty(PropertyName = "attachments")] - public object[] Attachments; + public Attachment[] Attachments; [JsonProperty(PropertyName = "content")] public string Content; [JsonProperty(PropertyName = "author")] diff --git a/src/Discord.Net/DiscordClient.cs b/src/Discord.Net/DiscordClient.cs index a84a046b9..91ce50a5c 100644 --- a/src/Discord.Net/DiscordClient.cs +++ b/src/Discord.Net/DiscordClient.cs @@ -3,6 +3,7 @@ using Discord.API.Models; using Discord.Helpers; using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Net; using System.Threading; @@ -100,7 +101,19 @@ namespace Discord if (model is API.Models.Message) { var extendedModel = model as API.Models.Message; - message.Attachments = extendedModel.Attachments; + if (extendedModel.Attachments != null) + { + message.Attachments = extendedModel.Attachments.Select(x => new Message.Attachment + { + Id = x.Id, + Url = x.Url, + ProxyUrl = x.ProxyUrl, + Size = x.Size, + Filename = x.Filename + }).ToArray(); + } + else + extendedModel.Attachments = null; message.Embeds = extendedModel.Embeds; message.IsMentioningEveryone = extendedModel.IsMentioningEveryone; message.IsTTS = extendedModel.IsTextToSpeech; @@ -802,6 +815,18 @@ namespace Discord return null; } + public Task SendFile(Channel channel, string path) + => SendFile(channel.Id, path); + public Task SendFile(string channelId, string path) + => SendFile(channelId, File.OpenRead(path), Path.GetFileName(path)); + public Task SendFile(Channel channel, Stream stream, string filename = null) + => SendFile(channel.Id, stream, filename); + public Task SendFile(string channelId, Stream stream, string filename = null) + { + return DiscordAPI.SendFile(channelId, stream, filename); + } + + //Voice public Task Mute(Server server, User user) => Mute(server.Id, user.Id); diff --git a/src/Discord.Net/Helpers/Http.cs b/src/Discord.Net/Helpers/Http.cs index cc96bd25d..e8075365f 100644 --- a/src/Discord.Net/Helpers/Http.cs +++ b/src/Discord.Net/Helpers/Http.cs @@ -6,6 +6,8 @@ using System.Net.Http; using System.Reflection; using System.Diagnostics; using System.Net; +using System.IO; +using System.Globalization; namespace Discord.Helpers { @@ -55,9 +57,9 @@ namespace Discord.Helpers internal static Task Post(string path, object data) where ResponseT : class - => Send(HttpMethod.Post, path, data); + => Send(HttpMethod.Post, path, AsJson(data)); internal static Task Post(string path, object data) - => Send(HttpMethod.Post, path, data); + => Send(HttpMethod.Post, path, AsJson(data)); internal static Task Post(string path) where ResponseT : class => Send(HttpMethod.Post, path, null); @@ -66,9 +68,9 @@ namespace Discord.Helpers internal static Task Put(string path, object data) where ResponseT : class - => Send(HttpMethod.Put, path, data); + => Send(HttpMethod.Put, path, AsJson(data)); internal static Task Put(string path, object data) - => Send(HttpMethod.Put, path, data); + => Send(HttpMethod.Put, path, AsJson(data)); internal static Task Put(string path) where ResponseT : class => Send(HttpMethod.Put, path, null); @@ -77,9 +79,9 @@ namespace Discord.Helpers internal static Task Patch(string path, object data) where ResponseT : class - => Send(_patch, path, data); + => Send(_patch, path, AsJson(data)); internal static Task Patch(string path, object data) - => Send(_patch, path, data); + => Send(_patch, path, AsJson(data)); internal static Task Patch(string path) where ResponseT : class => Send(_patch, path, null); @@ -88,49 +90,52 @@ namespace Discord.Helpers internal static Task Delete(string path, object data) where ResponseT : class - => Send(HttpMethod.Delete, path, data); + => Send(HttpMethod.Delete, path, AsJson(data)); internal static Task Delete(string path, object data) - => Send(HttpMethod.Delete, path, data); + => Send(HttpMethod.Delete, path, AsJson(data)); internal static Task Delete(string path) where ResponseT : class => Send(HttpMethod.Delete, path, null); internal static Task Delete(string path) => Send(HttpMethod.Delete, path, null); - internal static async Task Send(HttpMethod method, string path, object data) + internal static Task File(string path, Stream stream, string filename = null) + where ResponseT : class + => Send(HttpMethod.Post, path, AsFormData(stream, filename)); + internal static Task File(string path, Stream stream, string filename = null) + => Send(HttpMethod.Post, path, AsFormData(stream, filename)); + + private static async Task Send(HttpMethod method, string path, HttpContent content) where ResponseT : class { - string requestJson = data != null ? JsonConvert.SerializeObject(data) : null; - string responseJson = await SendRequest(method, path, requestJson, true); + string responseJson = await SendRequest(method, path, content, true); var response = JsonConvert.DeserializeObject(responseJson); #if DEBUG CheckResponse(responseJson, response); #endif return response; } - internal static async Task Send(HttpMethod method, string path, object data) + private static async Task Send(HttpMethod method, string path, HttpContent content) { - string requestJson = data != null ? JsonConvert.SerializeObject(data) : null; - string responseJson = await SendRequest(method, path, requestJson, _isDebug); + string responseJson = await SendRequest(method, path, content, _isDebug); #if DEBUG CheckEmptyResponse(responseJson); #endif return responseJson; } - private static async Task SendRequest(HttpMethod method, string path, string data, bool hasResponse) + private static async Task SendRequest(HttpMethod method, string path, HttpContent content, bool hasResponse) { #if DEBUG Stopwatch stopwatch = Stopwatch.StartNew(); #endif HttpRequestMessage msg = new HttpRequestMessage(method, path); - - if (data != null) - msg.Content = new StringContent(data, Encoding.UTF8, "application/json"); + if (content != null) + msg.Content = content; string result; HttpResponseMessage response; - if (hasResponse) + if (hasResponse) { response = await _client.SendAsync(msg, HttpCompletionOption.ResponseContentRead); if (!response.IsSuccessStatusCode) @@ -167,5 +172,16 @@ namespace Discord.Helpers throw new Exception("API check failed: Response is not empty."); } #endif + + private static StringContent AsJson(object obj) + { + return new StringContent(JsonConvert.SerializeObject(obj), Encoding.UTF8, "application/json"); + } + private static MultipartFormDataContent AsFormData(Stream stream, string filename) + { + var content = new MultipartFormDataContent("Upload----" + DateTime.Now.ToString(CultureInfo.InvariantCulture)); + content.Add(new StreamContent(stream), "file", filename); + return content; + } } } diff --git a/src/Discord.Net/Message.cs b/src/Discord.Net/Message.cs index 1e69c370f..260775df1 100644 --- a/src/Discord.Net/Message.cs +++ b/src/Discord.Net/Message.cs @@ -7,6 +7,15 @@ namespace Discord { public sealed class Message { + public struct Attachment + { + public string Id; + public string Url; + public string ProxyUrl; + public int Size; + public string Filename; + } + private readonly DiscordClient _client; public string Id { get; } @@ -15,6 +24,7 @@ namespace Discord public bool IsTTS { get; internal set; } public string Text { get; internal set; } public DateTime Timestamp { get; internal set; } + public Attachment[] Attachments { get; internal set; } public string[] MentionIds { get; internal set; } [JsonIgnore] @@ -29,7 +39,6 @@ namespace Discord public User User => _client.GetUser(UserId); //Not Implemented - public object[] Attachments { get; internal set; } public object[] Embeds { get; internal set; } internal Message(string id, string channelId, DiscordClient client)