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.

BaseDiscordClient.cs 8.2 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. using Discord.Logging;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Collections.Immutable;
  5. using System.IO;
  6. using System.Threading;
  7. using System.Threading.Tasks;
  8. namespace Discord.Rest
  9. {
  10. public abstract class BaseDiscordClient : IDiscordClient
  11. {
  12. public event Func<LogMessage, Task> Log { add { _logEvent.Add(value); } remove { _logEvent.Remove(value); } }
  13. internal readonly AsyncEvent<Func<LogMessage, Task>> _logEvent = new AsyncEvent<Func<LogMessage, Task>>();
  14. public event Func<Task> LoggedIn { add { _loggedInEvent.Add(value); } remove { _loggedInEvent.Remove(value); } }
  15. private readonly AsyncEvent<Func<Task>> _loggedInEvent = new AsyncEvent<Func<Task>>();
  16. public event Func<Task> LoggedOut { add { _loggedOutEvent.Add(value); } remove { _loggedOutEvent.Remove(value); } }
  17. private readonly AsyncEvent<Func<Task>> _loggedOutEvent = new AsyncEvent<Func<Task>>();
  18. internal readonly Logger _restLogger;
  19. private readonly SemaphoreSlim _stateLock;
  20. private bool _isFirstLogin, _isDisposed;
  21. internal API.DiscordRestApiClient ApiClient { get; }
  22. internal LogManager LogManager { get; }
  23. public LoginState LoginState { get; private set; }
  24. public ISelfUser CurrentUser { get; protected set; }
  25. public TokenType TokenType => ApiClient.AuthTokenType;
  26. /// <summary> Creates a new REST-only discord client. </summary>
  27. internal BaseDiscordClient(DiscordRestConfig config, API.DiscordRestApiClient client)
  28. {
  29. ApiClient = client;
  30. LogManager = new LogManager(config.LogLevel);
  31. LogManager.Message += async msg => await _logEvent.InvokeAsync(msg).ConfigureAwait(false);
  32. _stateLock = new SemaphoreSlim(1, 1);
  33. _restLogger = LogManager.CreateLogger("Rest");
  34. _isFirstLogin = config.DisplayInitialLog;
  35. ApiClient.RequestQueue.RateLimitTriggered += async (id, info) =>
  36. {
  37. if (info == null)
  38. await _restLogger.VerboseAsync($"Preemptive Rate limit triggered: {id ?? "null"}").ConfigureAwait(false);
  39. else
  40. await _restLogger.WarningAsync($"Rate limit triggered: {id ?? "null"}").ConfigureAwait(false);
  41. };
  42. ApiClient.SentRequest += async (method, endpoint, millis) => await _restLogger.VerboseAsync($"{method} {endpoint}: {millis} ms").ConfigureAwait(false);
  43. }
  44. /// <inheritdoc />
  45. public async Task LoginAsync(TokenType tokenType, string token, bool validateToken = true)
  46. {
  47. await _stateLock.WaitAsync().ConfigureAwait(false);
  48. try
  49. {
  50. await LoginInternalAsync(tokenType, token).ConfigureAwait(false);
  51. }
  52. finally { _stateLock.Release(); }
  53. }
  54. private async Task LoginInternalAsync(TokenType tokenType, string token)
  55. {
  56. if (_isFirstLogin)
  57. {
  58. _isFirstLogin = false;
  59. await LogManager.WriteInitialLog().ConfigureAwait(false);
  60. }
  61. if (LoginState != LoginState.LoggedOut)
  62. await LogoutInternalAsync().ConfigureAwait(false);
  63. LoginState = LoginState.LoggingIn;
  64. try
  65. {
  66. await ApiClient.LoginAsync(tokenType, token).ConfigureAwait(false);
  67. await OnLoginAsync(tokenType, token).ConfigureAwait(false);
  68. LoginState = LoginState.LoggedIn;
  69. }
  70. catch (Exception)
  71. {
  72. await LogoutInternalAsync().ConfigureAwait(false);
  73. throw;
  74. }
  75. await _loggedInEvent.InvokeAsync().ConfigureAwait(false);
  76. }
  77. internal virtual Task OnLoginAsync(TokenType tokenType, string token)
  78. => Task.Delay(0);
  79. /// <inheritdoc />
  80. public async Task LogoutAsync()
  81. {
  82. await _stateLock.WaitAsync().ConfigureAwait(false);
  83. try
  84. {
  85. await LogoutInternalAsync().ConfigureAwait(false);
  86. }
  87. finally { _stateLock.Release(); }
  88. }
  89. private async Task LogoutInternalAsync()
  90. {
  91. if (LoginState == LoginState.LoggedOut) return;
  92. LoginState = LoginState.LoggingOut;
  93. await ApiClient.LogoutAsync().ConfigureAwait(false);
  94. await OnLogoutAsync().ConfigureAwait(false);
  95. CurrentUser = null;
  96. LoginState = LoginState.LoggedOut;
  97. await _loggedOutEvent.InvokeAsync().ConfigureAwait(false);
  98. }
  99. internal virtual Task OnLogoutAsync()
  100. => Task.Delay(0);
  101. internal virtual void Dispose(bool disposing)
  102. {
  103. if (!_isDisposed)
  104. {
  105. ApiClient.Dispose();
  106. _isDisposed = true;
  107. }
  108. }
  109. /// <inheritdoc />
  110. public void Dispose() => Dispose(true);
  111. /// <inheritdoc />
  112. public Task<int> GetRecommendedShardCountAsync(RequestOptions options = null)
  113. => ClientHelper.GetRecommendShardCountAsync(this, options);
  114. //IDiscordClient
  115. ConnectionState IDiscordClient.ConnectionState => ConnectionState.Disconnected;
  116. ISelfUser IDiscordClient.CurrentUser => CurrentUser;
  117. Task<IApplication> IDiscordClient.GetApplicationInfoAsync(RequestOptions options)
  118. => throw new NotSupportedException();
  119. Task<IChannel> IDiscordClient.GetChannelAsync(ulong id, CacheMode mode, RequestOptions options)
  120. => Task.FromResult<IChannel>(null);
  121. Task<IReadOnlyCollection<IPrivateChannel>> IDiscordClient.GetPrivateChannelsAsync(CacheMode mode, RequestOptions options)
  122. => Task.FromResult<IReadOnlyCollection<IPrivateChannel>>(ImmutableArray.Create<IPrivateChannel>());
  123. Task<IReadOnlyCollection<IDMChannel>> IDiscordClient.GetDMChannelsAsync(CacheMode mode, RequestOptions options)
  124. => Task.FromResult<IReadOnlyCollection<IDMChannel>>(ImmutableArray.Create<IDMChannel>());
  125. Task<IReadOnlyCollection<IGroupChannel>> IDiscordClient.GetGroupChannelsAsync(CacheMode mode, RequestOptions options)
  126. => Task.FromResult<IReadOnlyCollection<IGroupChannel>>(ImmutableArray.Create<IGroupChannel>());
  127. Task<IReadOnlyCollection<IConnection>> IDiscordClient.GetConnectionsAsync(RequestOptions options)
  128. => Task.FromResult<IReadOnlyCollection<IConnection>>(ImmutableArray.Create<IConnection>());
  129. Task<IInvite> IDiscordClient.GetInviteAsync(string inviteId, RequestOptions options)
  130. => Task.FromResult<IInvite>(null);
  131. Task<IGuild> IDiscordClient.GetGuildAsync(ulong id, CacheMode mode, RequestOptions options)
  132. => Task.FromResult<IGuild>(null);
  133. Task<IReadOnlyCollection<IGuild>> IDiscordClient.GetGuildsAsync(CacheMode mode, RequestOptions options)
  134. => Task.FromResult<IReadOnlyCollection<IGuild>>(ImmutableArray.Create<IGuild>());
  135. Task<IGuild> IDiscordClient.CreateGuildAsync(string name, IVoiceRegion region, Stream jpegIcon, RequestOptions options)
  136. => throw new NotSupportedException();
  137. Task<IUser> IDiscordClient.GetUserAsync(ulong id, CacheMode mode, RequestOptions options)
  138. => Task.FromResult<IUser>(null);
  139. Task<IUser> IDiscordClient.GetUserAsync(string username, string discriminator, RequestOptions options)
  140. => Task.FromResult<IUser>(null);
  141. Task<IReadOnlyCollection<IVoiceRegion>> IDiscordClient.GetVoiceRegionsAsync(RequestOptions options)
  142. => Task.FromResult<IReadOnlyCollection<IVoiceRegion>>(ImmutableArray.Create<IVoiceRegion>());
  143. Task<IVoiceRegion> IDiscordClient.GetVoiceRegionAsync(string id, RequestOptions options)
  144. => Task.FromResult<IVoiceRegion>(null);
  145. Task<IWebhook> IDiscordClient.GetWebhookAsync(ulong id, RequestOptions options)
  146. => Task.FromResult<IWebhook>(null);
  147. Task IDiscordClient.StartAsync()
  148. => Task.Delay(0);
  149. Task IDiscordClient.StopAsync()
  150. => Task.Delay(0);
  151. }
  152. }