refactor to use using statement whenever it makes sense

This commit is contained in:
13xforever
2019-11-25 18:07:01 +05:00
parent e5a1395c12
commit eac6be7e23
57 changed files with 1810 additions and 1980 deletions

View File

@@ -139,24 +139,20 @@ namespace AppveyorClient
{
try
{
using (var message = new HttpRequestMessage(HttpMethod.Get, buildUrl))
using var message = new HttpRequestMessage(HttpMethod.Get, buildUrl);
message.Headers.UserAgent.Add(ProductInfoHeader);
using var response = await client.SendAsync(message, HttpCompletionOption.ResponseContentRead, cancellationToken).ConfigureAwait(false);
try
{
message.Headers.UserAgent.Add(ProductInfoHeader);
using (var response = await client.SendAsync(message, HttpCompletionOption.ResponseContentRead, cancellationToken).ConfigureAwait(false))
{
try
{
await response.Content.LoadIntoBufferAsync().ConfigureAwait(false);
var result = await response.Content.ReadAsAsync<BuildInfo>(formatters, cancellationToken).ConfigureAwait(false);
ResponseCache.Set(buildUrl, result, CacheTime);
//ApiConfig.Log.Debug($"Cached {nameof(BuildInfo)} for {buildUrl} for {CacheTime}");
return result;
}
catch (Exception e)
{
ConsoleLogger.PrintError(e, response);
}
}
await response.Content.LoadIntoBufferAsync().ConfigureAwait(false);
var result = await response.Content.ReadAsAsync<BuildInfo>(formatters, cancellationToken).ConfigureAwait(false);
ResponseCache.Set(buildUrl, result, CacheTime);
//ApiConfig.Log.Debug($"Cached {nameof(BuildInfo)} for {buildUrl} for {CacheTime}");
return result;
}
catch (Exception e)
{
ConsoleLogger.PrintError(e, response);
}
}
catch (Exception e)
@@ -206,24 +202,20 @@ namespace AppveyorClient
var requestUri = $"https://ci.appveyor.com/api/buildjobs/{jobId}/artifacts";
try
{
using (var message = new HttpRequestMessage(HttpMethod.Get, requestUri))
using var message = new HttpRequestMessage(HttpMethod.Get, requestUri);
message.Headers.UserAgent.Add(ProductInfoHeader);
using var response = await client.SendAsync(message, HttpCompletionOption.ResponseContentRead, cancellationToken).ConfigureAwait(false);
try
{
message.Headers.UserAgent.Add(ProductInfoHeader);
using (var response = await client.SendAsync(message, HttpCompletionOption.ResponseContentRead, cancellationToken).ConfigureAwait(false))
{
try
{
await response.Content.LoadIntoBufferAsync().ConfigureAwait(false);
var result = await response.Content.ReadAsAsync<List<Artifact>>(formatters, cancellationToken).ConfigureAwait(false);
ResponseCache.Set(requestUri, result, CacheTime);
ApiConfig.Log.Debug($"Cached {nameof(Artifact)} for {jobId} for {CacheTime}");
return result;
}
catch (Exception e)
{
ConsoleLogger.PrintError(e, response);
}
}
await response.Content.LoadIntoBufferAsync().ConfigureAwait(false);
var result = await response.Content.ReadAsAsync<List<Artifact>>(formatters, cancellationToken).ConfigureAwait(false);
ResponseCache.Set(requestUri, result, CacheTime);
ApiConfig.Log.Debug($"Cached {nameof(Artifact)} for {jobId} for {CacheTime}");
return result;
}
catch (Exception e)
{
ConsoleLogger.PrintError(e, response);
}
}
catch (Exception e)
@@ -273,23 +265,19 @@ namespace AppveyorClient
Build build = null;
do
{
using (var message = new HttpRequestMessage(HttpMethod.Get, historyUrl))
using var message = new HttpRequestMessage(HttpMethod.Get, historyUrl);
message.Headers.UserAgent.Add(ProductInfoHeader);
using var response = await client.SendAsync(message, HttpCompletionOption.ResponseContentRead, cancellationToken).ConfigureAwait(false);
try
{
message.Headers.UserAgent.Add(ProductInfoHeader);
using (var response = await client.SendAsync(message, HttpCompletionOption.ResponseContentRead, cancellationToken).ConfigureAwait(false))
{
try
{
await response.Content.LoadIntoBufferAsync().ConfigureAwait(false);
historyPage = await response.Content.ReadAsAsync<HistoryInfo>(formatters, cancellationToken).ConfigureAwait(false);
build = historyPage?.Builds?.FirstOrDefault(selectPredicate);
}
catch (Exception e)
{
ConsoleLogger.PrintError(e, response);
break;
}
}
await response.Content.LoadIntoBufferAsync().ConfigureAwait(false);
historyPage = await response.Content.ReadAsAsync<HistoryInfo>(formatters, cancellationToken).ConfigureAwait(false);
build = historyPage?.Builds?.FirstOrDefault(selectPredicate);
}
catch (Exception e)
{
ConsoleLogger.PrintError(e, response);
break;
}
historyUrl = baseUrl.SetQueryParameter("startBuildId", historyPage?.Builds?.Last().BuildId.ToString());
} while (build == null && historyPage?.Builds?.Count > 0 && takePredicate(historyPage));

View File

@@ -36,20 +36,20 @@ namespace CompatApiClient
{
try
{
using (var message = new HttpRequestMessage(HttpMethod.Get, url))
using (var response = await client.SendAsync(message, HttpCompletionOption.ResponseContentRead, cancellationToken).ConfigureAwait(false))
try
{
await response.Content.LoadIntoBufferAsync().ConfigureAwait(false);
var result = await response.Content.ReadAsAsync<CompatResult>(formatters, cancellationToken).ConfigureAwait(false);
result.RequestBuilder = requestBuilder;
result.RequestDuration = DateTime.UtcNow - startTime;
return result;
}
catch (Exception e)
{
ConsoleLogger.PrintError(e, response, false);
}
using var message = new HttpRequestMessage(HttpMethod.Get, url);
using var response = await client.SendAsync(message, HttpCompletionOption.ResponseContentRead, cancellationToken).ConfigureAwait(false);
try
{
await response.Content.LoadIntoBufferAsync().ConfigureAwait(false);
var result = await response.Content.ReadAsAsync<CompatResult>(formatters, cancellationToken).ConfigureAwait(false);
result.RequestBuilder = requestBuilder;
result.RequestDuration = DateTime.UtcNow - startTime;
return result;
}
catch (Exception e)
{
ConsoleLogger.PrintError(e, response, false);
}
}
catch (Exception e)
{
@@ -69,16 +69,16 @@ namespace CompatApiClient
{
try
{
using (var message = new HttpRequestMessage(HttpMethod.Get, "https://update.rpcs3.net/?api=v1&c=" + commit))
using (var response = await client.SendAsync(message, HttpCompletionOption.ResponseContentRead, cancellationToken).ConfigureAwait(false))
try
{
return await response.Content.ReadAsAsync<UpdateInfo>(formatters, cancellationToken).ConfigureAwait(false);
}
catch (Exception e)
{
ConsoleLogger.PrintError(e, response, false);
}
using var message = new HttpRequestMessage(HttpMethod.Get, "https://update.rpcs3.net/?api=v1&c=" + commit);
using var response = await client.SendAsync(message, HttpCompletionOption.ResponseContentRead, cancellationToken).ConfigureAwait(false);
try
{
return await response.Content.ReadAsAsync<UpdateInfo>(formatters, cancellationToken).ConfigureAwait(false);
}
catch (Exception e)
{
ConsoleLogger.PrintError(e, response, false);
}
}
catch (Exception e)
{

View File

@@ -11,26 +11,22 @@ namespace CompatApiClient.Compression
public virtual async Task<long> CompressAsync(Stream source, Stream destination)
{
using (var memStream = new MemoryStream())
{
using (var compressed = CreateCompressionStream(memStream))
await source.CopyToAsync(compressed).ConfigureAwait(false);
memStream.Seek(0, SeekOrigin.Begin);
await memStream.CopyToAsync(destination).ConfigureAwait(false);
return memStream.Length;
}
using var memStream = new MemoryStream();
using (var compressed = CreateCompressionStream(memStream))
await source.CopyToAsync(compressed).ConfigureAwait(false);
memStream.Seek(0, SeekOrigin.Begin);
await memStream.CopyToAsync(destination).ConfigureAwait(false);
return memStream.Length;
}
public virtual async Task<long> DecompressAsync(Stream source, Stream destination)
{
using (var memStream = new MemoryStream())
{
using (var decompressed = CreateDecompressionStream(source))
await decompressed.CopyToAsync(memStream).ConfigureAwait(false);
memStream.Seek(0, SeekOrigin.Begin);
await memStream.CopyToAsync(destination).ConfigureAwait(false);
return memStream.Length;
}
using var memStream = new MemoryStream();
using (var decompressed = CreateDecompressionStream(source))
await decompressed.CopyToAsync(memStream).ConfigureAwait(false);
memStream.Seek(0, SeekOrigin.Begin);
await memStream.CopyToAsync(destination).ConfigureAwait(false);
return memStream.Length;
}
}
}

View File

@@ -52,22 +52,18 @@ namespace GithubClient
try
{
using (var message = new HttpRequestMessage(HttpMethod.Get, "https://api.github.com/repos/RPCS3/rpcs3/pulls/" + pr))
using var message = new HttpRequestMessage(HttpMethod.Get, "https://api.github.com/repos/RPCS3/rpcs3/pulls/" + pr);
message.Headers.UserAgent.Add(ProductInfoHeader);
using var response = await client.SendAsync(message, HttpCompletionOption.ResponseContentRead, cancellationToken).ConfigureAwait(false);
try
{
message.Headers.UserAgent.Add(ProductInfoHeader);
using (var response = await client.SendAsync(message, HttpCompletionOption.ResponseContentRead, cancellationToken).ConfigureAwait(false))
{
try
{
await response.Content.LoadIntoBufferAsync().ConfigureAwait(false);
UpdateRateLimitStats(response.Headers);
result = await response.Content.ReadAsAsync<PrInfo>(formatters, cancellationToken).ConfigureAwait(false);
}
catch (Exception e)
{
ConsoleLogger.PrintError(e, response);
}
}
await response.Content.LoadIntoBufferAsync().ConfigureAwait(false);
UpdateRateLimitStats(response.Headers);
result = await response.Content.ReadAsAsync<PrInfo>(formatters, cancellationToken).ConfigureAwait(false);
}
catch (Exception e)
{
ConsoleLogger.PrintError(e, response);
}
}
catch (Exception e)
@@ -95,22 +91,18 @@ namespace GithubClient
try
{
using (var message = new HttpRequestMessage(HttpMethod.Get, "https://api.github.com/repos/RPCS3/rpcs3/issues/" + issue))
using var message = new HttpRequestMessage(HttpMethod.Get, "https://api.github.com/repos/RPCS3/rpcs3/issues/" + issue);
message.Headers.UserAgent.Add(ProductInfoHeader);
using var response = await client.SendAsync(message, HttpCompletionOption.ResponseContentRead, cancellationToken).ConfigureAwait(false);
try
{
message.Headers.UserAgent.Add(ProductInfoHeader);
using (var response = await client.SendAsync(message, HttpCompletionOption.ResponseContentRead, cancellationToken).ConfigureAwait(false))
{
try
{
await response.Content.LoadIntoBufferAsync().ConfigureAwait(false);
UpdateRateLimitStats(response.Headers);
result = await response.Content.ReadAsAsync<IssueInfo>(formatters, cancellationToken).ConfigureAwait(false);
}
catch (Exception e)
{
ConsoleLogger.PrintError(e, response);
}
}
await response.Content.LoadIntoBufferAsync().ConfigureAwait(false);
UpdateRateLimitStats(response.Headers);
result = await response.Content.ReadAsAsync<IssueInfo>(formatters, cancellationToken).ConfigureAwait(false);
}
catch (Exception e)
{
ConsoleLogger.PrintError(e, response);
}
}
catch (Exception e)
@@ -139,22 +131,18 @@ namespace GithubClient
try
{
using (var message = new HttpRequestMessage(HttpMethod.Get, requestUri))
using var message = new HttpRequestMessage(HttpMethod.Get, requestUri);
message.Headers.UserAgent.Add(ProductInfoHeader);
using var response = await client.SendAsync(message, HttpCompletionOption.ResponseContentRead, cancellationToken).ConfigureAwait(false);
try
{
message.Headers.UserAgent.Add(ProductInfoHeader);
using (var response = await client.SendAsync(message, HttpCompletionOption.ResponseContentRead, cancellationToken).ConfigureAwait(false))
{
try
{
await response.Content.LoadIntoBufferAsync().ConfigureAwait(false);
UpdateRateLimitStats(response.Headers);
result = await response.Content.ReadAsAsync<List<PrInfo>>(formatters, cancellationToken).ConfigureAwait(false);
}
catch (Exception e)
{
ConsoleLogger.PrintError(e, response);
}
}
await response.Content.LoadIntoBufferAsync().ConfigureAwait(false);
UpdateRateLimitStats(response.Headers);
result = await response.Content.ReadAsAsync<List<PrInfo>>(formatters, cancellationToken).ConfigureAwait(false);
}
catch (Exception e)
{
ConsoleLogger.PrintError(e, response);
}
}
catch (Exception e)
@@ -179,22 +167,18 @@ namespace GithubClient
try
{
using (var message = new HttpRequestMessage(HttpMethod.Get, statusesUrl))
using var message = new HttpRequestMessage(HttpMethod.Get, statusesUrl);
message.Headers.UserAgent.Add(ProductInfoHeader);
using var response = await client.SendAsync(message, HttpCompletionOption.ResponseContentRead, cancellationToken).ConfigureAwait(false);
try
{
message.Headers.UserAgent.Add(ProductInfoHeader);
using (var response = await client.SendAsync(message, HttpCompletionOption.ResponseContentRead, cancellationToken).ConfigureAwait(false))
{
try
{
await response.Content.LoadIntoBufferAsync().ConfigureAwait(false);
UpdateRateLimitStats(response.Headers);
result = await response.Content.ReadAsAsync<List<StatusInfo>>(formatters, cancellationToken).ConfigureAwait(false);
}
catch (Exception e)
{
ConsoleLogger.PrintError(e, response);
}
}
await response.Content.LoadIntoBufferAsync().ConfigureAwait(false);
UpdateRateLimitStats(response.Headers);
result = await response.Content.ReadAsAsync<List<StatusInfo>>(formatters, cancellationToken).ConfigureAwait(false);
}
catch (Exception e)
{
ConsoleLogger.PrintError(e, response);
}
}
catch (Exception e)

View File

@@ -76,25 +76,25 @@ namespace IrdLibraryClient
["_"] = DateTime.UtcNow.Ticks.ToString(),
});
using (var getMessage = new HttpRequestMessage(HttpMethod.Get, requestUri))
using (var response = await client.SendAsync(getMessage, cancellationToken).ConfigureAwait(false))
try
using var getMessage = new HttpRequestMessage(HttpMethod.Get, requestUri);
using var response = await client.SendAsync(getMessage, cancellationToken).ConfigureAwait(false);
try
{
await response.Content.LoadIntoBufferAsync().ConfigureAwait(false);
var result = await response.Content.ReadAsAsync<SearchResult>(underscoreFormatters, cancellationToken).ConfigureAwait(false);
result.Data ??= new List<SearchResultItem>(0);
foreach (var item in result.Data)
{
await response.Content.LoadIntoBufferAsync().ConfigureAwait(false);
var result = await response.Content.ReadAsAsync<SearchResult>(underscoreFormatters, cancellationToken).ConfigureAwait(false);
result.Data ??= new List<SearchResultItem>(0);
foreach (var item in result.Data)
{
item.Filename = GetIrdFilename(item.Filename);
item.Title = GetTitle(item.Title);
}
return result;
}
catch (Exception e)
{
ConsoleLogger.PrintError(e, response);
return null;
item.Filename = GetIrdFilename(item.Filename);
item.Title = GetTitle(item.Title);
}
return result;
}
catch (Exception e)
{
ConsoleLogger.PrintError(e, response);
return null;
}
}
catch (Exception e)
{

View File

@@ -18,62 +18,59 @@ namespace IrdLibraryClient.IrdFormat
throw new ArgumentException("Data is too small to be a valid IRD structure", nameof(content));
if (BitConverter.ToInt32(content, 0) != Ird.Magic)
using (var compressedStream = new MemoryStream(content, false))
using (var gzip = new GZipStream(compressedStream, CompressionMode.Decompress))
using (var decompressedStream = new MemoryStream())
{
gzip.CopyTo(decompressedStream);
content = decompressedStream.ToArray();
}
{
using var compressedStream = new MemoryStream(content, false);
using var gzip = new GZipStream(compressedStream, CompressionMode.Decompress);
using var decompressedStream = new MemoryStream();
gzip.CopyTo(decompressedStream);
content = decompressedStream.ToArray();
}
if (BitConverter.ToInt32(content, 0) != Ird.Magic)
throw new FormatException("Not a valid IRD file");
var result = new Ird();
using (var stream = new MemoryStream(content, false))
using (var reader = new BinaryReader(stream, Encoding.UTF8))
using var stream = new MemoryStream(content, false);
using var reader = new BinaryReader(stream, Encoding.UTF8);
reader.ReadInt32(); // magic
result.Version = reader.ReadByte();
result.ProductCode = Encoding.ASCII.GetString(reader.ReadBytes(9));
result.TitleLength = reader.ReadByte();
result.Title = Encoding.UTF8.GetString(reader.ReadBytes(result.TitleLength));
result.UpdateVersion = Encoding.ASCII.GetString(reader.ReadBytes(4)).Trim();
result.GameVersion = Encoding.ASCII.GetString(reader.ReadBytes(5)).Trim();
result.AppVersion = Encoding.ASCII.GetString(reader.ReadBytes(5)).Trim();
if (result.Version == 7)
result.Id = reader.ReadInt32();
result.HeaderLength = reader.ReadInt32();
result.Header = reader.ReadBytes(result.HeaderLength);
result.FooterLength = reader.ReadInt32();
result.Footer = reader.ReadBytes(result.FooterLength);
result.RegionCount = reader.ReadByte();
result.RegionMd5Checksums = new List<byte[]>(result.RegionCount);
for (var i = 0; i < result.RegionCount; i++)
result.RegionMd5Checksums.Add(reader.ReadBytes(16));
result.FileCount = reader.ReadInt32();
result.Files = new List<IrdFile>(result.FileCount);
for (var i = 0; i < result.FileCount; i++)
{
reader.ReadInt32(); // magic
result.Version = reader.ReadByte();
result.ProductCode = Encoding.ASCII.GetString(reader.ReadBytes(9));
result.TitleLength = reader.ReadByte();
result.Title = Encoding.UTF8.GetString(reader.ReadBytes(result.TitleLength));
result.UpdateVersion = Encoding.ASCII.GetString(reader.ReadBytes(4)).Trim();
result.GameVersion = Encoding.ASCII.GetString(reader.ReadBytes(5)).Trim();
result.AppVersion = Encoding.ASCII.GetString(reader.ReadBytes(5)).Trim();
if (result.Version == 7)
result.Id = reader.ReadInt32();
result.HeaderLength = reader.ReadInt32();
result.Header = reader.ReadBytes(result.HeaderLength);
result.FooterLength = reader.ReadInt32();
result.Footer = reader.ReadBytes(result.FooterLength);
result.RegionCount = reader.ReadByte();
result.RegionMd5Checksums = new List<byte[]>(result.RegionCount);
for (var i = 0; i < result.RegionCount; i++)
result.RegionMd5Checksums.Add(reader.ReadBytes(16));
result.FileCount = reader.ReadInt32();
result.Files = new List<IrdFile>(result.FileCount);
for (var i = 0; i < result.FileCount; i++)
{
var file = new IrdFile();
file.Offset = reader.ReadInt64();
file.Md5Checksum = reader.ReadBytes(16);
result.Files.Add(file);
}
result.Unknown = reader.ReadInt32();
if (result.Version == 9)
result.Pic = reader.ReadBytes(115);
result.Data1 = reader.ReadBytes(16);
result.Data2 = reader.ReadBytes(16);
if (result.Version < 9)
result.Pic = reader.ReadBytes(115);
result.Uid = reader.ReadInt32();
var dataLength = reader.BaseStream.Position;
result.Crc32 = reader.ReadUInt32();
var crc32 = Crc32Algorithm.Compute(content, 0, (int)dataLength);
if (result.Crc32 != crc32)
throw new InvalidDataException($"Corrupted IRD data, expected {result.Crc32:x8}, but was {crc32:x8}");
var file = new IrdFile();
file.Offset = reader.ReadInt64();
file.Md5Checksum = reader.ReadBytes(16);
result.Files.Add(file);
}
result.Unknown = reader.ReadInt32();
if (result.Version == 9)
result.Pic = reader.ReadBytes(115);
result.Data1 = reader.ReadBytes(16);
result.Data2 = reader.ReadBytes(16);
if (result.Version < 9)
result.Pic = reader.ReadBytes(115);
result.Uid = reader.ReadInt32();
var dataLength = reader.BaseStream.Position;
result.Crc32 = reader.ReadUInt32();
var crc32 = Crc32Algorithm.Compute(content, 0, (int)dataLength);
if (result.Crc32 != crc32)
throw new InvalidDataException($"Corrupted IRD data, expected {result.Crc32:x8}, but was {crc32:x8}");
return result;
}
}

View File

@@ -10,16 +10,16 @@ namespace IrdLibraryClient.IrdFormat
{
public static List<string> GetFilenames(this Ird ird)
{
using (var decompressedStream = new MemoryStream())
using var decompressedStream = new MemoryStream();
using (var compressedStream = new MemoryStream(ird.Header, false))
{
using (var compressedStream = new MemoryStream(ird.Header, false))
using (var gzip = new GZipStream(compressedStream, CompressionMode.Decompress))
gzip.CopyTo(decompressedStream);
decompressedStream.Seek(0, SeekOrigin.Begin);
var reader = new CDReader(decompressedStream, true, true);
return reader.GetFiles(reader.Root.FullName, "*.*", SearchOption.AllDirectories).Distinct().Select(n => n.TrimStart('\\').Replace('\\', '/').TrimEnd('.')).ToList();
using var gzip = new GZipStream(compressedStream, CompressionMode.Decompress);
gzip.CopyTo(decompressedStream);
}
decompressedStream.Seek(0, SeekOrigin.Begin);
var reader = new CDReader(decompressedStream, true, true);
return reader.GetFiles(reader.Root.FullName, "*.*", SearchOption.AllDirectories).Distinct().Select(n => n.TrimStart('\\').Replace('\\', '/').TrimEnd('.')).ToList();
}
}
}

View File

@@ -31,18 +31,16 @@ namespace PsnClient
foreach (var resource in certNames)
{
using (var stream = current.GetManifestResourceStream(resource))
using (var memStream = new MemoryStream())
using var stream = current.GetManifestResourceStream(resource);
using var memStream = new MemoryStream();
stream.CopyTo(memStream);
var cert = new X509Certificate2(memStream.ToArray());
var cn = cert.GetNameInfo(X509NameType.SimpleName, false);
if ((cn?.StartsWith("SCEI DNAS Root") ?? false))
{
stream.CopyTo(memStream);
var cert = new X509Certificate2(memStream.ToArray());
var cn = cert.GetNameInfo(X509NameType.SimpleName, false);
if ((cn?.StartsWith("SCEI DNAS Root") ?? false))
{
CustomCACollecction.Add(cert);
ApiConfig.Log.Debug($"Using Sony root CA with CN '{cn}' for custom certificate validation");
importedCAs = true;
}
CustomCACollecction.Add(cert);
ApiConfig.Log.Debug($"Using Sony root CA with CN '{cn}' for custom certificate validation");
importedCAs = true;
}
}
}
@@ -75,24 +73,22 @@ namespace PsnClient
result = false;
try
{
using (var customChain = new X509Chain(false))
using var customChain = new X509Chain(false);
var policy = customChain.ChainPolicy;
policy.ExtraStore.AddRange(CustomCACollecction);
policy.RevocationMode = X509RevocationMode.NoCheck;
if (customChain.Build(certificate) && customChain.ChainStatus.All(s => s.Status == X509ChainStatusFlags.NoError))
{
var policy = customChain.ChainPolicy;
policy.ExtraStore.AddRange(CustomCACollecction);
policy.RevocationMode = X509RevocationMode.NoCheck;
if (customChain.Build(certificate) && customChain.ChainStatus.All(s => s.Status == X509ChainStatusFlags.NoError))
{
ApiConfig.Log.Debug($"Successfully validated certificate {thumbprint} for {requestMessage.RequestUri.Host}");
result = true;
}
if (!result)
result = customChain.ChainStatus.All(s => s.Status == X509ChainStatusFlags.UntrustedRoot);
if (!result)
{
ApiConfig.Log.Warn($"Failed to validate certificate {thumbprint} for {requestMessage.RequestUri.Host}");
foreach (var s in customChain.ChainStatus)
ApiConfig.Log.Debug($"{s.Status}: {s.StatusInformation}");
}
ApiConfig.Log.Debug($"Successfully validated certificate {thumbprint} for {requestMessage.RequestUri.Host}");
result = true;
}
if (!result)
result = customChain.ChainStatus.All(s => s.Status == X509ChainStatusFlags.UntrustedRoot);
if (!result)
{
ApiConfig.Log.Warn($"Failed to validate certificate {thumbprint} for {requestMessage.RequestUri.Host}");
foreach (var s in customChain.ChainStatus)
ApiConfig.Log.Debug($"{s.Status}: {s.StatusInformation}");
}
ValidationCache[thumbprint] = result;
}

View File

