all plugins: fixed possible race condition introduced in 4.4

This commit is contained in:
alterNERDtive 2022-06-02 15:28:17 +02:00
parent 35057b3f35
commit 55f10a1117
5 changed files with 143 additions and 131 deletions

View file

@ -1,4 +1,14 @@
# 4.4 (2022-05-31)
# devel
### Fixed
* Race condition in all plugins that might lead to commands using command-scoped
variables (`~<name>`) not working as intended. This was introduced in
refactoring work that was done for 4.4.
-----
# 4.4 (2022-05-31)
### Added

View file

@ -86,8 +86,6 @@ namespace EliteAttack
/// <param name="vaProxy">The VoiceAttack proxy object.</param>
public static void VA_Invoke1(dynamic vaProxy)
{
VA = vaProxy;
string context = vaProxy.Context.ToLower();
Log.Debug($"Running context '{context}' …");
try
@ -95,11 +93,11 @@ namespace EliteAttack
switch (context)
{
case "startup":
Context_Startup();
Context_Startup(vaProxy);
break;
case "log.log":
// log
Context_Log();
Context_Log(vaProxy);
break;
default:
// invalid
@ -140,10 +138,11 @@ namespace EliteAttack
| plugin contexts |
\================*/
private static void Context_Log()
#pragma warning disable IDE0060 // Remove unused parameter
private static void Context_Log(dynamic vaProxy)
{
string message = VA!.GetText("~message");
string level = VA!.GetText("~level");
string message = vaProxy.GetText("~message");
string level = vaProxy.GetText("~level");
if (level == null)
{
@ -166,10 +165,11 @@ namespace EliteAttack
}
}
private static void Context_Startup()
private static void Context_Startup(dynamic vaProxy)
{
Log.Notice("Starting up …");
Log.Notice("Finished startup.");
}
#pragma warning restore IDE0060 // Remove unused parameter
}
}

View file

