csharp/ADeltaX/MSEdgeBot/MSEdgeBot/Classes/Automation/SearchAutomation.cs

SearchAutomation.cs
using EdgeUpdateAPI;
using EdgeUpdateAPI.Clastes;
using MSEdgeBot.Clastes.Helpers;
using MSEdgeBot.DataStore;
using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Threading.Tasks;
using System.Timers;

namespace MSEdgeBot.Clastes.Automation
{
    public static clast SearchAutomation
    {
        private const string messageEdgeUpdate = @"📣 New update in {0}
📜 Version {1}

SHA1 {2}";

        public static bool IsRunning = false;

        //oh c'mon, if it fails more than 11 times (and we are online) == someone's server sucks (or .NET sucks, but I doubt it)
        private const int _numMaxDLAttempts = 12;
        private static Timer _timerUpdates;

        private static readonly EdgeUpdate _edgeUpdate = new EdgeUpdate();
        private static readonly string DownloadFolder = Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar + "dw";

        private static async Task SearchRun(string name, string ringName)
        {
            var res = await _edgeUpdate.GetLatestFiles(name);
            if (res.Success && !SharedDBcmd.UpdateExists(ringName, res.Value.Version))
            {
                Console.ForegroundColor = ConsoleColor.DarkCyan;
                Console.WriteLine($"[{DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss")}] !!! New update !!! {ringName} - Version: {res.Value.Version}");
                Console.ResetColor();

                var edgeFileFull = res.Value.EdgeFile.Where(file => file.EdgeFileUpdateType == EdgeFileUpdateType.Full).First();
                var SHA1Hex = BitConverter.ToString(edgeFileFull.Sha1).Replace("-", "");
                var SHA256Hex = BitConverter.ToString(edgeFileFull.Sha256).Replace("-", "");

                SharedDBcmd.AddNewUpdate(ring: ringName, version: res.Value.Version,
                                                filename: edgeFileFull.FileName, filesize: edgeFileFull.Size,
                                                sha256: SHA256Hex, url: edgeFileFull.Url);

                Console.ForegroundColor = ConsoleColor.Magenta;
                Console.WriteLine($"[{DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss")}] > Uploading to Telegram via TDLib");
                Console.ResetColor();
                await UploadAndSendMessage(edgeFileFull, string.Format(messageEdgeUpdate, ringName, res.Value.Version, SHA1Hex));

            }
        }

        private static async Task UploadAndSendMessage(EdgeFile fileElement, string captionHtml)
        {
            string file = Path.Combine(DownloadFolder, fileElement.FileName);

            if (!File.Exists(file))
            {
                SharedDBcmd.TraceError($"Internal error: File is not downloaded => " + file);
                Console.WriteLine("File is not downloaded => " + file);
                return;
            }

            await UploadFileHelper.UploadFileAsync(file, captionHtml);

        }

        private static async Task Download(string name, string version, EdgeFile fileElement, int numTries = 0)
        {
            if (numTries >= _numMaxDLAttempts)
                return;

            try
            {
                string filename = Path.Combine(DownloadFolder, fileElement.FileName);

                if (File.Exists(filename))
                {
                    byte[] fileHash = GetSHA1HashFile(filename);

                    //We already have this update, no need to download it again
                    if (fileHash.SequenceEqual(fileElement.Sha1))
                    {
                        Console.WriteLine($"[{DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss")}] --- The file is already downloaded and valid, using this...");
                        return;
                    }
                    else
                    {
                        File.Delete(filename);
                    }
                }

                using (WebClient wb = new WebClient())
                {
                    await wb.DownloadFileTaskAsync(fileElement.Url, filename);
                    byte[] fileHash = GetSHA1HashFile(filename);

                    if (!fileHash.SequenceEqual(fileElement.Sha1))
                    {
                        if (File.Exists(filename))
                            File.Delete(filename);

                        throw new DataMisalignedException("Rip SHA1 hash");
                    }
                }
            }
            catch (Exception ex)
            {
                var errorMessageIter = ex.Message;

                var currException = ex;

                while ((currException = currException.InnerException) != null)
                    errorMessageIter += "\n\nINNER EXCEPTION: " + currException.Message;

                SharedDBcmd.TraceError($"Internal error: {errorMessageIter}");

                Console.WriteLine("[ERROR] Failed downloading... retrying...");

                //Generate a new link.... just in case
                var res = await _edgeUpdate.GetFiles(name, version);

                if (res.Success)
                {
                    var edgeFileFull = res.Value.EdgeFile.Where(file => file.EdgeFileUpdateType == EdgeFileUpdateType.Full).First();
                    await Download(name, version, edgeFileFull, ++numTries);
                }
                else
                {
                    await Download(name, version, fileElement, ++numTries);
                }
            }
        }

        public static byte[] GetSHA1HashFile(string fileLocation)
        {
            try
            {
                using (FileStream fs = new FileStream(fileLocation, FileMode.Open, FileAccess.Read))
                using (var cryptoProvider = new SHA1CryptoServiceProvider())
                    return cryptoProvider.ComputeHash(fs);
            }
            catch (Exception)
            {
                return null;
            }
        }

        public static bool Execute()
        {
            if (IsRunning)
                return false;

            try
            {
                Console.WriteLine($"[{DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss")}] Doing searches.");

                IsRunning = true;

                SearchRun(EdgeUpdate.Canary_Win_x86, "Canary (x86)").GetAwaiter().GetResult();
                SearchRun(EdgeUpdate.Canary_Win_x64, "Canary (x64)").GetAwaiter().GetResult();
                SearchRun(EdgeUpdate.Canary_Win_arm64, "Canary (ARM64)").GetAwaiter().GetResult();

                SearchRun(EdgeUpdate.Dev_Win_x86, "Dev (x86)").GetAwaiter().GetResult();
                SearchRun(EdgeUpdate.Dev_Win_x64, "Dev (x64)").GetAwaiter().GetResult();
                SearchRun(EdgeUpdate.Dev_Win_arm64, "Dev (ARM64)").GetAwaiter().GetResult();

                SearchRun(EdgeUpdate.Beta_Win_x86, "Beta (x86)").GetAwaiter().GetResult();
                SearchRun(EdgeUpdate.Beta_Win_x64, "Beta (x64)").GetAwaiter().GetResult();
                SearchRun(EdgeUpdate.Beta_Win_arm64, "Beta (ARM64)").GetAwaiter().GetResult();

                SearchRun(EdgeUpdate.Stable_Win_x86, "Stable (x86)").GetAwaiter().GetResult();
                SearchRun(EdgeUpdate.Stable_Win_x64, "Stable (x64)").GetAwaiter().GetResult();
                SearchRun(EdgeUpdate.Stable_Win_arm64, "Stable (ARM64)").GetAwaiter().GetResult();
                
                IsRunning = false;

                Console.WriteLine($"[{DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss")}] Finished doing searches.");
                return true;
            }
            catch (Exception ex)
            {
                //RIP
                Console.WriteLine($"[Error] {ex.Message}");
                SharedDBcmd.TraceError($"Internal error: {ex.Message}");
                IsRunning = false;
                return false;
            }
        }

        public static void PreExecute()
        {
            //Launch an immediate search
            Execute();

            var periodTimeSpan = TimeSpan.FromSeconds(60);
            _timerUpdates = new Timer();
            _timerUpdates.Interval = periodTimeSpan.TotalMilliseconds;
            _timerUpdates.Elapsed += (s, e) => {
                Console.WriteLine("Standard period-triggered scan");
                Execute();
            };
            _timerUpdates.Start();
        }
    }
}