@@ -69,20 +69,18 @@ namespace PsnClient
try
{
var cookieHeaderValue = await GetSessionCookies(locale, cancellationToken).ConfigureAwait(false);
using (var getMessage = new HttpRequestMessage(HttpMethod.Get, "https://store.playstation.com/kamaji/api/valkyrie_storefront/00_09_000/user/stores"))
using var getMessage = new HttpRequestMessage(HttpMethod.Get, "https://store.playstation.com/kamaji/api/valkyrie_storefront/00_09_000/user/stores");
getMessage.Headers.Add("Cookie", cookieHeaderValue);
using var response = await client.SendAsync(getMessage, cancellationToken).ConfigureAwait(false);
try
{
getMessage.Headers.Add("Cookie", cookieHeaderValue);
using (var response = await client.SendAsync(getMessage, cancellationToken).ConfigureAwait(false))
try
{
await response.Content.LoadIntoBufferAsync().ConfigureAwait(false);
return await response.Content.ReadAsAsync<Stores>(underscoreFormatters, cancellationToken).ConfigureAwait(false);
}
catch (Exception e)
{
ConsoleLogger.PrintError(e, response);
return null;
}
await response.Content.LoadIntoBufferAsync().ConfigureAwait(false);
return await response.Content.ReadAsAsync<Stores>(underscoreFormatters, cancellationToken).ConfigureAwait(false);
}
catch (Exception e)
{
ConsoleLogger.PrintError(e, response);
return null;
}
}
catch (Exception e)
@@ -152,21 +150,21 @@ namespace PsnClient
{
var loc = locale.AsLocaleData();
var baseUrl = $"https://store.playstation.com/valkyrie-api/{loc.language}/{loc.country}/999/storefront/{containerId}";
using (var message = new HttpRequestMessage(HttpMethod.Get, baseUrl))
using (var response = await client.SendAsync(message, cancellationToken).ConfigureAwait(false))
try
{
if (response.StatusCode == HttpStatusCode.NotFound)
return null;
await response.Content.LoadIntoBufferAsync().ConfigureAwait(false);
return await response.Content.ReadAsAsync<StoreNavigation>(dashedFormatters, cancellationToken).ConfigureAwait(false);
}
catch (Exception e)
{
ConsoleLogger.PrintError(e, response);
using var message = new HttpRequestMessage(HttpMethod.Get, baseUrl);
using var response = await client.SendAsync(message, cancellationToken).ConfigureAwait(false);
try
{
if (response.StatusCode == HttpStatusCode.NotFound)
return null;
}
await response.Content.LoadIntoBufferAsync().ConfigureAwait(false);
return await response.Content.ReadAsAsync<StoreNavigation>(dashedFormatters, cancellationToken).ConfigureAwait(false);
}
catch (Exception e)
{
ConsoleLogger.PrintError(e, response);
return null;
}
}
catch (Exception e)
{
@@ -186,21 +184,21 @@ namespace PsnClient
filters["size"] = take.ToString();
filters["bucket"] = "games";
url = url.SetQueryParameters(filters);
using (var message = new HttpRequestMessage(HttpMethod.Get, url))
using (var response = await client.SendAsync(message, cancellationToken).ConfigureAwait(false))
try
{
if (response.StatusCode == HttpStatusCode.NotFound)
return null;
await response.Content.LoadIntoBufferAsync().ConfigureAwait(false);
return await response.Content.ReadAsAsync<Container>(dashedFormatters, cancellationToken).ConfigureAwait(false);
}
catch (Exception e)
{
ConsoleLogger.PrintError(e, response);
using var message = new HttpRequestMessage(HttpMethod.Get, url);
using var response = await client.SendAsync(message, cancellationToken).ConfigureAwait(false);
try
{
if (response.StatusCode == HttpStatusCode.NotFound)
return null;
}
await response.Content.LoadIntoBufferAsync().ConfigureAwait(false);
return await response.Content.ReadAsAsync<Container>(dashedFormatters, cancellationToken).ConfigureAwait(false);
}
catch (Exception e)
{
ConsoleLogger.PrintError(e, response);
return null;
}
}
catch (Exception e)
{
@@ -214,21 +212,21 @@ namespace PsnClient
try
{
var loc = locale.AsLocaleData();
using (var message = new HttpRequestMessage(HttpMethod.Get, $"https://store.playstation.com/valkyrie-api/{loc.language}/{loc.country}/999/resolve/{contentId}?depth={depth}"))
using (var response = await client.SendAsync(message, cancellationToken).ConfigureAwait(false))
try
{
if (response.StatusCode == HttpStatusCode.NotFound)
return null;
await response.Content.LoadIntoBufferAsync().ConfigureAwait(false);
return await response.Content.ReadAsAsync<Container>(dashedFormatters, cancellationToken).ConfigureAwait(false);
}
catch (Exception e)
{
ConsoleLogger.PrintError(e, response);
using var message = new HttpRequestMessage(HttpMethod.Get, $"https://store.playstation.com/valkyrie-api/{loc.language}/{loc.country}/999/resolve/{contentId}?depth={depth}");
using var response = await client.SendAsync(message, cancellationToken).ConfigureAwait(false);
try
{
if (response.StatusCode == HttpStatusCode.NotFound)
return null;
}
await response.Content.LoadIntoBufferAsync().ConfigureAwait(false);
return await response.Content.ReadAsAsync<Container>(dashedFormatters, cancellationToken).ConfigureAwait(false);
}
catch (Exception e)
{
ConsoleLogger.PrintError(e, response);
return null;
}
}
catch (Exception e)
{
@@ -242,23 +240,23 @@ namespace PsnClient
if (ResponseCache.TryGetValue(productId, out TitlePatch patchInfo))
return patchInfo;
using (var message = new HttpRequestMessage(HttpMethod.Get, $"https://a0.ww.np.dl.playstation.net/tpl/np/{productId}/{productId}-ver.xml"))
using (var response = await client.SendAsync(message, cancellationToken).ConfigureAwait(false))
try
{
if (response.StatusCode == HttpStatusCode.NotFound)
return null;
using var message = new HttpRequestMessage(HttpMethod.Get, $"https://a0.ww.np.dl.playstation.net/tpl/np/{productId}/{productId}-ver.xml");
using var response = await client.SendAsync(message, cancellationToken).ConfigureAwait(false);
try
{
if (response.StatusCode == HttpStatusCode.NotFound)
return null;
await response.Content.LoadIntoBufferAsync().ConfigureAwait(false);
patchInfo = await response.Content.ReadAsAsync<TitlePatch>(xmlFormatters, cancellationToken).ConfigureAwait(false);
ResponseCache.Set(productId, patchInfo);
return patchInfo ?? new TitlePatch { Tag = new TitlePatchTag { Packages = new TitlePatchPackage[0], }, };
}
catch (Exception e)
{
ConsoleLogger.PrintError(e, response);
throw e;
}
await response.Content.LoadIntoBufferAsync().ConfigureAwait(false);
patchInfo = await response.Content.ReadAsAsync<TitlePatch>(xmlFormatters, cancellationToken).ConfigureAwait(false);
ResponseCache.Set(productId, patchInfo);
return patchInfo ?? new TitlePatch { Tag = new TitlePatchTag { Packages = new TitlePatchPackage[0], }, };
}
catch (Exception e)
{
ConsoleLogger.PrintError(e, response);
throw e;
}
}
public async Task<TitleMeta> GetTitleMetaAsync(string productId, CancellationToken cancellationToken)
@@ -270,23 +268,23 @@ namespace PsnClient
var hash = TmdbHasher.GetTitleHash(id);
try
{
using (var message = new HttpRequestMessage(HttpMethod.Get, $"https://tmdb.np.dl.playstation.net/tmdb/{id}_{hash}/{id}.xml"))
using (var response = await client.SendAsync(message, cancellationToken).ConfigureAwait(false))
try
{
if (response.StatusCode == HttpStatusCode.NotFound)
return null;
await response.Content.LoadIntoBufferAsync().ConfigureAwait(false);
meta = await response.Content.ReadAsAsync<TitleMeta>(xmlFormatters, cancellationToken).ConfigureAwait(false);
ResponseCache.Set(id, meta);
return meta;
}
catch (Exception e)
{
ConsoleLogger.PrintError(e, response);
using var message = new HttpRequestMessage(HttpMethod.Get, $"https://tmdb.np.dl.playstation.net/tmdb/{id}_{hash}/{id}.xml");
using var response = await client.SendAsync(message, cancellationToken).ConfigureAwait(false);
try
{
if (response.StatusCode == HttpStatusCode.NotFound)
return null;
}
await response.Content.LoadIntoBufferAsync().ConfigureAwait(false);
meta = await response.Content.ReadAsAsync<TitleMeta>(xmlFormatters, cancellationToken).ConfigureAwait(false);
ResponseCache.Set(id, meta);
return meta;
}
catch (Exception e)
{
ConsoleLogger.PrintError(e, response);
return null;
}
}
catch (Exception e)
{
@@ -303,21 +301,21 @@ namespace PsnClient
var searchId = Uri.EscapeUriString(search);
var queryId = Uri.EscapeDataString(searchId);
var uri = new Uri($"https://store.playstation.com/valkyrie-api/{loc.language}/{loc.country}/999/faceted-search/{searchId}?query={queryId}&game_content_type=games&size=30&bucket=games&platform=ps3&start=0");
using (var message = new HttpRequestMessage(HttpMethod.Get, uri))
using (var response = await client.SendAsync(message, cancellationToken).ConfigureAwait(false))
try
{
if (response.StatusCode == HttpStatusCode.NotFound)
return null;
await response.Content.LoadIntoBufferAsync().ConfigureAwait(false);
return await response.Content.ReadAsAsync<Container>(dashedFormatters, cancellationToken).ConfigureAwait(false);
}
catch (Exception e)
{
ConsoleLogger.PrintError(e, response);
using var message = new HttpRequestMessage(HttpMethod.Get, uri);
using var response = await client.SendAsync(message, cancellationToken).ConfigureAwait(false);
try
{
if (response.StatusCode == HttpStatusCode.NotFound)
return null;
}
await response.Content.LoadIntoBufferAsync().ConfigureAwait(false);
return await response.Content.ReadAsAsync<Container>(dashedFormatters, cancellationToken).ConfigureAwait(false);
}
catch (Exception e)
{
ConsoleLogger.PrintError(e, response);
return null;
}
}
catch (Exception e)
{
@@ -409,38 +407,38 @@ namespace PsnClient
var uri = new Uri($"http://f{fwLocale}01.ps3.update.playstation.net/update/ps3/list/{fwLocale}/ps3-updatelist.txt");
try
{
using (var message = new HttpRequestMessage(HttpMethod.Get, uri))
using (var response = await client.SendAsync(message, cancellationToken).ConfigureAwait(false))
try
using var message = new HttpRequestMessage(HttpMethod.Get, uri);
using var response = await client.SendAsync(message, cancellationToken).ConfigureAwait(false);
try
{
if (response.StatusCode != HttpStatusCode.OK)
return null;
await response.Content.LoadIntoBufferAsync().ConfigureAwait(false);
var data = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
if (string.IsNullOrEmpty(data))
return null;
if (FwVersionInfo.Match(data) is Match m && m.Success)
{
if (response.StatusCode != HttpStatusCode.OK)
return null;
await response.Content.LoadIntoBufferAsync().ConfigureAwait(false);
var data = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
if (string.IsNullOrEmpty(data))
return null;
if (FwVersionInfo.Match(data) is Match m && m.Success)
var ver = m.Groups["version"].Value;
if (!string.IsNullOrEmpty(ver) && ver.Length > 4)
{
var ver = m.Groups["version"].Value;
if (!string.IsNullOrEmpty(ver) && ver.Length > 4)
{
if (ver.EndsWith("00"))
ver = ver[..4]; //4.85
else
ver = ver[..4] + "." + ver[4..].TrimEnd('0'); //4.851 -> 4.85.1
}
return new FirmwareInfo { Version = ver, DownloadUrl = m.Groups["url"].Value, Locale = fwLocale};
if (ver.EndsWith("00"))
ver = ver[..4]; //4.85
else
ver = ver[..4] + "." + ver[4..].TrimEnd('0'); //4.851 -> 4.85.1
}
return new FirmwareInfo { Version = ver, DownloadUrl = m.Groups["url"].Value, Locale = fwLocale};
}
return null;
}
catch (Exception e)
{
ConsoleLogger.PrintError(e, response);
return null;
}
return null;
}
catch (Exception e)
{
ConsoleLogger.PrintError(e, response);
return null;
}
}
catch (Exception e)
{

View File

@@ -11,8 +11,8 @@ namespace PsnClient.Utils
public static string GetTitleHash(string productId)
{
using (var hmacSha1 = new HMACSHA1(HmacKey))
return hmacSha1.ComputeHash(Encoding.ASCII.GetBytes(productId)).ToHexString();
using var hmacSha1 = new HMACSHA1(HmacKey);
return hmacSha1.ComputeHash(Encoding.ASCII.GetBytes(productId)).ToHexString();
}
public static byte[] FromHexString(this string hexString)

View File

@@ -13,8 +13,8 @@ namespace CompatBot.Commands.Attributes
private const string Source = "https://cdn.discordapp.com/attachments/417347469521715210/534798232858001418/24qx11.jpg";
private static readonly Lazy<byte[]> Poster = new Lazy<byte[]>(() =>
{
using (var client = HttpClientFactory.Create())
return client.GetByteArrayAsync(Source).ConfigureAwait(true).GetAwaiter().GetResult();
using var client = HttpClientFactory.Create();
return client.GetByteArrayAsync(Source).ConfigureAwait(true).GetAwaiter().GetResult();
});
public override async Task<bool> ExecuteCheckAsync(CommandContext ctx, bool help)

View File

@@ -56,68 +56,66 @@ namespace CompatBot.Commands
{
try
{
using (var db = new BotDb())
using var db = new BotDb();
var timestamps = db.Warning
.Where(w => w.Timestamp.HasValue && !w.Retracted)
.OrderBy(w => w.Timestamp)
.Select(w => w.Timestamp.Value)
.ToList();
var firstWarnTimestamp = timestamps.FirstOrDefault();
var previousTimestamp = firstWarnTimestamp;
var longestGapBetweenWarning = 0L;
long longestGapStart = 0L, longestGapEnd = 0L;
var span24h = TimeSpan.FromHours(24).Ticks;
var currentSpan = new Queue<long>();
long mostWarningsStart = 0L, mostWarningsEnd = 0L, daysWithoutWarnings = 0L;
var mostWarnings = 0;
for (var i = 0; i < timestamps.Count; i++)
{
var timestamps = db.Warning
.Where(w => w.Timestamp.HasValue && !w.Retracted)
.OrderBy(w => w.Timestamp)
.Select(w => w.Timestamp.Value)
.ToList();
var firstWarnTimestamp = timestamps.FirstOrDefault();
var previousTimestamp = firstWarnTimestamp;
var longestGapBetweenWarning = 0L;
long longestGapStart = 0L, longestGapEnd = 0L;
var span24h = TimeSpan.FromHours(24).Ticks;
var currentSpan = new Queue<long>();
long mostWarningsStart = 0L, mostWarningsEnd = 0L, daysWithoutWarnings = 0L;
var mostWarnings = 0;
for (var i = 0; i < timestamps.Count; i++)
var currentTimestamp = timestamps[i];
var newGap = currentTimestamp - previousTimestamp;
if (newGap > longestGapBetweenWarning)
{
var currentTimestamp = timestamps[i];
var newGap = currentTimestamp - previousTimestamp;
if (newGap > longestGapBetweenWarning)
{
longestGapBetweenWarning = newGap;
longestGapStart = previousTimestamp;
longestGapEnd = currentTimestamp;
}
if (newGap > span24h)
daysWithoutWarnings += newGap / span24h;
previousTimestamp = currentTimestamp;
longestGapBetweenWarning = newGap;
longestGapStart = previousTimestamp;
longestGapEnd = currentTimestamp;
}
if (newGap > span24h)
daysWithoutWarnings += newGap / span24h;
previousTimestamp = currentTimestamp;
currentSpan.Enqueue(currentTimestamp);
while (currentSpan.Count > 0 && currentTimestamp - currentSpan.Peek() > span24h)
currentSpan.Dequeue();
if (currentSpan.Count > mostWarnings)
{
mostWarnings = currentSpan.Count;
mostWarningsStart = currentSpan.Peek();
mostWarningsEnd = currentTimestamp;
}
}
var yesterday = DateTime.UtcNow.AddDays(-1).Ticks;
var warnCount = db.Warning.Count(w => w.Timestamp > yesterday);
var lastWarn = timestamps.Any() ? timestamps.Last() : (long?)null;
if (lastWarn.HasValue)
longestGapBetweenWarning = Math.Max(longestGapBetweenWarning, DateTime.UtcNow.Ticks - lastWarn.Value);
// most warnings per 24h
var statsBuilder = new StringBuilder();
if (longestGapBetweenWarning > 0)
statsBuilder.AppendLine($@"Longest between warnings: **{TimeSpan.FromTicks(longestGapBetweenWarning).AsShortTimespan()}** between {longestGapStart.AsUtc():yyyy-MM-dd} and {longestGapEnd.AsUtc():yyyy-MM-dd}");
if (mostWarnings > 0)
statsBuilder.AppendLine($"Most warnings in 24h: **{mostWarnings}** on {mostWarningsEnd.AsUtc():yyyy-MM-dd}");
if (daysWithoutWarnings > 0 && firstWarnTimestamp > 0)
statsBuilder.AppendLine($"Full days without warnings: **{daysWithoutWarnings}** out of {(DateTime.UtcNow - firstWarnTimestamp.AsUtc()).TotalDays:0}");
currentSpan.Enqueue(currentTimestamp);
while (currentSpan.Count > 0 && currentTimestamp - currentSpan.Peek() > span24h)
currentSpan.Dequeue();
if (currentSpan.Count > mostWarnings)
{
statsBuilder.Append($"Warnings in the last 24h: **{warnCount}**");
if (warnCount == 0)
statsBuilder.Append(" ").Append(BotReactionsHandler.RandomPositiveReaction);
statsBuilder.AppendLine();
mostWarnings = currentSpan.Count;
mostWarningsStart = currentSpan.Peek();
mostWarningsEnd = currentTimestamp;
}
if (lastWarn.HasValue)
statsBuilder.AppendLine($@"Time since last warning: {(DateTime.UtcNow - lastWarn.Value.AsUtc()).AsShortTimespan()}");
embed.AddField("Warning stats", statsBuilder.ToString().TrimEnd(), true);
}
var yesterday = DateTime.UtcNow.AddDays(-1).Ticks;
var warnCount = db.Warning.Count(w => w.Timestamp > yesterday);
var lastWarn = timestamps.Any() ? timestamps.Last() : (long?)null;
if (lastWarn.HasValue)
longestGapBetweenWarning = Math.Max(longestGapBetweenWarning, DateTime.UtcNow.Ticks - lastWarn.Value);
// most warnings per 24h
var statsBuilder = new StringBuilder();
if (longestGapBetweenWarning > 0)
statsBuilder.AppendLine($@"Longest between warnings: **{TimeSpan.FromTicks(longestGapBetweenWarning).AsShortTimespan()}** between {longestGapStart.AsUtc():yyyy-MM-dd} and {longestGapEnd.AsUtc():yyyy-MM-dd}");
if (mostWarnings > 0)
statsBuilder.AppendLine($"Most warnings in 24h: **{mostWarnings}** on {mostWarningsEnd.AsUtc():yyyy-MM-dd}");
if (daysWithoutWarnings > 0 && firstWarnTimestamp > 0)
statsBuilder.AppendLine($"Full days without warnings: **{daysWithoutWarnings}** out of {(DateTime.UtcNow - firstWarnTimestamp.AsUtc()).TotalDays:0}");
{
statsBuilder.Append($"Warnings in the last 24h: **{warnCount}**");
if (warnCount == 0)
statsBuilder.Append(" ").Append(BotReactionsHandler.RandomPositiveReaction);
statsBuilder.AppendLine();
}
if (lastWarn.HasValue)
statsBuilder.AppendLine($@"Time since last warning: {(DateTime.UtcNow - lastWarn.Value.AsUtc()).AsShortTimespan()}");
embed.AddField("Warning stats", statsBuilder.ToString().TrimEnd(), true);
}
catch (Exception e)
{
@@ -192,21 +190,19 @@ namespace CompatBot.Commands
{
try
{
using (var db = new ThumbnailDb())
{
var syscallCount = db.SyscallInfo.Where(sci => sci.Function.StartsWith("sys_")).Distinct().Count();
var syscallModuleCount = db.SyscallInfo.Where(sci => sci.Function.StartsWith("sys_")).Select(sci => sci.Module).Distinct().Count();
var totalFuncCount = db.SyscallInfo.Select(sci => sci.Function).Distinct().Count();
var totalModuleCount = db.SyscallInfo.Select(sci => sci.Module).Distinct().Count();
var fwCallCount = totalFuncCount - syscallCount;
var fwModuleCount = totalModuleCount - syscallModuleCount;
var gameCount = db.SyscallToProductMap.Select(m => m.ProductId).Distinct().Count();
embed.AddField("SceCall Stats",
$"Tracked game IDs: {gameCount}\n" +
$"Tracked syscalls: {syscallCount} function{(syscallCount == 1 ? "" : "s")} in {syscallModuleCount} module{(syscallModuleCount == 1 ? "" : "s")}\n" +
$"Tracked fw calls: {fwCallCount} function{(fwCallCount == 1 ? "" : "s")} in {fwModuleCount} module{(fwModuleCount == 1 ? "" : "s")}\n",
true);
}
using var db = new ThumbnailDb();
var syscallCount = db.SyscallInfo.Where(sci => sci.Function.StartsWith("sys_")).Distinct().Count();
var syscallModuleCount = db.SyscallInfo.Where(sci => sci.Function.StartsWith("sys_")).Select(sci => sci.Module).Distinct().Count();
var totalFuncCount = db.SyscallInfo.Select(sci => sci.Function).Distinct().Count();
var totalModuleCount = db.SyscallInfo.Select(sci => sci.Module).Distinct().Count();
var fwCallCount = totalFuncCount - syscallCount;
var fwModuleCount = totalModuleCount - syscallModuleCount;
var gameCount = db.SyscallToProductMap.Select(m => m.ProductId).Distinct().Count();
embed.AddField("SceCall Stats",
$"Tracked game IDs: {gameCount}\n" +
$"Tracked syscalls: {syscallCount} function{(syscallCount == 1 ? "" : "s")} in {syscallModuleCount} module{(syscallModuleCount == 1 ? "" : "s")}\n" +
$"Tracked fw calls: {fwCallCount} function{(fwCallCount == 1 ? "" : "s")} in {fwModuleCount} module{(fwModuleCount == 1 ? "" : "s")}\n",
true);
}
catch (Exception e)
{
@@ -218,17 +214,15 @@ namespace CompatBot.Commands
{
try
{
using (var db = new BotDb())
{
var kots = db.Kot.Count();
var doggos = db.Doggo.Count();
if (kots == 0 && doggos == 0)
return;
using var db = new BotDb();
var kots = db.Kot.Count();
var doggos = db.Doggo.Count();
if (kots == 0 && doggos == 0)
return;
var diff = kots > doggos ? (double)kots / doggos - 1.0 : (double)doggos / kots - 1.0;
var sign = double.IsNaN(diff) || (double.IsFinite(diff) && !double.IsNegative(diff) && diff < 0.05) ? ":" : (kots > doggos ? ">" : "<");
embed.AddField("🐾 Stats", $"🐱 {kots - 1} {sign} {doggos - 1} 🐶", true);
}
var diff = kots > doggos ? (double)kots / doggos - 1.0 : (double)doggos / kots - 1.0;
var sign = double.IsNaN(diff) || (double.IsFinite(diff) && !double.IsNegative(diff) && diff < 0.05) ? ":" : (kots > doggos ? ">" : "<");
embed.AddField("🐾 Stats", $"🐱 {kots - 1} {sign} {doggos - 1} 🐶", true);
}
catch (Exception e)
{

View File

@@ -34,8 +34,8 @@ namespace CompatBot.Commands
static CompatList()
{
using (var db = new BotDb())
lastUpdateInfo = db.BotState.FirstOrDefault(k => k.Key == Rpcs3UpdateStateKey)?.Value;
using var db = new BotDb();
lastUpdateInfo = db.BotState.FirstOrDefault(k => k.Key == Rpcs3UpdateStateKey)?.Value;
}
[Command("compat"), Aliases("c", "compatibility")]

View File

@@ -89,76 +89,70 @@ namespace CompatBot.Commands
[Description("Adds a new content filter")]
public async Task Add(CommandContext ctx, [RemainingText, Description("A plain string to match")] string trigger)
{
using (var db = new BotDb())
using var db = new BotDb();
Piracystring filter;
if (string.IsNullOrEmpty(trigger))
filter = new Piracystring();
else
{
Piracystring filter;
if (string.IsNullOrEmpty(trigger))
filter = new Piracystring();
filter = await db.Piracystring.FirstOrDefaultAsync(ps => ps.String == trigger && ps.Disabled).ConfigureAwait(false);
if (filter == null)
filter = new Piracystring {String = trigger};
else
{
filter = await db.Piracystring.FirstOrDefaultAsync(ps => ps.String == trigger && ps.Disabled).ConfigureAwait(false);
if (filter == null)
filter = new Piracystring {String = trigger};
else
filter.Disabled = false;
}
var isNewFilter = filter.Id == default;
if (isNewFilter)
{
filter.Context = FilterContext.Chat | FilterContext.Log;
filter.Actions = FilterAction.RemoveContent | FilterAction.IssueWarning | FilterAction.SendMessage;
}
var (success, msg) = await EditFilterPropertiesAsync(ctx, db, filter).ConfigureAwait(false);
if (success)
{
if (isNewFilter)
await db.Piracystring.AddAsync(filter).ConfigureAwait(false);
await db.SaveChangesAsync().ConfigureAwait(false);
await msg.UpdateOrCreateMessageAsync(ctx.Channel, embed: FormatFilter(filter).WithTitle("Created a new content filter")).ConfigureAwait(false);
var member = ctx.Member ?? ctx.Client.GetMember(ctx.User);
var reportMsg = $"{member.GetMentionWithNickname()} added a new content filter: `{filter.String.Sanitize()}`";
if (!string.IsNullOrEmpty(filter.ValidatingRegex))
reportMsg += $"\nValidation: `{filter.ValidatingRegex}`";
await ctx.Client.ReportAsync("🆕 Content filter created", reportMsg, null, ReportSeverity.Low).ConfigureAwait(false);
ContentFilter.RebuildMatcher();
}
else
await msg.UpdateOrCreateMessageAsync(ctx.Channel, "Content filter creation aborted").ConfigureAwait(false);
filter.Disabled = false;
}
var isNewFilter = filter.Id == default;
if (isNewFilter)
{
filter.Context = FilterContext.Chat | FilterContext.Log;
filter.Actions = FilterAction.RemoveContent | FilterAction.IssueWarning | FilterAction.SendMessage;
}
var (success, msg) = await EditFilterPropertiesAsync(ctx, db, filter).ConfigureAwait(false);
if (success)
{
if (isNewFilter)
await db.Piracystring.AddAsync(filter).ConfigureAwait(false);
await db.SaveChangesAsync().ConfigureAwait(false);
await msg.UpdateOrCreateMessageAsync(ctx.Channel, embed: FormatFilter(filter).WithTitle("Created a new content filter")).ConfigureAwait(false);
var member = ctx.Member ?? ctx.Client.GetMember(ctx.User);
var reportMsg = $"{member.GetMentionWithNickname()} added a new content filter: `{filter.String.Sanitize()}`";
if (!string.IsNullOrEmpty(filter.ValidatingRegex))
reportMsg += $"\nValidation: `{filter.ValidatingRegex}`";
await ctx.Client.ReportAsync("🆕 Content filter created", reportMsg, null, ReportSeverity.Low).ConfigureAwait(false);
ContentFilter.RebuildMatcher();
}
else
await msg.UpdateOrCreateMessageAsync(ctx.Channel, "Content filter creation aborted").ConfigureAwait(false);
}
[Command("edit"), Aliases("fix", "update", "change")]
[Description("Modifies the specified content filter")]
public async Task Edit(CommandContext ctx, [Description("Filter ID")] int id)
{
using (var db = new BotDb())
using var db = new BotDb();
var filter = await db.Piracystring.FirstOrDefaultAsync(ps => ps.Id == id && !ps.Disabled).ConfigureAwait(false);
if (filter == null)
{
var filter = await db.Piracystring.FirstOrDefaultAsync(ps => ps.Id == id && !ps.Disabled).ConfigureAwait(false);
if (filter == null)
{
await ctx.RespondAsync("Specified filter does not exist").ConfigureAwait(false);
return;
}
await EditFilterCmd(ctx, db, filter).ConfigureAwait(false);
await ctx.RespondAsync("Specified filter does not exist").ConfigureAwait(false);
return;
}
await EditFilterCmd(ctx, db, filter).ConfigureAwait(false);
}
[Command("edit")]
public async Task Edit(CommandContext ctx, [Description("Trigger to edit"), RemainingText] string trigger)
{
using (var db = new BotDb())
using var db = new BotDb();
var filter = await db.Piracystring.FirstOrDefaultAsync(ps => ps.String.Equals(trigger, StringComparison.InvariantCultureIgnoreCase) && !ps.Disabled).ConfigureAwait(false);
if (filter == null)
{
var filter = await db.Piracystring.FirstOrDefaultAsync(ps => ps.String.Equals(trigger, StringComparison.InvariantCultureIgnoreCase) && !ps.Disabled).ConfigureAwait(false);
if (filter == null)
{
await ctx.RespondAsync("Specified filter does not exist").ConfigureAwait(false);
return;
}
await EditFilterCmd(ctx, db, filter).ConfigureAwait(false);
await ctx.RespondAsync("Specified filter does not exist").ConfigureAwait(false);
return;
}
await EditFilterCmd(ctx, db, filter).ConfigureAwait(false);
}
[Command("remove"), Aliases("delete", "del")]

View File

@@ -28,71 +28,101 @@ namespace CompatBot.Commands
var originalEventName = eventName = eventName.Trim(40);
var current = DateTime.UtcNow;
var currentTicks = current.Ticks;
using (var db = new BotDb())
using var db = new BotDb();
var currentEvents = await db.EventSchedule.OrderBy(e => e.End).Where(e => e.Start <= currentTicks && e.End >= currentTicks).ToListAsync().ConfigureAwait(false);
var nextEvent = await db.EventSchedule.OrderBy(e => e.Start).FirstOrDefaultAsync(e => e.Start > currentTicks).ConfigureAwait(false);
if (string.IsNullOrEmpty(eventName))
{
var currentEvents = await db.EventSchedule.OrderBy(e => e.End).Where(e => e.Start <= currentTicks && e.End >= currentTicks).ToListAsync().ConfigureAwait(false);
var nextEvent = await db.EventSchedule.OrderBy(e => e.Start).FirstOrDefaultAsync(e => e.Start > currentTicks).ConfigureAwait(false);
if (string.IsNullOrEmpty(eventName))
var nearestEventMsg = "";
if (currentEvents.Count > 0)
{
var nearestEventMsg = "";
if (currentEvents.Count > 0)
if (currentEvents.Count == 1)
nearestEventMsg = $"Current event: {currentEvents[0].Name} (going for {FormatCountdown(current - currentEvents[0].Start.AsUtc())})\n";
else
{
if (currentEvents.Count == 1)
nearestEventMsg = $"Current event: {currentEvents[0].Name} (going for {FormatCountdown(current - currentEvents[0].Start.AsUtc())})\n";
else
{
nearestEventMsg = "Current events:\n";
foreach (var e in currentEvents)
nearestEventMsg += $"{e.Name} (going for {FormatCountdown(current - e.Start.AsUtc())})\n";
}
nearestEventMsg = "Current events:\n";
foreach (var e in currentEvents)
nearestEventMsg += $"{e.Name} (going for {FormatCountdown(current - e.Start.AsUtc())})\n";
}
if (nextEvent != null)
nearestEventMsg += $"Next event: {nextEvent.Name} (starts in {FormatCountdown(nextEvent.Start.AsUtc() - current)})";
await ctx.RespondAsync(nearestEventMsg.TrimEnd()).ConfigureAwait(false);
}
if (nextEvent != null)
nearestEventMsg += $"Next event: {nextEvent.Name} (starts in {FormatCountdown(nextEvent.Start.AsUtc() - current)})";
await ctx.RespondAsync(nearestEventMsg.TrimEnd()).ConfigureAwait(false);
return;
}
eventName = await FuzzyMatchEventName(db, eventName).ConfigureAwait(false);
var promo = "";
if (currentEvents.Count > 0)
promo = $"\nMeanwhile check out this {(string.IsNullOrEmpty(currentEvents[0].EventName) ? "" : currentEvents[0].EventName + " " + currentEvents[0].Year + " ")}event in progress: {currentEvents[0].Name} (going for {FormatCountdown(current - currentEvents[0].Start.AsUtc())})";
else if (nextEvent != null)
promo = $"\nMeanwhile check out this upcoming {(string.IsNullOrEmpty(nextEvent.EventName) ? "" : nextEvent.EventName + " " + nextEvent.Year + " ")}event: {nextEvent.Name} (starts in {FormatCountdown(nextEvent.Start.AsUtc() - current)})";
var firstNamedEvent = await db.EventSchedule.OrderBy(e => e.Start).FirstOrDefaultAsync(e => e.Year >= current.Year && e.EventName == eventName).ConfigureAwait(false);
if (firstNamedEvent == null)
{
var scheduleEntry = await FuzzyMatchEntryName(db, originalEventName).ConfigureAwait(false);
var events = await db.EventSchedule.OrderBy(e => e.Start).Where(e => e.End > current.Ticks && e.Name == scheduleEntry).ToListAsync().ConfigureAwait(false);
if (events.Any())
{
var eventListMsg = new StringBuilder();
foreach (var eventEntry in events)
{
if (eventEntry.Start < current.Ticks)
eventListMsg.AppendLine($"{eventEntry.Name} ends in {FormatCountdown(eventEntry.End.AsUtc() - current)}");
else
eventListMsg.AppendLine($"{eventEntry.Name} starts in {FormatCountdown(eventEntry.Start.AsUtc() - current)}");
}
await ctx.SendAutosplitMessageAsync(eventListMsg.ToString(), blockStart: "", blockEnd: "").ConfigureAwait(false);
return;
}
eventName = await FuzzyMatchEventName(db, eventName).ConfigureAwait(false);
var promo = "";
if (currentEvents.Count > 0)
promo = $"\nMeanwhile check out this {(string.IsNullOrEmpty(currentEvents[0].EventName) ? "" : currentEvents[0].EventName + " " + currentEvents[0].Year + " ")}event in progress: {currentEvents[0].Name} (going for {FormatCountdown(current - currentEvents[0].Start.AsUtc())})";
else if (nextEvent != null)
promo = $"\nMeanwhile check out this upcoming {(string.IsNullOrEmpty(nextEvent.EventName) ? "" : nextEvent.EventName + " " + nextEvent.Year + " ")}event: {nextEvent.Name} (starts in {FormatCountdown(nextEvent.Start.AsUtc() - current)})";
var firstNamedEvent = await db.EventSchedule.OrderBy(e => e.Start).FirstOrDefaultAsync(e => e.Year >= current.Year && e.EventName == eventName).ConfigureAwait(false);
if (firstNamedEvent == null)
var noEventMsg = $"No information about the upcoming {eventName.Sanitize(replaceBackTicks: true)} at the moment";
if (eventName.Length > 10)
noEventMsg = "No information about such event at the moment";
else if (ctx.User.Id == 259997001880436737ul || ctx.User.Id == 377190919327318018ul)
{
var scheduleEntry = await FuzzyMatchEntryName(db, originalEventName).ConfigureAwait(false);
var events = await db.EventSchedule.OrderBy(e => e.Start).Where(e => e.End > current.Ticks && e.Name == scheduleEntry).ToListAsync().ConfigureAwait(false);
if (events.Any())
noEventMsg = $"Haha, very funny, {ctx.User.Mention}. So original. Never saw this joke before.";
promo = null;
}
if (!string.IsNullOrEmpty(promo))
noEventMsg += promo;
await ctx.RespondAsync(noEventMsg).ConfigureAwait(false);
return;
}
if (firstNamedEvent.Start >= currentTicks)
{
var upcomingNamedEventMsg = $"__{FormatCountdown(firstNamedEvent.Start.AsUtc() - current)} until {eventName} {firstNamedEvent.Year}!__";
if (string.IsNullOrEmpty(promo) || nextEvent?.Id == firstNamedEvent.Id)
upcomingNamedEventMsg += $"\nFirst event: {firstNamedEvent.Name}";
else
upcomingNamedEventMsg += promo;
await ctx.RespondAsync(upcomingNamedEventMsg).ConfigureAwait(false);
return;
}
var lastNamedEvent = await db.EventSchedule.OrderByDescending(e => e.End).FirstOrDefaultAsync(e => e.Year == current.Year && e.EventName == eventName).ConfigureAwait(false);
if (lastNamedEvent.End <= currentTicks)
{
if (lastNamedEvent.End < current.AddMonths(-1).Ticks)
{
firstNamedEvent = await db.EventSchedule.OrderBy(e => e.Start).FirstOrDefaultAsync(e => e.Year >= current.Year + 1 && e.EventName == eventName).ConfigureAwait(false);
if (firstNamedEvent == null)
{
var eventListMsg = new StringBuilder();
foreach (var eventEntry in events)
var noEventMsg = $"No information about the upcoming {eventName.Sanitize(replaceBackTicks: true)} at the moment";
if (eventName.Length > 10)
noEventMsg = "No information about such event at the moment";
else if (ctx.User.Id == 259997001880436737ul || ctx.User.Id == 377190919327318018ul)
{
if (eventEntry.Start < current.Ticks)
eventListMsg.AppendLine($"{eventEntry.Name} ends in {FormatCountdown(eventEntry.End.AsUtc() - current)}");
else
eventListMsg.AppendLine($"{eventEntry.Name} starts in {FormatCountdown(eventEntry.Start.AsUtc() - current)}");
noEventMsg = $"Haha, very funny, {ctx.User.Mention}. So original. Never saw this joke before.";
promo = null;
}
await ctx.SendAutosplitMessageAsync(eventListMsg.ToString(), blockStart: "", blockEnd: "").ConfigureAwait(false);
if (!string.IsNullOrEmpty(promo))
noEventMsg += promo;
await ctx.RespondAsync(noEventMsg).ConfigureAwait(false);
return;
}
var noEventMsg = $"No information about the upcoming {eventName.Sanitize(replaceBackTicks: true)} at the moment";
if (eventName.Length > 10)
noEventMsg = "No information about such event at the moment";
else if (ctx.User.Id == 259997001880436737ul || ctx.User.Id == 377190919327318018ul)
{
noEventMsg = $"Haha, very funny, {ctx.User.Mention}. So original. Never saw this joke before.";
promo = null;
}
if (!string.IsNullOrEmpty(promo))
noEventMsg += promo;
await ctx.RespondAsync(noEventMsg).ConfigureAwait(false);
return;
}
if (firstNamedEvent.Start >= currentTicks)
{
var upcomingNamedEventMsg = $"__{FormatCountdown(firstNamedEvent.Start.AsUtc() - current)} until {eventName} {firstNamedEvent.Year}!__";
if (string.IsNullOrEmpty(promo) || nextEvent?.Id == firstNamedEvent.Id)
upcomingNamedEventMsg += $"\nFirst event: {firstNamedEvent.Name}";
@@ -102,53 +132,21 @@ namespace CompatBot.Commands
return;
}
var lastNamedEvent = await db.EventSchedule.OrderByDescending(e => e.End).FirstOrDefaultAsync(e => e.Year == current.Year && e.EventName == eventName).ConfigureAwait(false);
if (lastNamedEvent.End <= currentTicks)
{
if (lastNamedEvent.End < current.AddMonths(-1).Ticks)
{
firstNamedEvent = await db.EventSchedule.OrderBy(e => e.Start).FirstOrDefaultAsync(e => e.Year >= current.Year + 1 && e.EventName == eventName).ConfigureAwait(false);
if (firstNamedEvent == null)
{
var noEventMsg = $"No information about the upcoming {eventName.Sanitize(replaceBackTicks: true)} at the moment";
if (eventName.Length > 10)
noEventMsg = "No information about such event at the moment";
else if (ctx.User.Id == 259997001880436737ul || ctx.User.Id == 377190919327318018ul)
{
noEventMsg = $"Haha, very funny, {ctx.User.Mention}. So original. Never saw this joke before.";
promo = null;
}
if (!string.IsNullOrEmpty(promo))
noEventMsg += promo;
await ctx.RespondAsync(noEventMsg).ConfigureAwait(false);
return;
}
var upcomingNamedEventMsg = $"__{FormatCountdown(firstNamedEvent.Start.AsUtc() - current)} until {eventName} {firstNamedEvent.Year}!__";
if (string.IsNullOrEmpty(promo) || nextEvent?.Id == firstNamedEvent.Id)
upcomingNamedEventMsg += $"\nFirst event: {firstNamedEvent.Name}";
else
upcomingNamedEventMsg += promo;
await ctx.RespondAsync(upcomingNamedEventMsg).ConfigureAwait(false);
return;
}
var e3EndedMsg = $"__{eventName} {current.Year} has concluded. See you next year! (maybe)__";
if (!string.IsNullOrEmpty(promo))
e3EndedMsg += promo;
await ctx.RespondAsync(e3EndedMsg).ConfigureAwait(false);
return;
}
var currentNamedEvent = await db.EventSchedule.OrderBy(e => e.End).FirstOrDefaultAsync(e => e.Start <= currentTicks && e.End >= currentTicks && e.EventName == eventName).ConfigureAwait(false);
var nextNamedEvent = await db.EventSchedule.OrderBy(e => e.Start).FirstOrDefaultAsync(e => e.Start > currentTicks && e.EventName == eventName).ConfigureAwait(false);
var msg = $"__{eventName} {current.Year} is already in progress!__\n";
if (currentNamedEvent != null)
msg += $"Current event: {currentNamedEvent.Name} (going for {FormatCountdown(current - currentNamedEvent.Start.AsUtc())})\n";
if (nextNamedEvent != null)
msg += $"Next event: {nextNamedEvent.Name} (starts in {FormatCountdown(nextNamedEvent.Start.AsUtc() - current)})";
await ctx.SendAutosplitMessageAsync(msg.TrimEnd(), blockStart: "", blockEnd: "").ConfigureAwait(false);
var e3EndedMsg = $"__{eventName} {current.Year} has concluded. See you next year! (maybe)__";
if (!string.IsNullOrEmpty(promo))
e3EndedMsg += promo;
await ctx.RespondAsync(e3EndedMsg).ConfigureAwait(false);
return;
}
var currentNamedEvent = await db.EventSchedule.OrderBy(e => e.End).FirstOrDefaultAsync(e => e.Start <= currentTicks && e.End >= currentTicks && e.EventName == eventName).ConfigureAwait(false);
var nextNamedEvent = await db.EventSchedule.OrderBy(e => e.Start).FirstOrDefaultAsync(e => e.Start > currentTicks && e.EventName == eventName).ConfigureAwait(false);
var msg = $"__{eventName} {current.Year} is already in progress!__\n";
if (currentNamedEvent != null)
msg += $"Current event: {currentNamedEvent.Name} (going for {FormatCountdown(current - currentNamedEvent.Start.AsUtc())})\n";
if (nextNamedEvent != null)
msg += $"Next event: {nextNamedEvent.Name} (starts in {FormatCountdown(nextNamedEvent.Start.AsUtc() - current)})";
await ctx.SendAutosplitMessageAsync(msg.TrimEnd(), blockStart: "", blockEnd: "").ConfigureAwait(false);
}
protected async Task Add(CommandContext ctx, string eventName = null)
@@ -206,30 +204,28 @@ namespace CompatBot.Commands
protected async Task Update(CommandContext ctx, int id, string eventName = null)
{
using (var db = new BotDb())
using var db = new BotDb();
var evt = eventName == null
? db.EventSchedule.FirstOrDefault(e => e.Id == id)
: db.EventSchedule.FirstOrDefault(e => e.Id == id && e.EventName == eventName);
if (evt == null)
{
var evt = eventName == null
? db.EventSchedule.FirstOrDefault(e => e.Id == id)
: db.EventSchedule.FirstOrDefault(e => e.Id == id && e.EventName == eventName);
if (evt == null)
{
await ctx.ReactWithAsync(Config.Reactions.Failure, $"No event with id {id}").ConfigureAwait(false);
return;
}
await ctx.ReactWithAsync(Config.Reactions.Failure, $"No event with id {id}").ConfigureAwait(false);
return;
}
var (success, msg) = await EditEventPropertiesAsync(ctx, evt, eventName).ConfigureAwait(false);
if (success)
{
await db.SaveChangesAsync().ConfigureAwait(false);
if (LimitedToSpamChannel.IsSpamChannel(ctx.Channel))
await msg.UpdateOrCreateMessageAsync(ctx.Channel, embed: FormatEvent(evt).WithTitle("Updated event schedule entry #" + evt.Id)).ConfigureAwait(false);
else
await msg.UpdateOrCreateMessageAsync(ctx.Channel, "Updated the schedule entry").ConfigureAwait(false);
}
var (success, msg) = await EditEventPropertiesAsync(ctx, evt, eventName).ConfigureAwait(false);
if (success)
{
await db.SaveChangesAsync().ConfigureAwait(false);
if (LimitedToSpamChannel.IsSpamChannel(ctx.Channel))
await msg.UpdateOrCreateMessageAsync(ctx.Channel, embed: FormatEvent(evt).WithTitle("Updated event schedule entry #" + evt.Id)).ConfigureAwait(false);
else
{
await msg.UpdateOrCreateMessageAsync(ctx.Channel, "Event update aborted, changes weren't saved").ConfigureAwait(false);
}
await msg.UpdateOrCreateMessageAsync(ctx.Channel, "Updated the schedule entry").ConfigureAwait(false);
}
else
{
await msg.UpdateOrCreateMessageAsync(ctx.Channel, "Event update aborted, changes weren't saved").ConfigureAwait(false);
}
}

View File

@@ -144,8 +144,8 @@ namespace CompatBot.Commands
attachmentFilename = att.FileName;
try
{
using (var httpClient = HttpClientFactory.Create(new CompressionMessageHandler()))
attachment = await httpClient.GetByteArrayAsync(att.Url).ConfigureAwait(false);
using var httpClient = HttpClientFactory.Create(new CompressionMessageHandler());
attachment = await httpClient.GetByteArrayAsync(att.Url).ConfigureAwait(false);
}
catch (Exception e)
{
@@ -157,21 +157,19 @@ namespace CompatBot.Commands
await ctx.ReactWithAsync(Config.Reactions.Failure, "An explanation for the term must be provided").ConfigureAwait(false);
else
{
using (var db = new BotDb())
using var db = new BotDb();
if (await db.Explanation.AnyAsync(e => e.Keyword == term).ConfigureAwait(false))
await ctx.ReactWithAsync(Config.Reactions.Failure, $"`{term}` is already defined. Use `update` to update an existing term.").ConfigureAwait(false);
else
{
if (await db.Explanation.AnyAsync(e => e.Keyword == term).ConfigureAwait(false))
await ctx.ReactWithAsync(Config.Reactions.Failure, $"`{term}` is already defined. Use `update` to update an existing term.").ConfigureAwait(false);
else
var entity = new Explanation
{
var entity = new Explanation
{
Keyword = term, Text = explanation ?? "", Attachment = attachment,
AttachmentFilename = attachmentFilename
};
await db.Explanation.AddAsync(entity).ConfigureAwait(false);
await db.SaveChangesAsync().ConfigureAwait(false);
await ctx.ReactWithAsync(Config.Reactions.Success, $"`{term}` was successfully added").ConfigureAwait(false);
}
Keyword = term, Text = explanation ?? "", Attachment = attachment,
AttachmentFilename = attachmentFilename
};
await db.Explanation.AddAsync(entity).ConfigureAwait(false);
await db.SaveChangesAsync().ConfigureAwait(false);
await ctx.ReactWithAsync(Config.Reactions.Success, $"`{term}` was successfully added").ConfigureAwait(false);
}
}
}
@@ -195,31 +193,29 @@ namespace CompatBot.Commands
attachmentFilename = att.FileName;
try
{
using (var httpClient = HttpClientFactory.Create(new CompressionMessageHandler()))
attachment = await httpClient.GetByteArrayAsync(att.Url).ConfigureAwait(false);
using var httpClient = HttpClientFactory.Create(new CompressionMessageHandler());
attachment = await httpClient.GetByteArrayAsync(att.Url).ConfigureAwait(false);
}
catch (Exception e)
{
Config.Log.Warn(e, "Failed to download explanation attachment " + ctx);
}
}
using (var db = new BotDb())
using var db = new BotDb();
var item = await db.Explanation.FirstOrDefaultAsync(e => e.Keyword == term).ConfigureAwait(false);
if (item == null)
await ctx.ReactWithAsync(Config.Reactions.Failure, $"Term `{term}` is not defined").ConfigureAwait(false);
else
{
var item = await db.Explanation.FirstOrDefaultAsync(e => e.Keyword == term).ConfigureAwait(false);
if (item == null)
await ctx.ReactWithAsync(Config.Reactions.Failure, $"Term `{term}` is not defined").ConfigureAwait(false);
else
if (!string.IsNullOrEmpty(explanation))
item.Text = explanation;
if (attachment?.Length > 0)
{
if (!string.IsNullOrEmpty(explanation))
item.Text = explanation;
if (attachment?.Length > 0)
{
item.Attachment = attachment;
item.AttachmentFilename = attachmentFilename;
}
await db.SaveChangesAsync().ConfigureAwait(false);
await ctx.ReactWithAsync(Config.Reactions.Success, "Term was updated").ConfigureAwait(false);
item.Attachment = attachment;
item.AttachmentFilename = attachmentFilename;
}
await db.SaveChangesAsync().ConfigureAwait(false);
await ctx.ReactWithAsync(Config.Reactions.Success, "Term was updated").ConfigureAwait(false);
}
}
@@ -230,19 +226,17 @@ namespace CompatBot.Commands
{
oldTerm = oldTerm.ToLowerInvariant().StripQuotes();
newTerm = newTerm.ToLowerInvariant().StripQuotes();
using (var db = new BotDb())
using var db = new BotDb();
var item = await db.Explanation.FirstOrDefaultAsync(e => e.Keyword == oldTerm).ConfigureAwait(false);
if (item == null)
await ctx.ReactWithAsync(Config.Reactions.Failure, $"Term `{oldTerm}` is not defined").ConfigureAwait(false);
else if (await db.Explanation.AnyAsync(e => e.Keyword == newTerm).ConfigureAwait(false))
await ctx.ReactWithAsync(Config.Reactions.Failure, $"Term `{newTerm}` already defined, can't replace it with explanation for `{oldTerm}`").ConfigureAwait(false);
else
{
var item = await db.Explanation.FirstOrDefaultAsync(e => e.Keyword == oldTerm).ConfigureAwait(false);
if (item == null)
await ctx.ReactWithAsync(Config.Reactions.Failure, $"Term `{oldTerm}` is not defined").ConfigureAwait(false);
else if (await db.Explanation.AnyAsync(e => e.Keyword == newTerm).ConfigureAwait(false))
await ctx.ReactWithAsync(Config.Reactions.Failure, $"Term `{newTerm}` already defined, can't replace it with explanation for `{oldTerm}`").ConfigureAwait(false);
else
{
item.Keyword = newTerm;
await db.SaveChangesAsync().ConfigureAwait(false);
await ctx.ReactWithAsync(Config.Reactions.Success, $"Renamed `{oldTerm}` to `{newTerm}`").ConfigureAwait(false);
}
item.Keyword = newTerm;
await db.SaveChangesAsync().ConfigureAwait(false);
await ctx.ReactWithAsync(Config.Reactions.Success, $"Renamed `{oldTerm}` to `{newTerm}`").ConfigureAwait(false);
}
}
@@ -264,22 +258,20 @@ namespace CompatBot.Commands
public async Task List(CommandContext ctx)
{
var responseChannel = await ctx.GetChannelForSpamAsync().ConfigureAwait(false);
using (var db = new BotDb())
{
var keywords = await db.Explanation.Select(e => e.Keyword).OrderBy(t => t).ToListAsync().ConfigureAwait(false);
if (keywords.Count == 0)
await ctx.RespondAsync("Nothing has been defined yet").ConfigureAwait(false);
else
try
{
foreach (var embed in keywords.BreakInEmbeds(new DiscordEmbedBuilder {Title = TermListTitle, Color = Config.Colors.Help}))
await responseChannel.SendMessageAsync(embed: embed).ConfigureAwait(false);
}
catch (Exception e)
{
Config.Log.Error(e);
}
}
using var db = new BotDb();
var keywords = await db.Explanation.Select(e => e.Keyword).OrderBy(t => t).ToListAsync().ConfigureAwait(false);
if (keywords.Count == 0)
await ctx.RespondAsync("Nothing has been defined yet").ConfigureAwait(false);
else
try
{
foreach (var embed in keywords.BreakInEmbeds(new DiscordEmbedBuilder {Title = TermListTitle, Color = Config.Colors.Help}))
await responseChannel.SendMessageAsync(embed: embed).ConfigureAwait(false);
}
catch (Exception e)
{
Config.Log.Error(e);
}
}
[Group("remove"), Aliases("delete", "del", "erase", "obliterate"), RequiresBotModRole]
@@ -290,17 +282,15 @@ namespace CompatBot.Commands
public async Task RemoveExplanation(CommandContext ctx, [RemainingText, Description("Term to remove")] string term)
{
term = term.ToLowerInvariant().StripQuotes();
using (var db = new BotDb())
using var db = new BotDb();
var item = await db.Explanation.FirstOrDefaultAsync(e => e.Keyword == term).ConfigureAwait(false);
if (item == null)
await ctx.ReactWithAsync(Config.Reactions.Failure, $"Term `{term}` is not defined").ConfigureAwait(false);
else
{
var item = await db.Explanation.FirstOrDefaultAsync(e => e.Keyword == term).ConfigureAwait(false);
if (item == null)
await ctx.ReactWithAsync(Config.Reactions.Failure, $"Term `{term}` is not defined").ConfigureAwait(false);
else
{
db.Explanation.Remove(item);
await db.SaveChangesAsync().ConfigureAwait(false);
await ctx.ReactWithAsync(Config.Reactions.Success, $"Removed `{term}`").ConfigureAwait(false);
}
db.Explanation.Remove(item);
await db.SaveChangesAsync().ConfigureAwait(false);
await ctx.ReactWithAsync(Config.Reactions.Success, $"Removed `{term}`").ConfigureAwait(false);
}
}
@@ -309,22 +299,20 @@ namespace CompatBot.Commands
public async Task Attachment(CommandContext ctx, [RemainingText, Description("Term to remove")] string term)
{
term = term.ToLowerInvariant().StripQuotes();
using (var db = new BotDb())
using var db = new BotDb();
var item = await db.Explanation.FirstOrDefaultAsync(e => e.Keyword == term).ConfigureAwait(false);
if (item == null)
await ctx.ReactWithAsync(Config.Reactions.Failure, $"Term `{term}` is not defined").ConfigureAwait(false);
else if (string.IsNullOrEmpty(item.AttachmentFilename))
await ctx.ReactWithAsync(Config.Reactions.Failure, $"Term `{term}` doesn't have any attachments").ConfigureAwait(false);
else if (string.IsNullOrEmpty(item.Text))
await RemoveExplanation(ctx, term).ConfigureAwait(false);
else
{
var item = await db.Explanation.FirstOrDefaultAsync(e => e.Keyword == term).ConfigureAwait(false);
if (item == null)
await ctx.ReactWithAsync(Config.Reactions.Failure, $"Term `{term}` is not defined").ConfigureAwait(false);
else if (string.IsNullOrEmpty(item.AttachmentFilename))
await ctx.ReactWithAsync(Config.Reactions.Failure, $"Term `{term}` doesn't have any attachments").ConfigureAwait(false);
else if (string.IsNullOrEmpty(item.Text))
await RemoveExplanation(ctx, term).ConfigureAwait(false);
else
{
item.Attachment = null;
item.AttachmentFilename = null;
await db.SaveChangesAsync().ConfigureAwait(false);
await ctx.ReactWithAsync(Config.Reactions.Success, $"Removed attachment for `{term}`").ConfigureAwait(false);
}
item.Attachment = null;
item.AttachmentFilename = null;
await db.SaveChangesAsync().ConfigureAwait(false);
await ctx.ReactWithAsync(Config.Reactions.Success, $"Removed attachment for `{term}`").ConfigureAwait(false);
}
}
@@ -333,21 +321,19 @@ namespace CompatBot.Commands
public async Task Text(CommandContext ctx, [RemainingText, Description("Term to remove")] string term)
{
term = term.ToLowerInvariant().StripQuotes();
using (var db = new BotDb())
using var db = new BotDb();
var item = await db.Explanation.FirstOrDefaultAsync(e => e.Keyword == term).ConfigureAwait(false);
if (item == null)
await ctx.ReactWithAsync(Config.Reactions.Failure, $"Term `{term}` is not defined").ConfigureAwait(false);
else if (string.IsNullOrEmpty(item.Text))
await ctx.ReactWithAsync(Config.Reactions.Failure, $"Term `{term}` doesn't have any text").ConfigureAwait(false);
else if (string.IsNullOrEmpty(item.AttachmentFilename))
await RemoveExplanation(ctx, term).ConfigureAwait(false);
else
{
var item = await db.Explanation.FirstOrDefaultAsync(e => e.Keyword == term).ConfigureAwait(false);
if (item == null)
await ctx.ReactWithAsync(Config.Reactions.Failure, $"Term `{term}` is not defined").ConfigureAwait(false);
else if (string.IsNullOrEmpty(item.Text))
await ctx.ReactWithAsync(Config.Reactions.Failure, $"Term `{term}` doesn't have any text").ConfigureAwait(false);
else if (string.IsNullOrEmpty(item.AttachmentFilename))
await RemoveExplanation(ctx, term).ConfigureAwait(false);
else
{
item.Text = "";
await db.SaveChangesAsync().ConfigureAwait(false);
await ctx.ReactWithAsync(Config.Reactions.Success, $"Removed explanation text for `{term}`").ConfigureAwait(false);
}
item.Text = "";
await db.SaveChangesAsync().ConfigureAwait(false);
await ctx.ReactWithAsync(Config.Reactions.Success, $"Removed explanation text for `{term}`").ConfigureAwait(false);
}
}
}
@@ -374,45 +360,44 @@ namespace CompatBot.Commands
return;
}
using (var db = new BotDb())
using var db = new BotDb();
var item = await db.Explanation.FirstOrDefaultAsync(e => e.Keyword == termOrLink).ConfigureAwait(false);
if (item == null)
{
var item = await db.Explanation.FirstOrDefaultAsync(e => e.Keyword == termOrLink).ConfigureAwait(false);
if (item == null)
var term = ctx.Message.Content.Split(' ', 2).Last();
await ShowExplanation(ctx, term).ConfigureAwait(false);
}
else
{
if (!string.IsNullOrEmpty(item.Text))
{
var term = ctx.Message.Content.Split(' ', 2).Last();
await ShowExplanation(ctx, term).ConfigureAwait(false);
using var stream = new MemoryStream(Encoding.UTF8.GetBytes(item.Text));
await ctx.Channel.SendFileAsync($"{termOrLink}.txt", stream).ConfigureAwait(false);
}
else
if (!string.IsNullOrEmpty(item.AttachmentFilename))
{
if (!string.IsNullOrEmpty(item.Text))
using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(item.Text)))
await ctx.Channel.SendFileAsync($"{termOrLink}.txt", stream).ConfigureAwait(false);
if (!string.IsNullOrEmpty(item.AttachmentFilename))
using (var stream = new MemoryStream(item.Attachment))
await ctx.Channel.SendFileAsync(item.AttachmentFilename, stream).ConfigureAwait(false);
using var stream = new MemoryStream(item.Attachment);
await ctx.Channel.SendFileAsync(item.AttachmentFilename, stream).ConfigureAwait(false);
}
}
}
internal static async Task<(Explanation explanation, string fuzzyMatch, double score)> LookupTerm(string term)
{
using var db = new BotDb();
string fuzzyMatch = null;
double coefficient;
Explanation explanation;
using (var db = new BotDb())
var explanation = await db.Explanation.FirstOrDefaultAsync(e => e.Keyword == term).ConfigureAwait(false);
if (explanation == null)
{
explanation = await db.Explanation.FirstOrDefaultAsync(e => e.Keyword == term).ConfigureAwait(false);
if (explanation == null)
{
var termList = await db.Explanation.Select(e => e.Keyword).ToListAsync().ConfigureAwait(false);
var bestSuggestion = termList.OrderByDescending(term.GetFuzzyCoefficientCached).First();
coefficient = term.GetFuzzyCoefficientCached(bestSuggestion);
explanation = await db.Explanation.FirstOrDefaultAsync(e => e.Keyword == bestSuggestion).ConfigureAwait(false);
fuzzyMatch = bestSuggestion;
}
else
coefficient = 2.0;
var termList = await db.Explanation.Select(e => e.Keyword).ToListAsync().ConfigureAwait(false);
var bestSuggestion = termList.OrderByDescending(term.GetFuzzyCoefficientCached).First();
coefficient = term.GetFuzzyCoefficientCached(bestSuggestion);
explanation = await db.Explanation.FirstOrDefaultAsync(e => e.Keyword == bestSuggestion).ConfigureAwait(false);
fuzzyMatch = bestSuggestion;
}
else
coefficient = 2.0;
return (explanation, fuzzyMatch, coefficient);
}
@@ -432,8 +417,10 @@ namespace CompatBot.Commands
if (string.IsNullOrEmpty(explanation))
await ctx.ReactWithAsync(Config.Reactions.Failure, "Couldn't find any text in the specified message").ConfigureAwait(false);
else
using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(explanation)))
await ctx.Channel.SendFileAsync("explanation.txt", stream).ConfigureAwait(false);
{
using var stream = new MemoryStream(Encoding.UTF8.GetBytes(explanation));
await ctx.Channel.SendFileAsync("explanation.txt", stream).ConfigureAwait(false);
}
}
}
}