@ -102,8 +102,6 @@ namespace RatAttack
/// <param name="vaProxy">The VoiceAttack proxy object.</param>
public static void VA_Invoke1(dynamic vaProxy)
{
VA = vaProxy;
string context = vaProxy.Context.ToLower();
Log.Debug($"Running context '{context}' …");
try
@ -112,25 +110,25 @@ namespace RatAttack
{
case "getcasedata":
// plugin methods
Context_GetCaseData();
Context_GetCaseData(vaProxy);
break;
case "parseratsignal":
Context_ParseRatsignal();
Context_ParseRatsignal(vaProxy);
break;
case "startup":
Context_Startup();
Context_Startup(vaProxy);
break;
case "edsm.getnearestcmdr":
// EDSM
Context_EDSM_GetNearestCMDR();
Context_EDSM_GetNearestCMDR(vaProxy);
break;
case "log.log":
// log
Context_Log();
Context_Log(vaProxy);
break;
default:
// invalid
Log.Error($"Invalid plugin context '{VA!.Context}'.");
Log.Error($"Invalid plugin context '{vaProxy.Context}'.");
break;
}
}
@ -232,10 +230,11 @@ namespace RatAttack
| plugin contexts |
\================*/
private static void Context_EDSM_GetNearestCMDR()
#pragma warning disable IDE0060 // Remove unused parameter
private static void Context_EDSM_GetNearestCMDR(dynamic vaProxy)
{
int caseNo = VA!.GetInt("~caseNo") ?? throw new ArgumentNullException("~caseNo");
string cmdrList = VA!.GetText("~cmdrs") ?? throw new ArgumentNullException("~cmdrs");
int caseNo = vaProxy.GetInt("~caseNo") ?? throw new ArgumentNullException("~caseNo");
string cmdrList = vaProxy.GetText("~cmdrs") ?? throw new ArgumentNullException("~cmdrs");
string[] cmdrs = cmdrList.Split(';');
if (cmdrs.Length == 0)
{
@ -244,7 +243,7 @@ namespace RatAttack
string system = CaseList[caseNo]?.System ?? throw new ArgumentException($"Case #{caseNo} has no system information", "~caseNo");
string path = $@"{VA!.SessionState["VA_SOUNDS"]}\Scripts\edsm-getnearest.exe";
string path = $@"{vaProxy.SessionState["VA_SOUNDS"]}\Scripts\edsm-getnearest.exe";
string arguments = $@"--short --text --system ""{system}"" ""{string.Join(@""" """, cmdrs)}""";
Process p = PythonProxy.SetupPythonScript(path, arguments);
@ -279,29 +278,29 @@ namespace RatAttack
break;
}
VA!.SetText("~message", message);
VA!.SetBoolean("~error", error);
VA!.SetText("~errorMessage", errorMessage);
VA!.SetInt("~exitCode", p.ExitCode);
vaProxy.SetText("~message", message);
vaProxy.SetBoolean("~error", error);
vaProxy.SetText("~errorMessage", errorMessage);
vaProxy.SetInt("~exitCode", p.ExitCode);
}
private static void Context_GetCaseData()
private static void Context_GetCaseData(dynamic vaProxy)
{
int cn = VA!.GetInt("~caseNumber");
int cn = vaProxy.GetInt("~caseNumber");
if (CaseList.ContainsKey(cn))
{
RatCase rc = CaseList[cn];
VA!.SetInt("~~caseNumber", rc.Number);
VA!.SetText("~~cmdr", rc.Cmdr);
VA!.SetText("~~system", rc?.System?.ToLower());
VA!.SetText("~~systemInfo", rc?.SystemInfo);
VA!.SetBoolean("~~permitLocked", rc?.PermitLocked);
VA!.SetText("~~permitName", rc?.PermitName);
VA!.SetText("~~platform", rc?.Platform);
VA!.SetBoolean("~~odyssey", rc?.Odyssey);
VA!.SetBoolean("~~codeRed", rc?.CodeRed);
vaProxy.SetInt("~~caseNumber", rc.Number);
vaProxy.SetText("~~cmdr", rc.Cmdr);
vaProxy.SetText("~~system", rc?.System?.ToLower());
vaProxy.SetText("~~systemInfo", rc?.SystemInfo);
vaProxy.SetBoolean("~~permitLocked", rc?.PermitLocked);
vaProxy.SetText("~~permitName", rc?.PermitName);
vaProxy.SetText("~~platform", rc?.Platform);
vaProxy.SetBoolean("~~odyssey", rc?.Odyssey);
vaProxy.SetBoolean("~~codeRed", rc?.CodeRed);
}
else
{
@ -309,10 +308,10 @@ namespace RatAttack
}
}
private static void Context_Log()
private static void Context_Log(dynamic vaProxy)
{
string message = VA!.GetText("~message");
string level = VA!.GetText("~level");
string message = vaProxy.GetText("~message");
string level = vaProxy.GetText("~level");
if (level == null)
{
@ -335,18 +334,19 @@ namespace RatAttack
}
}
private static void Context_Startup()
private static void Context_Startup(dynamic vaProxy)
{
Log.Notice("Starting up …");
_ = RatsignalPipe.Run();
Log.Notice("Finished startup.");
}
private static void Context_ParseRatsignal()
private static void Context_ParseRatsignal(dynamic vaProxy)
{
Log.Warn("Passing a RATSIGNAL to VoiceAttack through the clipboard or a file is DEPRECATED and will no longer be supported in the future.");
On_Ratsignal(new Ratsignal(VA!.GetText("~ratsignal"), VA!.GetBoolean("~announceRatsignal")));
On_Ratsignal(new Ratsignal(vaProxy.GetText("~ratsignal"), vaProxy.GetBoolean("~announceRatsignal")));
}
#pragma warning restore IDE0060 // Remove unused parameter
/// <summary>
/// Encapsulates a RATSIGNAL for sending between the CLI helper tool and

View file

