| @@ -3,14 +3,14 @@ | |||
| internal static class CDN | |||
| { | |||
| public static string GetApplicationIconUrl(ulong appId, string iconId) | |||
| => iconId != null ? $"{DiscordConfig.CDNUrl}app-icons/{appId}/{iconId}.jpg" : null; | |||
| => iconId != null ? $"{DiscordRestConfig.CDNUrl}app-icons/{appId}/{iconId}.jpg" : null; | |||
| public static string GetUserAvatarUrl(ulong userId, string avatarId) | |||
| => avatarId != null ? $"{DiscordConfig.CDNUrl}avatars/{userId}/{avatarId}.jpg" : null; | |||
| => avatarId != null ? $"{DiscordRestConfig.CDNUrl}avatars/{userId}/{avatarId}.jpg" : null; | |||
| public static string GetGuildIconUrl(ulong guildId, string iconId) | |||
| => iconId != null ? $"{DiscordConfig.CDNUrl}icons/{guildId}/{iconId}.jpg" : null; | |||
| => iconId != null ? $"{DiscordRestConfig.CDNUrl}icons/{guildId}/{iconId}.jpg" : null; | |||
| public static string GetGuildSplashUrl(ulong guildId, string splashId) | |||
| => splashId != null ? $"{DiscordConfig.CDNUrl}splashes/{guildId}/{splashId}.jpg" : null; | |||
| => splashId != null ? $"{DiscordRestConfig.CDNUrl}splashes/{guildId}/{splashId}.jpg" : null; | |||
| public static string GetChannelIconUrl(ulong channelId, string iconId) | |||
| => iconId != null ? $"{DiscordConfig.CDNUrl}channel-icons/{channelId}/{iconId}.jpg" : null; | |||
| => iconId != null ? $"{DiscordRestConfig.CDNUrl}channel-icons/{channelId}/{iconId}.jpg" : null; | |||
| } | |||
| } | |||
| @@ -55,9 +55,9 @@ namespace Discord.API | |||
| _requestQueue = requestQueue ?? new RequestQueue(); | |||
| _restClient = restClientProvider(DiscordConfig.ClientAPIUrl); | |||
| _restClient = restClientProvider(DiscordRestConfig.ClientAPIUrl); | |||
| _restClient.SetHeader("accept", "*/*"); | |||
| _restClient.SetHeader("user-agent", DiscordConfig.UserAgent); | |||
| _restClient.SetHeader("user-agent", DiscordRestConfig.UserAgent); | |||
| if (webSocketProvider != null) | |||
| { | |||
| _gatewayClient = webSocketProvider(); | |||
| @@ -211,7 +211,7 @@ namespace Discord.API | |||
| if (_gatewayUrl == null) | |||
| { | |||
| var gatewayResponse = await GetGatewayAsync().ConfigureAwait(false); | |||
| _gatewayUrl = $"{gatewayResponse.Url}?v={DiscordConfig.APIVersion}&encoding={DiscordConfig.GatewayEncoding}"; | |||
| _gatewayUrl = $"{gatewayResponse.Url}?v={DiscordConfig.APIVersion}&encoding={DiscordSocketConfig.GatewayEncoding}"; | |||
| } | |||
| await _gatewayClient.ConnectAsync(_gatewayUrl).ConfigureAwait(false); | |||
| @@ -791,13 +791,13 @@ namespace Discord.API | |||
| List<GuildMember[]> result; | |||
| if (args.Limit.IsSpecified) | |||
| result = new List<GuildMember[]>((limit + DiscordConfig.MaxUsersPerBatch - 1) / DiscordConfig.MaxUsersPerBatch); | |||
| result = new List<GuildMember[]>((limit + DiscordRestConfig.MaxUsersPerBatch - 1) / DiscordRestConfig.MaxUsersPerBatch); | |||
| else | |||
| result = new List<GuildMember[]>(); | |||
| while (true) | |||
| { | |||
| int runLimit = (limit >= DiscordConfig.MaxUsersPerBatch) ? DiscordConfig.MaxUsersPerBatch : limit; | |||
| int runLimit = (limit >= DiscordRestConfig.MaxUsersPerBatch) ? DiscordRestConfig.MaxUsersPerBatch : limit; | |||
| string endpoint = $"guilds/{guildId}/members?limit={runLimit}&after={afterUserId}"; | |||
| var models = await SendAsync<GuildMember[]>("GET", endpoint, options: options).ConfigureAwait(false); | |||
| @@ -806,11 +806,11 @@ namespace Discord.API | |||
| result.Add(models); | |||
| limit -= DiscordConfig.MaxUsersPerBatch; | |||
| limit -= DiscordRestConfig.MaxUsersPerBatch; | |||
| afterUserId = models[models.Length - 1].User.Id; | |||
| //Was this an incomplete (the last) batch? | |||
| if (models.Length != DiscordConfig.MaxUsersPerBatch) break; | |||
| if (models.Length != DiscordRestConfig.MaxUsersPerBatch) break; | |||
| } | |||
| if (result.Count > 1) | |||
| @@ -920,14 +920,14 @@ namespace Discord.API | |||
| break; | |||
| } | |||
| int runs = (limit + DiscordConfig.MaxMessagesPerBatch - 1) / DiscordConfig.MaxMessagesPerBatch; | |||
| int lastRunCount = limit - (runs - 1) * DiscordConfig.MaxMessagesPerBatch; | |||
| int runs = (limit + DiscordRestConfig.MaxMessagesPerBatch - 1) / DiscordRestConfig.MaxMessagesPerBatch; | |||
| int lastRunCount = limit - (runs - 1) * DiscordRestConfig.MaxMessagesPerBatch; | |||
| var result = new API.Message[runs][]; | |||
| int i = 0; | |||
| for (; i < runs; i++) | |||
| { | |||
| int runCount = i == (runs - 1) ? lastRunCount : DiscordConfig.MaxMessagesPerBatch; | |||
| int runCount = i == (runs - 1) ? lastRunCount : DiscordRestConfig.MaxMessagesPerBatch; | |||
| string endpoint; | |||
| if (relativeId != null) | |||
| endpoint = $"channels/{channelId}/messages?limit={runCount}&{relativeDir}={relativeId}"; | |||
| @@ -966,7 +966,7 @@ namespace Discord.API | |||
| } | |||
| //Was this an incomplete (the last) batch? | |||
| if (models.Length != DiscordConfig.MaxMessagesPerBatch) { i++; break; } | |||
| if (models.Length != DiscordRestConfig.MaxMessagesPerBatch) { i++; break; } | |||
| } | |||
| if (i > 1) | |||
| @@ -1011,8 +1011,8 @@ namespace Discord.API | |||
| Preconditions.NotEqual(channelId, 0, nameof(channelId)); | |||
| Preconditions.NotNull(args, nameof(args)); | |||
| Preconditions.NotNullOrEmpty(args.Content, nameof(args.Content)); | |||
| if (args.Content.Length > DiscordConfig.MaxMessageSize) | |||
| throw new ArgumentException($"Message content is too long, length must be less or equal to {DiscordConfig.MaxMessageSize}.", nameof(args.Content)); | |||
| if (args.Content.Length > DiscordRestConfig.MaxMessageSize) | |||
| throw new ArgumentException($"Message content is too long, length must be less or equal to {DiscordRestConfig.MaxMessageSize}.", nameof(args.Content)); | |||
| if (guildId != 0) | |||
| return await SendAsync<Message>("POST", $"channels/{channelId}/messages", args, GuildBucket.SendEditMessage, guildId, options: options).ConfigureAwait(false); | |||
| @@ -1040,8 +1040,8 @@ namespace Discord.API | |||
| { | |||
| if (args.Content.Value == null) | |||
| args.Content = ""; | |||
| if (args.Content.Value?.Length > DiscordConfig.MaxMessageSize) | |||
| throw new ArgumentOutOfRangeException($"Message content is too long, length must be less or equal to {DiscordConfig.MaxMessageSize}.", nameof(args.Content)); | |||
| if (args.Content.Value?.Length > DiscordRestConfig.MaxMessageSize) | |||
| throw new ArgumentOutOfRangeException($"Message content is too long, length must be less or equal to {DiscordRestConfig.MaxMessageSize}.", nameof(args.Content)); | |||
| } | |||
| if (guildId != 0) | |||
| @@ -1121,8 +1121,8 @@ namespace Discord.API | |||
| if (args.Content.IsSpecified) | |||
| { | |||
| Preconditions.NotNullOrEmpty(args.Content, nameof(args.Content)); | |||
| if (args.Content.Value.Length > DiscordConfig.MaxMessageSize) | |||
| throw new ArgumentOutOfRangeException($"Message content is too long, length must be less or equal to {DiscordConfig.MaxMessageSize}.", nameof(args.Content)); | |||
| if (args.Content.Value.Length > DiscordRestConfig.MaxMessageSize) | |||
| throw new ArgumentOutOfRangeException($"Message content is too long, length must be less or equal to {DiscordRestConfig.MaxMessageSize}.", nameof(args.Content)); | |||
| } | |||
| if (guildId != 0) | |||
| @@ -2,7 +2,7 @@ | |||
| { | |||
| public class GetChannelMessagesParams | |||
| { | |||
| public int Limit { get; set; } = DiscordConfig.MaxMessagesPerBatch; | |||
| public int Limit { get; set; } = DiscordRestConfig.MaxMessagesPerBatch; | |||
| public Direction RelativeDirection { get; set; } = Direction.Before; | |||
| public Optional<ulong> RelativeMessageId { get; set; } | |||
| @@ -1,33 +1,17 @@ | |||
| using Discord.Net.Rest; | |||
| using System.Reflection; | |||
| using System.Reflection; | |||
| namespace Discord | |||
| { | |||
| public class DiscordConfig | |||
| { | |||
| public static string Version { get; } = typeof(DiscordConfig).GetTypeInfo().Assembly?.GetName().Version.ToString(3) ?? "Unknown"; | |||
| public static string FullVersion { get; } = typeof(DiscordConfig).GetTypeInfo().Assembly?.GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion ?? "Unknown"; | |||
| public static string UserAgent { get; } = $"DiscordBot (https://github.com/RogueException/Discord.Net, v{Version})"; | |||
| public const int APIVersion = 6; | |||
| public const string GatewayEncoding = "json"; | |||
| public const int APIVersion = 6; | |||
| public static string Version { get; } = typeof(DiscordRestConfig).GetTypeInfo().Assembly?.GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion ?? "Unknown"; | |||
| public static readonly string ClientAPIUrl = $"https://discordapp.com/api/v{APIVersion}/"; | |||
| public const string CDNUrl = "https://cdn.discordapp.com/"; | |||
| public const string InviteUrl = "https://discord.gg/"; | |||
| public const int MaxMessageSize = 2000; | |||
| public const int MaxMessagesPerBatch = 100; | |||
| public const int MaxUsersPerBatch = 1000; | |||
| internal const int RestTimeout = 10000; | |||
| internal const int MessageQueueInterval = 100; | |||
| internal const int WebSocketQueueInterval = 100; | |||
| /// <summary> Gets or sets the minimum log level severity that will be sent to the LogMessage event. </summary> | |||
| public LogSeverity LogLevel { get; set; } = LogSeverity.Info; | |||
| /// <summary> Gets or sets the provider used to generate new REST connections. </summary> | |||
| public RestClientProvider RestClientProvider { get; set; } = url => new DefaultRestClient(url); | |||
| } | |||
| } | |||
| @@ -37,9 +37,9 @@ namespace Discord | |||
| public LoginState LoginState { get; private set; } | |||
| /// <summary> Creates a new REST-only discord client. </summary> | |||
| public DiscordRestClient() : this(new DiscordConfig()) { } | |||
| public DiscordRestClient() : this(new DiscordRestConfig()) { } | |||
| /// <summary> Creates a new REST-only discord client. </summary> | |||
| public DiscordRestClient(DiscordConfig config) | |||
| public DiscordRestClient(DiscordRestConfig config) | |||
| { | |||
| LogManager = new LogManager(config.LogLevel); | |||
| LogManager.Message += async msg => await _logEvent.InvokeAsync(msg).ConfigureAwait(false); | |||
| @@ -304,9 +304,10 @@ namespace Discord | |||
| private async Task WriteInitialLog() | |||
| { | |||
| if (this is DiscordSocketClient) | |||
| await _clientLogger.InfoAsync($"DiscordSocketClient v{DiscordConfig.FullVersion} (API v{DiscordConfig.APIVersion}, {DiscordConfig.GatewayEncoding})").ConfigureAwait(false); | |||
| await _clientLogger.InfoAsync($"DiscordSocketClient v{DiscordConfig.Version} (API v{DiscordConfig.APIVersion}, {DiscordSocketConfig.GatewayEncoding})").ConfigureAwait(false); | |||
| else | |||
| await _clientLogger.InfoAsync($"DiscordClient v{DiscordConfig.FullVersion} (API v{DiscordConfig.APIVersion})").ConfigureAwait(false); | |||
| await _clientLogger.InfoAsync($"DiscordRestClient v{DiscordConfig.Version} (API v{DiscordConfig.APIVersion})").ConfigureAwait(false); | |||
| await _clientLogger.VerboseAsync($"Runtime: {RuntimeInformation.FrameworkDescription.Trim()} ({ToArchString(RuntimeInformation.ProcessArchitecture)})").ConfigureAwait(false); | |||
| await _clientLogger.VerboseAsync($"OS: {RuntimeInformation.OSDescription.Trim()} ({ToArchString(RuntimeInformation.OSArchitecture)})").ConfigureAwait(false); | |||
| await _clientLogger.VerboseAsync($"Processors: {Environment.ProcessorCount}").ConfigureAwait(false); | |||
| @@ -0,0 +1,20 @@ | |||
| using Discord.Net.Rest; | |||
| namespace Discord | |||
| { | |||
| public class DiscordRestConfig : DiscordConfig | |||
| { | |||
| public static string UserAgent { get; } = $"DiscordBot (https://github.com/RogueException/Discord.Net, v{Version})"; | |||
| public const int MaxMessageSize = 2000; | |||
| public const int MaxMessagesPerBatch = 100; | |||
| public const int MaxUsersPerBatch = 1000; | |||
| internal const int RestTimeout = 10000; | |||
| internal const int MessageQueueInterval = 100; | |||
| internal const int WebSocketQueueInterval = 100; | |||
| /// <summary> Gets or sets the provider used to generate new REST connections. </summary> | |||
| public RestClientProvider RestClientProvider { get; set; } = url => new DefaultRestClient(url); | |||
| } | |||
| } | |||
| @@ -46,9 +46,6 @@ namespace Discord | |||
| //From DiscordSocketConfig | |||
| internal int TotalShards { get; private set; } | |||
| internal int ConnectionTimeout { get; private set; } | |||
| internal int ReconnectDelay { get; private set; } | |||
| internal int FailedReconnectDelay { get; private set; } | |||
| internal int MessageCacheSize { get; private set; } | |||
| internal int LargeThreshold { get; private set; } | |||
| internal AudioMode AudioMode { get; private set; } | |||
| @@ -67,9 +64,6 @@ namespace Discord | |||
| { | |||
| ShardId = config.ShardId; | |||
| TotalShards = config.TotalShards; | |||
| ConnectionTimeout = config.ConnectionTimeout; | |||
| ReconnectDelay = config.ReconnectDelay; | |||
| FailedReconnectDelay = config.FailedReconnectDelay; | |||
| MessageCacheSize = config.MessageCacheSize; | |||
| LargeThreshold = config.LargeThreshold; | |||
| AudioMode = config.AudioMode; | |||
| @@ -3,20 +3,15 @@ using Discord.Net.WebSockets; | |||
| namespace Discord | |||
| { | |||
| public class DiscordSocketConfig : DiscordConfig | |||
| public class DiscordSocketConfig : DiscordRestConfig | |||
| { | |||
| public const string GatewayEncoding = "json"; | |||
| /// <summary> Gets or sets the id for this shard. Must be less than TotalShards. </summary> | |||
| public int ShardId { get; set; } = 0; | |||
| /// <summary> Gets or sets the total number of shards for this application. </summary> | |||
| public int TotalShards { get; set; } = 1; | |||
| /// <summary> Gets or sets the time (in milliseconds) to wait for the websocket to connect and initialize. </summary> | |||
| public int ConnectionTimeout { get; set; } = 30000; | |||
| /// <summary> Gets or sets the time (in milliseconds) to wait after an unexpected disconnect before reconnecting. </summary> | |||
| public int ReconnectDelay { get; set; } = 1000; | |||
| /// <summary> Gets or sets the time (in milliseconds) to wait after an reconnect fails before retrying. </summary> | |||
| public int FailedReconnectDelay { get; set; } = 15000; | |||
| /// <summary> Gets or sets the number of messages per channel that should be kept in cache. Setting this to zero disables the message cache entirely. </summary> | |||
| public int MessageCacheSize { get; set; } = 0; | |||
| /*/// <summary> | |||
| @@ -20,9 +20,9 @@ namespace Discord | |||
| /// <summary> Gets the message from this channel's cache with the given id, or null if not found. </summary> | |||
| IMessage GetCachedMessage(ulong id); | |||
| /// <summary> Gets the last N messages from this message channel. </summary> | |||
| Task<IReadOnlyCollection<IMessage>> GetMessagesAsync(int limit = DiscordConfig.MaxMessagesPerBatch); | |||
| Task<IReadOnlyCollection<IMessage>> GetMessagesAsync(int limit = DiscordRestConfig.MaxMessagesPerBatch); | |||
| /// <summary> Gets a collection of messages in this channel. </summary> | |||
| Task<IReadOnlyCollection<IMessage>> GetMessagesAsync(ulong fromMessageId, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch); | |||
| Task<IReadOnlyCollection<IMessage>> GetMessagesAsync(ulong fromMessageId, Direction dir, int limit = DiscordRestConfig.MaxMessagesPerBatch); | |||
| /// <summary> Bulk deletes multiple messages. </summary> | |||
| Task DeleteMessagesAsync(IEnumerable<IMessage> messages); | |||
| @@ -16,8 +16,8 @@ namespace Discord | |||
| public override DiscordRestClient Discord { get; } | |||
| public string Code => Id; | |||
| public string Url => $"{DiscordConfig.InviteUrl}/{XkcdCode ?? Code}"; | |||
| public string XkcdUrl => XkcdCode != null ? $"{DiscordConfig.InviteUrl}/{XkcdCode}" : null; | |||
| public string Url => $"{DiscordRestConfig.InviteUrl}/{XkcdCode ?? Code}"; | |||
| public string XkcdUrl => XkcdCode != null ? $"{DiscordRestConfig.InviteUrl}/{XkcdCode}" : null; | |||
| public Invite(DiscordRestClient discord, Model model) | |||
| : base(model.Code) | |||
| @@ -24,7 +24,7 @@ namespace Discord | |||
| public virtual UserStatus Status => UserStatus.Unknown; | |||
| public virtual Game Game => null; | |||
| public DiscordClient Discord => Channel.Discord; | |||
| public DiscordRestClient Discord => Channel.Discord; | |||
| public GroupUser(GroupChannel channel, User user) | |||
| { | |||
| @@ -51,7 +51,7 @@ namespace Discord | |||
| return result; | |||
| return null; | |||
| } | |||
| public override IImmutableList<SocketMessage> GetMany(ulong? fromMessageId, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch) | |||
| public override IImmutableList<SocketMessage> GetMany(ulong? fromMessageId, Direction dir, int limit = DiscordRestConfig.MaxMessagesPerBatch) | |||
| { | |||
| if (limit < 0) throw new ArgumentOutOfRangeException(nameof(limit)); | |||
| if (limit == 0) return ImmutableArray<SocketMessage>.Empty; | |||
| @@ -25,7 +25,7 @@ namespace Discord | |||
| public virtual SocketMessage Remove(ulong id) => null; | |||
| public virtual SocketMessage Get(ulong id) => null; | |||
| public virtual IImmutableList<SocketMessage> GetMany(ulong? fromMessageId, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch) | |||
| public virtual IImmutableList<SocketMessage> GetMany(ulong? fromMessageId, Direction dir, int limit = DiscordRestConfig.MaxMessagesPerBatch) | |||
| => ImmutableArray.Create<SocketMessage>(); | |||
| public virtual async Task<SocketMessage> DownloadAsync(ulong id) | |||
| @@ -48,11 +48,11 @@ namespace Discord | |||
| { | |||
| return await _messages.DownloadAsync(id).ConfigureAwait(false); | |||
| } | |||
| public override async Task<IReadOnlyCollection<IMessage>> GetMessagesAsync(int limit = DiscordConfig.MaxMessagesPerBatch) | |||
| public override async Task<IReadOnlyCollection<IMessage>> GetMessagesAsync(int limit = DiscordRestConfig.MaxMessagesPerBatch) | |||
| { | |||
| return await _messages.DownloadAsync(null, Direction.Before, limit).ConfigureAwait(false); | |||
| } | |||
| public override async Task<IReadOnlyCollection<IMessage>> GetMessagesAsync(ulong fromMessageId, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch) | |||
| public override async Task<IReadOnlyCollection<IMessage>> GetMessagesAsync(ulong fromMessageId, Direction dir, int limit = DiscordRestConfig.MaxMessagesPerBatch) | |||
| { | |||
| return await _messages.DownloadAsync(fromMessageId, dir, limit).ConfigureAwait(false); | |||
| } | |||
| @@ -11,14 +11,10 @@ namespace Discord | |||
| //TODO: Docstrings should explain when REST requests are sent and how many | |||
| public interface IDiscordClient : IDisposable | |||
| { | |||
| LoginState LoginState { get; } | |||
| ConnectionState ConnectionState { get; } | |||
| DiscordApiClient ApiClient { get; } | |||
| ILogManager LogManager { get; } | |||
| Task LoginAsync(TokenType tokenType, string token, bool validateToken = true); | |||
| Task LogoutAsync(); | |||
| Task ConnectAsync(); | |||
| Task DisconnectAsync(); | |||