View File

@@ -22,51 +22,49 @@ namespace CompatBot.Commands
public async Task List(CommandContext ctx)
{
const string linkPrefix = "discord.gg/";
using (var db = new BotDb())
using var db = new BotDb();
var whitelistedInvites = await db.WhitelistedInvites.ToListAsync().ConfigureAwait(false);
if (whitelistedInvites.Count == 0)
{
var whitelistedInvites = await db.WhitelistedInvites.ToListAsync().ConfigureAwait(false);
if (whitelistedInvites.Count == 0)
{
await ctx.RespondAsync("There are no whitelisted discord servers").ConfigureAwait(false);
return;
}
var table = new AsciiTable(
new AsciiColumn("ID", alignToRight: true),
new AsciiColumn("Server ID", alignToRight: true),
new AsciiColumn("Invite", disabled: !ctx.Channel.IsPrivate),
new AsciiColumn("Server Name")
);
foreach (var item in whitelistedInvites)
{
string guildName = null;
if (!string.IsNullOrEmpty(item.InviteCode))
try
{
var invite = await ctx.Client.GetInviteByCodeAsync(item.InviteCode).ConfigureAwait(false);
guildName = invite?.Guild.Name;
}
catch { }
if (string.IsNullOrEmpty(guildName))
try
{
var guild = await ctx.Client.GetGuildAsync(item.GuildId).ConfigureAwait(false);
guildName = guild.Name;
}
catch { }
if (string.IsNullOrEmpty(guildName))
guildName = item.Name ?? "";
var link = "";
if (!string.IsNullOrEmpty(item.InviteCode))
link = linkPrefix + item.InviteCode;
//discord expands invite links even if they're inside the code block for some reason
table.Add(item.Id.ToString(), item.GuildId.ToString(), "\u200d" + link, guildName.Sanitize());
}
var result = new StringBuilder()
.AppendLine("Whitelisted discord servers:")
.Append(table);
await ctx.SendAutosplitMessageAsync(result).ConfigureAwait(false);
await ctx.RespondAsync("There are no whitelisted discord servers").ConfigureAwait(false);
return;
}
var table = new AsciiTable(
new AsciiColumn("ID", alignToRight: true),
new AsciiColumn("Server ID", alignToRight: true),
new AsciiColumn("Invite", disabled: !ctx.Channel.IsPrivate),
new AsciiColumn("Server Name")
);
foreach (var item in whitelistedInvites)
{
string guildName = null;
if (!string.IsNullOrEmpty(item.InviteCode))
try
{
var invite = await ctx.Client.GetInviteByCodeAsync(item.InviteCode).ConfigureAwait(false);
guildName = invite?.Guild.Name;
}
catch { }
if (string.IsNullOrEmpty(guildName))
try
{
var guild = await ctx.Client.GetGuildAsync(item.GuildId).ConfigureAwait(false);
guildName = guild.Name;
}
catch { }
if (string.IsNullOrEmpty(guildName))
guildName = item.Name ?? "";
var link = "";
if (!string.IsNullOrEmpty(item.InviteCode))
link = linkPrefix + item.InviteCode;
//discord expands invite links even if they're inside the code block for some reason
table.Add(item.Id.ToString(), item.GuildId.ToString(), "\u200d" + link, guildName.Sanitize());
}
var result = new StringBuilder()
.AppendLine("Whitelisted discord servers:")
.Append(table);
await ctx.SendAutosplitMessageAsync(result).ConfigureAwait(false);
}
[Command("whitelist"), Aliases("add", "allow"), Priority(10)]

