using Newtonsoft.Json.Linq;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.IO;
|
|
using System.IO.MemoryMappedFiles;
|
|
using System.Linq;
|
|
using System.Net;
|
|
using System.Net.Http;
|
|
using System.Runtime.InteropServices;
|
|
using System.ServiceProcess;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using System.Windows;
|
|
using System.Xml;
|
|
using System.Xml.Serialization;
|
|
using TrustedUninstaller.Shared.Actions;
|
|
using TrustedUninstaller.Shared.Parser;
|
|
using TrustedUninstaller.Shared.Tasks;
|
|
|
|
namespace TrustedUninstaller.Shared
|
|
{
|
|
|
|
public static class AmeliorationUtil
|
|
{
|
|
private static readonly ConfigParser Parser = new ConfigParser();
|
|
|
|
private static readonly HttpClient Client = new HttpClient();
|
|
|
|
public static Playbook Playbook { set; get; }
|
|
|
|
public static readonly List<string> ErrorDisplayList = new List<string>();
|
|
|
|
public static int GetProgressMaximum(List<string> options)
|
|
{
|
|
return Parser.Tasks.Sum(task => task.Actions.Sum(action =>
|
|
{
|
|
var taskAction = (TaskAction)action;
|
|
if (!String.IsNullOrEmpty(taskAction.Option) && (options == null ||
|
|
(taskAction.Option.StartsWith("!") && options.Contains(taskAction.Option.Substring(1), StringComparer.OrdinalIgnoreCase)) ||
|
|
(!options.Contains(taskAction.Option, StringComparer.OrdinalIgnoreCase))))
|
|
return 0;
|
|
|
|
if (!String.IsNullOrEmpty(taskAction.Arch) && (
|
|
(taskAction.Arch.StartsWith("!") && String.Equals(taskAction.Arch, RuntimeInformation.ProcessArchitecture.ToString(), StringComparison.OrdinalIgnoreCase)) ||
|
|
(!String.Equals(taskAction.Arch, RuntimeInformation.ProcessArchitecture.ToString(), StringComparison.OrdinalIgnoreCase))))
|
|
return 0;
|
|
|
|
return action.GetProgressWeight();
|
|
}));
|
|
}
|
|
|
|
public static bool AddTasks(string configPath, string file)
|
|
{
|
|
try
|
|
{
|
|
//This allows for a proper detection of if any error occurred, and if so the CLI will relay an :AME-Fatal Error:
|
|
//This is important, as we want the process to stop immediately if a YAML syntax error was detected.
|
|
bool hadError = false;
|
|
|
|
//Adds the config file to the parser's task list
|
|
Parser.Add(Path.Combine(configPath, file));
|
|
|
|
var currentTask = Parser.Tasks[Parser.Tasks.Count - 1];
|
|
|
|
if (File.Exists("TasksAdded.txt"))
|
|
{
|
|
var doneTasks = File.ReadAllText("TasksAdded.txt").Split(new[] { "\r\n" }, StringSplitOptions.None);
|
|
|
|
if (doneTasks.Contains(currentTask.Title))
|
|
{
|
|
Parser.Tasks.Remove(currentTask);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
//Get the features of the last added task (the task that was just added from the config file)
|
|
var features = currentTask.Features;
|
|
|
|
//Each feature would reference a directory that has a YAML file, we take those directories and then run the
|
|
//AddTasks function again, until we reach a file that doesn't reference any other YAML files, and add them
|
|
//all to the parser's tasks list.
|
|
if (features == null) return true;
|
|
foreach (var feature in features)
|
|
{
|
|
var subResult = AddTasks(configPath, feature);
|
|
|
|
// We could return false here, however we want to output ALL detected YAML errors,
|
|
// which is why we continue here.
|
|
if (!subResult) hadError = true;
|
|
}
|
|
|
|
return hadError ? false : true;
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Console.WriteLine($"Error adding tasks in {configPath + "\\" + file}:\r\n{e.Message}");
|
|
ErrorLogger.WriteToErrorLog(e.Message, e.StackTrace, $"Error adding tasks in {configPath + "\\" + file}.");
|
|
return false;
|
|
}
|
|
}
|
|
public static async Task<int> DoActions(UninstallTask task, UninstallTaskPrivilege privilege)
|
|
{
|
|
try
|
|
{
|
|
//If the privilege is admin and the program is running as TI, do not do the action.
|
|
//if (privilege == UninstallTaskPrivilege.Admin && WinUtil.IsTrustedInstaller())
|
|
//{
|
|
// return 0;
|
|
//}
|
|
|
|
if (!WinUtil.IsTrustedInstaller())
|
|
{
|
|
Console.WriteLine("Relaunching as Trusted Installer!");
|
|
|
|
var mmf = MemoryMappedFile.CreateNew("ImgA", 30000000);
|
|
WinUtil.RelaunchAsTrustedInstaller();
|
|
if (NativeProcess.Process == null)
|
|
{
|
|
ErrorLogger.WriteToErrorLog($"Could not launch TrustedInstaller process. Return output was null.",
|
|
Environment.StackTrace, "Error while attempting to sync with TrustedInstaller process.");
|
|
|
|
Console.WriteLine(":AME-Fatal Error: Could not launch TrustedInstaller process.");
|
|
Environment.Exit(-1);
|
|
}
|
|
|
|
var delay = 20;
|
|
while (!NativeProcess.Process.HasExited)
|
|
{
|
|
if (delay > 3500)
|
|
{
|
|
NativeProcess.Process.Kill();
|
|
|
|
ErrorLogger.WriteToErrorLog($"Could not initialize memory data exchange. Timeframe exceeded.",
|
|
Environment.StackTrace, "Error while attempting to sync with TrustedInstaller process.");
|
|
|
|
Console.WriteLine(":AME-Fatal Error: Could not initialize memory data exchange.");
|
|
Environment.Exit(-1);
|
|
}
|
|
|
|
Task.Delay(delay).Wait();
|
|
// Kind of inefficient looping this, however it's likely to cause access errors otherwise
|
|
using var stream = mmf.CreateViewStream();
|
|
using BinaryReader binReader = new BinaryReader(stream);
|
|
{
|
|
var res = binReader.ReadBytes((int)stream.Length);
|
|
var data = Encoding.UTF8.GetString(res);
|
|
|
|
var end = data.IndexOf('\0');
|
|
if (end == 0)
|
|
{
|
|
delay += 200;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
var offset = 0;
|
|
var read = false;
|
|
using (var stream = mmf.CreateViewStream())
|
|
{
|
|
while (!NativeProcess.Process.HasExited || read)
|
|
{
|
|
read = false;
|
|
|
|
BinaryReader binReader = new BinaryReader(stream);
|
|
|
|
binReader.BaseStream.Seek(offset, SeekOrigin.Begin);
|
|
|
|
var res = binReader.ReadBytes((int)stream.Length - offset);
|
|
var data = Encoding.UTF8.GetString(res);
|
|
|
|
var end = data.IndexOf("\0");
|
|
|
|
var content = data.Substring(0, end);
|
|
offset += Encoding.UTF8.GetBytes(content).Length;
|
|
|
|
var output = content.Split(new [] {Environment.NewLine}, StringSplitOptions.None);
|
|
if (output.Length > 0) output = output.Take(output.Length - 1).ToArray();
|
|
|
|
foreach (var line in output)
|
|
{
|
|
Console.WriteLine(line);
|
|
read = true;
|
|
// Introducing ANY delay here makes it lag behind, which isn't ideal
|
|
//Task.Delay(5).Wait();
|
|
}
|
|
Task.Delay(20).Wait();
|
|
}
|
|
}
|
|
mmf.Dispose();
|
|
return 0; //Only returns after TI is done
|
|
}
|
|
|
|
//Goes through the list of tasks that are inside the parser class,
|
|
//and runs the task using the RunTask method
|
|
//Check the Actions folder inside the Shared folder for reference.
|
|
foreach (ITaskAction action in task.Actions)
|
|
{
|
|
var taskAction = (TaskAction)action;
|
|
|
|
if (!String.IsNullOrEmpty(taskAction.Option) && (Playbook.Options == null ||
|
|
(taskAction.Option.StartsWith("!") && Playbook.Options.Contains(taskAction.Option.Substring(1), StringComparer.OrdinalIgnoreCase)) ||
|
|
(!Playbook.Options.Contains(taskAction.Option, StringComparer.OrdinalIgnoreCase))))
|
|
continue;
|
|
|
|
if (!String.IsNullOrEmpty(taskAction.Arch) && (
|
|
(taskAction.Arch.StartsWith("!") && String.Equals(taskAction.Arch, RuntimeInformation.ProcessArchitecture.ToString(), StringComparison.OrdinalIgnoreCase)) ||
|
|
(!String.Equals(taskAction.Arch, RuntimeInformation.ProcessArchitecture.ToString(), StringComparison.OrdinalIgnoreCase))))
|
|
continue;
|
|
|
|
int i = 0;
|
|
|
|
//var actionType = action.GetType().ToString().Replace("TrustedUninstaller.Shared.Actions.", "");
|
|
|
|
try
|
|
{
|
|
do
|
|
{
|
|
//Console.WriteLine($"Running {actionType}");
|
|
Console.WriteLine();
|
|
try
|
|
{
|
|
await action.RunTask();
|
|
action.ResetProgress();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
action.ResetProgress();
|
|
if (e.InnerException != null)
|
|
{
|
|
ErrorLogger.WriteToErrorLog(e.InnerException.Message, e.InnerException.StackTrace, e.Message);
|
|
}
|
|
else
|
|
{
|
|
ErrorLogger.WriteToErrorLog(e.Message, e.StackTrace, action.ErrorString());
|
|
List<string> ExceptionBreakList = new List<string>() { "System.ArgumentException", "System.SecurityException", "System.UnauthorizedAccessException", "System.UnauthorizedAccessException", "System.TimeoutException" };
|
|
if (ExceptionBreakList.Any(x => x.Equals(e.GetType().ToString())))
|
|
{
|
|
i = 10;
|
|
break;
|
|
}
|
|
}
|
|
Thread.Sleep(300);
|
|
}
|
|
Console.WriteLine($"Status: {action.GetStatus()}");
|
|
if (i > 0) Thread.Sleep(50);
|
|
i++;
|
|
} while (action.GetStatus() != UninstallTaskStatus.Completed && i < 10);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
ErrorLogger.WriteToErrorLog(e.Message, e.StackTrace, "Critical error while running action.");
|
|
if (!((TaskAction)action).IgnoreErrors)
|
|
Console.WriteLine($":AME-ERROR: Critical error while running action: " + e.Message);
|
|
}
|
|
|
|
if (i == 10)
|
|
{
|
|
var errorString = action.ErrorString();
|
|
ErrorLogger.WriteToErrorLog(errorString, Environment.StackTrace, "Action failed to complete.");
|
|
// AmeliorationUtil.ErrorDisplayList.Add(errorString) would NOT work here since this
|
|
// might be a separate process, and thus has to be forwarded via the console
|
|
if (!((TaskAction)action).IgnoreErrors)
|
|
Console.WriteLine($":AME-ERROR: {errorString}");
|
|
//Environment.Exit(-2);
|
|
Console.WriteLine($"Action completed. Weight:{action.GetProgressWeight()}");
|
|
continue;
|
|
}
|
|
Console.WriteLine($"Action completed. Weight:{action.GetProgressWeight()}");
|
|
}
|
|
Console.WriteLine("Task completed.");
|
|
|
|
File.AppendAllText("TasksAdded.txt", task.Title + Environment.NewLine);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
ErrorLogger.WriteToErrorLog(e.Message, e.StackTrace,
|
|
"Encountered an error while doing task actions.");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
public static Task<Playbook> DeserializePlaybook(string dir)
|
|
{
|
|
Playbook pb;
|
|
|
|
XmlSerializer serializer = new XmlSerializer(typeof(Playbook));
|
|
/*serializer.UnknownElement += delegate(object sender, XmlElementEventArgs args)
|
|
{
|
|
MessageBox.Show(args.Element.Name);
|
|
};
|
|
serializer.UnknownAttribute += delegate(object sender, XmlAttributeEventArgs args)
|
|
{
|
|
MessageBox.Show(args.Attr.Name);
|
|
};*/
|
|
using (XmlReader reader = XmlReader.Create($"{dir}\\playbook.conf"))
|
|
{
|
|
pb = (Playbook)serializer.Deserialize(reader);
|
|
}
|
|
var validateResult = pb.Validate();
|
|
if (validateResult != null)
|
|
throw new XmlException(validateResult);
|
|
|
|
if (File.Exists($"{dir}\\options.txt"))
|
|
{
|
|
pb.Options = new List<string>();
|
|
using (var reader = new StreamReader($"{dir}\\options.txt"))
|
|
{
|
|
while (!reader.EndOfStream)
|
|
pb.Options.Add(reader.ReadLine());
|
|
}
|
|
}
|
|
pb.Path = dir;
|
|
return Task.FromResult(pb);
|
|
}
|
|
|
|
public static async Task<int> StartAmelioration()
|
|
{
|
|
//Needed after defender removal's reboot, the "current directory" will be set to System32
|
|
//After the auto start up.
|
|
Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory);
|
|
|
|
if (File.Exists("TasksAdded.txt") && !WinUtil.IsTrustedInstaller())
|
|
{
|
|
File.Delete("TasksAdded.txt");
|
|
}
|
|
|
|
if (Directory.Exists("Logs") && !WinUtil.IsTrustedInstaller())
|
|
{
|
|
if (File.Exists("Logs\\AdminOutput.txt"))
|
|
{
|
|
File.Delete("Logs\\AdminOutput.txt");
|
|
}
|
|
|
|
if (File.Exists("Logs\\TIOutput.txt"))
|
|
{
|
|
File.Delete("Logs\\TIOutput.txt");
|
|
}
|
|
|
|
if (File.Exists("Logs\\FileChecklist.txt"))
|
|
{
|
|
File.Delete("Logs\\FileChecklist.txt");
|
|
}
|
|
}
|
|
|
|
//Check if KPH is installed.
|
|
ServiceController service = ServiceController.GetDevices()
|
|
.FirstOrDefault(s => s.DisplayName == "KProcessHacker2");
|
|
if (service == null)
|
|
{
|
|
//Installs KPH
|
|
await WinUtil.RemoveProtectionAsync();
|
|
}
|
|
|
|
var langsFile = Path.Combine($"{Playbook.Path}\\Configuration", "langs.txt");
|
|
//Download language packs that were selected by the user
|
|
if (!File.Exists(langsFile))
|
|
{
|
|
File.Create(langsFile);
|
|
}
|
|
|
|
//var langsSelected = File.ReadLines(langsFile);
|
|
|
|
//await DownloadLanguagesAsync(langsSelected);
|
|
|
|
//Start adding tasks from the top level configuration folder.
|
|
if (!AddTasks($"{Playbook.Path}\\Configuration", "custom.yml"))
|
|
{
|
|
Console.WriteLine($":AME-Fatal Error: Error adding tasks.");
|
|
Environment.Exit(1);
|
|
}
|
|
|
|
if (!Parser.Tasks.Any())
|
|
{
|
|
Console.Error.WriteLine($"Couldn't find any tasks.");
|
|
return -1;
|
|
}
|
|
|
|
//Sort the list based on the priority value.
|
|
if (Parser.Tasks.Any(x => x.Priority != Parser.Tasks.First().Priority))
|
|
Parser.Tasks.Sort(new TaskComparer());
|
|
|
|
bool launched = false;
|
|
foreach (var task in Parser.Tasks.Where(task => task.Actions.Count != 0))
|
|
{
|
|
try
|
|
{
|
|
//if (prevPriv == UninstallTaskPrivilege.TrustedInstaller && task.Privilege == UninstallTaskPrivilege.TrustedInstaller && !WinUtil.IsTrustedInstaller())
|
|
if (!WinUtil.IsTrustedInstaller() && launched)
|
|
{
|
|
continue;
|
|
}
|
|
launched = true;
|
|
await DoActions(task, task.Privilege);
|
|
//prevPriv = task.Privilege;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ErrorLogger.WriteToErrorLog(ex.Message, ex.StackTrace, "Error during DoAction loop.");
|
|
}
|
|
}
|
|
|
|
if (WinUtil.IsTrustedInstaller()) return 0;
|
|
|
|
WinUtil.RegistryManager.UnhookUserHives();
|
|
|
|
//Check how many files were successfully and unsuccessfully deleted.
|
|
var deletedItemsCount = 0;
|
|
var failedDeletedItemsCount = 0;
|
|
|
|
if (File.Exists("Logs\\FileChecklist.txt"))
|
|
{
|
|
using (var reader = new StreamReader("Logs\\FileChecklist.txt"))
|
|
{
|
|
var data = reader.ReadToEnd();
|
|
var listData = data.Split(new [] { Environment.NewLine }, StringSplitOptions.None).ToList();
|
|
deletedItemsCount = listData.FindAll(s => s == "Deleted: True").Count();
|
|
failedDeletedItemsCount = listData.FindAll(s => s == "Deleted: False").Count();
|
|
}
|
|
|
|
using (var writer = new StreamWriter("Logs\\FileChecklist.txt", true))
|
|
{
|
|
writer.WriteLine($"{deletedItemsCount} files were deleted successfully. " +
|
|
$"{failedDeletedItemsCount} files couldn't be deleted.");
|
|
}
|
|
}
|
|
|
|
Console.WriteLine($"{deletedItemsCount} files were deleted successfully. " +
|
|
$"{failedDeletedItemsCount} files couldn't be deleted.");
|
|
|
|
|
|
//Check if the kernel driver is installed.
|
|
//service = ServiceController.GetDevices()
|
|
//.FirstOrDefault(s => s.DisplayName == "KProcessHacker2");
|
|
if (true)
|
|
{
|
|
//Remove Process Hacker's kernel driver.
|
|
await WinUtil.UninstallDriver();
|
|
}
|
|
await AmeliorationUtil.SafeRunAction(new RegistryKeyAction()
|
|
{
|
|
KeyName = @"HKLM\SYSTEM\CurrentControlSet\Services\KProcessHacker2",
|
|
});
|
|
|
|
File.Delete("TasksAdded.txt");
|
|
|
|
Console.WriteLine();
|
|
Console.WriteLine("Playbook finished.");
|
|
|
|
return 0;
|
|
}
|
|
public static async Task DownloadLanguagesAsync(IEnumerable<string> langsSelected)
|
|
{
|
|
|
|
foreach (var lang in langsSelected)
|
|
{
|
|
|
|
var lowerLang = lang.ToLower();
|
|
|
|
var arch = RuntimeInformation.OSArchitecture;
|
|
var winVersion = Environment.OSVersion.Version.Build;
|
|
|
|
var convertedArch = "";
|
|
switch (arch)
|
|
{
|
|
case Architecture.X64:
|
|
convertedArch = "amd64";
|
|
break;
|
|
case Architecture.Arm64:
|
|
convertedArch = "arm64";
|
|
break;
|
|
case Architecture.X86:
|
|
convertedArch = "x86";
|
|
break;
|
|
}
|
|
|
|
var uuidOfWindowsVersion = "";
|
|
var uuidResponse =
|
|
await Client.GetAsync(
|
|
$"https://api.uupdump.net/listid.php?search={winVersion}%20{convertedArch}&sortByDate=1");
|
|
switch (uuidResponse.StatusCode)
|
|
{
|
|
//200 Status code
|
|
case HttpStatusCode.OK:
|
|
{
|
|
var result = uuidResponse.Content.ReadAsStringAsync().Result;
|
|
//Gets the UUID of the first build object in the response, we take the first since it's the newest.
|
|
uuidOfWindowsVersion = (string)(JToken.Parse(result)["response"]?["builds"]?.Children().First()
|
|
.Children().First().Last());
|
|
break;
|
|
}
|
|
//400 Status code
|
|
case HttpStatusCode.BadRequest:
|
|
{
|
|
var result = uuidResponse.Content.ReadAsStringAsync().Result;
|
|
dynamic data = JObject.Parse(result);
|
|
Console.WriteLine($"Bad request.\r\nError:{data["response"]["error"]}");
|
|
break;
|
|
}
|
|
//429 Status code
|
|
case (HttpStatusCode)429:
|
|
{
|
|
var result = uuidResponse.Content.ReadAsStringAsync().Result;
|
|
dynamic data = JObject.Parse(result);
|
|
Console.WriteLine($"Too many requests, try again later.\r\nError:{data["response"]["error"]}");
|
|
break;
|
|
}
|
|
//500 Status code
|
|
case HttpStatusCode.InternalServerError:
|
|
{
|
|
var result = uuidResponse.Content.ReadAsStringAsync().Result;
|
|
dynamic data = JObject.Parse(result);
|
|
Console.WriteLine($"Internal Server Error.\r\nError:{data["response"]["error"]}");
|
|
break;
|
|
}
|
|
default:
|
|
throw new ArgumentOutOfRangeException();
|
|
}
|
|
|
|
var responseString =
|
|
await Client.GetAsync(
|
|
$"https://api.uupdump.net/get.php?id={uuidOfWindowsVersion}&lang={lowerLang}");
|
|
switch (responseString.StatusCode)
|
|
{
|
|
//200 Status code
|
|
case HttpStatusCode.OK:
|
|
{
|
|
|
|
var result = responseString.Content.ReadAsStringAsync().Result;
|
|
dynamic data = JObject.Parse(result);
|
|
//Add different urls to different packages to a list
|
|
var urls = new Dictionary<string, string>
|
|
{
|
|
{
|
|
"basic", (string) data["response"]["files"][
|
|
$"microsoft-windows-languagefeatures-basic-{lowerLang}-package-{convertedArch}.cab"]
|
|
[
|
|
"url"]
|
|
},
|
|
{
|
|
"hw", (string) data["response"]["files"][
|
|
$"microsoft-windows-languagefeatures-handwriting-{lowerLang}-package-{convertedArch}.cab"]
|
|
[
|
|
"url"]
|
|
},
|
|
{
|
|
"ocr", (string) data["response"]["files"][
|
|
$"microsoft-windows-languagefeatures-ocr-{lowerLang}-package-{convertedArch}.cab"][
|
|
"url"]
|
|
},
|
|
{
|
|
"speech", (string) data["response"]["files"][
|
|
$"microsoft-windows-languagefeatures-speech-{lowerLang}-package-{convertedArch}.cab"]
|
|
[
|
|
"url"]
|
|
},
|
|
{
|
|
"tts", (string) data["response"]["files"][
|
|
$"microsoft-windows-languagefeatures-texttospeech-{lowerLang}-package-{convertedArch}.cab"]
|
|
[
|
|
"url"]
|
|
}
|
|
};
|
|
|
|
|
|
var amePath = Path.Combine(Path.GetTempPath(), "AME\\");
|
|
//Create the directory if it doesn't exist.
|
|
var file = new FileInfo(amePath);
|
|
file.Directory?.Create(); //Does nothing if the directory already exists
|
|
|
|
//Final result being "temp\AME\Languages\file.cab"
|
|
var downloadPath = Path.Combine(amePath, "Languages\\");
|
|
file = new FileInfo(downloadPath);
|
|
file.Directory?.Create();
|
|
using (var webClient = new WebClient())
|
|
{
|
|
Console.WriteLine($"Downloading {lowerLang}.cab file, please wait..");
|
|
foreach (var url in urls)
|
|
{
|
|
//Check if the file exists, if it does exist, skip it.
|
|
if (File.Exists(Path.Combine(downloadPath, $"{url.Key}_{lowerLang}.cab")))
|
|
{
|
|
Console.WriteLine($"{url.Key}_{lowerLang} already exists, skipping.");
|
|
continue;
|
|
}
|
|
//Output file format: featureName_languageCode.cab: speech_de-de.cab
|
|
webClient.DownloadFile(url.Value, $@"{downloadPath}\{url.Key}_{lowerLang}.cab");
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
//400 Status code
|
|
case HttpStatusCode.BadRequest:
|
|
{
|
|
var result = responseString.Content.ReadAsStringAsync().Result;
|
|
dynamic data = JObject.Parse(result);
|
|
Console.WriteLine($"Bad request.\r\nError:{data["response"]["error"]}");
|
|
break;
|
|
}
|
|
//429 Status code
|
|
case (HttpStatusCode)429:
|
|
{
|
|
var result = responseString.Content.ReadAsStringAsync().Result;
|
|
dynamic data = JObject.Parse(result);
|
|
Console.WriteLine($"Too many requests, try again later.\r\nError:{data["response"]["error"]}");
|
|
break;
|
|
}
|
|
//500 Status code
|
|
case HttpStatusCode.InternalServerError:
|
|
{
|
|
var result = responseString.Content.ReadAsStringAsync().Result;
|
|
dynamic data = JObject.Parse(result);
|
|
Console.WriteLine($"Internal Server Error.\r\nError:{data["response"]["error"]}");
|
|
break;
|
|
}
|
|
default:
|
|
throw new ArgumentOutOfRangeException();
|
|
}
|
|
}
|
|
}
|
|
|
|
public static async Task<bool> SafeRunAction(ITaskAction action)
|
|
{
|
|
try
|
|
{
|
|
return await action.RunTask();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
action.ResetProgress();
|
|
if (e.InnerException != null)
|
|
{
|
|
ErrorLogger.WriteToErrorLog(e.InnerException.Message, e.InnerException.StackTrace, e.Message);
|
|
}
|
|
else
|
|
{
|
|
ErrorLogger.WriteToErrorLog(e.Message, e.StackTrace, action.ErrorString());
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
}
|