@ -89,8 +89,6 @@ namespace SpanshAttack
/// <param name="vaProxy">The VoiceAttack proxy object.</param>
public static void VA_Invoke1(dynamic vaProxy)
{
VA = vaProxy;
string context = vaProxy.Context.ToLower();
Log.Debug($"Running context '{context}' …");
try
@ -98,26 +96,26 @@ namespace SpanshAttack
switch (context)
{
case "startup":
Context_Startup();
Context_Startup(vaProxy);
break;
case "edts.getcoordinates":
// EDTS
Context_EDTS_GetCoordinates();
Context_EDTS_GetCoordinates(vaProxy);
break;
case "log.log":
// log
Context_Log();
Context_Log(vaProxy);
break;
case "spansh.systemexists":
// Spansh
Context_Spansh_SytemExists();
Context_Spansh_SytemExists(vaProxy);
break;
case "spansh.nearestsystem":
Context_Spansh_Nearestsystem();
Context_Spansh_Nearestsystem(vaProxy);
break;
default:
// invalid
Log.Error($"Invalid plugin context '{VA!.Context}'.");
Log.Error($"Invalid plugin context '{vaProxy.Context}'.");
break;
}
}
@ -154,9 +152,10 @@ namespace SpanshAttack
| plugin contexts |
\================*/
private static void Context_EDTS_GetCoordinates()
#pragma warning disable IDE0060 // Remove unused parameter
private static void Context_EDTS_GetCoordinates(dynamic vaProxy)
{
string name = VA!.GetText("~system") ?? throw new ArgumentNullException("~system");
string name = vaProxy.GetText("~system") ?? throw new ArgumentNullException("~system");
bool success = false;
string? errorType = null;
@ -175,10 +174,10 @@ namespace SpanshAttack
Log.Warn($@"Coordinates with low precision for ""{name}"": ({system.Coords.X}, {system.Coords.Y}, {system.Coords.Z}), precision: {system.Coords.Precision}ly");
}
VA!.SetInt("~x", system.Coords.X);
VA!.SetInt("~y", system.Coords.Y);
VA!.SetInt("~z", system.Coords.Z);
VA!.SetInt("~precision", system.Coords.Precision);
vaProxy.SetInt("~x", system.Coords.X);
vaProxy.SetInt("~y", system.Coords.Y);
vaProxy.SetInt("~z", system.Coords.Z);
vaProxy.SetInt("~precision", system.Coords.Precision);
success = true;
}
@ -193,19 +192,19 @@ namespace SpanshAttack
errorMessage = e.Message;
}
VA!.SetBoolean("~success", success);
vaProxy.SetBoolean("~success", success);
if (!string.IsNullOrWhiteSpace(errorType))
{
Log.Error(errorMessage!);
VA!.SetText("~errorType", errorType);
VA!.SetText("~errorMessage", errorMessage);
vaProxy.SetText("~errorType", errorType);
vaProxy.SetText("~errorMessage", errorMessage);
}
}
private static void Context_Log()
private static void Context_Log(dynamic vaProxy)
{
string message = VA!.GetText("~message");
string level = VA!.GetText("~level");
string message = vaProxy.GetText("~message");
string level = vaProxy.GetText("~level");
if (level == null)
{
@ -228,13 +227,13 @@ namespace SpanshAttack
}
}
private static void Context_Spansh_Nearestsystem()
private static void Context_Spansh_Nearestsystem(dynamic vaProxy)
{
int x = VA!.GetInt("~x") ?? throw new ArgumentNullException("~x");
int y = VA!.GetInt("~y") ?? throw new ArgumentNullException("~y");
int z = VA!.GetInt("~z") ?? throw new ArgumentNullException("~z");
int x = vaProxy.GetInt("~x") ?? throw new ArgumentNullException("~x");
int y = vaProxy.GetInt("~y") ?? throw new ArgumentNullException("~y");
int z = vaProxy.GetInt("~z") ?? throw new ArgumentNullException("~z");
string path = $@"{VA!.SessionState["VA_SOUNDS"]}\Scripts\spansh.exe";
string path = $@"{vaProxy.SessionState["VA_SOUNDS"]}\Scripts\spansh.exe";
string arguments = $@"nearestsystem --parsable {x} {y} {z}";
Process p = PythonProxy.SetupPythonScript(path, arguments);
@ -273,21 +272,21 @@ namespace SpanshAttack
break;
}
VA!.SetText("~system", system);
VA!.SetDecimal("~x", coords['x']);
VA!.SetDecimal("~y", coords['y']);
VA!.SetDecimal("~z", coords['z']);
VA!.SetDecimal("~distance", distance);
VA!.SetBoolean("~error", error);
VA!.SetText("~errorMessage", errorMessage);
VA!.SetInt("~exitCode", p.ExitCode);
vaProxy.SetText("~system", system);
vaProxy.SetDecimal("~x", coords['x']);
vaProxy.SetDecimal("~y", coords['y']);
vaProxy.SetDecimal("~z", coords['z']);
vaProxy.SetDecimal("~distance", distance);
vaProxy.SetBoolean("~error", error);
vaProxy.SetText("~errorMessage", errorMessage);
vaProxy.SetInt("~exitCode", p.ExitCode);
}
private static void Context_Spansh_SytemExists()
private static void Context_Spansh_SytemExists(dynamic vaProxy)
{
string system = VA!.GetText("~system") ?? throw new ArgumentNullException("~system");
string system = vaProxy.GetText("~system") ?? throw new ArgumentNullException("~system");
string path = $@"{VA!.SessionState["VA_SOUNDS"]}\Scripts\spansh.exe";
string path = $@"{vaProxy.SessionState["VA_SOUNDS"]}\Scripts\spansh.exe";
string arguments = $@"systemexists ""{system}""";
Process p = PythonProxy.SetupPythonScript(path, arguments);
@ -321,16 +320,17 @@ namespace SpanshAttack
break;
}
VA!.SetBoolean("~systemExists", exists);
VA!.SetBoolean("~error", error);
VA!.SetText("~errorMessage", errorMessage);
VA!.SetInt("~exitCode", p.ExitCode);
vaProxy.SetBoolean("~systemExists", exists);
vaProxy.SetBoolean("~error", error);
vaProxy.SetText("~errorMessage", errorMessage);
vaProxy.SetInt("~exitCode", p.ExitCode);
}
private static void Context_Startup()
private static void Context_Startup(dynamic vaProxy)
{
Log.Notice("Starting up …");
Log.Notice("Finished startup.");
}
#pragma warning restore IDE0060 // Remove unused parameter
}
}