View File

@@ -46,35 +46,31 @@ namespace CompatBot.Commands
{
await ctx.ReactWithAsync(Config.Reactions.PleaseWait).ConfigureAwait(false);
var members = GetMembers(ctx.Client);
using (var compressedResult = new MemoryStream())
using var compressedResult = new MemoryStream();
using (var memoryStream = new MemoryStream())
{
using (var memoryStream = new MemoryStream())
using (var writer = new StreamWriter(memoryStream, new UTF8Encoding(false), 4096, true))
{
using (var writer = new StreamWriter(memoryStream, new UTF8Encoding(false), 4096, true))
{
foreach (var member in members)
await writer.WriteLineAsync($"{member.Username}\t{member.Nickname}\t{member.JoinedAt:O}\t{(string.Join(',', member.Roles.Select(r => r.Name)))}").ConfigureAwait(false);
await writer.FlushAsync().ConfigureAwait(false);
}
memoryStream.Seek(0, SeekOrigin.Begin);
if (memoryStream.Length <= Config.AttachmentSizeLimit)
{
await ctx.RespondWithFileAsync("names.txt", memoryStream).ConfigureAwait(false);
return;
}
using (var gzip = new GZipStream(compressedResult, CompressionLevel.Optimal, true))
{
await memoryStream.CopyToAsync(gzip).ConfigureAwait(false);
await gzip.FlushAsync().ConfigureAwait(false);
}
foreach (var member in members)
await writer.WriteLineAsync($"{member.Username}\t{member.Nickname}\t{member.JoinedAt:O}\t{(string.Join(',', member.Roles.Select(r => r.Name)))}").ConfigureAwait(false);
await writer.FlushAsync().ConfigureAwait(false);
}
compressedResult.Seek(0, SeekOrigin.Begin);
if (compressedResult.Length <= Config.AttachmentSizeLimit)
await ctx.RespondWithFileAsync("names.txt.gz", compressedResult).ConfigureAwait(false);
else
await ctx.RespondAsync($"Dump is too large: {compressedResult.Length} bytes").ConfigureAwait(false);
memoryStream.Seek(0, SeekOrigin.Begin);
if (memoryStream.Length <= Config.AttachmentSizeLimit)
{
await ctx.RespondWithFileAsync("names.txt", memoryStream).ConfigureAwait(false);
return;
}
using var gzip = new GZipStream(compressedResult, CompressionLevel.Optimal, true);
await memoryStream.CopyToAsync(gzip).ConfigureAwait(false);
await gzip.FlushAsync().ConfigureAwait(false);
}
compressedResult.Seek(0, SeekOrigin.Begin);
if (compressedResult.Length <= Config.AttachmentSizeLimit)
await ctx.RespondWithFileAsync("names.txt.gz", compressedResult).ConfigureAwait(false);
else
await ctx.RespondAsync($"Dump is too large: {compressedResult.Length} bytes").ConfigureAwait(false);
}
catch (Exception e)
{
@@ -208,40 +204,36 @@ namespace CompatBot.Commands
checkedMembers.Add(member);
}
using (var compressedStream = new MemoryStream())
using var compressedStream = new MemoryStream();
using var uncompressedStream = new MemoryStream();
using (var writer = new StreamWriter(uncompressedStream, new UTF8Encoding(false), 4096, true))
{
using (var uncompressedStream = new MemoryStream())
{
using (var writer = new StreamWriter(uncompressedStream, new UTF8Encoding(false), 4096, true))
{
writer.Write(result.ToString());
writer.Flush();
}
uncompressedStream.Seek(0, SeekOrigin.Begin);
if (result.Length <= headerLength)
{
await ctx.RespondAsync("No potential name spoofing was detected").ConfigureAwait(false);
return;
}
if (uncompressedStream.Length <= Config.AttachmentSizeLimit)
{
await ctx.RespondWithFileAsync("spoofing_check_results.txt", uncompressedStream).ConfigureAwait(false);
return;
}
using (var gzip = new GZipStream(compressedStream, CompressionLevel.Optimal, true))
{
uncompressedStream.CopyTo(gzip);
gzip.Flush();
}
compressedStream.Seek(0, SeekOrigin.Begin);
if (compressedStream.Length <= Config.AttachmentSizeLimit)
await ctx.RespondWithFileAsync("spoofing_check_results.txt.gz", compressedStream).ConfigureAwait(false);
else
await ctx.RespondAsync($"Dump is too large: {compressedStream.Length} bytes").ConfigureAwait(false);
}
writer.Write(result.ToString());
writer.Flush();
}
uncompressedStream.Seek(0, SeekOrigin.Begin);
if (result.Length <= headerLength)
{
await ctx.RespondAsync("No potential name spoofing was detected").ConfigureAwait(false);
return;
}
if (uncompressedStream.Length <= Config.AttachmentSizeLimit)
{
await ctx.RespondWithFileAsync("spoofing_check_results.txt", uncompressedStream).ConfigureAwait(false);
return;
}
using (var gzip = new GZipStream(compressedStream, CompressionLevel.Optimal, true))
{
uncompressedStream.CopyTo(gzip);
gzip.Flush();
}
compressedStream.Seek(0, SeekOrigin.Begin);
if (compressedStream.Length <= Config.AttachmentSizeLimit)
await ctx.RespondWithFileAsync("spoofing_check_results.txt.gz", compressedStream).ConfigureAwait(false);
else
await ctx.RespondAsync($"Dump is too large: {compressedStream.Length} bytes").ConfigureAwait(false);
}
catch (Exception e)
{

View File

@@ -106,14 +106,12 @@ namespace CompatBot.Commands
var productIds = ProductCodeLookup.GetProductIds(search);
if (productIds.Count > 0)
{
using (var db = new ThumbnailDb())
{
var contentId = await db.Thumbnail.FirstOrDefaultAsync(t => t.ProductCode == productIds[0].ToUpperInvariant()).ConfigureAwait(false);
if (contentId?.ContentId != null)
titleId = contentId.ContentId;
if (contentId?.Name != null)
search = contentId.Name;
}
using var db = new ThumbnailDb();
var contentId = await db.Thumbnail.FirstOrDefaultAsync(t => t.ProductCode == productIds[0].ToUpperInvariant()).ConfigureAwait(false);
if (contentId?.ContentId != null)
titleId = contentId.ContentId;
if (contentId?.Name != null)
search = contentId.Name;
}
var alteredSearch = search.Trim();

View File

@@ -31,7 +31,7 @@ namespace CompatBot.Commands
[Description("Returns currently checked out bot commit")]
public async Task Version(CommandContext ctx)
{
using (var git = new Process
using var git = new Process
{
StartInfo = new ProcessStartInfo("git", "log -1 --oneline")
{
@@ -40,14 +40,12 @@ namespace CompatBot.Commands
RedirectStandardOutput = true,
StandardOutputEncoding = Encoding.UTF8,
},
})
{
git.Start();
var stdout = await git.StandardOutput.ReadToEndAsync().ConfigureAwait(false);
git.WaitForExit();
if (!string.IsNullOrEmpty(stdout))
await ctx.RespondAsync("```" + stdout + "```").ConfigureAwait(false);
}
};
git.Start();
var stdout = await git.StandardOutput.ReadToEndAsync().ConfigureAwait(false);
git.WaitForExit();
if (!string.IsNullOrEmpty(stdout))
await ctx.RespondAsync("```" + stdout + "```").ConfigureAwait(false);
}
[Command("update"), Aliases("upgrade", "pull")]
@@ -131,31 +129,29 @@ namespace CompatBot.Commands
{
try
{
using (var db = new BotDb())
using var db = new BotDb();
var status = await db.BotState.FirstOrDefaultAsync(s => s.Key == "bot-status-activity").ConfigureAwait(false);
var txt = await db.BotState.FirstOrDefaultAsync(s => s.Key == "bot-status-text").ConfigureAwait(false);
if (Enum.TryParse(activity, true, out ActivityType activityType)
&& !string.IsNullOrEmpty(message))
{
var status = await db.BotState.FirstOrDefaultAsync(s => s.Key == "bot-status-activity").ConfigureAwait(false);
var txt = await db.BotState.FirstOrDefaultAsync(s => s.Key == "bot-status-text").ConfigureAwait(false);
if (Enum.TryParse(activity, true, out ActivityType activityType)
&& !string.IsNullOrEmpty(message))
{
if (status == null)
await db.BotState.AddAsync(new BotState {Key = "bot-status-activity", Value = activity}).ConfigureAwait(false);
else
status.Value = activity;
if (txt == null)
await db.BotState.AddAsync(new BotState {Key = "bot-status-text", Value = message}).ConfigureAwait(false);
else
txt.Value = message;
await ctx.Client.UpdateStatusAsync(new DiscordActivity(message, activityType), UserStatus.Online).ConfigureAwait(false);
}
if (status == null)
await db.BotState.AddAsync(new BotState {Key = "bot-status-activity", Value = activity}).ConfigureAwait(false);
else
{
if (status != null)
db.BotState.Remove(status);
await ctx.Client.UpdateStatusAsync(new DiscordActivity()).ConfigureAwait(false);
}
await db.SaveChangesAsync(Config.Cts.Token).ConfigureAwait(false);
status.Value = activity;
if (txt == null)
await db.BotState.AddAsync(new BotState {Key = "bot-status-text", Value = message}).ConfigureAwait(false);
else
txt.Value = message;
await ctx.Client.UpdateStatusAsync(new DiscordActivity(message, activityType), UserStatus.Online).ConfigureAwait(false);
}
else
{
if (status != null)
db.BotState.Remove(status);
await ctx.Client.UpdateStatusAsync(new DiscordActivity()).ConfigureAwait(false);
}
await db.SaveChangesAsync(Config.Cts.Token).ConfigureAwait(false);
}
catch (Exception e)
{

View File

@@ -110,22 +110,20 @@ namespace CompatBot.Commands
{
var logPath = Config.CurrentLogPath;
var attachmentSizeLimit = Config.AttachmentSizeLimit;
using (var log = File.Open(logPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (var result = new MemoryStream((int)Math.Min(attachmentSizeLimit, log.Length)))
using var log = File.Open(logPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
using var result = new MemoryStream((int)Math.Min(attachmentSizeLimit, log.Length));
using (var gzip = new GZipStream(result, CompressionLevel.Optimal, true))
{
using (var gzip = new GZipStream(result, CompressionLevel.Optimal, true))
{
await log.CopyToAsync(gzip, Config.Cts.Token).ConfigureAwait(false);
await gzip.FlushAsync().ConfigureAwait(false);
}
if (result.Length <= attachmentSizeLimit)
{
result.Seek(0, SeekOrigin.Begin);
await ctx.RespondWithFileAsync(Path.GetFileName(logPath) + ".gz", result).ConfigureAwait(false);
}
else
await ctx.ReactWithAsync(Config.Reactions.Failure, "Compressed log size is too large, ask Nicba for help :(", true).ConfigureAwait(false);
await log.CopyToAsync(gzip, Config.Cts.Token).ConfigureAwait(false);
await gzip.FlushAsync().ConfigureAwait(false);
}
if (result.Length <= attachmentSizeLimit)
{
result.Seek(0, SeekOrigin.Begin);
await ctx.RespondWithFileAsync(Path.GetFileName(logPath) + ".gz", result).ConfigureAwait(false);
}
else
await ctx.ReactWithAsync(Config.Reactions.Failure, "Compressed log size is too large, ask Nicba for help :(", true).ConfigureAwait(false);
}
catch (Exception e)
{

View File

@@ -39,101 +39,99 @@ namespace CompatBot.Commands
return;
}
using (var db = new ThumbnailDb())
using var db = new ThumbnailDb();
if (db.SyscallInfo.Any(sci => sci.Module == search || sci.Function == search))
{
if (db.SyscallInfo.Any(sci => sci.Module == search || sci.Function == search))
var productInfoList = db.SyscallToProductMap.AsNoTracking()
.Where(m => m.SyscallInfo.Module == search || m.SyscallInfo.Function == search)
.Select(m => new {m.Product.ProductCode, Name = m.Product.Name.StripMarks() ?? "???"})
.Distinct()
.ToList();
var groupedList = productInfoList
.GroupBy(m => m.Name, m => m.ProductCode, StringComparer.InvariantCultureIgnoreCase)
.OrderBy(g => g.Key, StringComparer.OrdinalIgnoreCase)
.ToList();
if (groupedList.Any())
{
var productInfoList = db.SyscallToProductMap.AsNoTracking()
.Where(m => m.SyscallInfo.Module == search || m.SyscallInfo.Function == search)
.Select(m => new {m.Product.ProductCode, Name = m.Product.Name.StripMarks() ?? "???"})
.Distinct()
.ToList();
var groupedList = productInfoList
.GroupBy(m => m.Name, m => m.ProductCode, StringComparer.InvariantCultureIgnoreCase)
.OrderBy(g => g.Key, StringComparer.OrdinalIgnoreCase)
.ToList();
if (groupedList.Any())
{
var bigList = groupedList.Count >= Config.MaxSyscallResultLines;
var bigList = groupedList.Count >= Config.MaxSyscallResultLines;
var result = new StringBuilder();
var fullList = bigList ? new StringBuilder() : null;
result.AppendLine($"List of games using `{search}`:```");
var c = 0;
foreach (var gi in groupedList)
{
var productIds = string.Join(", ", gi.Distinct().OrderBy(pc => pc).AsEnumerable());
if (c < Config.MaxSyscallResultLines)
result.AppendLine($"{gi.Key.Trim(60)} [{productIds}]");
if (bigList)
fullList.AppendLine($"{gi.Key} [{productIds}]");
c++;
}
await ctx.SendAutosplitMessageAsync(result.Append("```")).ConfigureAwait(false);
var result = new StringBuilder();
var fullList = bigList ? new StringBuilder() : null;
result.AppendLine($"List of games using `{search}`:```");
var c = 0;
foreach (var gi in groupedList)
{
var productIds = string.Join(", ", gi.Distinct().OrderBy(pc => pc).AsEnumerable());
if (c < Config.MaxSyscallResultLines)
result.AppendLine($"{gi.Key.Trim(60)} [{productIds}]");
if (bigList)
{
using var memoryStream = new MemoryStream((int)(fullList.Capacity*1.25));
using var streamWriter = new StreamWriter(memoryStream, Encoding.UTF8);
await streamWriter.WriteAsync(fullList).ConfigureAwait(false);
await streamWriter.FlushAsync().ConfigureAwait(false);
memoryStream.Seek(0, SeekOrigin.Begin);
await ctx.RespondWithFileAsync($"{search}.txt", memoryStream, $"See attached file for full list of {groupedList.Count} entries").ConfigureAwait(false);
}
fullList.AppendLine($"{gi.Key} [{productIds}]");
c++;
}
await ctx.SendAutosplitMessageAsync(result.Append("```")).ConfigureAwait(false);
if (bigList)
{
using var memoryStream = new MemoryStream((int)(fullList.Capacity*1.25));
using var streamWriter = new StreamWriter(memoryStream, Encoding.UTF8);
await streamWriter.WriteAsync(fullList).ConfigureAwait(false);
await streamWriter.FlushAsync().ConfigureAwait(false);
memoryStream.Seek(0, SeekOrigin.Begin);
await ctx.RespondWithFileAsync($"{search}.txt", memoryStream, $"See attached file for full list of {groupedList.Count} entries").ConfigureAwait(false);
}
else
await ctx.RespondAsync($"No games found that use `{search}`").ConfigureAwait(false);
}
else
await ctx.RespondAsync($"No games found that use `{search}`").ConfigureAwait(false);
}
else
{
var result = new StringBuilder("Unknown entity name");
var modules = await db.SyscallInfo.Select(sci => sci.Module).Distinct().ToListAsync().ConfigureAwait(false);
var substrModules = modules.Where(m => m.Contains(search, StringComparison.CurrentCultureIgnoreCase));
var fuzzyModules = modules
.Select(m => (name: m, score: search.GetFuzzyCoefficientCached(m)))
.Where(i => i.score > 0.6)
.OrderByDescending(i => i.score)
.Select(i => i.name)
.ToList();
modules = substrModules
.Concat(fuzzyModules)
.Distinct()
.OrderBy(m => m, StringComparer.OrdinalIgnoreCase)
.ToList();
var modulesFound = modules.Any();
if (modulesFound)
{
var result = new StringBuilder("Unknown entity name");
var modules = await db.SyscallInfo.Select(sci => sci.Module).Distinct().ToListAsync().ConfigureAwait(false);
var substrModules = modules.Where(m => m.Contains(search, StringComparison.CurrentCultureIgnoreCase));
var fuzzyModules = modules
.Select(m => (name: m, score: search.GetFuzzyCoefficientCached(m)))
.Where(i => i.score > 0.6)
.OrderByDescending(i => i.score)
.Select(i => i.name)
.ToList();
modules = substrModules
.Concat(fuzzyModules)
.Distinct()
.OrderBy(m => m, StringComparer.OrdinalIgnoreCase)
.ToList();
var modulesFound = modules.Any();
if (modulesFound)
{
result.AppendLine(", possible modules:```");
foreach (var m in modules)
result.AppendLine(m);
result.AppendLine("```");
}
var functions = await db.SyscallInfo.Select(sci => sci.Function).Distinct().ToListAsync().ConfigureAwait(false);
var substrFuncs = functions.Where(f => f.Contains(search, StringComparison.InvariantCultureIgnoreCase));
var fuzzyFuncs = functions
.Select(f => (name: f, score: search.GetFuzzyCoefficientCached(f)))
.Where(i => i.score > 0.6)
.OrderByDescending(i => i.score)
.Select(i => i.name)
.ToList();
functions = substrFuncs
.Concat(fuzzyFuncs)
.Distinct()
.OrderBy(f => f, StringComparer.OrdinalIgnoreCase)
.ToList();
var functionsFound = functions.Any();
if (functionsFound)
{
if (modulesFound)
result.AppendLine("Possible functions:```");
else
result.AppendLine(", possible functions:```");
foreach (var f in functions)
result.AppendLine(f);
result.AppendLine("```");
}
await ctx.SendAutosplitMessageAsync(result).ConfigureAwait(false);
result.AppendLine(", possible modules:```");
foreach (var m in modules)
result.AppendLine(m);
result.AppendLine("```");
}
var functions = await db.SyscallInfo.Select(sci => sci.Function).Distinct().ToListAsync().ConfigureAwait(false);
var substrFuncs = functions.Where(f => f.Contains(search, StringComparison.InvariantCultureIgnoreCase));
var fuzzyFuncs = functions
.Select(f => (name: f, score: search.GetFuzzyCoefficientCached(f)))
.Where(i => i.score > 0.6)
.OrderByDescending(i => i.score)
.Select(i => i.name)
.ToList();
functions = substrFuncs
.Concat(fuzzyFuncs)
.Distinct()
.OrderBy(f => f, StringComparer.OrdinalIgnoreCase)
.ToList();
var functionsFound = functions.Any();
if (functionsFound)
{
if (modulesFound)
result.AppendLine("Possible functions:```");
else
result.AppendLine(", possible functions:```");
foreach (var f in functions)
result.AppendLine(f);
result.AppendLine("```");
}
await ctx.SendAutosplitMessageAsync(result).ConfigureAwait(false);
}
}
@@ -141,30 +139,28 @@ namespace CompatBot.Commands
{
productId = productId.ToUpperInvariant();
string title = null;
using (var db = new ThumbnailDb())
using var db = new ThumbnailDb();
title = db.Thumbnail.FirstOrDefault(t => t.ProductCode == productId)?.Name;
title = string.IsNullOrEmpty(title) ? productId : $"[{productId}] {title.Trim(40)}";
var sysInfoList = db.SyscallToProductMap.AsNoTracking()
.Where(m => m.Product.ProductCode == productId)
.Select(m => m.SyscallInfo)
.Distinct()
.AsEnumerable()
.OrderBy(sci => sci.Module)
.ThenBy(sci => sci.Function)
.ToList();
if (ctx.User.Id == 216724245957312512UL)
sysInfoList = sysInfoList.Where(i => i.Function.StartsWith("sys_", StringComparison.InvariantCultureIgnoreCase)).ToList();
if (sysInfoList.Any())
{
title = db.Thumbnail.FirstOrDefault(t => t.ProductCode == productId)?.Name;
title = string.IsNullOrEmpty(title) ? productId : $"[{productId}] {title.Trim(40)}";
var sysInfoList = db.SyscallToProductMap.AsNoTracking()
.Where(m => m.Product.ProductCode == productId)
.Select(m => m.SyscallInfo)
.Distinct()
.AsEnumerable()
.OrderBy(sci => sci.Module)
.ThenBy(sci => sci.Function)
.ToList();
if (ctx.User.Id == 216724245957312512UL)
sysInfoList = sysInfoList.Where(i => i.Function.StartsWith("sys_", StringComparison.InvariantCultureIgnoreCase)).ToList();
if (sysInfoList.Any())
{
var result = new StringBuilder($"List of syscalls used by `{title}`:```").AppendLine();
foreach (var sci in sysInfoList)
result.AppendLine($"{sci.Module}: {sci.Function}");
await ctx.SendAutosplitMessageAsync(result.Append("```")).ConfigureAwait(false);
}
else
await ctx.RespondAsync($"No information available for `{title}`").ConfigureAwait(false);
var result = new StringBuilder($"List of syscalls used by `{title}`:```").AppendLine();
foreach (var sci in sysInfoList)
result.AppendLine($"{sci.Module}: {sci.Function}");
await ctx.SendAutosplitMessageAsync(result.Append("```")).ConfigureAwait(false);
}
else
await ctx.RespondAsync($"No information available for `{title}`").ConfigureAwait(false);
}
}
}

View File

@@ -125,21 +125,19 @@ namespace CompatBot.Commands
[Description("Changes the state of the warning status")]
public async Task Revert(CommandContext ctx, [Description("Warning ID to change")] int id)
{
using (var db = new BotDb())
using var db = new BotDb();
var warn = await db.Warning.FirstOrDefaultAsync(w => w.Id == id).ConfigureAwait(false);
if (warn.Retracted)
{
var warn = await db.Warning.FirstOrDefaultAsync(w => w.Id == id).ConfigureAwait(false);
if (warn.Retracted)
{
warn.Retracted = false;
warn.RetractedBy = null;
warn.RetractionReason = null;
warn.RetractionTimestamp = null;
await db.SaveChangesAsync(Config.Cts.Token).ConfigureAwait(false);
await ctx.ReactWithAsync(Config.Reactions.Success, "Reissued the warning", true).ConfigureAwait(false);
}
else
await Remove(ctx, id).ConfigureAwait(false);
warn.Retracted = false;
warn.RetractedBy = null;
warn.RetractionReason = null;
warn.RetractionTimestamp = null;
await db.SaveChangesAsync(Config.Cts.Token).ConfigureAwait(false);
await ctx.ReactWithAsync(Config.Reactions.Success, "Reissued the warning", true).ConfigureAwait(false);
}
else
await Remove(ctx, id).ConfigureAwait(false);
}
internal static async Task<bool> AddAsync(CommandContext ctx, ulong userId, string userName, DiscordUser issuer, string reason, string fullReason = null)

View File

@@ -50,64 +50,62 @@ namespace CompatBot.Database
private static async Task ImportAsync(BotDb dbContext, CancellationToken cancellationToken)
{
var db = dbContext.Database;
using (var tx = await db.BeginTransactionAsync(cancellationToken))
using var tx = await db.BeginTransactionAsync(cancellationToken);
try
{
try
{
// __EFMigrationsHistory table will be already created by the failed migration attempt
// __EFMigrationsHistory table will be already created by the failed migration attempt
#pragma warning disable EF1001 // Internal EF Core API usage.
await db.ExecuteSqlRawAsync($"INSERT INTO `__EFMigrationsHistory`(`MigrationId`,`ProductVersion`) VALUES ({new InitialCreate().GetId()},'manual')", cancellationToken);
await db.ExecuteSqlRawAsync($"INSERT INTO `__EFMigrationsHistory`(`MigrationId`,`ProductVersion`) VALUES ({new Explanations().GetId()},'manual')", cancellationToken);
await db.ExecuteSqlRawAsync($"INSERT INTO `__EFMigrationsHistory`(`MigrationId`,`ProductVersion`) VALUES ({new InitialCreate().GetId()},'manual')", cancellationToken);
await db.ExecuteSqlRawAsync($"INSERT INTO `__EFMigrationsHistory`(`MigrationId`,`ProductVersion`) VALUES ({new Explanations().GetId()},'manual')", cancellationToken);
#pragma warning restore EF1001 // Internal EF Core API usage.
// create constraints on moderator
await db.ExecuteSqlRawAsync(@"CREATE TABLE `temp_new_moderator` (
// create constraints on moderator
await db.ExecuteSqlRawAsync(@"CREATE TABLE `temp_new_moderator` (
`id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
`discord_id` INTEGER NOT NULL,
`sudoer` INTEGER NOT NULL
)", cancellationToken);
await db.ExecuteSqlRawAsync("INSERT INTO temp_new_moderator SELECT `id`,`discord_id`,`sudoer` FROM `moderator`", cancellationToken);
await db.ExecuteSqlRawAsync("DROP TABLE `moderator`", cancellationToken);
await db.ExecuteSqlRawAsync("ALTER TABLE `temp_new_moderator` RENAME TO `moderator`", cancellationToken);
await db.ExecuteSqlRawAsync("CREATE UNIQUE INDEX `moderator_discord_id` ON `moderator` (`discord_id`)", cancellationToken);
// create constraints on piracystring
await db.ExecuteSqlRawAsync(@"CREATE TABLE `temp_new_piracystring` (
await db.ExecuteSqlRawAsync("INSERT INTO temp_new_moderator SELECT `id`,`discord_id`,`sudoer` FROM `moderator`", cancellationToken);
await db.ExecuteSqlRawAsync("DROP TABLE `moderator`", cancellationToken);
await db.ExecuteSqlRawAsync("ALTER TABLE `temp_new_moderator` RENAME TO `moderator`", cancellationToken);
await db.ExecuteSqlRawAsync("CREATE UNIQUE INDEX `moderator_discord_id` ON `moderator` (`discord_id`)", cancellationToken);
// create constraints on piracystring
await db.ExecuteSqlRawAsync(@"CREATE TABLE `temp_new_piracystring` (
`id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
`string` varchar ( 255 ) NOT NULL
)", cancellationToken);
await db.ExecuteSqlRawAsync("INSERT INTO temp_new_piracystring SELECT `id`,`string` FROM `piracystring`", cancellationToken);
await db.ExecuteSqlRawAsync("DROP TABLE `piracystring`", cancellationToken);
await db.ExecuteSqlRawAsync("ALTER TABLE `temp_new_piracystring` RENAME TO `piracystring`", cancellationToken);
await db.ExecuteSqlRawAsync("CREATE UNIQUE INDEX `piracystring_string` ON `piracystring` (`string`)", cancellationToken);
// create constraints on warning
await db.ExecuteSqlRawAsync(@"CREATE TABLE `temp_new_warning` (
await db.ExecuteSqlRawAsync("INSERT INTO temp_new_piracystring SELECT `id`,`string` FROM `piracystring`", cancellationToken);
await db.ExecuteSqlRawAsync("DROP TABLE `piracystring`", cancellationToken);
await db.ExecuteSqlRawAsync("ALTER TABLE `temp_new_piracystring` RENAME TO `piracystring`", cancellationToken);
await db.ExecuteSqlRawAsync("CREATE UNIQUE INDEX `piracystring_string` ON `piracystring` (`string`)", cancellationToken);
// create constraints on warning
await db.ExecuteSqlRawAsync(@"CREATE TABLE `temp_new_warning` (
`id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
`discord_id` INTEGER NOT NULL,
`reason` TEXT NOT NULL,
`full_reason` TEXT NOT NULL,
`issuer_id` INTEGER NOT NULL DEFAULT 0
)", cancellationToken);
await db.ExecuteSqlRawAsync("INSERT INTO temp_new_warning SELECT `id`,`discord_id`,`reason`,`full_reason`,`issuer_id` FROM `warning`", cancellationToken);
await db.ExecuteSqlRawAsync("DROP TABLE `warning`", cancellationToken);
await db.ExecuteSqlRawAsync("ALTER TABLE `temp_new_warning` RENAME TO `warning`", cancellationToken);
await db.ExecuteSqlRawAsync("CREATE INDEX `warning_discord_id` ON `warning` (`discord_id`)", cancellationToken);
// create constraints on explanation
await db.ExecuteSqlRawAsync(@"CREATE TABLE `temp_new_explanation` (
await db.ExecuteSqlRawAsync("INSERT INTO temp_new_warning SELECT `id`,`discord_id`,`reason`,`full_reason`,`issuer_id` FROM `warning`", cancellationToken);
await db.ExecuteSqlRawAsync("DROP TABLE `warning`", cancellationToken);
await db.ExecuteSqlRawAsync("ALTER TABLE `temp_new_warning` RENAME TO `warning`", cancellationToken);
await db.ExecuteSqlRawAsync("CREATE INDEX `warning_discord_id` ON `warning` (`discord_id`)", cancellationToken);
// create constraints on explanation
await db.ExecuteSqlRawAsync(@"CREATE TABLE `temp_new_explanation` (
`id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
`keyword` TEXT NOT NULL,
`text` TEXT NOT NULL
)", cancellationToken);
await db.ExecuteSqlRawAsync("INSERT INTO temp_new_explanation SELECT `id`,`keyword`,`text` FROM `explanation`", cancellationToken);
await db.ExecuteSqlRawAsync("DROP TABLE `explanation`", cancellationToken);
await db.ExecuteSqlRawAsync("ALTER TABLE `temp_new_explanation` RENAME TO `explanation`", cancellationToken);
await db.ExecuteSqlRawAsync("CREATE UNIQUE INDEX `explanation_keyword` ON `explanation` (`keyword`)", cancellationToken);
tx.Commit();
}
catch (Exception e)
{
//tx.Rollback();
tx.Commit();
throw e;
}
await db.ExecuteSqlRawAsync("INSERT INTO temp_new_explanation SELECT `id`,`keyword`,`text` FROM `explanation`", cancellationToken);
await db.ExecuteSqlRawAsync("DROP TABLE `explanation`", cancellationToken);
await db.ExecuteSqlRawAsync("ALTER TABLE `temp_new_explanation` RENAME TO `explanation`", cancellationToken);
await db.ExecuteSqlRawAsync("CREATE UNIQUE INDEX `explanation_keyword` ON `explanation` (`keyword`)", cancellationToken);
tx.Commit();
}
catch (Exception e)
{
//tx.Rollback();
tx.Commit();
throw e;
}
}

View File

@@ -21,8 +21,8 @@ namespace CompatBot.Database.Providers
try
{
using (var httpClient = HttpClientFactory.Create(new CompressionMessageHandler()))
using (var response = await httpClient.GetStreamAsync("https://raw.githubusercontent.com/GPUOpen-Drivers/amd-vulkan-versions/master/amdversions.xml").ConfigureAwait(false))
{
using var response = await httpClient.GetStreamAsync("https://raw.githubusercontent.com/GPUOpen-Drivers/amd-vulkan-versions/master/amdversions.xml").ConfigureAwait(false);
var xml = await XDocument.LoadAsync(response, LoadOptions.None, Config.Cts.Token).ConfigureAwait(false);
foreach (var driver in xml.Root.Elements("driver"))
{

View File

@@ -11,9 +11,11 @@ namespace CompatBot.Database.Providers
static DisabledCommandsProvider()
{
lock (DisabledCommands)
using (var db = new BotDb())
foreach (var cmd in db.DisabledCommands.ToList())
DisabledCommands.Add(cmd.Command);
{
using var db = new BotDb();
foreach (var cmd in db.DisabledCommands.ToList())
DisabledCommands.Add(cmd.Command);
}
}
public static HashSet<string> Get() => DisabledCommands;
@@ -22,26 +24,26 @@ namespace CompatBot.Database.Providers
{
lock (DisabledCommands)
if (DisabledCommands.Add(command))
using (var db = new BotDb())
{
db.DisabledCommands.Add(new DisabledCommand {Command = command});
db.SaveChanges();
}
{
using var db = new BotDb();
db.DisabledCommands.Add(new DisabledCommand {Command = command});
db.SaveChanges();
}
}
public static void Enable(string command)
{
lock (DisabledCommands)
if (DisabledCommands.Remove(command))
using (var db = new BotDb())
{
var cmd = db.DisabledCommands.FirstOrDefault(c => c.Command == command);
if (cmd == null)
return;
{
using var db = new BotDb();
var cmd = db.DisabledCommands.FirstOrDefault(c => c.Command == command);
if (cmd == null)
return;
db.DisabledCommands.Remove(cmd);
db.SaveChanges();
}
db.DisabledCommands.Remove(cmd);
db.SaveChanges();
}
}
public static void Clear()
@@ -49,11 +51,9 @@ namespace CompatBot.Database.Providers
lock (DisabledCommands)
{
DisabledCommands.Clear();
using (var db = new BotDb())
{
db.DisabledCommands.RemoveRange(db.DisabledCommands);
db.SaveChanges();
}
using var db = new BotDb();
db.DisabledCommands.RemoveRange(db.DisabledCommands);
db.SaveChanges();
}
}
}

View File

@@ -12,27 +12,25 @@ namespace CompatBot.Database.Providers
{
public static bool IsWhitelisted(ulong guildId)
{
using (var db = new BotDb())
return db.WhitelistedInvites.Any(i => i.GuildId == guildId);
using var db = new BotDb();
return db.WhitelistedInvites.Any(i => i.GuildId == guildId);
}
public static async Task<bool> IsWhitelistedAsync(DiscordInvite invite)
{
var code = string.IsNullOrWhiteSpace(invite.Code) ? null : invite.Code;
var name = string.IsNullOrWhiteSpace(invite.Guild.Name) ? null : invite.Guild.Name;
using (var db = new BotDb())
{
var whitelistedInvite = await db.WhitelistedInvites.FirstOrDefaultAsync(i => i.GuildId == invite.Guild.Id);
if (whitelistedInvite == null)
return false;
using var db = new BotDb();
var whitelistedInvite = await db.WhitelistedInvites.FirstOrDefaultAsync(i => i.GuildId == invite.Guild.Id);
if (whitelistedInvite == null)
return false;
if (name != null && name != whitelistedInvite.Name)
whitelistedInvite.Name = invite.Guild.Name;
if (string.IsNullOrEmpty(whitelistedInvite.InviteCode) && code != null)
whitelistedInvite.InviteCode = code;
await db.SaveChangesAsync().ConfigureAwait(false);
return true;
}
if (name != null && name != whitelistedInvite.Name)
whitelistedInvite.Name = invite.Guild.Name;
if (string.IsNullOrEmpty(whitelistedInvite.InviteCode) && code != null)
whitelistedInvite.InviteCode = code;
await db.SaveChangesAsync().ConfigureAwait(false);
return true;
}
public static async Task<bool> AddAsync(DiscordInvite invite)
@@ -65,16 +63,14 @@ namespace CompatBot.Database.Providers
public static async Task<bool> RemoveAsync(int id)
{
using (var db = new BotDb())
{
var dbItem = await db.WhitelistedInvites.FirstOrDefaultAsync(i => i.Id == id).ConfigureAwait(false);
if (dbItem == null)
return false;
using var db = new BotDb();
var dbItem = await db.WhitelistedInvites.FirstOrDefaultAsync(i => i.Id == id).ConfigureAwait(false);
if (dbItem == null)
return false;
db.WhitelistedInvites.Remove(dbItem);
await db.SaveChangesAsync().ConfigureAwait(false);
return true;
}
db.WhitelistedInvites.Remove(dbItem);
await db.SaveChangesAsync().ConfigureAwait(false);
return true;
}
public static async Task CleanupAsync(DiscordClient client)

View File

@@ -48,30 +48,26 @@ namespace CompatBot.Database.Providers
throw new ArgumentException(nameof(locale));
var id = GetId(locale, containerId);
using (var db = new ThumbnailDb())
{
var timestamp = db.State.FirstOrDefault(s => s.Locale == id);
if (timestamp == null)
db.State.Add(new State {Locale = id, Timestamp = DateTime.UtcNow.Ticks});
else
timestamp.Timestamp = DateTime.UtcNow.Ticks;
await db.SaveChangesAsync().ConfigureAwait(false);
}
using var db = new ThumbnailDb();
var timestamp = db.State.FirstOrDefault(s => s.Locale == id);
if (timestamp == null)
db.State.Add(new State {Locale = id, Timestamp = DateTime.UtcNow.Ticks});
else
timestamp.Timestamp = DateTime.UtcNow.Ticks;
await db.SaveChangesAsync().ConfigureAwait(false);
}
public static async Task CleanAsync(CancellationToken cancellationToken)
{
using (var db = new ThumbnailDb())
{
var latestTimestamp = db.State.OrderByDescending(s => s.Timestamp).FirstOrDefault()?.Timestamp;
if (!latestTimestamp.HasValue)
return;
using var db = new ThumbnailDb();
var latestTimestamp = db.State.OrderByDescending(s => s.Timestamp).FirstOrDefault()?.Timestamp;
if (!latestTimestamp.HasValue)
return;
var cutOff = new DateTime(latestTimestamp.Value, DateTimeKind.Utc).Add(-CheckInterval);
var oldItems = db.State.Where(s => s.Timestamp < cutOff.Ticks);
db.State.RemoveRange(oldItems);
await db.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
}
var cutOff = new DateTime(latestTimestamp.Value, DateTimeKind.Utc).Add(-CheckInterval);
var oldItems = db.State.Where(s => s.Timestamp < cutOff.Ticks);
db.State.RemoveRange(oldItems);
await db.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
}
private static string GetId(string locale, string containerId)

View File

@@ -31,29 +31,27 @@ namespace CompatBot.Database.Providers
try
{
Config.Log.Debug("Got stats saving lock");
using (var db = new BotDb())
using var db = new BotDb();
db.Stats.RemoveRange(db.Stats);
await db.SaveChangesAsync().ConfigureAwait(false);
foreach (var cache in AllCaches)
{
db.Stats.RemoveRange(db.Stats);
await db.SaveChangesAsync().ConfigureAwait(false);
foreach (var cache in AllCaches)
{
var category = cache.name;
var entries = cache.cache.GetCacheEntries<string>();
var savedKeys = new HashSet<string>();
foreach (var entry in entries)
if (savedKeys.Add(entry.Key))
await db.Stats.AddAsync(new Stats
{
Category = category,
Key = entry.Key,
Value = ((int?) entry.Value.Value) ?? 0,
ExpirationTimestamp = entry.Value.AbsoluteExpiration?.ToUniversalTime().Ticks ?? 0
}).ConfigureAwait(false);
else
Config.Log.Warn($"Somehow there's another '{entry.Key}' in the {category} cache");
}
await db.SaveChangesAsync().ConfigureAwait(false);
var category = cache.name;
var entries = cache.cache.GetCacheEntries<string>();
var savedKeys = new HashSet<string>();
foreach (var entry in entries)
if (savedKeys.Add(entry.Key))
await db.Stats.AddAsync(new Stats
{
Category = category,
Key = entry.Key,
Value = ((int?) entry.Value.Value) ?? 0,
ExpirationTimestamp = entry.Value.AbsoluteExpiration?.ToUniversalTime().Ticks ?? 0
}).ConfigureAwait(false);
else
Config.Log.Warn($"Somehow there's another '{entry.Key}' in the {category} cache");
}
await db.SaveChangesAsync().ConfigureAwait(false);
}
catch(Exception e)
{
@@ -75,18 +73,18 @@ namespace CompatBot.Database.Providers
public static async Task RestoreAsync()
{
var now = DateTime.UtcNow;
using (var db = new BotDb())
foreach (var cache in AllCaches)
using var db = new BotDb();
foreach (var cache in AllCaches)
{
var category = cache.name;
var entries = await db.Stats.Where(e => e.Category == category).ToListAsync().ConfigureAwait(false);
foreach (var entry in entries)
{
var category = cache.name;
var entries = await db.Stats.Where(e => e.Category == category).ToListAsync().ConfigureAwait(false);
foreach (var entry in entries)
{
var time = entry.ExpirationTimestamp.AsUtc();
if (time > now)
cache.cache.Set(entry.Key, entry.Value, time);
}
var time = entry.ExpirationTimestamp.AsUtc();
if (time > now)
cache.cache.Set(entry.Key, entry.Value, time);
}
}
}
public static async Task BackgroundSaveAsync()

View File

@@ -23,29 +23,27 @@ namespace CompatBot.Database.Providers
{
try
{
using (var db = new ThumbnailDb())
using var db = new ThumbnailDb();
foreach (var productCodeMap in syscallInfo)
{
foreach (var productCodeMap in syscallInfo)
var product = db.Thumbnail.AsNoTracking().FirstOrDefault(t => t.ProductCode == productCodeMap.Key)
?? db.Thumbnail.Add(new Thumbnail {ProductCode = productCodeMap.Key}).Entity;
if (product.Id == 0)
await db.SaveChangesAsync(Config.Cts.Token).ConfigureAwait(false);
foreach (var moduleMap in productCodeMap.Value)
foreach (var func in moduleMap.Value)
{
var product = db.Thumbnail.AsNoTracking().FirstOrDefault(t => t.ProductCode == productCodeMap.Key)
?? db.Thumbnail.Add(new Thumbnail {ProductCode = productCodeMap.Key}).Entity;
if (product.Id == 0)
var syscall = db.SyscallInfo.AsNoTracking().FirstOrDefault(sci => sci.Module == moduleMap.Key.ToUtf8() && sci.Function == func.ToUtf8())
?? db.SyscallInfo.Add(new SyscallInfo {Module = moduleMap.Key.ToUtf8(), Function = func.ToUtf8() }).Entity;
if (syscall.Id == 0)
await db.SaveChangesAsync(Config.Cts.Token).ConfigureAwait(false);
foreach (var moduleMap in productCodeMap.Value)
foreach (var func in moduleMap.Value)
{
var syscall = db.SyscallInfo.AsNoTracking().FirstOrDefault(sci => sci.Module == moduleMap.Key.ToUtf8() && sci.Function == func.ToUtf8())
?? db.SyscallInfo.Add(new SyscallInfo {Module = moduleMap.Key.ToUtf8(), Function = func.ToUtf8() }).Entity;
if (syscall.Id == 0)
await db.SaveChangesAsync(Config.Cts.Token).ConfigureAwait(false);
if (!db.SyscallToProductMap.Any(m => m.ProductId == product.Id && m.SyscallInfoId == syscall.Id))
db.SyscallToProductMap.Add(new SyscallToProductMap {ProductId = product.Id, SyscallInfoId = syscall.Id});
}
if (!db.SyscallToProductMap.Any(m => m.ProductId == product.Id && m.SyscallInfoId == syscall.Id))
db.SyscallToProductMap.Add(new SyscallToProductMap {ProductId = product.Id, SyscallInfoId = syscall.Id});
}
await db.SaveChangesAsync(Config.Cts.Token).ConfigureAwait(false);
}
await db.SaveChangesAsync(Config.Cts.Token).ConfigureAwait(false);
}
finally
{

View File

@@ -70,41 +70,39 @@ namespace CompatBot.Database.Providers
return null;
productCode = productCode.ToUpperInvariant();
using (var db = new ThumbnailDb())
{
var thumb = await db.Thumbnail.FirstOrDefaultAsync(
t => t.ProductCode == productCode,
cancellationToken: cancellationToken
).ConfigureAwait(false);
if (thumb?.Name is string title)
return title;
var meta = await PsnClient.GetTitleMetaAsync(productCode, cancellationToken).ConfigureAwait(false);
title = meta?.Name;
try
{
if (!string.IsNullOrEmpty(title))
{
if (thumb == null)
thumb = (
await db.Thumbnail.AddAsync(new Thumbnail
{
ProductCode = productCode,
Name = title,
}, cancellationToken).ConfigureAwait(false)
).Entity;
else
thumb.Name = title;
await db.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
}
}
catch (Exception e)
{
Config.Log.Warn(e);
}
using var db = new ThumbnailDb();
var thumb = await db.Thumbnail.FirstOrDefaultAsync(
t => t.ProductCode == productCode,
cancellationToken: cancellationToken
).ConfigureAwait(false);
if (thumb?.Name is string title)
return title;
var meta = await PsnClient.GetTitleMetaAsync(productCode, cancellationToken).ConfigureAwait(false);
title = meta?.Name;
try
{
if (!string.IsNullOrEmpty(title))
{
if (thumb == null)
thumb = (
await db.Thumbnail.AddAsync(new Thumbnail
{
ProductCode = productCode,
Name = title,
}, cancellationToken).ConfigureAwait(false)
).Entity;
else
thumb.Name = title;
await db.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
}
}
catch (Exception e)
{
Config.Log.Warn(e);
}
return title;
}
public static async Task<(string url, DiscordColor color)> GetThumbnailUrlWithColorAsync(DiscordClient client, string contentId, DiscordColor defaultColor, string url = null)
@@ -113,50 +111,48 @@ namespace CompatBot.Database.Providers
throw new ArgumentException("ContentID can't be empty", nameof(contentId));
contentId = contentId.ToUpperInvariant();
using (var db = new ThumbnailDb())
using var db = new ThumbnailDb();
var info = await db.TitleInfo.FirstOrDefaultAsync(ti => ti.ContentId == contentId, Config.Cts.Token).ConfigureAwait(false);
if (info == null)
{
var info = await db.TitleInfo.FirstOrDefaultAsync(ti => ti.ContentId == contentId, Config.Cts.Token).ConfigureAwait(false);
if (info == null)
info = new TitleInfo {ContentId = contentId, ThumbnailUrl = url, Timestamp = DateTime.UtcNow.Ticks};
var thumb = await db.Thumbnail.FirstOrDefaultAsync(t => t.ContentId == contentId).ConfigureAwait(false);
if (thumb?.EmbeddableUrl is string eUrl
&& thumb.Url is string thumbUrl
&& thumbUrl == url)
info.ThumbnailEmbeddableUrl = eUrl;
info = db.TitleInfo.Add(info).Entity;
await db.SaveChangesAsync(Config.Cts.Token).ConfigureAwait(false);
}
DiscordColor? analyzedColor = null;
if (string.IsNullOrEmpty(info.ThumbnailEmbeddableUrl))
{
var em = await GetEmbeddableUrlAsync(client, contentId, info.ThumbnailUrl).ConfigureAwait(false);
if (em.url is string eUrl)
{
info = new TitleInfo {ContentId = contentId, ThumbnailUrl = url, Timestamp = DateTime.UtcNow.Ticks};
var thumb = await db.Thumbnail.FirstOrDefaultAsync(t => t.ContentId == contentId).ConfigureAwait(false);
if (thumb?.EmbeddableUrl is string eUrl
&& thumb.Url is string thumbUrl
&& thumbUrl == url)
info.ThumbnailEmbeddableUrl = eUrl;
info = db.TitleInfo.Add(info).Entity;
info.ThumbnailEmbeddableUrl = eUrl;
if (em.image is byte[] jpg)
{
analyzedColor = ColorGetter.Analyze(jpg, defaultColor);
var c = analyzedColor.Value.Value;
if (c != defaultColor.Value)
info.EmbedColor = c;
}
await db.SaveChangesAsync(Config.Cts.Token).ConfigureAwait(false);
}
DiscordColor? analyzedColor = null;
if (string.IsNullOrEmpty(info.ThumbnailEmbeddableUrl))
{
var em = await GetEmbeddableUrlAsync(client, contentId, info.ThumbnailUrl).ConfigureAwait(false);
if (em.url is string eUrl)
{
info.ThumbnailEmbeddableUrl = eUrl;
if (em.image is byte[] jpg)
{
analyzedColor = ColorGetter.Analyze(jpg, defaultColor);
var c = analyzedColor.Value.Value;
if (c != defaultColor.Value)
info.EmbedColor = c;
}
await db.SaveChangesAsync(Config.Cts.Token).ConfigureAwait(false);
}
}
if ((!info.EmbedColor.HasValue && !analyzedColor.HasValue)
|| (info.EmbedColor.HasValue && info.EmbedColor.Value == defaultColor.Value))
{
var c = await GetImageColorAsync(info.ThumbnailEmbeddableUrl, defaultColor).ConfigureAwait(false);
if (c.HasValue && c.Value.Value != defaultColor.Value)
{
info.EmbedColor = c.Value.Value;
await db.SaveChangesAsync(Config.Cts.Token).ConfigureAwait(false);
}
}
var color = info.EmbedColor.HasValue ? new DiscordColor(info.EmbedColor.Value) : defaultColor;
return (info.ThumbnailEmbeddableUrl, color);
}
if ((!info.EmbedColor.HasValue && !analyzedColor.HasValue)
|| (info.EmbedColor.HasValue && info.EmbedColor.Value == defaultColor.Value))
{
var c = await GetImageColorAsync(info.ThumbnailEmbeddableUrl, defaultColor).ConfigureAwait(false);
if (c.HasValue && c.Value.Value != defaultColor.Value)
{
info.EmbedColor = c.Value.Value;
await db.SaveChangesAsync(Config.Cts.Token).ConfigureAwait(false);
}
}
var color = info.EmbedColor.HasValue ? new DiscordColor(info.EmbedColor.Value) : defaultColor;
return (info.ThumbnailEmbeddableUrl, color);
}
public static async Task<(string url, byte[] image)> GetEmbeddableUrlAsync(DiscordClient client, string contentId, string url)
@@ -166,20 +162,18 @@ namespace CompatBot.Database.Providers
if (!string.IsNullOrEmpty(Path.GetExtension(url)))
return (url, null);
using (var imgStream = await HttpClient.GetStreamAsync(url).ConfigureAwait(false))
using (var memStream = new MemoryStream())
{
await imgStream.CopyToAsync(memStream).ConfigureAwait(false);
// minimum jpg size is 119 bytes, png is 67 bytes
if (memStream.Length < 64)
return (null, null);
using var imgStream = await HttpClient.GetStreamAsync(url).ConfigureAwait(false);
using var memStream = new MemoryStream();
await imgStream.CopyToAsync(memStream).ConfigureAwait(false);
// minimum jpg size is 119 bytes, png is 67 bytes
if (memStream.Length < 64)
return (null, null);
memStream.Seek(0, SeekOrigin.Begin);
var spam = await client.GetChannelAsync(Config.ThumbnailSpamId).ConfigureAwait(false);
var message = await spam.SendFileAsync(contentId + ".jpg", memStream, contentId).ConfigureAwait(false);
url = message.Attachments.First().Url;
return (url, memStream.ToArray());
}
memStream.Seek(0, SeekOrigin.Begin);
var spam = await client.GetChannelAsync(Config.ThumbnailSpamId).ConfigureAwait(false);
var message = await spam.SendFileAsync(contentId + ".jpg", memStream, contentId).ConfigureAwait(false);
url = message.Attachments.First().Url;
return (url, memStream.ToArray());
}
catch (Exception e)
{
@@ -195,18 +189,16 @@ namespace CompatBot.Database.Providers
if (string.IsNullOrEmpty(url))
return null;
using (var imgStream = await HttpClient.GetStreamAsync(url).ConfigureAwait(false))
using (var memStream = new MemoryStream())
{
await imgStream.CopyToAsync(memStream).ConfigureAwait(false);
// minimum jpg size is 119 bytes, png is 67 bytes
if (memStream.Length < 64)
return null;
using var imgStream = await HttpClient.GetStreamAsync(url).ConfigureAwait(false);
using var memStream = new MemoryStream();
await imgStream.CopyToAsync(memStream).ConfigureAwait(false);
// minimum jpg size is 119 bytes, png is 67 bytes
if (memStream.Length < 64)
return null;
memStream.Seek(0, SeekOrigin.Begin);
memStream.Seek(0, SeekOrigin.Begin);
return ColorGetter.Analyze(memStream.ToArray(), defaultColor);
}
return ColorGetter.Analyze(memStream.ToArray(), defaultColor);
}
catch (Exception e)
{

View File

@@ -56,12 +56,10 @@ namespace CompatBot.EventHandlers
}
else if (match.Groups["job_id"].Value is string jobId && !string.IsNullOrEmpty(jobId))
{
using (var timeoutCts = new CancellationTokenSource(Config.LogParsingTimeout))
using (var combinedCts = CancellationTokenSource.CreateLinkedTokenSource(Config.Cts.Token, timeoutCts.Token))
{
var buildInfo = await AppveyorClient.GetBuildAsync(jobId, combinedCts.Token).ConfigureAwait(false);
pr = buildInfo?.PullRequestId;
}
using var timeoutCts = new CancellationTokenSource(Config.LogParsingTimeout);
using var combinedCts = CancellationTokenSource.CreateLinkedTokenSource(Config.Cts.Token, timeoutCts.Token);
var buildInfo = await AppveyorClient.GetBuildAsync(jobId, combinedCts.Token).ConfigureAwait(false);
pr = buildInfo?.PullRequestId;
}
if (pr > 0)
await Commands.Pr.LinkPrBuild(args.Client, args.Message, pr.Value).ConfigureAwait(false);

View File

@@ -126,31 +126,31 @@ namespace CompatBot.EventHandlers
#endif
if (!string.IsNullOrEmpty(args.Message.Content) && Paws.Matches(args.Message.Content) is MatchCollection mc)
using (var db = new BotDb())
{
using var db = new BotDb();
var matchedGroups = (from m in mc
from Group g in m.Groups
where g.Success && !string.IsNullOrEmpty(g.Value)
select g.Name
).Distinct()
.ToArray();
if (matchedGroups.Contains("kot"))
{
var matchedGroups = (from m in mc
from Group g in m.Groups
where g.Success && !string.IsNullOrEmpty(g.Value)
select g.Name
).Distinct()
.ToArray();
if (matchedGroups.Contains("kot"))
if (!db.Kot.Any(k => k.UserId == args.Author.Id))
{
if (!db.Kot.Any(k => k.UserId == args.Author.Id))
{
db.Kot.Add(new Kot {UserId = args.Author.Id});
await db.SaveChangesAsync().ConfigureAwait(false);
}
}
if (matchedGroups.Contains("doggo"))
{
if (!db.Doggo.Any(d => d.UserId == args.Author.Id))
{
db.Doggo.Add(new Doggo {UserId = args.Author.Id});
await db.SaveChangesAsync().ConfigureAwait(false);
}
db.Kot.Add(new Kot {UserId = args.Author.Id});
await db.SaveChangesAsync().ConfigureAwait(false);
}
}
if (matchedGroups.Contains("doggo"))
{
if (!db.Doggo.Any(d => d.UserId == args.Author.Id))
{
db.Doggo.Add(new Doggo {UserId = args.Author.Id});
await db.SaveChangesAsync().ConfigureAwait(false);
}
}
}
var (needToSilence, needToThank) = NeedToSilence(args.Message);
if (!(needToSilence || needToThank))

View File

@@ -16,15 +16,13 @@ namespace CompatBot.EventHandlers
try
{
using (var db = new BotDb())
{
var status = await db.BotState.FirstOrDefaultAsync(s => s.Key == "bot-status-activity").ConfigureAwait(false);
var txt = await db.BotState.FirstOrDefaultAsync(s => s.Key == "bot-status-text").ConfigureAwait(false);
var msg = txt?.Value;
if (Enum.TryParse(status?.Value ?? "Watching", true, out ActivityType activity)
&& !string.IsNullOrEmpty(msg))
await client.UpdateStatusAsync(new DiscordActivity(msg, activity), UserStatus.Online).ConfigureAwait(false);
}
using var db = new BotDb();
var status = await db.BotState.FirstOrDefaultAsync(s => s.Key == "bot-status-activity").ConfigureAwait(false);
var txt = await db.BotState.FirstOrDefaultAsync(s => s.Key == "bot-status-text").ConfigureAwait(false);
var msg = txt?.Value;
if (Enum.TryParse(status?.Value ?? "Watching", true, out ActivityType activity)
&& !string.IsNullOrEmpty(msg))
await client.UpdateStatusAsync(new DiscordActivity(msg, activity), UserStatus.Online).ConfigureAwait(false);
}
catch (Exception e)
{

View File

@@ -200,28 +200,24 @@ namespace CompatBot.EventHandlers
{
try
{
using (var request = new HttpRequestMessage(HttpMethod.Get, "https://discord.me/" + meLink))
using var request = new HttpRequestMessage(HttpMethod.Get, "https://discord.me/" + meLink);
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("text/html"));
request.Headers.CacheControl = CacheControlHeaderValue.Parse("no-cache");
request.Headers.UserAgent.Add(new ProductInfoHeaderValue("RPCS3CompatibilityBot", "2.0"));
using var response = await HttpClient.SendAsync(request);
var html = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
if (response.IsSuccessStatusCode)
{
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("text/html"));
request.Headers.CacheControl = CacheControlHeaderValue.Parse("no-cache");
request.Headers.UserAgent.Add(new ProductInfoHeaderValue("RPCS3CompatibilityBot", "2.0"));
using (var response = await HttpClient.SendAsync(request))
{
var html = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
if (response.IsSuccessStatusCode)
{
if (string.IsNullOrEmpty(html))
continue;
if (string.IsNullOrEmpty(html))
continue;
foreach (Match match in DiscordInviteLink.Matches(html))
inviteCodes.Add(match.Groups["invite_id"].Value);
}
else
{
hasInvalidInvites = true;
Config.Log.Warn($"Got {response.StatusCode} from discord.me: {html}");
}
}
foreach (Match match in DiscordInviteLink.Matches(html))
inviteCodes.Add(match.Groups["invite_id"].Value);
}
else
{
hasInvalidInvites = true;
Config.Log.Warn($"Got {response.StatusCode} from discord.me: {html}");
}
}
catch (Exception e)

View File

@@ -10,15 +10,13 @@ namespace CompatBot.EventHandlers
{
public static async Task OnMemberAdded(GuildMemberAddEventArgs args)
{
using (var db = new BotDb())
using var db = new BotDb();
var explanation = await db.Explanation.FirstOrDefaultAsync(e => e.Keyword == "motd").ConfigureAwait(false);
if (explanation != null)
{
var explanation = await db.Explanation.FirstOrDefaultAsync(e => e.Keyword == "motd").ConfigureAwait(false);
if (explanation != null)
{
var dm = await args.Member.CreateDmChannelAsync().ConfigureAwait(false);
await dm.SendMessageAsync(explanation.Text, explanation.Attachment, explanation.AttachmentFilename).ConfigureAwait(false);
Config.Log.Info($"Sent motd to {args.Member.GetMentionWithNickname()}");
}
var dm = await args.Member.CreateDmChannelAsync().ConfigureAwait(false);
await dm.SendMessageAsync(explanation.Text, explanation.Attachment, explanation.AttachmentFilename).ConfigureAwait(false);
Config.Log.Info($"Sent motd to {args.Member.GetMentionWithNickname()}");
}
}
}

View File

@@ -31,33 +31,31 @@ namespace CompatBot.EventHandlers.LogParsing.ArchiveHandlers
public async Task FillPipeAsync(Stream sourceStream, PipeWriter writer, CancellationToken cancellationToken)
{
using (var statsStream = new BufferCopyStream(sourceStream) )
using (var gzipStream = new GZipStream(statsStream, CompressionMode.Decompress))
using var statsStream = new BufferCopyStream(sourceStream);
using var gzipStream = new GZipStream(statsStream, CompressionMode.Decompress);
try
{
try
int read;
FlushResult flushed;
do
{
int read;
FlushResult flushed;
do
{
var memory = writer.GetMemory(Config.MinimumBufferSize);
read = await gzipStream.ReadAsync(memory, cancellationToken);
writer.Advance(read);
SourcePosition = statsStream.Position;
flushed = await writer.FlushAsync(cancellationToken).ConfigureAwait(false);
SourcePosition = statsStream.Position;
} while (read > 0 && !(flushed.IsCompleted || flushed.IsCanceled || cancellationToken.IsCancellationRequested));
var memory = writer.GetMemory(Config.MinimumBufferSize);
read = await gzipStream.ReadAsync(memory, cancellationToken);
writer.Advance(read);
SourcePosition = statsStream.Position;
flushed = await writer.FlushAsync(cancellationToken).ConfigureAwait(false);
SourcePosition = statsStream.Position;
} while (read > 0 && !(flushed.IsCompleted || flushed.IsCanceled || cancellationToken.IsCancellationRequested));
var buf = statsStream.GetBufferedBytes();
if (buf.Length > 3)
LogSize = BitConverter.ToInt32(buf.AsSpan(buf.Length - 4, 4));
}
catch (Exception e)
{
Config.Log.Error(e, "Error filling the log pipe");
writer.Complete(e);
return;
}
var buf = statsStream.GetBufferedBytes();
if (buf.Length > 3)
LogSize = BitConverter.ToInt32(buf.AsSpan(buf.Length - 4, 4));
}
catch (Exception e)
{
Config.Log.Error(e, "Error filling the log pipe");
writer.Complete(e);
return;
}
writer.Complete();
}

View File

@@ -36,34 +36,32 @@ namespace CompatBot.EventHandlers.LogParsing.ArchiveHandlers
{
try
{
using (var statsStream = new BufferCopyStream(sourceStream))
using (var rarReader = RarReader.Open(statsStream))
while (rarReader.MoveToNextEntry())
using var statsStream = new BufferCopyStream(sourceStream);
using var rarReader = RarReader.Open(statsStream);
while (rarReader.MoveToNextEntry())
{
if (!rarReader.Entry.IsDirectory
&& rarReader.Entry.Key.EndsWith(".log", StringComparison.InvariantCultureIgnoreCase)
&& !rarReader.Entry.Key.Contains("tty.log", StringComparison.InvariantCultureIgnoreCase))
{
if (!rarReader.Entry.IsDirectory
&& rarReader.Entry.Key.EndsWith(".log", StringComparison.InvariantCultureIgnoreCase)
&& !rarReader.Entry.Key.Contains("tty.log", StringComparison.InvariantCultureIgnoreCase))
LogSize = rarReader.Entry.Size;
using var rarStream = rarReader.OpenEntryStream();
int read;
FlushResult flushed;
do
{
LogSize = rarReader.Entry.Size;
using (var rarStream = rarReader.OpenEntryStream())
{
int read;
FlushResult flushed;
do
{
var memory = writer.GetMemory(Config.MinimumBufferSize);
read = await rarStream.ReadAsync(memory, cancellationToken);
writer.Advance(read);
SourcePosition = statsStream.Position;
flushed = await writer.FlushAsync(cancellationToken).ConfigureAwait(false);
SourcePosition = statsStream.Position;
} while (read > 0 && !(flushed.IsCompleted || flushed.IsCanceled || cancellationToken.IsCancellationRequested));
}
writer.Complete();
return;
}
SourcePosition = statsStream.Position;
var memory = writer.GetMemory(Config.MinimumBufferSize);
read = await rarStream.ReadAsync(memory, cancellationToken);
writer.Advance(read);
SourcePosition = statsStream.Position;
flushed = await writer.FlushAsync(cancellationToken).ConfigureAwait(false);
SourcePosition = statsStream.Position;
} while (read > 0 && !(flushed.IsCompleted || flushed.IsCanceled || cancellationToken.IsCancellationRequested));
writer.Complete();
return;
}
SourcePosition = statsStream.Position;
}
Config.Log.Warn("No rar entries that match the log criteria");
}
catch (Exception e)

View File

@@ -33,35 +33,31 @@ namespace CompatBot.EventHandlers.LogParsing.ArchiveHandlers
{
try
{
using (var fileStream = new FileStream(Path.GetTempFileName(), FileMode.Create, FileAccess.ReadWrite, FileShare.Read, 16384, FileOptions.Asynchronous | FileOptions.RandomAccess | FileOptions.DeleteOnClose))
{
await sourceStream.CopyToAsync(fileStream, 16384, cancellationToken).ConfigureAwait(false);
fileStream.Seek(0, SeekOrigin.Begin);
using (var zipArchive = SevenZipArchive.Open(fileStream))
using (var zipReader = zipArchive.ExtractAllEntries())
while (zipReader.MoveToNextEntry())
if (!zipReader.Entry.IsDirectory
&& zipReader.Entry.Key.EndsWith(".log", StringComparison.InvariantCultureIgnoreCase)
&& !zipReader.Entry.Key.Contains("tty.log", StringComparison.InvariantCultureIgnoreCase))
{
LogSize = zipReader.Entry.Size;
using (var entryStream = zipReader.OpenEntryStream())
{
int read;
FlushResult flushed;
do
{
var memory = writer.GetMemory(Config.MinimumBufferSize);
read = await entryStream.ReadAsync(memory, cancellationToken);
writer.Advance(read);
flushed = await writer.FlushAsync(cancellationToken).ConfigureAwait(false);
} while (read > 0 && !(flushed.IsCompleted || flushed.IsCanceled || cancellationToken.IsCancellationRequested));
}
writer.Complete();
return;
}
Config.Log.Warn("No 7z entries that match the log criteria");
}
using var fileStream = new FileStream(Path.GetTempFileName(), FileMode.Create, FileAccess.ReadWrite, FileShare.Read, 16384, FileOptions.Asynchronous | FileOptions.RandomAccess | FileOptions.DeleteOnClose);
await sourceStream.CopyToAsync(fileStream, 16384, cancellationToken).ConfigureAwait(false);
fileStream.Seek(0, SeekOrigin.Begin);
using var zipArchive = SevenZipArchive.Open(fileStream);
using var zipReader = zipArchive.ExtractAllEntries();
while (zipReader.MoveToNextEntry())
if (!zipReader.Entry.IsDirectory
&& zipReader.Entry.Key.EndsWith(".log", StringComparison.InvariantCultureIgnoreCase)
&& !zipReader.Entry.Key.Contains("tty.log", StringComparison.InvariantCultureIgnoreCase))
{
LogSize = zipReader.Entry.Size;
using var entryStream = zipReader.OpenEntryStream();
int read;
FlushResult flushed;
do
{
var memory = writer.GetMemory(Config.MinimumBufferSize);
read = await entryStream.ReadAsync(memory, cancellationToken);
writer.Advance(read);
flushed = await writer.FlushAsync(cancellationToken).ConfigureAwait(false);
} while (read > 0 && !(flushed.IsCompleted || flushed.IsCanceled || cancellationToken.IsCancellationRequested));
writer.Complete();
return;
}
Config.Log.Warn("No 7z entries that match the log criteria");
}
catch (Exception e)
{

View File

@@ -36,34 +36,32 @@ namespace CompatBot.EventHandlers.LogParsing.ArchiveHandlers
{
try
{
using (var statsStream = new BufferCopyStream(sourceStream))
using (var zipReader = ZipReader.Open(statsStream))
while (zipReader.MoveToNextEntry())
using var statsStream = new BufferCopyStream(sourceStream);
using var zipReader = ZipReader.Open(statsStream);
while (zipReader.MoveToNextEntry())
{
if (!zipReader.Entry.IsDirectory
&& zipReader.Entry.Key.EndsWith(".log", StringComparison.InvariantCultureIgnoreCase)
&& !zipReader.Entry.Key.Contains("tty.log", StringComparison.InvariantCultureIgnoreCase))
{
if (!zipReader.Entry.IsDirectory
&& zipReader.Entry.Key.EndsWith(".log", StringComparison.InvariantCultureIgnoreCase)
&& !zipReader.Entry.Key.Contains("tty.log", StringComparison.InvariantCultureIgnoreCase))
LogSize = zipReader.Entry.Size;
using var rarStream = zipReader.OpenEntryStream();
int read;
FlushResult flushed;
do
{
LogSize = zipReader.Entry.Size;
using (var rarStream = zipReader.OpenEntryStream())
{
int read;
FlushResult flushed;
do
{
var memory = writer.GetMemory(Config.MinimumBufferSize);
read = await rarStream.ReadAsync(memory, cancellationToken);
writer.Advance(read);
SourcePosition = statsStream.Position;
flushed = await writer.FlushAsync(cancellationToken).ConfigureAwait(false);
SourcePosition = statsStream.Position;
} while (read > 0 && !(flushed.IsCompleted || flushed.IsCanceled || cancellationToken.IsCancellationRequested));
}
writer.Complete();
return;
}
SourcePosition = statsStream.Position;
var memory = writer.GetMemory(Config.MinimumBufferSize);
read = await rarStream.ReadAsync(memory, cancellationToken);
writer.Advance(read);
SourcePosition = statsStream.Position;
flushed = await writer.FlushAsync(cancellationToken).ConfigureAwait(false);
SourcePosition = statsStream.Position;
} while (read > 0 && !(flushed.IsCompleted || flushed.IsCanceled || cancellationToken.IsCancellationRequested));
writer.Complete();
return;
}
SourcePosition = statsStream.Position;
}
Config.Log.Warn("No rar entries that match the log criteria");
}
catch (Exception e)

View File

@@ -14,44 +14,42 @@ namespace CompatBot.EventHandlers.LogParsing.SourceHandlers
{
public override async Task<(ISource source, string failReason)> FindHandlerAsync(DiscordMessage message, ICollection<IArchiveHandler> handlers)
{
using (var client = HttpClientFactory.Create())
foreach (var attachment in message.Attachments)
using var client = HttpClientFactory.Create();
foreach (var attachment in message.Attachments)
{
try
{
using var stream = await client.GetStreamAsync(attachment.Url).ConfigureAwait(false);
var buf = bufferPool.Rent(1024);
try
{
using (var stream = await client.GetStreamAsync(attachment.Url).ConfigureAwait(false))
var read = await stream.ReadBytesAsync(buf).ConfigureAwait(false);
foreach (var handler in handlers)
{
var buf = bufferPool.Rent(1024);
try
{
var read = await stream.ReadBytesAsync(buf).ConfigureAwait(false);
foreach (var handler in handlers)
{
var (canHandle, reason) = handler.CanHandle(attachment.FileName, attachment.FileSize, buf.AsSpan(0, read));
if (canHandle)
return (new DiscordAttachmentSource(attachment, handler, attachment.FileName, attachment.FileSize), null);
else if (!string.IsNullOrEmpty(reason))
return (null, reason);
}
}
finally
{
bufferPool.Return(buf);
}
var (canHandle, reason) = handler.CanHandle(attachment.FileName, attachment.FileSize, buf.AsSpan(0, read));
if (canHandle)
return (new DiscordAttachmentSource(attachment, handler, attachment.FileName, attachment.FileSize), null);
else if (!string.IsNullOrEmpty(reason))
return (null, reason);
}
}
catch (Exception e)
finally
{
Config.Log.Error(e, "Error sniffing the rar content");
bufferPool.Return(buf);
}
}
catch (Exception e)
{
Config.Log.Error(e, "Error sniffing the rar content");
}
}
return (null, null);
}
private sealed class DiscordAttachmentSource : ISource
{
private DiscordAttachment attachment;
private IArchiveHandler handler;
private readonly DiscordAttachment attachment;
private readonly IArchiveHandler handler;
public string SourceType => "Discord attachment";
public string FileName { get; }
@@ -69,9 +67,9 @@ namespace CompatBot.EventHandlers.LogParsing.SourceHandlers
public async Task FillPipeAsync(PipeWriter writer, CancellationToken cancellationToken)
{
using (var client = HttpClientFactory.Create())
using (var stream = await client.GetStreamAsync(attachment.Url).ConfigureAwait(false))
await handler.FillPipeAsync(stream, writer, cancellationToken).ConfigureAwait(false);
using var client = HttpClientFactory.Create();
using var stream = await client.GetStreamAsync(attachment.Url).ConfigureAwait(false);
await handler.FillPipeAsync(stream, writer, cancellationToken).ConfigureAwait(false);
}
}
}

View File

@@ -27,64 +27,62 @@ namespace CompatBot.EventHandlers.LogParsing.SourceHandlers
if (matches.Count == 0)
return (null, null);
using (var client = HttpClientFactory.Create())
foreach (Match m in matches)
using var client = HttpClientFactory.Create();
foreach (Match m in matches)
{
if (m.Groups["dropbox_link"].Value is string lnk
&& !string.IsNullOrEmpty(lnk)
&& Uri.TryCreate(lnk, UriKind.Absolute, out var uri))
{
if (m.Groups["dropbox_link"].Value is string lnk
&& !string.IsNullOrEmpty(lnk)
&& Uri.TryCreate(lnk, UriKind.Absolute, out var uri))
try
{
uri = uri.SetQueryParameter("dl", "1");
var filename = Path.GetFileName(lnk);
var filesize = -1;
using (var request = new HttpRequestMessage(HttpMethod.Head, uri))
{
using var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, Config.Cts.Token);
if (response?.Content?.Headers?.ContentLength > 0)
filesize = (int)response.Content.Headers.ContentLength.Value;
if (response?.Content?.Headers?.ContentDisposition?.FileNameStar is string fname && !string.IsNullOrEmpty(fname))
filename = fname;
uri = response.RequestMessage.RequestUri;
}
using var stream = await client.GetStreamAsync(uri).ConfigureAwait(false);
var buf = bufferPool.Rent(1024);
try
{
uri = uri.SetQueryParameter("dl", "1");
var filename = Path.GetFileName(lnk);
var filesize = -1;
using (var request = new HttpRequestMessage(HttpMethod.Head, uri))
using (var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, Config.Cts.Token))
var read = await stream.ReadBytesAsync(buf).ConfigureAwait(false);
foreach (var handler in handlers)
{
if (response?.Content?.Headers?.ContentLength > 0)
filesize = (int)response.Content.Headers.ContentLength.Value;
if (response?.Content?.Headers?.ContentDisposition?.FileNameStar is string fname && !string.IsNullOrEmpty(fname))
filename = fname;
uri = response.RequestMessage.RequestUri;
}
using (var stream = await client.GetStreamAsync(uri).ConfigureAwait(false))
{
var buf = bufferPool.Rent(1024);
try
{
var read = await stream.ReadBytesAsync(buf).ConfigureAwait(false);
foreach (var handler in handlers)
{
var (canHandle, reason) = handler.CanHandle(filename, filesize, buf.AsSpan(0, read));
if (canHandle)
return (new DropboxSource(uri, handler, filename, filesize), null);
else if (!string.IsNullOrEmpty(reason))
return (null, reason);
}
}
finally
{
bufferPool.Return(buf);
}
var (canHandle, reason) = handler.CanHandle(filename, filesize, buf.AsSpan(0, read));
if (canHandle)
return (new DropboxSource(uri, handler, filename, filesize), null);
else if (!string.IsNullOrEmpty(reason))
return (null, reason);
}
}
catch (Exception e)
finally
{
Config.Log.Warn(e, $"Error sniffing {m.Groups["dropbox_link"].Value}");
bufferPool.Return(buf);
}
}
catch (Exception e)
{
Config.Log.Warn(e, $"Error sniffing {m.Groups["dropbox_link"].Value}");
}
}
}
return (null, null);
}
private sealed class DropboxSource : ISource
{
private Uri uri;
private IArchiveHandler handler;
private readonly Uri uri;
private readonly IArchiveHandler handler;
public string SourceType => "Dropbox";
public string FileName { get; }
@@ -102,9 +100,9 @@ namespace CompatBot.EventHandlers.LogParsing.SourceHandlers
public async Task FillPipeAsync(PipeWriter writer, CancellationToken cancellationToken)
{
using (var client = HttpClientFactory.Create())
using (var stream = await client.GetStreamAsync(uri).ConfigureAwait(false))
await handler.FillPipeAsync(stream, writer, cancellationToken).ConfigureAwait(false);
using var client = HttpClientFactory.Create();
using var stream = await client.GetStreamAsync(uri).ConfigureAwait(false);
await handler.FillPipeAsync(stream, writer, cancellationToken).ConfigureAwait(false);
}
}
}

View File

@@ -31,25 +31,23 @@ namespace CompatBot.EventHandlers.LogParsing.SourceHandlers
public async Task FillPipeAsync(PipeWriter writer, CancellationToken cancellationToken)
{
using (var stream = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read))
await handler.FillPipeAsync(stream, writer, cancellationToken).ConfigureAwait(false);
using var stream = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read);
await handler.FillPipeAsync(stream, writer, cancellationToken).ConfigureAwait(false);
}
public static async Task<ISource> DetectArchiveHandlerAsync(string path, ICollection<IArchiveHandler> handlers)
{
var buf = new byte[1024];
using (var stream = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read))
using var stream = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read);
var read = await stream.ReadBytesAsync(buf).ConfigureAwait(false);
foreach (var handler in handlers)
{
var read = await stream.ReadBytesAsync(buf).ConfigureAwait(false);
foreach (var handler in handlers)
{
var (canHandle, reason) = handler.CanHandle(Path.GetFileName(path), (int)stream.Length, buf.AsSpan(0, read));
if (canHandle)
return new FileSource(path, handler);
else if (!string.IsNullOrEmpty(reason))
throw new InvalidOperationException(reason);
}
var (canHandle, reason) = handler.CanHandle(Path.GetFileName(path), (int)stream.Length, buf.AsSpan(0, read));
if (canHandle)
return new FileSource(path, handler);
if (!string.IsNullOrEmpty(reason))
throw new InvalidOperationException(reason);
}
throw new InvalidOperationException("Unknown source type");
}

