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.

ChannelHelper.cs 16 kB

8 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. using Discord.API.Rest;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Collections.Immutable;
  5. using System.IO;
  6. using System.Linq;
  7. using System.Threading.Tasks;
  8. using Model = Discord.API.Channel;
  9. using UserModel = Discord.API.User;
  10. using WebhookModel = Discord.API.Webhook;
  11. namespace Discord.Rest
  12. {
  13. internal static class ChannelHelper
  14. {
  15. //General
  16. public static async Task DeleteAsync(IChannel channel, BaseDiscordClient client,
  17. RequestOptions options)
  18. {
  19. await client.ApiClient.DeleteChannelAsync(channel.Id, options).ConfigureAwait(false);
  20. }
  21. public static async Task<Model> ModifyAsync(IGuildChannel channel, BaseDiscordClient client,
  22. Action<GuildChannelProperties> func,
  23. RequestOptions options)
  24. {
  25. var args = new GuildChannelProperties();
  26. func(args);
  27. var apiArgs = new API.Rest.ModifyGuildChannelParams
  28. {
  29. Name = args.Name,
  30. Position = args.Position
  31. };
  32. return await client.ApiClient.ModifyGuildChannelAsync(channel.Id, apiArgs, options).ConfigureAwait(false);
  33. }
  34. public static async Task<Model> ModifyAsync(ITextChannel channel, BaseDiscordClient client,
  35. Action<TextChannelProperties> func,
  36. RequestOptions options)
  37. {
  38. var args = new TextChannelProperties();
  39. func(args);
  40. var apiArgs = new API.Rest.ModifyTextChannelParams
  41. {
  42. Name = args.Name,
  43. Position = args.Position,
  44. Topic = args.Topic,
  45. IsNsfw = args.IsNsfw
  46. };
  47. return await client.ApiClient.ModifyGuildChannelAsync(channel.Id, apiArgs, options).ConfigureAwait(false);
  48. }
  49. public static async Task<Model> ModifyAsync(IVoiceChannel channel, BaseDiscordClient client,
  50. Action<VoiceChannelProperties> func,
  51. RequestOptions options)
  52. {
  53. var args = new VoiceChannelProperties();
  54. func(args);
  55. var apiArgs = new API.Rest.ModifyVoiceChannelParams
  56. {
  57. Bitrate = args.Bitrate,
  58. Name = args.Name,
  59. Position = args.Position,
  60. UserLimit = args.UserLimit.IsSpecified ? (args.UserLimit.Value ?? 0) : Optional.Create<int>()
  61. };
  62. return await client.ApiClient.ModifyGuildChannelAsync(channel.Id, apiArgs, options).ConfigureAwait(false);
  63. }
  64. //Invites
  65. public static async Task<IReadOnlyCollection<RestInviteMetadata>> GetInvitesAsync(IGuildChannel channel, BaseDiscordClient client,
  66. RequestOptions options)
  67. {
  68. var models = await client.ApiClient.GetChannelInvitesAsync(channel.Id, options).ConfigureAwait(false);
  69. return models.Select(x => RestInviteMetadata.Create(client, null, channel, x)).ToImmutableArray();
  70. }
  71. public static async Task<RestInviteMetadata> CreateInviteAsync(IGuildChannel channel, BaseDiscordClient client,
  72. int? maxAge, int? maxUses, bool isTemporary, bool isUnique, RequestOptions options)
  73. {
  74. var args = new CreateChannelInviteParams { IsTemporary = isTemporary, IsUnique = isUnique };
  75. if (maxAge.HasValue)
  76. args.MaxAge = maxAge.Value;
  77. else
  78. args.MaxAge = 0;
  79. if (maxUses.HasValue)
  80. args.MaxUses = maxUses.Value;
  81. else
  82. args.MaxUses = 0;
  83. var model = await client.ApiClient.CreateChannelInviteAsync(channel.Id, args, options).ConfigureAwait(false);
  84. return RestInviteMetadata.Create(client, null, channel, model);
  85. }
  86. //Messages
  87. public static async Task<RestMessage> GetMessageAsync(IMessageChannel channel, BaseDiscordClient client,
  88. ulong id, RequestOptions options)
  89. {
  90. var guildId = (channel as IGuildChannel)?.GuildId;
  91. var guild = guildId != null ? await (client as IDiscordClient).GetGuildAsync(guildId.Value, CacheMode.CacheOnly).ConfigureAwait(false) : null;
  92. var model = await client.ApiClient.GetChannelMessageAsync(channel.Id, id, options).ConfigureAwait(false);
  93. if (model == null)
  94. return null;
  95. var author = GetAuthor(client, guild, model.Author.Value, model.WebhookId.ToNullable());
  96. return RestMessage.Create(client, channel, author, model);
  97. }
  98. public static IAsyncEnumerable<IReadOnlyCollection<RestMessage>> GetMessagesAsync(IMessageChannel channel, BaseDiscordClient client,
  99. ulong? fromMessageId, Direction dir, int limit, RequestOptions options)
  100. {
  101. if (dir == Direction.Around)
  102. throw new NotImplementedException(); //TODO: Impl
  103. var guildId = (channel as IGuildChannel)?.GuildId;
  104. var guild = guildId != null ? (client as IDiscordClient).GetGuildAsync(guildId.Value, CacheMode.CacheOnly).Result : null;
  105. return new PagedAsyncEnumerable<RestMessage>(
  106. DiscordConfig.MaxMessagesPerBatch,
  107. async (info, ct) =>
  108. {
  109. var args = new GetChannelMessagesParams
  110. {
  111. RelativeDirection = dir,
  112. Limit = info.PageSize
  113. };
  114. if (info.Position != null)
  115. args.RelativeMessageId = info.Position.Value;
  116. var models = await client.ApiClient.GetChannelMessagesAsync(channel.Id, args, options).ConfigureAwait(false);
  117. var builder = ImmutableArray.CreateBuilder<RestMessage>();
  118. foreach (var model in models)
  119. {
  120. var author = GetAuthor(client, guild, model.Author.Value, model.WebhookId.ToNullable());
  121. builder.Add(RestMessage.Create(client, channel, author, model));
  122. }
  123. return builder.ToImmutable();
  124. },
  125. nextPage: (info, lastPage) =>
  126. {
  127. if (lastPage.Count != DiscordConfig.MaxMessagesPerBatch)
  128. return false;
  129. if (dir == Direction.Before)
  130. info.Position = lastPage.Min(x => x.Id);
  131. else
  132. info.Position = lastPage.Max(x => x.Id);
  133. return true;
  134. },
  135. start: fromMessageId,
  136. count: limit
  137. );
  138. }
  139. public static async Task<IReadOnlyCollection<RestMessage>> GetPinnedMessagesAsync(IMessageChannel channel, BaseDiscordClient client,
  140. RequestOptions options)
  141. {
  142. var guildId = (channel as IGuildChannel)?.GuildId;
  143. var guild = guildId != null ? await (client as IDiscordClient).GetGuildAsync(guildId.Value, CacheMode.CacheOnly).ConfigureAwait(false) : null;
  144. var models = await client.ApiClient.GetPinsAsync(channel.Id, options).ConfigureAwait(false);
  145. var builder = ImmutableArray.CreateBuilder<RestMessage>();
  146. foreach (var model in models)
  147. {
  148. var author = GetAuthor(client, guild, model.Author.Value, model.WebhookId.ToNullable());
  149. builder.Add(RestMessage.Create(client, channel, author, model));
  150. }
  151. return builder.ToImmutable();
  152. }
  153. public static async Task<RestUserMessage> SendMessageAsync(IMessageChannel channel, BaseDiscordClient client,
  154. string text, bool isTTS, Embed embed, RequestOptions options)
  155. {
  156. var args = new CreateMessageParams(text) { IsTTS = isTTS, Embed = embed?.ToModel() };
  157. var model = await client.ApiClient.CreateMessageAsync(channel.Id, args, options).ConfigureAwait(false);
  158. return RestUserMessage.Create(client, channel, client.CurrentUser, model);
  159. }
  160. #if FILESYSTEM
  161. public static async Task<RestUserMessage> SendFileAsync(IMessageChannel channel, BaseDiscordClient client,
  162. string filePath, string text, bool isTTS, RequestOptions options)
  163. {
  164. string filename = Path.GetFileName(filePath);
  165. using (var file = File.OpenRead(filePath))
  166. return await SendFileAsync(channel, client, file, filename, text, isTTS, options).ConfigureAwait(false);
  167. }
  168. #endif
  169. public static async Task<RestUserMessage> SendFileAsync(IMessageChannel channel, BaseDiscordClient client,
  170. Stream stream, string filename, string text, bool isTTS, RequestOptions options)
  171. {
  172. var args = new UploadFileParams(stream) { Filename = filename, Content = text, IsTTS = isTTS };
  173. var model = await client.ApiClient.UploadFileAsync(channel.Id, args, options).ConfigureAwait(false);
  174. return RestUserMessage.Create(client, channel, client.CurrentUser, model);
  175. }
  176. public static async Task DeleteMessagesAsync(ITextChannel channel, BaseDiscordClient client,
  177. IEnumerable<ulong> messageIds, RequestOptions options)
  178. {
  179. var msgs = messageIds.ToArray();
  180. if (msgs.Length < 100)
  181. {
  182. var args = new DeleteMessagesParams(msgs);
  183. await client.ApiClient.DeleteMessagesAsync(channel.Id, args, options).ConfigureAwait(false);
  184. }
  185. else
  186. {
  187. var batch = new ulong[100];
  188. for (int i = 0; i < (msgs.Length + 99) / 100; i++)
  189. {
  190. Array.Copy(msgs, i * 100, batch, 0, Math.Min(msgs.Length - (100 * i), 100));
  191. var args = new DeleteMessagesParams(batch);
  192. await client.ApiClient.DeleteMessagesAsync(channel.Id, args, options).ConfigureAwait(false);
  193. }
  194. }
  195. }
  196. //Permission Overwrites
  197. public static async Task AddPermissionOverwriteAsync(IGuildChannel channel, BaseDiscordClient client,
  198. IUser user, OverwritePermissions perms, RequestOptions options)
  199. {
  200. var args = new ModifyChannelPermissionsParams("member", perms.AllowValue, perms.DenyValue);
  201. await client.ApiClient.ModifyChannelPermissionsAsync(channel.Id, user.Id, args, options).ConfigureAwait(false);
  202. }
  203. public static async Task AddPermissionOverwriteAsync(IGuildChannel channel, BaseDiscordClient client,
  204. IRole role, OverwritePermissions perms, RequestOptions options)
  205. {
  206. var args = new ModifyChannelPermissionsParams("role", perms.AllowValue, perms.DenyValue);
  207. await client.ApiClient.ModifyChannelPermissionsAsync(channel.Id, role.Id, args, options).ConfigureAwait(false);
  208. }
  209. public static async Task RemovePermissionOverwriteAsync(IGuildChannel channel, BaseDiscordClient client,
  210. IUser user, RequestOptions options)
  211. {
  212. await client.ApiClient.DeleteChannelPermissionAsync(channel.Id, user.Id, options).ConfigureAwait(false);
  213. }
  214. public static async Task RemovePermissionOverwriteAsync(IGuildChannel channel, BaseDiscordClient client,
  215. IRole role, RequestOptions options)
  216. {
  217. await client.ApiClient.DeleteChannelPermissionAsync(channel.Id, role.Id, options).ConfigureAwait(false);
  218. }
  219. //Users
  220. public static async Task<RestGuildUser> GetUserAsync(IGuildChannel channel, IGuild guild, BaseDiscordClient client,
  221. ulong id, RequestOptions options)
  222. {
  223. var model = await client.ApiClient.GetGuildMemberAsync(channel.GuildId, id, options).ConfigureAwait(false);
  224. if (model == null)
  225. return null;
  226. var user = RestGuildUser.Create(client, guild, model);
  227. if (!user.GetPermissions(channel).ReadMessages)
  228. return null;
  229. return user;
  230. }
  231. public static IAsyncEnumerable<IReadOnlyCollection<RestGuildUser>> GetUsersAsync(IGuildChannel channel, IGuild guild, BaseDiscordClient client,
  232. ulong? fromUserId, int? limit, RequestOptions options)
  233. {
  234. return new PagedAsyncEnumerable<RestGuildUser>(
  235. DiscordConfig.MaxUsersPerBatch,
  236. async (info, ct) =>
  237. {
  238. var args = new GetGuildMembersParams
  239. {
  240. Limit = info.PageSize
  241. };
  242. if (info.Position != null)
  243. args.AfterUserId = info.Position.Value;
  244. var models = await client.ApiClient.GetGuildMembersAsync(guild.Id, args, options).ConfigureAwait(false);
  245. return models
  246. .Select(x => RestGuildUser.Create(client, guild, x))
  247. .Where(x => x.GetPermissions(channel).ReadMessages)
  248. .ToImmutableArray();
  249. },
  250. nextPage: (info, lastPage) =>
  251. {
  252. if (lastPage.Count != DiscordConfig.MaxMessagesPerBatch)
  253. return false;
  254. info.Position = lastPage.Max(x => x.Id);
  255. return true;
  256. },
  257. start: fromUserId,
  258. count: limit
  259. );
  260. }
  261. //Typing
  262. public static async Task TriggerTypingAsync(IMessageChannel channel, BaseDiscordClient client,
  263. RequestOptions options = null)
  264. {
  265. await client.ApiClient.TriggerTypingIndicatorAsync(channel.Id, options).ConfigureAwait(false);
  266. }
  267. public static IDisposable EnterTypingState(IMessageChannel channel, BaseDiscordClient client,
  268. RequestOptions options)
  269. => new TypingNotifier(client, channel, options);
  270. //Webhooks
  271. public static async Task<RestWebhook> CreateWebhookAsync(ITextChannel channel, BaseDiscordClient client, string name, Stream avatar, RequestOptions options)
  272. {
  273. var args = new CreateWebhookParams { Name = name };
  274. if (avatar != null)
  275. args.Avatar = new API.Image(avatar);
  276. var model = await client.ApiClient.CreateWebhookAsync(channel.Id, args, options).ConfigureAwait(false);
  277. return RestWebhook.Create(client, channel, model);
  278. }
  279. public static async Task<RestWebhook> GetWebhookAsync(ITextChannel channel, BaseDiscordClient client, ulong id, RequestOptions options)
  280. {
  281. var model = await client.ApiClient.GetWebhookAsync(id, options: options).ConfigureAwait(false);
  282. if (model == null)
  283. return null;
  284. return RestWebhook.Create(client, channel, model);
  285. }
  286. public static async Task<IReadOnlyCollection<RestWebhook>> GetWebhooksAsync(ITextChannel channel, BaseDiscordClient client, RequestOptions options)
  287. {
  288. var models = await client.ApiClient.GetChannelWebhooksAsync(channel.Id, options).ConfigureAwait(false);
  289. return models.Select(x => RestWebhook.Create(client, channel, x))
  290. .ToImmutableArray();
  291. }
  292. //Helpers
  293. private static IUser GetAuthor(BaseDiscordClient client, IGuild guild, UserModel model, ulong? webhookId)
  294. {
  295. IUser author = null;
  296. if (guild != null)
  297. author = guild.GetUserAsync(model.Id, CacheMode.CacheOnly).Result;
  298. if (author == null)
  299. author = RestUser.Create(client, guild, model, webhookId);
  300. return author;
  301. }
  302. public static bool IsNsfw(IChannel channel)
  303. => IsNsfw(channel.Name);
  304. public static bool IsNsfw(string channelName) =>
  305. channelName == "nsfw" || channelName.StartsWith("nsfw-");
  306. }
  307. }