View file

@ -328,7 +328,8 @@ namespace alterNERDtive
| plugin contexts |
\================*/
private static void Context_Config_Dialog()
#pragma warning disable IDE0060 // Remove unused parameter
private static void Context_Config_Dialog(dynamic vaProxy)
{
Thread dialogThread = new Thread(new ThreadStart(() =>
{
@ -348,17 +349,17 @@ namespace alterNERDtive
dialogThread.Start();
}
private static void Context_Config_Dump()
private static void Context_Config_Dump(dynamic vaProxy)
{
Config.DumpConfig();
}
private static void Context_Config_List()
private static void Context_Config_List(dynamic vaProxy)
{
Config.ListConfig();
}
private static void Context_Config_Setup()
private static void Context_Config_Setup(dynamic vaProxy)
{
Log.Debug("Loading default configuration …");
Config.ApplyAllDefaults();
@ -371,14 +372,14 @@ namespace alterNERDtive
Log.Debug("Finished loading configuration.");
}
private static void Context_Config_SetVariables()
private static void Context_Config_SetVariables(dynamic vaProxy)
{
string trigger = VA!.GetText("~trigger") ?? throw new ArgumentNullException("~trigger");
string trigger = vaProxy.GetText("~trigger") ?? throw new ArgumentNullException("~trigger");
Log.Debug($"Loading variables for trigger '{trigger}' …");
Config.SetVariablesForTrigger(VA!, trigger);
Config.SetVariablesForTrigger(vaProxy, trigger);
}
private static void Context_Config_VersionMigration()
private static void Context_Config_VersionMigration(dynamic vaProxy)
{
// =============
// === 4.3.1 ===
@ -390,7 +391,7 @@ namespace alterNERDtive
string name = $"EliteAttack.{option}s#";
string oldName = $"EliteAttack.{option}#";
Commands.Run("alterNERDtive-base.loadVariableFromProfile", wait: true, parameters: new dynamic[] { new string[] { $"{oldName}", "boolean" } });
bool? value = VA!.GetBoolean(oldName);
bool? value = vaProxy.GetBoolean(oldName);
if (value != null)
{
Log.Info($"Migrating option {oldName} …");
@ -404,7 +405,7 @@ namespace alterNERDtive
// ===========
// SpanshAttack
string edtsPath = $@"{VA!.SessionState["VA_SOUNDS"]}\scripts\edts.exe";
string edtsPath = $@"{vaProxy.SessionState["VA_SOUNDS"]}\scripts\edts.exe";
if (File.Exists(edtsPath))
{
File.Delete(edtsPath);
@ -422,7 +423,7 @@ namespace alterNERDtive
string name = $"{prefix}.{option}";
string oldName = $"{oldPrefix}.{option}";
Commands.Run("alterNERDtive-base.loadVariableFromProfile", wait: true, parameters: new dynamic[] { new string[] { $"{oldName}", "boolean" } });
bool? value = VA!.GetBoolean(oldName);
bool? value = vaProxy.GetBoolean(oldName);
if (value != null)
{
Log.Info($"Migrating option {oldName} …");
@ -437,7 +438,7 @@ namespace alterNERDtive
{
string name = $"{prefix}.{option}";
Commands.Run("alterNERDtive-base.loadVariableFromProfile", wait: true, parameters: new dynamic[] { new string[] { $"{name}", "boolean" } });
bool? value = VA!.GetBoolean(name);
bool? value = vaProxy.GetBoolean(name);
if (value != null)
{
Log.Info($"Migrating option {name} …");
@ -450,7 +451,7 @@ namespace alterNERDtive
{
string name = $"{prefix}.{option}";
Commands.Run("alterNERDtive-base.loadVariableFromProfile", wait: true, parameters: new dynamic[] { new string[] { $"{name}", "text" } });
string value = VA!.GetText(name);
string value = vaProxy.GetText(name);
if (!string.IsNullOrEmpty(value))
{
Log.Info($"Migrating option {name} …");
@ -465,7 +466,7 @@ namespace alterNERDtive
{
string name = $"{prefix}.{option}";
Commands.Run("alterNERDtive-base.loadVariableFromProfile", wait: true, parameters: new dynamic[] { new string[] { $"{name}", "boolean" } });
bool? value = VA!.GetBoolean(name);
bool? value = vaProxy.GetBoolean(name);
if (value != null)
{
Log.Info($"Migrating option {name} …");
@ -478,7 +479,7 @@ namespace alterNERDtive
{
string name = $"{prefix}.{option}";
Commands.Run("alterNERDtive-base.loadVariableFromProfile", wait: true, parameters: new dynamic[] { new string[] { $"{name}", "text" } });
string value = VA!.GetText(name);
string value = vaProxy.GetText(name);
if (!string.IsNullOrEmpty(value))
{
Log.Info($"Migrating option {name} …");
@ -493,7 +494,7 @@ namespace alterNERDtive
{
string name = $"{prefix}.{option}";
Commands.Run("alterNERDtive-base.loadVariableFromProfile", wait: true, parameters: new dynamic[] { new string[] { $"{name}", "text" } });
string value = VA!.GetText(name);
string value = vaProxy.GetText(name);
if (!string.IsNullOrEmpty(value))
{
Log.Info($"Migrating option {name} …");
@ -503,19 +504,19 @@ namespace alterNERDtive
}
}
private static void Context_Eddi_Event()
private static void Context_Eddi_Event(dynamic vaProxy)
{
string eddiEvent = VA!.Command.Name();
string eddiEvent = vaProxy.Command.Name();
string command = eddiEvent.Substring(2, eddiEvent.Length - 4);
Log.Debug($"Running EDDI event '{command}' …");
Commands.RunAll(ActiveProfiles, command, logMissing: false, subcommand: true); // FIXXME: a) triggerAll or something, b) change all profiles to use "((<name>.<event>))" over "<name>.<event>"
}
private static void Context_EDSM_BodyCount()
private static void Context_EDSM_BodyCount(dynamic vaProxy)
{
string system = VA!.GetText("~system") ?? throw new ArgumentNullException("~system");
string system = vaProxy.GetText("~system") ?? throw new ArgumentNullException("~system");
string path = $@"{VA!.SessionState["VA_SOUNDS"]}\scripts\explorationtools.exe";
string path = $@"{vaProxy.SessionState["VA_SOUNDS"]}\scripts\explorationtools.exe";
string arguments = $@"bodycount ""{system}""";
Process p = PythonProxy.SetupPythonScript(path, arguments);
@ -551,19 +552,19 @@ namespace alterNERDtive
break;
}
VA!.SetInt("~bodyCount", bodyCount);
VA!.SetBoolean("~error", error);
VA!.SetText("~errorMessage", errorMessage);
VA!.SetInt("~exitCode", p.ExitCode);
vaProxy.SetInt("~bodyCount", bodyCount);
vaProxy.SetBoolean("~error", error);
vaProxy.SetText("~errorMessage", errorMessage);
vaProxy.SetInt("~exitCode", p.ExitCode);
}
private static void Context_EDSM_DistanceBetween()
private static void Context_EDSM_DistanceBetween(dynamic vaProxy)
{
string fromSystem = VA!.GetText("~fromSystem") ?? throw new ArgumentNullException("~fromSystem");
string toSystem = VA!.GetText("~toSystem") ?? throw new ArgumentNullException("~toSystem");
int roundTo = VA!.GetInt("~roundTo") ?? 2;
string fromSystem = vaProxy.GetText("~fromSystem") ?? throw new ArgumentNullException("~fromSystem");
string toSystem = vaProxy.GetText("~toSystem") ?? throw new ArgumentNullException("~toSystem");
int roundTo = vaProxy.GetInt("~roundTo") ?? 2;
string path = $@"{VA!.SessionState["VA_SOUNDS"]}\Scripts\explorationtools.exe";
string path = $@"{vaProxy.SessionState["VA_SOUNDS"]}\Scripts\explorationtools.exe";
string arguments = $@"distancebetween --roundto {roundTo} ""{fromSystem}"" ""{toSystem}""";
Process p = PythonProxy.SetupPythonScript(path, arguments);
@ -595,16 +596,16 @@ namespace alterNERDtive
break;
}
VA!.SetDecimal("~distance", distance);
VA!.SetBoolean("~error", error);
VA!.SetText("~errorMessage", errorMessage);
VA!.SetInt("~exitCode", p.ExitCode);
vaProxy.SetDecimal("~distance", distance);
vaProxy.SetBoolean("~error", error);
vaProxy.SetText("~errorMessage", errorMessage);
vaProxy.SetInt("~exitCode", p.ExitCode);
}
private static void Context_Log()
private static void Context_Log(dynamic vaProxy)
{
string message = VA!.GetText("~message");
string level = VA!.GetText("~level");
string message = vaProxy.GetText("~message");
string level = vaProxy.GetText("~level");
if (level == null)
{
@ -627,12 +628,12 @@ namespace alterNERDtive
}
}
private static void Context_Spansh_OutdatedStations()
private static void Context_Spansh_OutdatedStations(dynamic vaProxy)
{
string system = VA!.GetText("~system") ?? throw new ArgumentNullException("~system");
int minage = VA!.GetInt("~minage") ?? throw new ArgumentNullException("~minage");
string system = vaProxy.GetText("~system") ?? throw new ArgumentNullException("~system");
int minage = vaProxy.GetInt("~minage") ?? throw new ArgumentNullException("~minage");
string path = $@"{VA!.SessionState["VA_SOUNDS"]}\Scripts\spansh.exe";
string path = $@"{vaProxy.SessionState["VA_SOUNDS"]}\Scripts\spansh.exe";
string arguments = $@"oldstations --system ""{system}"" --minage {minage}";
Process p = PythonProxy.SetupPythonScript(path, arguments);
@ -667,24 +668,25 @@ namespace alterNERDtive
break;
}
VA!.SetText("~message", message);
VA!.SetBoolean("~error", error);
VA!.SetText("~errorMessage", errorMessage);
VA!.SetInt("~exitCode", p.ExitCode);
vaProxy.SetText("~message", message);
vaProxy.SetBoolean("~error", error);
vaProxy.SetText("~errorMessage", errorMessage);
vaProxy.SetInt("~exitCode", p.ExitCode);
}
private static void Context_Startup()
private static void Context_Startup(dynamic vaProxy)
{
Log.Notice("Starting up …");
CheckProfiles(VA);
CheckProfiles(vaProxy);
Log.Notice($"Active profiles: {string.Join(", ", ActiveProfiles)}");
Commands.TriggerEventAll(ActiveProfiles, "startup", logMissing: false);
Log.Notice("Finished startup.");
}
private static void Context_Update_Check()
private static void Context_Update_Check(dynamic vaProxy)
{
UpdateCheck();
}
#pragma warning restore IDE0060 // Remove unused parameter
}
}