View File

@@ -25,65 +25,63 @@ namespace CompatBot.EventHandlers.LogParsing.SourceHandlers
if (matches.Count == 0)
return (null, null);
using (var client = HttpClientFactory.Create())
foreach (Match m in matches)
using var client = HttpClientFactory.Create();
foreach (Match m in matches)
{
if (m.Groups["link"].Value is string lnk
&& !string.IsNullOrEmpty(lnk)
&& Uri.TryCreate(lnk, UriKind.Absolute, out var uri)
&& !"tty.log".Equals(m.Groups["filename"].Value, StringComparison.InvariantCultureIgnoreCase))
{
if (m.Groups["link"].Value is string lnk
&& !string.IsNullOrEmpty(lnk)
&& Uri.TryCreate(lnk, UriKind.Absolute, out var uri)
&& !"tty.log".Equals(m.Groups["filename"].Value, StringComparison.InvariantCultureIgnoreCase))
try
{
var host = uri.Host;
var filename = Path.GetFileName(lnk);
var filesize = -1;
using (var request = new HttpRequestMessage(HttpMethod.Head, uri))
{
using var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, Config.Cts.Token);
if (response?.Content?.Headers?.ContentLength > 0)
filesize = (int)response.Content.Headers.ContentLength.Value;
if (response?.Content?.Headers?.ContentDisposition?.FileNameStar is string fname && !string.IsNullOrEmpty(fname))
filename = fname;
uri = response.RequestMessage.RequestUri;
}
using var stream = await client.GetStreamAsync(uri).ConfigureAwait(false);
var buf = bufferPool.Rent(1024);
try
{
var host = uri.Host;
var filename = Path.GetFileName(lnk);
var filesize = -1;
using (var request = new HttpRequestMessage(HttpMethod.Head, uri))
using (var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, Config.Cts.Token))
var read = await stream.ReadBytesAsync(buf).ConfigureAwait(false);
foreach (var handler in handlers)
{
if (response?.Content?.Headers?.ContentLength > 0)
filesize = (int)response.Content.Headers.ContentLength.Value;
if (response?.Content?.Headers?.ContentDisposition?.FileNameStar is string fname && !string.IsNullOrEmpty(fname))
filename = fname;
uri = response.RequestMessage.RequestUri;
}
using (var stream = await client.GetStreamAsync(uri).ConfigureAwait(false))
{
var buf = bufferPool.Rent(1024);
try
{
var read = await stream.ReadBytesAsync(buf).ConfigureAwait(false);
foreach (var handler in handlers)
{
var (canHandle, reason) = handler.CanHandle(filename, filesize, buf.AsSpan(0, read));
if (canHandle)
return (new GenericSource(uri, handler, host, filename, filesize), null);
else if (!string.IsNullOrEmpty(reason))
return (null, reason);
}
}
finally
{
bufferPool.Return(buf);
}
var (canHandle, reason) = handler.CanHandle(filename, filesize, buf.AsSpan(0, read));
if (canHandle)
return (new GenericSource(uri, handler, host, filename, filesize), null);
else if (!string.IsNullOrEmpty(reason))
return (null, reason);
}
}
catch (Exception e)
finally
{
Config.Log.Warn(e, $"Error sniffing {m.Groups["link"].Value}");
bufferPool.Return(buf);
}
}
catch (Exception e)
{
Config.Log.Warn(e, $"Error sniffing {m.Groups["link"].Value}");
}
}
}
return (null, null);
}
private sealed class GenericSource : ISource
{
private Uri uri;
private IArchiveHandler handler;
private readonly Uri uri;
private readonly IArchiveHandler handler;
public string SourceType => "Generic link";
public string FileName { get; }
@@ -103,9 +101,9 @@ namespace CompatBot.EventHandlers.LogParsing.SourceHandlers
public async Task FillPipeAsync(PipeWriter writer, CancellationToken cancellationToken)
{
using (var client = HttpClientFactory.Create())
using (var stream = await client.GetStreamAsync(uri).ConfigureAwait(false))
await handler.FillPipeAsync(stream, writer, cancellationToken).ConfigureAwait(false);
using var client = HttpClientFactory.Create();
using var stream = await client.GetStreamAsync(uri).ConfigureAwait(false);
await handler.FillPipeAsync(stream, writer, cancellationToken).ConfigureAwait(false);
}
}
}

