diff --git a/c#/GlobalSuppressions.cs b/c#/GlobalSuppressions.cs index bfd97d2f..cb28700d 100644 --- a/c#/GlobalSuppressions.cs +++ b/c#/GlobalSuppressions.cs @@ -83,6 +83,7 @@ [assembly: SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1122:Use string.Empty for empty strings")] [assembly: SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1127:Generic type constraints should be on their own line")] [assembly: SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1128:Put constructor initializers on their own line")] +[assembly: SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1133:Each attribute should be placed on its own line of code")] [assembly: SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1134:Attributes should not share line")] [assembly: SuppressMessage("StyleCop.CSharp.SpacingRules", "SA1008:Opening parenthesis should be spaced correctly")] [assembly: SuppressMessage("StyleCop.CSharp.SpacingRules", "SA1009:Closing parenthesis should be spaced correctly")] diff --git a/c#/crawler/src/SonicPusher.cs b/c#/crawler/src/SonicPusher.cs index 6b3101a3..276aa5fb 100644 --- a/c#/crawler/src/SonicPusher.cs +++ b/c#/crawler/src/SonicPusher.cs @@ -14,7 +14,7 @@ public SonicPusher(ILogger logger, IConfiguration config) _config.GetValue("Hostname", "localhost"), _config.GetValue("Port", 1491), _config.GetValue("Secret", "SecretPassword")); - CollectionPrefix = _config.GetValue("CollectionPrefix") ?? "tbm_"; + CollectionPrefix = _config.GetValue("CollectionPrefix", "tbm_"); } public ISonicIngestConnection Ingest { get; } diff --git a/c#/crawler/src/Tieba/ClientRequester.cs b/c#/crawler/src/Tieba/ClientRequester.cs index 2d1fa3ee..fda5cd2a 100644 --- a/c#/crawler/src/Tieba/ClientRequester.cs +++ b/c#/crawler/src/Tieba/ClientRequester.cs @@ -100,7 +100,7 @@ private async Task PostJson( return acc; }) + "tiebaclient!!!"; #pragma warning disable CA5351 // Do Not Use Broken Cryptographic Algorithms - var signatureMd5 = BitConverter.ToString(MD5.HashData(Encoding.UTF8.GetBytes(signature))).Replace("-", ""); + var signatureMd5 = Convert.ToHexString(MD5.HashData(Encoding.UTF8.GetBytes(signature))); #pragma warning restore CA5351 // Do Not Use Broken Cryptographic Algorithms postParamPairs.Add(KeyValuePair.Create("sign", signatureMd5)); diff --git a/c#/crawler/src/Tieba/ClientRequesterTcs.cs b/c#/crawler/src/Tieba/ClientRequesterTcs.cs index 7c5fcbcc..77e6a15d 100644 --- a/c#/crawler/src/Tieba/ClientRequesterTcs.cs +++ b/c#/crawler/src/Tieba/ClientRequesterTcs.cs @@ -7,7 +7,6 @@ public sealed class ClientRequesterTcs : WithLogTrace private readonly ConcurrentQueue _queue = new(); private readonly Timer _timer = new() {Enabled = true}; private readonly Stopwatch _stopwatch = new(); - private double _maxRps; private uint _requestCounter; public ClientRequesterTcs(ILogger logger, IConfiguration config) @@ -28,10 +27,10 @@ public ClientRequesterTcs(ILogger logger, IConfiguration con private float AverageRps => _requestCounter / (float)_stopwatch.Elapsed.TotalSeconds; private double MaxRps { - get => _maxRps; + get; set { - _maxRps = value; + field = value; if ((uint)_timer.Interval != (uint)(1000 / value)) { // only update interval with a truncated integer to prevent frequently change it // which will cause the increment of real rps can't keep up with _maxRps with long queue length diff --git a/c#/crawler/src/Tieba/Crawl/Crawler/CrawlerLocks.cs b/c#/crawler/src/Tieba/Crawl/Crawler/CrawlerLocks.cs index 729d86b2..2deb7362 100644 --- a/c#/crawler/src/Tieba/Crawl/Crawler/CrawlerLocks.cs +++ b/c#/crawler/src/Tieba/Crawl/Crawler/CrawlerLocks.cs @@ -95,10 +95,11 @@ public IReadOnlyDictionary> Retr { lock (_failed) { - var failedClone = _failed.ToDictionary(pair => pair.Key, pair => + var failedClone = _failed.ToDictionary(pair => pair.Key, + IReadOnlyDictionary (pair) => { lock (pair.Value) - return (IReadOnlyDictionary)new Dictionary(pair.Value); + return new Dictionary(pair.Value); }); _failed.Clear(); return failedClone; diff --git a/c#/crawler/src/Tieba/Crawl/Facade/CrawlFacade.cs b/c#/crawler/src/Tieba/Crawl/Facade/CrawlFacade.cs index e3f7e275..e6653430 100644 --- a/c#/crawler/src/Tieba/Crawl/Facade/CrawlFacade.cs +++ b/c#/crawler/src/Tieba/Crawl/Facade/CrawlFacade.cs @@ -19,7 +19,6 @@ public abstract class CrawlFacade _lockingPages = []; private readonly ConcurrentDictionary _users = new(); - private UserParser? _userParser; private ICrawlFacade.ExceptionHandler _exceptionHandler = _ => { }; // ReSharper disable UnusedAutoPropertyAccessor.Global @@ -31,7 +30,9 @@ public required ILogger Posts { get; } = new(); - protected UserParser UserParser => _userParser ??= userParserFactory(_users); + + [field: AllowNull, MaybeNull] + protected UserParser UserParser => field ??= userParserFactory(_users); public virtual void Dispose() { diff --git a/c#/crawler/src/Tieba/Crawl/Saver/IRevisionProperties.cs b/c#/crawler/src/Tieba/Crawl/Saver/IRevisionProperties.cs index 7086bf96..47ebb83b 100644 --- a/c#/crawler/src/Tieba/Crawl/Saver/IRevisionProperties.cs +++ b/c#/crawler/src/Tieba/Crawl/Saver/IRevisionProperties.cs @@ -6,6 +6,7 @@ public interface IRevisionProperties [typeof(ThreadRevision), typeof(ReplyRevision), typeof(SubReplyRevision), typeof(UserRevision)]); private static IReadOnlyDictionary> GetPropsKeyByType(IEnumerable types) => - types.ToDictionary(type => type, type => - (IReadOnlyDictionary)type.GetProperties().ToDictionary(prop => prop.Name)); + types.ToDictionary(type => type, + IReadOnlyDictionary (type) => + type.GetProperties().ToDictionary(prop => prop.Name)); } diff --git a/c#/crawler/src/Tieba/Crawl/Saver/Post/ReplySaver.cs b/c#/crawler/src/Tieba/Crawl/Saver/Post/ReplySaver.cs index 2504ba5d..fe354045 100644 --- a/c#/crawler/src/Tieba/Crawl/Saver/Post/ReplySaver.cs +++ b/c#/crawler/src/Tieba/Crawl/Saver/Post/ReplySaver.cs @@ -26,10 +26,10 @@ public partial class ReplySaver( } public partial class ReplySaver { - private Lazy>? _addSplitRevisionsDelegatesKeyByEntityType; + [field: AllowNull, MaybeNull] protected override Lazy> AddSplitRevisionsDelegatesKeyByEntityType => - _addSplitRevisionsDelegatesKeyByEntityType ??= new(() => new() + field ??= new(() => new() { {typeof(ReplyRevision.SplitFloor), AddRevisionsWithDuplicateIndex}, {typeof(ReplyRevision.SplitSubReplyCount), AddRevisionsWithDuplicateIndex}, diff --git a/c#/crawler/src/Tieba/Crawl/Saver/Post/SubReplySaver.cs b/c#/crawler/src/Tieba/Crawl/Saver/Post/SubReplySaver.cs index dd7b0c4d..ee497a0a 100644 --- a/c#/crawler/src/Tieba/Crawl/Saver/Post/SubReplySaver.cs +++ b/c#/crawler/src/Tieba/Crawl/Saver/Post/SubReplySaver.cs @@ -22,10 +22,10 @@ public partial class SubReplySaver( } public partial class SubReplySaver { - private Lazy>? _addSplitRevisionsDelegatesKeyByEntityType; + [field: AllowNull, MaybeNull] protected override Lazy> AddSplitRevisionsDelegatesKeyByEntityType => - _addSplitRevisionsDelegatesKeyByEntityType ??= new(() => new() + field ??= new(() => new() { {typeof(SubReplyRevision.SplitAgreeCount), AddRevisionsWithDuplicateIndex}, {typeof(SubReplyRevision.SplitDisagreeCount), AddRevisionsWithDuplicateIndex} diff --git a/c#/crawler/src/Tieba/Crawl/Saver/Post/ThreadSaver.cs b/c#/crawler/src/Tieba/Crawl/Saver/Post/ThreadSaver.cs index 84381b14..5e2119a5 100644 --- a/c#/crawler/src/Tieba/Crawl/Saver/Post/ThreadSaver.cs +++ b/c#/crawler/src/Tieba/Crawl/Saver/Post/ThreadSaver.cs @@ -21,10 +21,10 @@ public partial class ThreadSaver( } public partial class ThreadSaver { - private Lazy>? _addSplitRevisionsDelegatesKeyByEntityType; + [field: AllowNull, MaybeNull] protected override Lazy> AddSplitRevisionsDelegatesKeyByEntityType => - _addSplitRevisionsDelegatesKeyByEntityType ??= new(() => new() + field ??= new(() => new() { {typeof(ThreadRevision.SplitViewCount), AddRevisionsWithDuplicateIndex} }); diff --git a/c#/crawler/src/Tieba/Crawl/Saver/Related/AuthorRevisionSaver.cs b/c#/crawler/src/Tieba/Crawl/Saver/Related/AuthorRevisionSaver.cs index 41ef2bc1..81124a18 100644 --- a/c#/crawler/src/Tieba/Crawl/Saver/Related/AuthorRevisionSaver.cs +++ b/c#/crawler/src/Tieba/Crawl/Saver/Related/AuthorRevisionSaver.cs @@ -91,7 +91,7 @@ private Action Save( // locking key only using AuthorRevision.Fid and Uid, ignoring TriggeredBy // this prevents inserting multiple entities with similar time and other fields with the same values // ReSharper disable NotAccessedPositionalProperty.Global - public record UniqueAuthorRevision(Fid Fid, Uid Uid); + private sealed record UniqueAuthorRevision(Fid Fid, Uid Uid); // ReSharper restore NotAccessedPositionalProperty.Global private sealed class LatestAuthorRevisionProjection diff --git a/c#/crawler/src/Tieba/Crawl/Saver/UserSaver.cs b/c#/crawler/src/Tieba/Crawl/Saver/UserSaver.cs index ff72db68..7b812415 100644 --- a/c#/crawler/src/Tieba/Crawl/Saver/UserSaver.cs +++ b/c#/crawler/src/Tieba/Crawl/Saver/UserSaver.cs @@ -61,10 +61,10 @@ public void SaveParentThreadLatestReplierUid(CrawlerDbContext db, Tid tid) => } public partial class UserSaver { - private Lazy>? _addSplitRevisionsDelegatesKeyByEntityType; + [field: AllowNull, MaybeNull] protected override Lazy> AddSplitRevisionsDelegatesKeyByEntityType => - _addSplitRevisionsDelegatesKeyByEntityType ??= new(() => new() + field ??= new(() => new() { {typeof(UserRevision.SplitDisplayName), AddRevisionsWithDuplicateIndex}, {typeof(UserRevision.SplitPortraitUpdatedAt), AddRevisionsWithDuplicateIndex}, diff --git a/c#/imagePipeline/src/Consumer/MetadataConsumer.cs b/c#/imagePipeline/src/Consumer/MetadataConsumer.cs index b37272c8..3d12c0c8 100644 --- a/c#/imagePipeline/src/Consumer/MetadataConsumer.cs +++ b/c#/imagePipeline/src/Consumer/MetadataConsumer.cs @@ -242,7 +242,7 @@ private static class ExifGpsTagValuesParser : null; } - private static double ConvertDmsToDd(IReadOnlyList dms) + private static double ConvertDmsToDd(List dms) { // https://stackoverflow.com/questions/3249700/convert-degrees-minutes-seconds-to-decimal-coordinates if (dms.Count != 3) throw new ArgumentException( "Unexpected length for DMS, expecting three doubles.", nameof(dms)); diff --git a/c#/imagePipeline/src/Consumer/QrCodeConsumer.cs b/c#/imagePipeline/src/Consumer/QrCodeConsumer.cs index 4f04de60..19c89a17 100644 --- a/c#/imagePipeline/src/Consumer/QrCodeConsumer.cs +++ b/c#/imagePipeline/src/Consumer/QrCodeConsumer.cs @@ -9,7 +9,7 @@ public QrCodeConsumer(IConfiguration config, FailedImageHandler failedImageHandl { _failedImageHandler = failedImageHandler; var modelsPath = config.GetSection("QrCodeConsumer") - .GetValue("ModelPath", "./OpenCvWechatModels") ?? "./OpenCvWechatModels"; + .GetValue("ModelPath", "./OpenCvWechatModels"); _qrCode = WeChatQRCode.Create( $"{modelsPath}/detect.prototxt", $"{modelsPath}/detect.caffemodel", diff --git a/c#/imagePipeline/src/ImageBatchConsumingWorker.cs b/c#/imagePipeline/src/ImageBatchConsumingWorker.cs index 574d9144..1f5c6ada 100644 --- a/c#/imagePipeline/src/ImageBatchConsumingWorker.cs +++ b/c#/imagePipeline/src/ImageBatchConsumingWorker.cs @@ -43,7 +43,7 @@ protected override async Task DoWork(CancellationToken stoppingToken) } private async Task Consume( - IReadOnlyCollection imagesWithBytes, + List imagesWithBytes, CancellationToken stoppingToken = default) { await using var dbFactory = dbContextDefaultFactory(); diff --git a/c#/imagePipeline/src/Ocr/PaddleOcrProvider.cs b/c#/imagePipeline/src/Ocr/PaddleOcrProvider.cs index e340ea74..38c4f999 100644 --- a/c#/imagePipeline/src/Ocr/PaddleOcrProvider.cs +++ b/c#/imagePipeline/src/Ocr/PaddleOcrProvider.cs @@ -18,8 +18,7 @@ public PaddleOcrProvider(IConfiguration config, string script, { _config = config.GetSection("OcrConsumer:PaddleOcr"); _script = script; - Settings.GlobalModelDirectory = - _config.GetValue("ModelPath", "./PaddleOcrModels") ?? "./PaddleOcrModels"; + Settings.GlobalModelDirectory = _config.GetValue("ModelPath", "./PaddleOcrModels"); _paddleOcrDetectorFactory = paddleOcrDetectorFactory; _paddleOcrRecognizerFactory = paddleOcrRecognizerFactory; } diff --git a/c#/imagePipeline/src/Ocr/TesseractRecognizer.cs b/c#/imagePipeline/src/Ocr/TesseractRecognizer.cs index e2813749..d9509afb 100644 --- a/c#/imagePipeline/src/Ocr/TesseractRecognizer.cs +++ b/c#/imagePipeline/src/Ocr/TesseractRecognizer.cs @@ -5,13 +5,12 @@ namespace tbm.ImagePipeline.Ocr; public sealed partial class TesseractRecognizer(IConfiguration config, string script) : IDisposable { private readonly IConfigurationSection _config = config.GetSection("OcrConsumer:Tesseract"); - private Lazy? _tesseractInstanceHorizontal; - private Lazy? _tesseractInstanceVertical; public delegate TesseractRecognizer New(string script); [SuppressMessage("ReSharper", "StringLiteralTypo")] - private Lazy TesseractInstanceHorizontal => _tesseractInstanceHorizontal ??= new(script switch + [field: AllowNull, MaybeNull] + private Lazy TesseractInstanceHorizontal => field ??= new(script switch { // https://en.wikipedia.org/wiki/Template:ISO_15924_script_codes_and_related_Unicode_data "Hans" => CreateTesseract("best/chi_sim+best/eng"), "Hant" => CreateTesseract("best/chi_tra+best/eng"), @@ -21,7 +20,8 @@ public sealed partial class TesseractRecognizer(IConfiguration config, string sc }); [SuppressMessage("ReSharper", "StringLiteralTypo")] - private Lazy TesseractInstanceVertical => _tesseractInstanceVertical ??= new(script switch + [field: AllowNull, MaybeNull] + private Lazy TesseractInstanceVertical => field ??= new(script switch { "Hans" => CreateTesseract("best/chi_sim_vert", isVertical: true), "Hant" => CreateTesseract("best/chi_tra_vert", isVertical: true), @@ -43,7 +43,7 @@ public void Dispose() // https://github.com/shimat/opencvsharp/issues/873#issuecomment-1458868153 // https://pyimagesearch.com/2021/11/15/tesseract-page-segmentation-modes-psms-explained-how-to-improve-your-ocr-accuracy/ private OCRTesseract CreateTesseract(string scripts, bool isVertical = false) => - OCRTesseract.Create(_config.GetValue("DataPath", "") ?? "", + OCRTesseract.Create(_config.GetValue("DataPath", ""), scripts, charWhitelist: "", oem: 1, psmode: isVertical ? 5 : 7); } public sealed partial class TesseractRecognizer