Files
Discord.Net/test/Discord.Net.Tests/Net/CachedRestClient.cs
Christopher F 1ce1c019b3 Add support for audit log reasons (#708)
* Add support for audit log reasons

* Made changes per discussion
2017-06-29 17:01:59 -03:00

120 lines
4.3 KiB
C#

using Akavache;
using Akavache.Sqlite3;
using Discord.Net.Rest;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Reactive.Concurrency;
using System.Reactive.Linq;
using System.Threading;
using System.Threading.Tasks;
using Splat;
namespace Discord.Net
{
internal class CachedRestClient : IRestClient
{
private readonly Dictionary<string, string> _headers;
private IBlobCache _blobCache;
private string _baseUrl;
private CancellationTokenSource _cancelTokenSource;
private CancellationToken _cancelToken, _parentToken;
private bool _isDisposed;
public CacheInfo Info { get; private set; }
public CachedRestClient()
{
_headers = new Dictionary<string, string>();
_cancelTokenSource = new CancellationTokenSource();
_cancelToken = CancellationToken.None;
_parentToken = CancellationToken.None;
Locator.CurrentMutable.Register(() => Scheduler.Default, typeof(IScheduler), "Taskpool");
Locator.CurrentMutable.Register(() => new FilesystemProvider(), typeof(IFilesystemProvider), null);
Locator.CurrentMutable.Register(() => new HttpMixin(), typeof(IAkavacheHttpMixin), null);
//new Akavache.Sqlite3.Registrations().Register(Locator.CurrentMutable);
_blobCache = new SQLitePersistentBlobCache("cache.db");
}
private void Dispose(bool disposing)
{
if (!_isDisposed)
{
if (disposing)
_blobCache.Dispose();
_isDisposed = true;
}
}
public void Dispose()
{
Dispose(true);
}
public void SetUrl(string url)
{
_baseUrl = url;
}
public void SetHeader(string key, string value)
{
_headers[key] = value;
}
public void SetCancelToken(CancellationToken cancelToken)
{
_parentToken = cancelToken;
_cancelToken = CancellationTokenSource.CreateLinkedTokenSource(_parentToken, _cancelTokenSource.Token).Token;
}
public async Task<RestResponse> SendAsync(string method, string endpoint, CancellationToken cancelToken, bool headerOnly, string reason = null)
{
if (method != "GET")
throw new InvalidOperationException("This RestClient only supports GET requests.");
string uri = Path.Combine(_baseUrl, endpoint);
var bytes = await _blobCache.DownloadUrl(uri, _headers);
return new RestResponse(HttpStatusCode.OK, _headers, new MemoryStream(bytes));
}
public Task<RestResponse> SendAsync(string method, string endpoint, string json, CancellationToken cancelToken, bool headerOnly, string reason = null)
{
throw new InvalidOperationException("This RestClient does not support payloads.");
}
public Task<RestResponse> SendAsync(string method, string endpoint, IReadOnlyDictionary<string, object> multipartParams, CancellationToken cancelToken, bool headerOnly, string reason = null)
{
throw new InvalidOperationException("This RestClient does not support multipart requests.");
}
public async Task ClearAsync()
{
await _blobCache.InvalidateAll();
}
public async Task LoadInfoAsync(ulong guildId)
{
if (Info != null)
return;
bool needsReset = false;
try
{
Info = await _blobCache.GetObject<CacheInfo>("info");
if (Info.GuildId != guildId)
needsReset = true;
}
catch (KeyNotFoundException)
{
needsReset = true;
}
if (needsReset)
{
Info = new CacheInfo() { GuildId = guildId, Version = 0 };
await SaveInfoAsync().ConfigureAwait(false);
}
}
public async Task SaveInfoAsync()
{
await ClearAsync().ConfigureAwait(false); //Version changed, invalidate cache
await _blobCache.InsertObject<CacheInfo>("info", Info);
}
}
}