View File

@@ -120,20 +120,16 @@ namespace CompatBot.EventHandlers.LogParsing.SourceHandlers
try
{
var pipe = new Pipe();
using (var pushStream = pipe.Writer.AsStream())
{
var progressTask = fileInfoRequest.DownloadAsync(pushStream, cancellationToken);
using (var pullStream = pipe.Reader.AsStream())
{
var pipingTask = handler.FillPipeAsync(pullStream, writer, cancellationToken);
var result = await progressTask.ConfigureAwait(false);
if (result.Status != DownloadStatus.Completed)
Config.Log.Error(result.Exception, "Failed to download file from Google Drive: " + result.Status);
await pipe.Writer.FlushAsync(cancellationToken).ConfigureAwait(false);
pipe.Writer.Complete();
await pipingTask.ConfigureAwait(false);
}
}
using var pushStream = pipe.Writer.AsStream();
var progressTask = fileInfoRequest.DownloadAsync(pushStream, cancellationToken);
using var pullStream = pipe.Reader.AsStream();
var pipingTask = handler.FillPipeAsync(pullStream, writer, cancellationToken);
var result = await progressTask.ConfigureAwait(false);
if (result.Status != DownloadStatus.Completed)
Config.Log.Error(result.Exception, "Failed to download file from Google Drive: " + result.Status);
await pipe.Writer.FlushAsync(cancellationToken).ConfigureAwait(false);
pipe.Writer.Complete();
await pipingTask.ConfigureAwait(false);
}
catch (Exception e)
{

View File

@@ -91,8 +91,8 @@ namespace CompatBot.EventHandlers.LogParsing.SourceHandlers
public async Task FillPipeAsync(PipeWriter writer, CancellationToken cancellationToken)
{
using (var stream = await client.DownloadAsync(uri, doodad, cancellationToken).ConfigureAwait(false))
await handler.FillPipeAsync(stream, writer, cancellationToken).ConfigureAwait(false);
using var stream = await client.DownloadAsync(uri, doodad, cancellationToken).ConfigureAwait(false);
await handler.FillPipeAsync(stream, writer, cancellationToken).ConfigureAwait(false);
}
}
}

