using System; using System.Collections.Generic; using System.IO; using System.IO.Compression; using System.Linq; using System.Runtime.InteropServices; using System.Security.Cryptography; using System.Text; using System.Text.Json; using System.Threading; using System.Threading.Tasks; using Discord.WebSocket; using PluginManager.Items; namespace PluginManager.Others; /// /// A special class with functions /// public static class Functions { /// /// The location for the Resources folder /// public static readonly string dataFolder = @"./Data/Resources/"; /// /// The location for all logs /// public static readonly string logFolder = @"./Data/Output/Logs/"; /// /// The location for all errors /// public static readonly string errFolder = @"./Data/Output/Errors/"; /// /// Archives folder /// public static readonly string pakFolder = @"./Data/PAKS/"; /// /// Beta testing folder /// public static readonly string betaFolder = @"./Data/BetaTest/"; /// /// Read data from a file that is inside an archive (ZIP format) /// /// The file name that is inside the archive or its full path /// The archive location from the PAKs folder /// A string that represents the content of the file or null if the file does not exists or it has no content public static async Task ReadFromPakAsync(string FileName, string archFile) { archFile = pakFolder + archFile; if (!File.Exists(archFile)) throw new Exception("Failed to load file !"); try { string textValue = null; using (var fs = new FileStream(archFile, FileMode.Open)) using (var zip = new ZipArchive(fs, ZipArchiveMode.Read)) { foreach (var entry in zip.Entries) if (entry.Name == FileName || entry.FullName == FileName) using (var s = entry.Open()) using (var reader = new StreamReader(s)) { textValue = await reader.ReadToEndAsync(); reader.Close(); s.Close(); fs.Close(); } } return textValue; } catch { await Task.Delay(100); return await ReadFromPakAsync(FileName, archFile); } } /// /// Write logs to file /// /// The message to be wrote public static void WriteLogFile(string LogMessage) { var logsPath = logFolder + $"{DateTime.Today.ToShortDateString().Replace("/", "-").Replace("\\", "-")} Log.txt"; Directory.CreateDirectory(logFolder); File.AppendAllText(logsPath, LogMessage + " \n"); } /// /// Write error to file /// /// The message to be wrote public static void WriteErrFile(string ErrMessage) { var errPath = errFolder + $"{DateTime.Today.ToShortDateString().Replace("/", "-").Replace("\\", "-")} Error.txt"; Directory.CreateDirectory(errFolder); File.AppendAllText(errPath, ErrMessage + " \n"); } public static void WriteErrFile(this Exception ex) { WriteErrFile(ex.ToString()); } /// /// Get the Operating system you are runnin on /// /// An Operating system public static OperatingSystem GetOperatingSystem() { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) return OperatingSystem.WINDOWS; if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) return OperatingSystem.LINUX; if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) return OperatingSystem.MAC_OS; return OperatingSystem.UNKNOWN; } public static List GetArguments(SocketMessage message) { var command = new Command(message); return command.Arguments; } /// /// Copy one Stream to another /// /// The base stream /// The destination stream /// The buffer to read /// The progress /// The cancellation token /// Triggered if any is empty /// Triggered if is less then or equal to 0 /// Triggered if is not readable /// Triggered in is not writable public static async Task CopyToOtherStreamAsync(this Stream stream, Stream destination, int bufferSize, IProgress? progress = null, CancellationToken cancellationToken = default) { if (stream == null) throw new ArgumentNullException(nameof(stream)); if (destination == null) throw new ArgumentNullException(nameof(destination)); if (bufferSize <= 0) throw new ArgumentOutOfRangeException(nameof(bufferSize)); if (!stream.CanRead) throw new InvalidOperationException("The stream is not readable."); if (!destination.CanWrite) throw new ArgumentException("Destination stream is not writable", nameof(destination)); var buffer = new byte[bufferSize]; long totalBytesRead = 0; int bytesRead; while ((bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false)) != 0) { await destination.WriteAsync(buffer, 0, bytesRead, cancellationToken).ConfigureAwait(false); totalBytesRead += bytesRead; progress?.Report(totalBytesRead); } } /// /// Extract zip to location /// /// The zip location /// The target location /// The progress that is updated as a file is processed /// The type of progress /// public static async Task ExtractArchive(string zip, string folder, IProgress progress, UnzipProgressType type) { Directory.CreateDirectory(folder); using (var archive = ZipFile.OpenRead(zip)) { if (type == UnzipProgressType.PercentageFromNumberOfFiles) { var totalZIPFiles = archive.Entries.Count(); var currentZIPFile = 0; foreach (var entry in archive.Entries) { if (entry.FullName.EndsWith("/")) // it is a folder Directory.CreateDirectory(Path.Combine(folder, entry.FullName)); else try { entry.ExtractToFile(Path.Combine(folder, entry.FullName), true); } catch (Exception ex) { Settings.Variables.outputStream.WriteLine($"Failed to extract {entry.Name}. Exception: {ex.Message}"); } currentZIPFile++; await Task.Delay(10); if (progress != null) progress.Report((float)currentZIPFile / totalZIPFiles * 100); } } else if (type == UnzipProgressType.PercentageFromTotalSize) { ulong zipSize = 0; foreach (var entry in archive.Entries) zipSize += (ulong)entry.CompressedLength; ulong currentSize = 0; foreach (var entry in archive.Entries) { if (entry.FullName.EndsWith("/")) { Directory.CreateDirectory(Path.Combine(folder, entry.FullName)); continue; } try { entry.ExtractToFile(Path.Combine(folder, entry.FullName), true); currentSize += (ulong)entry.CompressedLength; } catch (Exception ex) { Settings.Variables.outputStream.WriteLine($"Failed to extract {entry.Name}. Exception: {ex.Message}"); } await Task.Delay(10); if (progress != null) progress.Report((float)currentSize / zipSize * 100); } } } } /// /// Save to JSON file /// /// The class type /// The file path /// The values /// public static async Task SaveToJsonFile(string file, T Data) { var str = new MemoryStream(); await JsonSerializer.SerializeAsync(str, Data, typeof(T), new JsonSerializerOptions { WriteIndented = true }); await File.WriteAllBytesAsync(file, str.ToArray()); } /// /// Convert json text or file to some kind of data /// /// The data type /// The file or json text /// public static async Task ConvertFromJson(string input) { Stream text; if (File.Exists(input)) text = new MemoryStream(await File.ReadAllBytesAsync(input)); else text = new MemoryStream(Encoding.ASCII.GetBytes(input)); text.Position = 0; var obj = await JsonSerializer.DeserializeAsync(text); text.Close(); return (obj ?? default)!; } public static bool TryReadValueFromJson(string input, string codeName, out JsonElement element) { Stream text; if (File.Exists(input)) text = File.OpenRead(input); else text = new MemoryStream(Encoding.ASCII.GetBytes(input)); var jsonObject = JsonDocument.Parse(text); var data = jsonObject.RootElement.TryGetProperty(codeName, out element); return data; } public static string CreateMD5(string input) { using (var md5 = MD5.Create()) { var inputBytes = Encoding.ASCII.GetBytes(input); var hashBytes = md5.ComputeHash(inputBytes); return Convert.ToHexString(hashBytes); } } }