You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

RestTextChannel.cs 17 kB

7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Threading.Tasks;
  7. using Model = Discord.API.Channel;
  8. namespace Discord.Rest
  9. {
  10. /// <summary>
  11. /// Represents a REST-based channel in a guild that can send and receive messages.
  12. /// </summary>
  13. [DebuggerDisplay(@"{DebuggerDisplay,nq}")]
  14. public class RestTextChannel : RestGuildChannel, IRestMessageChannel, ITextChannel
  15. {
  16. /// <inheritdoc />
  17. public string Topic { get; private set; }
  18. public int SlowModeInterval { get; private set; }
  19. /// <inheritdoc />
  20. public ulong? CategoryId { get; private set; }
  21. /// <inheritdoc />
  22. public string Mention => MentionUtils.MentionChannel(Id);
  23. /// <inheritdoc />
  24. public bool IsNsfw { get; private set; }
  25. internal RestTextChannel(BaseDiscordClient discord, IGuild guild, ulong id)
  26. : base(discord, guild, id)
  27. {
  28. }
  29. internal new static RestTextChannel Create(BaseDiscordClient discord, IGuild guild, Model model)
  30. {
  31. var entity = new RestTextChannel(discord, guild, model.Id);
  32. entity.Update(model);
  33. return entity;
  34. }
  35. /// <inheritdoc />
  36. internal override void Update(Model model)
  37. {
  38. base.Update(model);
  39. CategoryId = model.CategoryId;
  40. Topic = model.Topic.Value;
  41. SlowModeInterval = model.SlowMode.Value;
  42. IsNsfw = model.Nsfw.GetValueOrDefault();
  43. }
  44. /// <inheritdoc />
  45. public async Task ModifyAsync(Action<TextChannelProperties> func, RequestOptions options = null)
  46. {
  47. var model = await ChannelHelper.ModifyAsync(this, Discord, func, options).ConfigureAwait(false);
  48. Update(model);
  49. }
  50. /// <summary>
  51. /// Gets a user in this channel.
  52. /// </summary>
  53. /// <param name="id">The snowflake identifier of the user.</param>
  54. /// <param name="options">The options to be used when sending the request.</param>
  55. /// <exception cref="InvalidOperationException">
  56. /// Resolving permissions requires the parent guild to be downloaded.
  57. /// </exception>
  58. /// <returns>
  59. /// A task representing the asynchronous get operation. The task result contains a guild user object that
  60. /// represents the user; <c>null</c> if none is found.
  61. /// </returns>
  62. public Task<RestGuildUser> GetUserAsync(ulong id, RequestOptions options = null)
  63. => ChannelHelper.GetUserAsync(this, Guild, Discord, id, options);
  64. /// <summary>
  65. /// Gets a collection of users that are able to view the channel.
  66. /// </summary>
  67. /// <param name="options">The options to be used when sending the request.</param>
  68. /// <exception cref="InvalidOperationException">
  69. /// Resolving permissions requires the parent guild to be downloaded.
  70. /// </exception>
  71. /// <returns>
  72. /// A paged collection containing a collection of guild users that can access this channel. Flattening the
  73. /// paginated response into a collection of users with
  74. /// <see cref="AsyncEnumerableExtensions.FlattenAsync{T}"/> is required if you wish to access the users.
  75. /// </returns>
  76. public IAsyncEnumerable<IReadOnlyCollection<RestGuildUser>> GetUsersAsync(RequestOptions options = null)
  77. => ChannelHelper.GetUsersAsync(this, Guild, Discord, null, null, options);
  78. /// <inheritdoc />
  79. public Task<RestMessage> GetMessageAsync(ulong id, RequestOptions options = null)
  80. => ChannelHelper.GetMessageAsync(this, Discord, id, options);
  81. /// <inheritdoc />
  82. public IAsyncEnumerable<IReadOnlyCollection<RestMessage>> GetMessagesAsync(int limit = DiscordConfig.MaxMessagesPerBatch, RequestOptions options = null)
  83. => ChannelHelper.GetMessagesAsync(this, Discord, null, Direction.Before, limit, options);
  84. /// <inheritdoc />
  85. public IAsyncEnumerable<IReadOnlyCollection<RestMessage>> GetMessagesAsync(ulong fromMessageId, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch, RequestOptions options = null)
  86. => ChannelHelper.GetMessagesAsync(this, Discord, fromMessageId, dir, limit, options);
  87. /// <inheritdoc />
  88. public IAsyncEnumerable<IReadOnlyCollection<RestMessage>> GetMessagesAsync(IMessage fromMessage, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch, RequestOptions options = null)
  89. => ChannelHelper.GetMessagesAsync(this, Discord, fromMessage.Id, dir, limit, options);
  90. /// <inheritdoc />
  91. public Task<IReadOnlyCollection<RestMessage>> GetPinnedMessagesAsync(RequestOptions options = null)
  92. => ChannelHelper.GetPinnedMessagesAsync(this, Discord, options);
  93. /// <inheritdoc />
  94. /// <exception cref="ArgumentOutOfRangeException">Message content is too long, length must be less or equal to <see cref="DiscordConfig.MaxMessageSize"/>.</exception>
  95. public Task<RestUserMessage> SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null)
  96. => ChannelHelper.SendMessageAsync(this, Discord, text, isTTS, embed, options);
  97. /// <inheritdoc />
  98. /// <exception cref="ArgumentException">
  99. /// <paramref name="filePath" /> is a zero-length string, contains only white space, or contains one or more
  100. /// invalid characters as defined by <see cref="System.IO.Path.GetInvalidPathChars"/>.
  101. /// </exception>
  102. /// <exception cref="ArgumentNullException">
  103. /// <paramref name="filePath" /> is <c>null</c>.
  104. /// </exception>
  105. /// <exception cref="PathTooLongException">
  106. /// The specified path, file name, or both exceed the system-defined maximum length. For example, on
  107. /// Windows-based platforms, paths must be less than 248 characters, and file names must be less than 260
  108. /// characters.
  109. /// </exception>
  110. /// <exception cref="DirectoryNotFoundException">
  111. /// The specified path is invalid, (for example, it is on an unmapped drive).
  112. /// </exception>
  113. /// <exception cref="UnauthorizedAccessException">
  114. /// <paramref name="filePath" /> specified a directory.-or- The caller does not have the required permission.
  115. /// </exception>
  116. /// <exception cref="FileNotFoundException">
  117. /// The file specified in <paramref name="filePath" /> was not found.
  118. /// </exception>
  119. /// <exception cref="NotSupportedException"><paramref name="filePath" /> is in an invalid format.</exception>
  120. /// <exception cref="IOException">An I/O error occurred while opening the file.</exception>
  121. /// <exception cref="ArgumentOutOfRangeException">Message content is too long, length must be less or equal to <see cref="DiscordConfig.MaxMessageSize"/>.</exception>
  122. public Task<RestUserMessage> SendFileAsync(string filePath, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null)
  123. => ChannelHelper.SendFileAsync(this, Discord, filePath, text, isTTS, embed, options);
  124. /// <inheritdoc />
  125. /// <exception cref="ArgumentOutOfRangeException">Message content is too long, length must be less or equal to <see cref="DiscordConfig.MaxMessageSize"/>.</exception>
  126. public Task<RestUserMessage> SendFileAsync(Stream stream, string filename, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null)
  127. => ChannelHelper.SendFileAsync(this, Discord, stream, filename, text, isTTS, embed, options);
  128. /// <inheritdoc />
  129. public Task DeleteMessageAsync(ulong messageId, RequestOptions options = null)
  130. => ChannelHelper.DeleteMessageAsync(this, messageId, Discord, options);
  131. /// <inheritdoc />
  132. public Task DeleteMessageAsync(IMessage message, RequestOptions options = null)
  133. => ChannelHelper.DeleteMessageAsync(this, message.Id, Discord, options);
  134. /// <inheritdoc />
  135. public Task DeleteMessagesAsync(IEnumerable<IMessage> messages, RequestOptions options = null)
  136. => ChannelHelper.DeleteMessagesAsync(this, Discord, messages.Select(x => x.Id), options);
  137. /// <inheritdoc />
  138. public Task DeleteMessagesAsync(IEnumerable<ulong> messageIds, RequestOptions options = null)
  139. => ChannelHelper.DeleteMessagesAsync(this, Discord, messageIds, options);
  140. /// <inheritdoc />
  141. public Task TriggerTypingAsync(RequestOptions options = null)
  142. => ChannelHelper.TriggerTypingAsync(this, Discord, options);
  143. /// <inheritdoc />
  144. public IDisposable EnterTypingState(RequestOptions options = null)
  145. => ChannelHelper.EnterTypingState(this, Discord, options);
  146. /// <summary>
  147. /// Creates a webhook in this text channel.
  148. /// </summary>
  149. /// <param name="name">The name of the webhook.</param>
  150. /// <param name="avatar">The avatar of the webhook.</param>
  151. /// <param name="options">The options to be used when sending the request.</param>
  152. /// <returns>
  153. /// A task that represents the asynchronous creation operation. The task result contains the newly created
  154. /// webhook.
  155. /// </returns>
  156. public Task<RestWebhook> CreateWebhookAsync(string name, Stream avatar = null, RequestOptions options = null)
  157. => ChannelHelper.CreateWebhookAsync(this, Discord, name, avatar, options);
  158. /// <summary>
  159. /// Gets a webhook available in this text channel.
  160. /// </summary>
  161. /// <param name="id">The identifier of the webhook.</param>
  162. /// <param name="options">The options to be used when sending the request.</param>
  163. /// <returns>
  164. /// A task that represents the asynchronous get operation. The task result contains a webhook associated
  165. /// with the identifier; <c>null</c> if the webhook is not found.
  166. /// </returns>
  167. public Task<RestWebhook> GetWebhookAsync(ulong id, RequestOptions options = null)
  168. => ChannelHelper.GetWebhookAsync(this, Discord, id, options);
  169. /// <summary>
  170. /// Gets the webhooks available in this text channel.
  171. /// </summary>
  172. /// <param name="options">The options to be used when sending the request.</param>
  173. /// <returns>
  174. /// A task that represents the asynchronous get operation. The task result contains a read-only collection
  175. /// of webhooks that is available in this channel.
  176. /// </returns>
  177. public Task<IReadOnlyCollection<RestWebhook>> GetWebhooksAsync(RequestOptions options = null)
  178. => ChannelHelper.GetWebhooksAsync(this, Discord, options);
  179. /// <summary>
  180. /// Gets the parent (category) channel of this channel.
  181. /// </summary>
  182. /// <param name="options">The options to be used when sending the request.</param>
  183. /// <returns>
  184. /// A task that represents the asynchronous get operation. The task result contains the category channel
  185. /// representing the parent of this channel; <c>null</c> if none is set.
  186. /// </returns>
  187. public Task<ICategoryChannel> GetCategoryAsync(RequestOptions options = null)
  188. => ChannelHelper.GetCategoryAsync(this, Discord, options);
  189. private string DebuggerDisplay => $"{Name} ({Id}, Text)";
  190. //ITextChannel
  191. /// <inheritdoc />
  192. async Task<IWebhook> ITextChannel.CreateWebhookAsync(string name, Stream avatar, RequestOptions options)
  193. => await CreateWebhookAsync(name, avatar, options).ConfigureAwait(false);
  194. /// <inheritdoc />
  195. async Task<IWebhook> ITextChannel.GetWebhookAsync(ulong id, RequestOptions options)
  196. => await GetWebhookAsync(id, options).ConfigureAwait(false);
  197. /// <inheritdoc />
  198. async Task<IReadOnlyCollection<IWebhook>> ITextChannel.GetWebhooksAsync(RequestOptions options)
  199. => await GetWebhooksAsync(options).ConfigureAwait(false);
  200. //IMessageChannel
  201. /// <inheritdoc />
  202. async Task<IMessage> IMessageChannel.GetMessageAsync(ulong id, CacheMode mode, RequestOptions options)
  203. {
  204. if (mode == CacheMode.AllowDownload)
  205. return await GetMessageAsync(id, options).ConfigureAwait(false);
  206. else
  207. return null;
  208. }
  209. /// <inheritdoc />
  210. IAsyncEnumerable<IReadOnlyCollection<IMessage>> IMessageChannel.GetMessagesAsync(int limit, CacheMode mode, RequestOptions options)
  211. {
  212. if (mode == CacheMode.AllowDownload)
  213. return GetMessagesAsync(limit, options);
  214. else
  215. return AsyncEnumerable.Empty<IReadOnlyCollection<IMessage>>();
  216. }
  217. /// <inheritdoc />
  218. IAsyncEnumerable<IReadOnlyCollection<IMessage>> IMessageChannel.GetMessagesAsync(ulong fromMessageId, Direction dir, int limit, CacheMode mode, RequestOptions options)
  219. {
  220. if (mode == CacheMode.AllowDownload)
  221. return GetMessagesAsync(fromMessageId, dir, limit, options);
  222. else
  223. return AsyncEnumerable.Empty<IReadOnlyCollection<IMessage>>();
  224. }
  225. /// <inheritdoc />
  226. IAsyncEnumerable<IReadOnlyCollection<IMessage>> IMessageChannel.GetMessagesAsync(IMessage fromMessage, Direction dir, int limit, CacheMode mode, RequestOptions options)
  227. {
  228. if (mode == CacheMode.AllowDownload)
  229. return GetMessagesAsync(fromMessage, dir, limit, options);
  230. else
  231. return AsyncEnumerable.Empty<IReadOnlyCollection<IMessage>>();
  232. }
  233. /// <inheritdoc />
  234. async Task<IReadOnlyCollection<IMessage>> IMessageChannel.GetPinnedMessagesAsync(RequestOptions options)
  235. => await GetPinnedMessagesAsync(options).ConfigureAwait(false);
  236. /// <inheritdoc />
  237. async Task<IUserMessage> IMessageChannel.SendFileAsync(string filePath, string text, bool isTTS, Embed embed, RequestOptions options)
  238. => await SendFileAsync(filePath, text, isTTS, embed, options).ConfigureAwait(false);
  239. /// <inheritdoc />
  240. async Task<IUserMessage> IMessageChannel.SendFileAsync(Stream stream, string filename, string text, bool isTTS, Embed embed, RequestOptions options)
  241. => await SendFileAsync(stream, filename, text, isTTS, embed, options).ConfigureAwait(false);
  242. /// <inheritdoc />
  243. async Task<IUserMessage> IMessageChannel.SendMessageAsync(string text, bool isTTS, Embed embed, RequestOptions options)
  244. => await SendMessageAsync(text, isTTS, embed, options).ConfigureAwait(false);
  245. //IGuildChannel
  246. /// <inheritdoc />
  247. async Task<IGuildUser> IGuildChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options)
  248. {
  249. if (mode == CacheMode.AllowDownload)
  250. return await GetUserAsync(id, options).ConfigureAwait(false);
  251. else
  252. return null;
  253. }
  254. /// <inheritdoc />
  255. IAsyncEnumerable<IReadOnlyCollection<IGuildUser>> IGuildChannel.GetUsersAsync(CacheMode mode, RequestOptions options)
  256. {
  257. if (mode == CacheMode.AllowDownload)
  258. return GetUsersAsync(options);
  259. else
  260. return AsyncEnumerable.Empty<IReadOnlyCollection<IGuildUser>>();
  261. }
  262. //IChannel
  263. /// <inheritdoc />
  264. async Task<IUser> IChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options)
  265. {
  266. if (mode == CacheMode.AllowDownload)
  267. return await GetUserAsync(id, options).ConfigureAwait(false);
  268. else
  269. return null;
  270. }
  271. /// <inheritdoc />
  272. IAsyncEnumerable<IReadOnlyCollection<IUser>> IChannel.GetUsersAsync(CacheMode mode, RequestOptions options)
  273. {
  274. if (mode == CacheMode.AllowDownload)
  275. return GetUsersAsync(options);
  276. else
  277. return AsyncEnumerable.Empty<IReadOnlyCollection<IGuildUser>>();
  278. }
  279. // INestedChannel
  280. /// <inheritdoc />
  281. async Task<ICategoryChannel> INestedChannel.GetCategoryAsync(CacheMode mode, RequestOptions options)
  282. {
  283. if (CategoryId.HasValue && mode == CacheMode.AllowDownload)
  284. return (await Guild.GetChannelAsync(CategoryId.Value, mode, options).ConfigureAwait(false)) as ICategoryChannel;
  285. return null;
  286. }
  287. }
  288. }