View File

@@ -24,50 +24,48 @@ namespace CompatBot.EventHandlers.LogParsing.SourceHandlers
if (matches.Count == 0)
return (null, null);
using (var client = HttpClientFactory.Create())
foreach (Match m in matches)
using var client = HttpClientFactory.Create();
foreach (Match m in matches)
{
try
{
try
if (m.Groups["pastebin_id"].Value is string pid
&& !string.IsNullOrEmpty(pid))
{
if (m.Groups["pastebin_id"].Value is string pid
&& !string.IsNullOrEmpty(pid))
var uri = new Uri("https://pastebin.com/raw/" + pid);
using var stream = await client.GetStreamAsync(uri).ConfigureAwait(false);
var buf = bufferPool.Rent(1024);
try
{
var uri = new Uri("https://pastebin.com/raw/" + pid);
using (var stream = await client.GetStreamAsync(uri).ConfigureAwait(false))
var read = await stream.ReadBytesAsync(buf).ConfigureAwait(false);
var filename = pid + ".log";
var filesize = stream.CanSeek ? (int)stream.Length : 0;
foreach (var handler in handlers)
{
var buf = bufferPool.Rent(1024);
try
{
var read = await stream.ReadBytesAsync(buf).ConfigureAwait(false);
var filename = pid + ".log";
var filesize = stream.CanSeek ? (int)stream.Length : 0;
foreach (var handler in handlers)
{
var (canHandle, reason) = handler.CanHandle(filename, filesize, buf.AsSpan(0, read));
if (canHandle)
return (new PastebinSource(uri, filename, filesize, handler), null);
else if (!string.IsNullOrEmpty(reason))
return (null, reason);
}
}
finally
{
bufferPool.Return(buf);
}
var (canHandle, reason) = handler.CanHandle(filename, filesize, buf.AsSpan(0, read));
if (canHandle)
return (new PastebinSource(uri, filename, filesize, handler), null);
else if (!string.IsNullOrEmpty(reason))
return (null, reason);
}
}
}
catch (Exception e)
{
Config.Log.Warn(e, $"Error sniffing {m.Groups["mega_link"].Value}");
finally
{
bufferPool.Return(buf);
}
}
}
catch (Exception e)
{
Config.Log.Warn(e, $"Error sniffing {m.Groups["mega_link"].Value}");
}
}
return (null, null);
}
private sealed class PastebinSource : ISource
{
private Uri uri;
private readonly Uri uri;
private readonly IArchiveHandler handler;
public long SourceFilePosition => handler.SourcePosition;
public long LogFileSize => handler.LogSize;
@@ -86,9 +84,9 @@ namespace CompatBot.EventHandlers.LogParsing.SourceHandlers
public async Task FillPipeAsync(PipeWriter writer, CancellationToken cancellationToken)
{
using (var client = HttpClientFactory.Create())
using (var stream = await client.GetStreamAsync(uri).ConfigureAwait(false))
await handler.FillPipeAsync(stream, writer, cancellationToken).ConfigureAwait(false);
using var client = HttpClientFactory.Create();
using var stream = await client.GetStreamAsync(uri).ConfigureAwait(false);
await handler.FillPipeAsync(stream, writer, cancellationToken).ConfigureAwait(false);
}
}
}

View File

@@ -97,8 +97,8 @@ namespace CompatBot.EventHandlers
LogParseState result = null;
using (var timeout = new CancellationTokenSource(Config.LogParsingTimeout))
using (var combinedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(timeout.Token, Config.Cts.Token))
{
using var combinedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(timeout.Token, Config.Cts.Token);
var tries = 0;
do
{

View File

@@ -63,9 +63,8 @@ namespace CompatBot.EventHandlers
public static async Task<Explanation> GetExplanationAsync(string term)
{
Explanation result;
using (var db = new BotDb())
result = await db.Explanation.FirstOrDefaultAsync(e => e.Keyword == term).ConfigureAwait(false);
using var db = new BotDb();
var result = await db.Explanation.FirstOrDefaultAsync(e => e.Keyword == term).ConfigureAwait(false);
return result ?? DefaultExplanation[term];
}
}

View File

@@ -18,14 +18,12 @@ namespace CompatBot.EventHandlers
if (!args.Message.Attachments.Any())
return;
using (var db = new ThumbnailDb())
using var db = new ThumbnailDb();
var thumb = db.Thumbnail.FirstOrDefault(i => i.ContentId == args.Message.Content);
if (thumb?.EmbeddableUrl is string url && !string.IsNullOrEmpty(url) && args.Message.Attachments.Any(a => a.Url == url))
{
var thumb = db.Thumbnail.FirstOrDefault(i => i.ContentId == args.Message.Content);
if (thumb?.EmbeddableUrl is string url && !string.IsNullOrEmpty(url) && args.Message.Attachments.Any(a => a.Url == url))
{
thumb.EmbeddableUrl = null;
await db.SaveChangesAsync(Config.Cts.Token).ConfigureAwait(false);
}
thumb.EmbeddableUrl = null;
await db.SaveChangesAsync(Config.Cts.Token).ConfigureAwait(false);
}
}
}

View File

@@ -38,21 +38,19 @@ namespace CompatBot
}
var singleInstanceCheckThread = new Thread(() =>
{
using (var instanceLock = new Mutex(false, @"Global\RPCS3 Compatibility Bot"))
{
if (instanceLock.WaitOne(1000))
try
{
InstanceCheck.Release();
ShutdownCheck.Wait();
}
finally
{
instanceLock.ReleaseMutex();
}
}
});
{
using var instanceLock = new Mutex(false, @"Global\RPCS3 Compatibility Bot");
if (instanceLock.WaitOne(1000))
try
{
InstanceCheck.Release();
ShutdownCheck.Wait();
}
finally
{
instanceLock.ReleaseMutex();
}
});
try
{
singleInstanceCheckThread.Start();
@@ -122,211 +120,207 @@ namespace CompatBot
Token = Config.Token,
TokenType = TokenType.Bot,
};
using (var client = new DiscordClient(config))
using var client = new DiscordClient(config);
var commands = client.UseCommandsNext(new CommandsNextConfiguration
{
var commands = client.UseCommandsNext(new CommandsNextConfiguration
StringPrefixes = new[] {Config.CommandPrefix, Config.AutoRemoveCommandPrefix},
Services = new ServiceCollection().BuildServiceProvider(),
});
commands.RegisterConverter(new TextOnlyDiscordChannelConverter());
commands.RegisterCommands<Misc>();
commands.RegisterCommands<CompatList>();
commands.RegisterCommands<Sudo>();
commands.RegisterCommands<CommandsManagement>();
commands.RegisterCommands<ContentFilters>();
commands.RegisterCommands<Warnings>();
commands.RegisterCommands<Explain>();
commands.RegisterCommands<Psn>();
commands.RegisterCommands<Invites>();
commands.RegisterCommands<Moderation>();
commands.RegisterCommands<Ird>();
commands.RegisterCommands<BotMath>();
commands.RegisterCommands<Pr>();
commands.RegisterCommands<Events>();
commands.RegisterCommands<E3>();
commands.RegisterCommands<Cyberpunk2077>();
commands.RegisterCommands<Rpcs3Ama>();
commands.RegisterCommands<BotStats>();
commands.RegisterCommands<Syscall>();
commands.CommandErrored += UnknownCommandHandler.OnError;
var interactivityConfig = new InteractivityConfiguration { };
client.UseInteractivity(interactivityConfig);
client.Ready += async r =>
{
Config.Log.Info("Bot is ready to serve!");
Config.Log.Info("");
Config.Log.Info($"Bot user id : {r.Client.CurrentUser.Id} ({r.Client.CurrentUser.Username})");
Config.Log.Info($"Bot admin id : {Config.BotAdminId} ({(await r.Client.GetUserAsync(Config.BotAdminId)).Username})");
Config.Log.Info("");
};
client.GuildAvailable += async gaArgs =>
{
await BotStatusMonitor.RefreshAsync(gaArgs.Client).ConfigureAwait(false);
Watchdog.DisconnectTimestamps.Clear();
if (gaArgs.Guild.Id != Config.BotGuildId)
{
StringPrefixes = new[] {Config.CommandPrefix, Config.AutoRemoveCommandPrefix},
Services = new ServiceCollection().BuildServiceProvider(),
});
commands.RegisterConverter(new TextOnlyDiscordChannelConverter());
commands.RegisterCommands<Misc>();
commands.RegisterCommands<CompatList>();
commands.RegisterCommands<Sudo>();
commands.RegisterCommands<CommandsManagement>();
commands.RegisterCommands<ContentFilters>();
commands.RegisterCommands<Warnings>();
commands.RegisterCommands<Explain>();
commands.RegisterCommands<Psn>();
commands.RegisterCommands<Invites>();
commands.RegisterCommands<Moderation>();
commands.RegisterCommands<Ird>();
commands.RegisterCommands<BotMath>();
commands.RegisterCommands<Pr>();
commands.RegisterCommands<Events>();
commands.RegisterCommands<E3>();
commands.RegisterCommands<Cyberpunk2077>();
commands.RegisterCommands<Rpcs3Ama>();
commands.RegisterCommands<BotStats>();
commands.RegisterCommands<Syscall>();
commands.CommandErrored += UnknownCommandHandler.OnError;
var interactivityConfig = new InteractivityConfiguration { };
client.UseInteractivity(interactivityConfig);
client.Ready += async r =>
{
Config.Log.Info("Bot is ready to serve!");
Config.Log.Info("");
Config.Log.Info($"Bot user id : {r.Client.CurrentUser.Id} ({r.Client.CurrentUser.Username})");
Config.Log.Info($"Bot admin id : {Config.BotAdminId} ({(await r.Client.GetUserAsync(Config.BotAdminId)).Username})");
Config.Log.Info("");
};
client.GuildAvailable += async gaArgs =>
{
await BotStatusMonitor.RefreshAsync(gaArgs.Client).ConfigureAwait(false);
Watchdog.DisconnectTimestamps.Clear();
if (gaArgs.Guild.Id != Config.BotGuildId)
{
#if DEBUG
Config.Log.Warn($"Unknown discord server {gaArgs.Guild.Id} ({gaArgs.Guild.Name})");
Config.Log.Warn($"Unknown discord server {gaArgs.Guild.Id} ({gaArgs.Guild.Name})");
#else
Config.Log.Warn($"Unknown discord server {gaArgs.Guild.Id} ({gaArgs.Guild.Name}), leaving...");
await gaArgs.Guild.LeaveAsync().ConfigureAwait(false);
Config.Log.Warn($"Unknown discord server {gaArgs.Guild.Id} ({gaArgs.Guild.Name}), leaving...");
await gaArgs.Guild.LeaveAsync().ConfigureAwait(false);
#endif
return;
}
Config.Log.Info($"Server {gaArgs.Guild.Name} is available now");
Config.Log.Info($"Checking moderation backlogs in {gaArgs.Guild.Name}...");
try
{
await Task.WhenAll(
Starbucks.CheckBacklogAsync(gaArgs.Client, gaArgs.Guild).ContinueWith(_ => Config.Log.Info($"Starbucks backlog checked in {gaArgs.Guild.Name}."), TaskScheduler.Default),
DiscordInviteFilter.CheckBacklogAsync(gaArgs.Client, gaArgs.Guild).ContinueWith(_ => Config.Log.Info($"Discord invites backlog checked in {gaArgs.Guild.Name}."), TaskScheduler.Default)
).ConfigureAwait(false);
}
catch (Exception e)
{
Config.Log.Warn(e, "Error running backlog tasks");
}
Config.Log.Info($"All moderation backlogs checked in {gaArgs.Guild.Name}.");
};
client.GuildUnavailable += guArgs =>
{
Config.Log.Warn($"{guArgs.Guild.Name} is unavailable");
return Task.CompletedTask;
};
client.MessageReactionAdded += Starbucks.Handler;
client.MessageReactionAdded += AntipiracyMonitor.OnReaction;
client.MessageCreated += AntipiracyMonitor.OnMessageCreated; // should be first
client.MessageCreated += ProductCodeLookup.OnMessageCreated;
client.MessageCreated += LogParsingHandler.OnMessageCreated;
client.MessageCreated += LogAsTextMonitor.OnMessageCreated;
client.MessageCreated += DiscordInviteFilter.OnMessageCreated;
client.MessageCreated += PostLogHelpHandler.OnMessageCreated;
client.MessageCreated += BotReactionsHandler.OnMessageCreated;
client.MessageCreated += AppveyorLinksHandler.OnMessageCreated;
client.MessageCreated += GithubLinksHandler.OnMessageCreated;
client.MessageCreated += NewBuildsMonitor.OnMessageCreated;
client.MessageCreated += TableFlipMonitor.OnMessageCreated;
client.MessageCreated += IsTheGamePlayableHandler.OnMessageCreated;
client.MessageCreated += EmpathySimulationHandler.OnMessageCreated;
client.MessageUpdated += AntipiracyMonitor.OnMessageUpdated;
client.MessageUpdated += DiscordInviteFilter.OnMessageUpdated;
client.MessageUpdated += EmpathySimulationHandler.OnMessageUpdated;
client.MessageDeleted += ThumbnailCacheMonitor.OnMessageDeleted;
client.MessageDeleted += EmpathySimulationHandler.OnMessageDeleted;
client.UserUpdated += UsernameSpoofMonitor.OnUserUpdated;
client.UserUpdated += UsernameZalgoMonitor.OnUserUpdated;
client.GuildMemberAdded += Greeter.OnMemberAdded;
client.GuildMemberAdded += UsernameSpoofMonitor.OnMemberAdded;
client.GuildMemberAdded += UsernameZalgoMonitor.OnMemberAdded;
client.GuildMemberUpdated += UsernameSpoofMonitor.OnMemberUpdated;
client.GuildMemberUpdated += UsernameZalgoMonitor.OnMemberUpdated;
client.DebugLogger.LogMessageReceived += (sender, eventArgs) =>
{
Action<Exception, string> logLevel = Config.Log.Info;
if (eventArgs.Level == LogLevel.Debug)
logLevel = Config.Log.Debug;
else if (eventArgs.Level == LogLevel.Info)
{
//logLevel = Config.Log.Info;
if (eventArgs.Message?.Contains("Session resumed") ?? false)
Watchdog.DisconnectTimestamps.Clear();
}
else if (eventArgs.Level == LogLevel.Warning)
{
logLevel = Config.Log.Warn;
if (eventArgs.Message?.Contains("Dispatch:PRESENCES_REPLACE") ?? false)
BotStatusMonitor.RefreshAsync(client).ConfigureAwait(false).GetAwaiter().GetResult();
}
else if (eventArgs.Level == LogLevel.Error)
logLevel = Config.Log.Error;
else if (eventArgs.Level == LogLevel.Critical)
{
logLevel = Config.Log.Fatal;
if ((eventArgs.Message?.Contains("Socket connection terminated") ?? false)
|| (eventArgs.Message?.Contains("heartbeats were skipped. Issuing reconnect.") ?? false))
Watchdog.DisconnectTimestamps.Enqueue(DateTime.UtcNow);
}
logLevel(eventArgs.Exception, eventArgs.Message);
};
Watchdog.DisconnectTimestamps.Enqueue(DateTime.UtcNow);
return;
}
Config.Log.Info($"Server {gaArgs.Guild.Name} is available now");
Config.Log.Info($"Checking moderation backlogs in {gaArgs.Guild.Name}...");
try
{
await client.ConnectAsync().ConfigureAwait(false);
await Task.WhenAll(
Starbucks.CheckBacklogAsync(gaArgs.Client, gaArgs.Guild).ContinueWith(_ => Config.Log.Info($"Starbucks backlog checked in {gaArgs.Guild.Name}."), TaskScheduler.Default),
DiscordInviteFilter.CheckBacklogAsync(gaArgs.Client, gaArgs.Guild).ContinueWith(_ => Config.Log.Info($"Discord invites backlog checked in {gaArgs.Guild.Name}."), TaskScheduler.Default)
).ConfigureAwait(false);
}
catch (Exception e)
{
Config.Log.Error(e, "Failed to connect to Discord: " + e.Message);
throw;
Config.Log.Warn(e, "Error running backlog tasks");
}
Config.Log.Info($"All moderation backlogs checked in {gaArgs.Guild.Name}.");
};
client.GuildUnavailable += guArgs =>
{
Config.Log.Warn($"{guArgs.Guild.Name} is unavailable");
return Task.CompletedTask;
};
ulong? channelId = null;
if (SandboxDetector.Detect() == SandboxType.Docker)
client.MessageReactionAdded += Starbucks.Handler;
client.MessageReactionAdded += AntipiracyMonitor.OnReaction;
client.MessageCreated += AntipiracyMonitor.OnMessageCreated; // should be first
client.MessageCreated += ProductCodeLookup.OnMessageCreated;
client.MessageCreated += LogParsingHandler.OnMessageCreated;
client.MessageCreated += LogAsTextMonitor.OnMessageCreated;
client.MessageCreated += DiscordInviteFilter.OnMessageCreated;
client.MessageCreated += PostLogHelpHandler.OnMessageCreated;
client.MessageCreated += BotReactionsHandler.OnMessageCreated;
client.MessageCreated += AppveyorLinksHandler.OnMessageCreated;
client.MessageCreated += GithubLinksHandler.OnMessageCreated;
client.MessageCreated += NewBuildsMonitor.OnMessageCreated;
client.MessageCreated += TableFlipMonitor.OnMessageCreated;
client.MessageCreated += IsTheGamePlayableHandler.OnMessageCreated;
client.MessageCreated += EmpathySimulationHandler.OnMessageCreated;
client.MessageUpdated += AntipiracyMonitor.OnMessageUpdated;
client.MessageUpdated += DiscordInviteFilter.OnMessageUpdated;
client.MessageUpdated += EmpathySimulationHandler.OnMessageUpdated;
client.MessageDeleted += ThumbnailCacheMonitor.OnMessageDeleted;
client.MessageDeleted += EmpathySimulationHandler.OnMessageDeleted;
client.UserUpdated += UsernameSpoofMonitor.OnUserUpdated;
client.UserUpdated += UsernameZalgoMonitor.OnUserUpdated;
client.GuildMemberAdded += Greeter.OnMemberAdded;
client.GuildMemberAdded += UsernameSpoofMonitor.OnMemberAdded;
client.GuildMemberAdded += UsernameZalgoMonitor.OnMemberAdded;
client.GuildMemberUpdated += UsernameSpoofMonitor.OnMemberUpdated;
client.GuildMemberUpdated += UsernameZalgoMonitor.OnMemberUpdated;
client.DebugLogger.LogMessageReceived += (sender, eventArgs) =>
{
Action<Exception, string> logLevel = Config.Log.Info;
if (eventArgs.Level == LogLevel.Debug)
logLevel = Config.Log.Debug;
else if (eventArgs.Level == LogLevel.Info)
{
using (var db = new BotDb())
{
var chState = db.BotState.FirstOrDefault(k => k.Key == "bot-restart-channel");
if (chState != null)
{
if (ulong.TryParse(chState.Value, out var ch))
channelId = ch;
db.BotState.Remove(chState);
db.SaveChanges();
}
}
//logLevel = Config.Log.Info;
if (eventArgs.Message?.Contains("Session resumed") ?? false)
Watchdog.DisconnectTimestamps.Clear();
}
if (args.LastOrDefault() is string strCh && ulong.TryParse(strCh, out var chId))
channelId = chId;
if (channelId.HasValue)
else if (eventArgs.Level == LogLevel.Warning)
{
Config.Log.Info($"Found channelId {channelId}");
DiscordChannel channel;
if (channelId == InvalidChannelId)
{
channel = await client.GetChannelAsync(Config.ThumbnailSpamId).ConfigureAwait(false);
await channel.SendMessageAsync("Bot has suffered some catastrophic failure and was restarted").ConfigureAwait(false);
}
else
{
channel = await client.GetChannelAsync(channelId.Value).ConfigureAwait(false);
await channel.SendMessageAsync("Bot is up and running").ConfigureAwait(false);
}
logLevel = Config.Log.Warn;
if (eventArgs.Message?.Contains("Dispatch:PRESENCES_REPLACE") ?? false)
BotStatusMonitor.RefreshAsync(client).ConfigureAwait(false).GetAwaiter().GetResult();
}
else if (eventArgs.Level == LogLevel.Error)
logLevel = Config.Log.Error;
else if (eventArgs.Level == LogLevel.Critical)
{
logLevel = Config.Log.Fatal;
if ((eventArgs.Message?.Contains("Socket connection terminated") ?? false)
|| (eventArgs.Message?.Contains("heartbeats were skipped. Issuing reconnect.") ?? false))
Watchdog.DisconnectTimestamps.Enqueue(DateTime.UtcNow);
}
logLevel(eventArgs.Exception, eventArgs.Message);
};
Watchdog.DisconnectTimestamps.Enqueue(DateTime.UtcNow);
try
{
await client.ConnectAsync().ConfigureAwait(false);
}
catch (Exception e)
{
Config.Log.Error(e, "Failed to connect to Discord: " + e.Message);
throw;
}
ulong? channelId = null;
if (SandboxDetector.Detect() == SandboxType.Docker)
{
using var db = new BotDb();
var chState = db.BotState.FirstOrDefault(k => k.Key == "bot-restart-channel");
if (chState != null)
{
if (ulong.TryParse(chState.Value, out var ch))
channelId = ch;
db.BotState.Remove(chState);
db.SaveChanges();
}
}
if (args.LastOrDefault() is string strCh && ulong.TryParse(strCh, out var chId))
channelId = chId;
if (channelId.HasValue)
{
Config.Log.Info($"Found channelId {channelId}");
DiscordChannel channel;
if (channelId == InvalidChannelId)
{
channel = await client.GetChannelAsync(Config.ThumbnailSpamId).ConfigureAwait(false);
await channel.SendMessageAsync("Bot has suffered some catastrophic failure and was restarted").ConfigureAwait(false);
}
else
{
Config.Log.Debug($"Args count: {args.Length}");
var pArgs = args.Select(a => a == Config.Token ? "<Token>" : $"[{a}]");
Config.Log.Debug("Args: " + string.Join(" ", pArgs));
channel = await client.GetChannelAsync(channelId.Value).ConfigureAwait(false);
await channel.SendMessageAsync("Bot is up and running").ConfigureAwait(false);
}
}
else
{
Config.Log.Debug($"Args count: {args.Length}");
var pArgs = args.Select(a => a == Config.Token ? "<Token>" : $"[{a}]");
Config.Log.Debug("Args: " + string.Join(" ", pArgs));
}
Config.Log.Debug("Running RPCS3 update check thread");
backgroundTasks = Task.WhenAll(
backgroundTasks,
NewBuildsMonitor.MonitorAsync(client),
Watchdog.Watch(client),
InviteWhitelistProvider.CleanupAsync(client)
);
Config.Log.Debug("Running RPCS3 update check thread");
backgroundTasks = Task.WhenAll(
backgroundTasks,
NewBuildsMonitor.MonitorAsync(client),
Watchdog.Watch(client),
InviteWhitelistProvider.CleanupAsync(client)
);
while (!Config.Cts.IsCancellationRequested)
{
if (client.Ping > 1000)
Config.Log.Warn($"High ping detected: {client.Ping}");
await Task.Delay(TimeSpan.FromMinutes(1), Config.Cts.Token).ContinueWith(dt => {/* in case it was cancelled */}, TaskScheduler.Default).ConfigureAwait(false);
}
while (!Config.Cts.IsCancellationRequested)
{
if (client.Ping > 1000)
Config.Log.Warn($"High ping detected: {client.Ping}");
await Task.Delay(TimeSpan.FromMinutes(1), Config.Cts.Token).ContinueWith(dt => {/* in case it was cancelled */}, TaskScheduler.Default).ConfigureAwait(false);
}
await backgroundTasks.ConfigureAwait(false);
}

View File

@@ -77,64 +77,57 @@ namespace CompatBot.ThumbScrapper
using (var downloadStream = await HttpClient.GetStreamAsync(TitleDownloadLink).ConfigureAwait(false))
await downloadStream.CopyToAsync(fileStream, 16384, cancellationToken).ConfigureAwait(false);
fileStream.Seek(0, SeekOrigin.Begin);
using (var zipArchive = new ZipArchive(fileStream, ZipArchiveMode.Read))
using var zipArchive = new ZipArchive(fileStream, ZipArchiveMode.Read);
var logEntry = zipArchive.Entries.FirstOrDefault(e => e.Name.EndsWith(".xml", StringComparison.InvariantCultureIgnoreCase));
if (logEntry == null)
throw new InvalidOperationException("No zip entries that match the .xml criteria");
using var zipStream = logEntry.Open();
using var xmlReader = XmlReader.Create(zipStream, new XmlReaderSettings { Async = true });
xmlReader.ReadToFollowing("PS3TDB");
var version = xmlReader.GetAttribute("version");
if (!DateTime.TryParseExact(version, "yyyyMMddHHmmss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out var timestamp))
return;
if (ScrapeStateProvider.IsFresh("PS3TDB", timestamp))
{
var logEntry = zipArchive.Entries.FirstOrDefault(e => e.Name.EndsWith(".xml", StringComparison.InvariantCultureIgnoreCase));
if (logEntry == null)
throw new InvalidOperationException("No zip entries that match the .xml criteria");
await ScrapeStateProvider.SetLastRunTimestampAsync("PS3TDB").ConfigureAwait(false);
return;
}
using (var zipStream = logEntry.Open())
using (var xmlReader = XmlReader.Create(zipStream, new XmlReaderSettings { Async = true }))
while (!cancellationToken.IsCancellationRequested && xmlReader.ReadToFollowing("game"))
{
if (xmlReader.ReadToFollowing("id"))
{
xmlReader.ReadToFollowing("PS3TDB");
var version = xmlReader.GetAttribute("version");
if (!DateTime.TryParseExact(version, "yyyyMMddHHmmss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out var timestamp))
return;
var productId = (await xmlReader.ReadElementContentAsStringAsync().ConfigureAwait(false)).ToUpperInvariant();
if (!ProductCodeLookup.ProductCode.IsMatch(productId))
continue;
if (ScrapeStateProvider.IsFresh("PS3TDB", timestamp))
{
await ScrapeStateProvider.SetLastRunTimestampAsync("PS3TDB").ConfigureAwait(false);
return;
}
string title = null;
if (xmlReader.ReadToFollowing("locale") && xmlReader.ReadToFollowing("title"))
title = await xmlReader.ReadElementContentAsStringAsync().ConfigureAwait(false);
while (!cancellationToken.IsCancellationRequested && xmlReader.ReadToFollowing("game"))
if (!string.IsNullOrEmpty(title))
{
if (xmlReader.ReadToFollowing("id"))
using var db = new ThumbnailDb();
var item = await db.Thumbnail.FirstOrDefaultAsync(t => t.ProductCode == productId, cancellationToken).ConfigureAwait(false);
if (item == null)
{
var productId = (await xmlReader.ReadElementContentAsStringAsync().ConfigureAwait(false)).ToUpperInvariant();
if (!ProductCodeLookup.ProductCode.IsMatch(productId))
continue;
string title = null;
if (xmlReader.ReadToFollowing("locale") && xmlReader.ReadToFollowing("title"))
title = await xmlReader.ReadElementContentAsStringAsync().ConfigureAwait(false);
if (!string.IsNullOrEmpty(title))
await db.Thumbnail.AddAsync(new Thumbnail {ProductCode = productId, Name = title}, cancellationToken).ConfigureAwait(false);
await db.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
}
else
{
if (item.Name != title && item.Timestamp == 0)
{
using (var db = new ThumbnailDb())
{
var item = await db.Thumbnail.FirstOrDefaultAsync(t => t.ProductCode == productId, cancellationToken).ConfigureAwait(false);
if (item == null)
{
await db.Thumbnail.AddAsync(new Thumbnail {ProductCode = productId, Name = title}, cancellationToken).ConfigureAwait(false);
await db.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
}
else
{
if (item.Name != title && item.Timestamp == 0)
{
item.Name = title;
await db.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
}
}
}
item.Name = title;
await db.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
}
}
}
await ScrapeStateProvider.SetLastRunTimestampAsync("PS3TDB").ConfigureAwait(false);
}
}
await ScrapeStateProvider.SetLastRunTimestampAsync("PS3TDB").ConfigureAwait(false);
}
await ScrapeStateProvider.SetLastRunTimestampAsync(container).ConfigureAwait(false);
}

View File

@@ -349,42 +349,40 @@ namespace CompatBot.ThumbScrapper
return;
name = string.IsNullOrEmpty(name) ? null : name;
using (var db = new ThumbnailDb())
using var db = new ThumbnailDb();
var savedItem = db.Thumbnail.FirstOrDefault(t => t.ProductCode == productCode);
if (savedItem == null)
{
var savedItem = db.Thumbnail.FirstOrDefault(t => t.ProductCode == productCode);
if (savedItem == null)
var newItem = new Thumbnail
{
var newItem = new Thumbnail
{
ProductCode = productCode,
ContentId = contentId,
Name = name,
Url = url,
Timestamp = DateTime.UtcNow.Ticks,
};
db.Thumbnail.Add(newItem);
}
else if (!string.IsNullOrEmpty(url))
{
if (string.IsNullOrEmpty(savedItem.Url))
savedItem.Url = url;
if (string.IsNullOrEmpty(savedItem.Name) && !string.IsNullOrEmpty(name))
savedItem.Name = name;
if (!ScrapeStateProvider.IsFresh(savedItem.Timestamp))
{
if (savedItem.Url != url)
{
savedItem.Url = url;
savedItem.EmbeddableUrl = null;
}
if (name != null && savedItem.Name != name)
savedItem.Name = name;
}
savedItem.ContentId = contentId;
savedItem.Timestamp = DateTime.UtcNow.Ticks;
}
await db.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
ProductCode = productCode,
ContentId = contentId,
Name = name,
Url = url,
Timestamp = DateTime.UtcNow.Ticks,
};
db.Thumbnail.Add(newItem);
}
else if (!string.IsNullOrEmpty(url))
{
if (string.IsNullOrEmpty(savedItem.Url))
savedItem.Url = url;
if (string.IsNullOrEmpty(savedItem.Name) && !string.IsNullOrEmpty(name))
savedItem.Name = name;
if (!ScrapeStateProvider.IsFresh(savedItem.Timestamp))
{
if (savedItem.Url != url)
{
savedItem.Url = url;
savedItem.EmbeddableUrl = null;
}
if (name != null && savedItem.Name != name)
savedItem.Name = name;
}
savedItem.ContentId = contentId;
savedItem.Timestamp = DateTime.UtcNow.Ticks;
}
await db.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
}
private static async Task ScrapeContainerIdsAsync(string locale, string containerId, HashSet<string> knownContainerIds, CancellationToken cancellationToken)

View File

@@ -18,24 +18,22 @@ namespace CompatBot.Utils
return defaultColor;
var analyzer = new ColorThief();
using (var stream = new MemoryStream(jpg))
{
var bmp = new Bitmap(stream, false);
var palette = analyzer.GetPalette(bmp, 4, ignoreWhite: false);
var colors = palette
.Select(p => new {c = p.Color, hsl = p.Color.ToHsl()})
.OrderBy(p => Math.Abs(0.75 - p.hsl.L))
.ThenByDescending(p => p.hsl.S)
.ToList();
using var stream = new MemoryStream(jpg);
var bmp = new Bitmap(stream, false);
var palette = analyzer.GetPalette(bmp, 4, ignoreWhite: false);
var colors = palette
.Select(p => new {c = p.Color, hsl = p.Color.ToHsl()})
.OrderBy(p => Math.Abs(0.75 - p.hsl.L))
.ThenByDescending(p => p.hsl.S)
.ToList();
#if DEBUG
Config.Log.Trace("Selected palette:");
foreach (var cl in colors)
Config.Log.Trace($"{cl.c.ToHexString()}, HSL: {cl.hsl.H+90:#00} {cl.hsl.S:0.00} {cl.hsl.L:0.00}");
Config.Log.Trace("Selected palette:");
foreach (var cl in colors)
Config.Log.Trace($"{cl.c.ToHexString()}, HSL: {cl.hsl.H+90:#00} {cl.hsl.S:0.00} {cl.hsl.L:0.00}");
#endif
var c = colors[0].c;
return new DiscordColor(c.R, c.G, c.B);
}
var c = colors[0].c;
return new DiscordColor(c.R, c.G, c.B);
}
catch (Exception e)
{

View File

@@ -14,21 +14,19 @@ namespace CompatBot.Utils
if (selector == null)
throw new ArgumentNullException(nameof(selector));
using (var e = source.GetEnumerator())
using var e = source.GetEnumerator();
if (!e.MoveNext())
yield break;
T prev = e.Current;
if (!e.MoveNext())
yield break;
do
{
if (!e.MoveNext())
yield break;
T prev = e.Current;
if (!e.MoveNext())
yield break;
do
{
yield return selector(prev, e.Current);
prev = e.Current;
} while (e.MoveNext());
}
yield return selector(prev, e.Current);
prev = e.Current;
} while (e.MoveNext());
}
public static IEnumerable<T> Single<T>(T item)

View File

@@ -22,32 +22,32 @@ namespace HomoglyphConverter
var assembly = Assembly.GetAssembly(typeof(ConfusablesBuilder));
var resourceName = assembly.GetManifestResourceNames().FirstOrDefault(n => n.EndsWith("confusables.txt.gz", StringComparison.InvariantCultureIgnoreCase));
using (var stream = assembly.GetManifestResourceStream(resourceName))
using (var gzip = new GZipStream(stream, CompressionMode.Decompress))
using (var reader = new StreamReader(gzip, Encoding.UTF8, false))
{
using var gzip = new GZipStream(stream, CompressionMode.Decompress);
using var reader = new StreamReader(gzip, Encoding.UTF8, false);
string line;
while ((line = reader.ReadLine()) != null)
{
string line;
while ((line = reader.ReadLine()) != null)
if (string.IsNullOrEmpty(line) || line.StartsWith("#"))
continue;
var lineParts = line.Split(CommentSplitter, 2);
var mapping = lineParts[0].Split(FieldSplitter, 3);
if (mapping.Length < 2)
throw new InvalidOperationException("Invalid confusable mapping line: " + line);
try
{
if (string.IsNullOrEmpty(line) || line.StartsWith("#"))
continue;
var lineParts = line.Split(CommentSplitter, 2);
var mapping = lineParts[0].Split(FieldSplitter, 3);
if (mapping.Length < 2)
throw new InvalidOperationException("Invalid confusable mapping line: " + line);
try
{
var confusableChar = uint.Parse(mapping[0].Trim(), NumberStyles.HexNumber);
var skeletonChars = mapping[1].Split(PairSplitter, StringSplitOptions.RemoveEmptyEntries).Select(l => uint.Parse(l, NumberStyles.HexNumber)).ToArray();
result.Add(confusableChar, skeletonChars);
}
catch (Exception e)
{
throw new InvalidOperationException("Invalid confusable mapping line:" + line, e);
}
var confusableChar = uint.Parse(mapping[0].Trim(), NumberStyles.HexNumber);
var skeletonChars = mapping[1].Split(PairSplitter, StringSplitOptions.RemoveEmptyEntries).Select(l => uint.Parse(l, NumberStyles.HexNumber)).ToArray();
result.Add(confusableChar, skeletonChars);
}
catch (Exception e)
{
throw new InvalidOperationException("Invalid confusable mapping line:" + line, e);
}
}
}
if (result.Count == 0)
throw new InvalidOperationException("Empty confusable mapping source");

View File

@@ -19,15 +19,15 @@ namespace Tests
var resultPath = Path.Combine(Path.GetDirectoryName(samplePath), "zalgo.txt");
var names = await File.ReadAllLinesAsync(samplePath, Encoding.UTF8);
using (var r = File.Open(resultPath, FileMode.Create, FileAccess.Write, FileShare.Read))
using (var w = new StreamWriter(r, new UTF8Encoding(false)))
foreach (var line in names)
{
var user = UserInfo.Parse(line);
var isZalgo = UsernameZalgoMonitor.NeedsRename(user.DisplayName);
if (isZalgo)
await w.WriteLineAsync(user.DisplayName).ConfigureAwait(false);
}
using var r = File.Open(resultPath, FileMode.Create, FileAccess.Write, FileShare.Read);
using var w = new StreamWriter(r, new UTF8Encoding(false));
foreach (var line in names)
{
var user = UserInfo.Parse(line);
var isZalgo = UsernameZalgoMonitor.NeedsRename(user.DisplayName);
if (isZalgo)
await w.WriteLineAsync(user.DisplayName).ConfigureAwait(false);
}
}
[Test, Explicit("Requires external data")]
@@ -39,7 +39,8 @@ namespace Tests
var stats = new int[10];
var names = await File.ReadAllLinesAsync(samplePath, Encoding.UTF8);
using (var r = File.Open(resultPath, FileMode.Create, FileAccess.Write, FileShare.Read))
using (var w = new StreamWriter(r, new UTF8Encoding(false)))
{
using var w = new StreamWriter(r, new UTF8Encoding(false));
foreach (var line in names)
{
var user = UserInfo.Parse(line);
@@ -49,6 +50,7 @@ namespace Tests
await w.WriteAsync('\t').ConfigureAwait(false);
await w.WriteLineAsync(user.DisplayName).ConfigureAwait(false);
}
}
for (var i = 0; i < stats.Length && stats[i] > 0; i++)
{