diff --git a/src/Tgstation.Server.Host/Components/Byond/ByondManager.cs b/src/Tgstation.Server.Host/Components/Byond/ByondManager.cs
index 7896369b02..d58ad67880 100644
--- a/src/Tgstation.Server.Host/Components/Byond/ByondManager.cs
+++ b/src/Tgstation.Server.Host/Components/Byond/ByondManager.cs
@@ -8,6 +8,7 @@ using System.Threading;
using System.Threading.Tasks;
using Tgstation.Server.Api;
using Tgstation.Server.Api.Models;
+using Tgstation.Server.Host.Components.Events;
using Tgstation.Server.Host.Core;
using Tgstation.Server.Host.IO;
using Tgstation.Server.Host.Jobs;
diff --git a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs
index e35cfd5b15..c73f5ad8d8 100644
--- a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs
+++ b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs
@@ -12,6 +12,7 @@ using Tgstation.Server.Api.Models;
using Tgstation.Server.Api.Models.Internal;
using Tgstation.Server.Host.Components.Byond;
using Tgstation.Server.Host.Components.Chat;
+using Tgstation.Server.Host.Components.Events;
using Tgstation.Server.Host.Components.Repository;
using Tgstation.Server.Host.Components.Session;
using Tgstation.Server.Host.Core;
diff --git a/src/Tgstation.Server.Host/Components/EventConsumer.cs b/src/Tgstation.Server.Host/Components/Events/EventConsumer.cs
similarity index 97%
rename from src/Tgstation.Server.Host/Components/EventConsumer.cs
rename to src/Tgstation.Server.Host/Components/Events/EventConsumer.cs
index 1cebdd1d2b..45cb18f0a0 100644
--- a/src/Tgstation.Server.Host/Components/EventConsumer.cs
+++ b/src/Tgstation.Server.Host/Components/Events/EventConsumer.cs
@@ -5,7 +5,7 @@ using System.Threading.Tasks;
using Tgstation.Server.Host.Components.StaticFiles;
using Tgstation.Server.Host.Components.Watchdog;
-namespace Tgstation.Server.Host.Components
+namespace Tgstation.Server.Host.Components.Events
{
///
sealed class EventConsumer : IEventConsumer
diff --git a/src/Tgstation.Server.Host/Components/Events/EventScriptAttribute.cs b/src/Tgstation.Server.Host/Components/Events/EventScriptAttribute.cs
new file mode 100644
index 0000000000..c42a4b2a6b
--- /dev/null
+++ b/src/Tgstation.Server.Host/Components/Events/EventScriptAttribute.cs
@@ -0,0 +1,25 @@
+using System;
+
+namespace Tgstation.Server.Host.Components.Events
+{
+ ///
+ /// Attribute for indicating the script that a given runs.
+ ///
+ [AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
+ sealed class EventScriptAttribute : Attribute
+ {
+ ///
+ /// The name of the script the event script the runs.
+ ///
+ public string ScriptName { get; }
+
+ ///
+ /// Initializes a new instance of the .
+ ///
+ /// The value of .
+ public EventScriptAttribute(string scriptName)
+ {
+ ScriptName = scriptName ?? throw new ArgumentNullException(nameof(scriptName));
+ }
+ }
+}
diff --git a/src/Tgstation.Server.Host/Components/EventType.cs b/src/Tgstation.Server.Host/Components/Events/EventType.cs
similarity index 73%
rename from src/Tgstation.Server.Host/Components/EventType.cs
rename to src/Tgstation.Server.Host/Components/Events/EventType.cs
index 2f57373b32..419fb9ec3b 100644
--- a/src/Tgstation.Server.Host/Components/EventType.cs
+++ b/src/Tgstation.Server.Host/Components/Events/EventType.cs
@@ -1,4 +1,4 @@
-namespace Tgstation.Server.Host.Components
+namespace Tgstation.Server.Host.Components.Events
{
///
/// Types of events. Mirror in tgs.dm
@@ -8,86 +8,103 @@
///
/// Parameters: Reference name, commit sha
///
+ [EventScript("RepoResetOrigin")]
RepoResetOrigin,
///
/// Parameters: Checkout target
///
+ [EventScript("RepoCheckout")]
RepoCheckout,
///
/// No parameters
///
+ [EventScript("RepoFetch")]
RepoFetch,
///
/// Parameters: Pull request number, pull request sha, merger message
///
+ [EventScript("RepoMergePullRequest")]
RepoMergePullRequest,
///
/// Parameters: Absolute path to repository root
///
+ [EventScript("PreSynchronize")]
RepoPreSynchronize,
///
/// Parameters: Version being installed
///
+ [EventScript("ByondInstallStart")]
ByondInstallStart,
///
/// Parameters: Error string
///
+ [EventScript("ByondInstallFail")]
ByondInstallFail,
///
/// Parameters: Old active version, new active version
///
+ [EventScript("ByondActiveVersionChange")]
ByondActiveVersionChange,
///
/// Parameters: Game directory path, origin commit sha
///
+ [EventScript("PreCompile")]
CompileStart,
///
/// No parameters
///
+ [EventScript("CompileCancelled")]
CompileCancelled,
///
/// Parameters: Game directory path, "1" if compile succeeded and api validation failed, "0" otherwise
///
+ [EventScript("CompileFailure")]
CompileFailure,
///
/// Parameters: Game directory path
///
+ [EventScript("PostCompile")]
CompileComplete,
///
/// No parameters
///
+ [EventScript("InstanceAutoUpdateStart")]
InstanceAutoUpdateStart,
///
/// Parameters: Base sha, target sha, base reference, target reference
///
+ [EventScript("RepoMergeConflict")]
RepoMergeConflict,
///
/// No parameters
///
+ [EventScript("DeploymentComplete")]
DeploymentComplete,
///
/// Before the watchdog shutsdown. Not sent for graceful shutdowns. No parameters.
///
+ [EventScript("WatchdogShutdown")]
WatchdogShutdown,
///
/// Before the watchdog detaches. No parameters.
///
+ [EventScript("WatchdogDetach")]
WatchdogDetach,
}
}
diff --git a/src/Tgstation.Server.Host/Components/IEventConsumer.cs b/src/Tgstation.Server.Host/Components/Events/IEventConsumer.cs
similarity index 93%
rename from src/Tgstation.Server.Host/Components/IEventConsumer.cs
rename to src/Tgstation.Server.Host/Components/Events/IEventConsumer.cs
index f4dd616bd8..6dbf73fe87 100644
--- a/src/Tgstation.Server.Host/Components/IEventConsumer.cs
+++ b/src/Tgstation.Server.Host/Components/Events/IEventConsumer.cs
@@ -2,7 +2,7 @@
using System.Threading;
using System.Threading.Tasks;
-namespace Tgstation.Server.Host.Components
+namespace Tgstation.Server.Host.Components.Events
{
///
/// Consumes s and takes the appropriate actions
diff --git a/src/Tgstation.Server.Host/Components/Events/README.md b/src/Tgstation.Server.Host/Components/Events/README.md
new file mode 100644
index 0000000000..12f8343ddd
--- /dev/null
+++ b/src/Tgstation.Server.Host/Components/Events/README.md
@@ -0,0 +1,8 @@
+# Event System
+
+Many actions in TGS generate events. They are dispatched via the [IEventConsumer](./IEventConsumer.cs) ([main implementation](./EventConsumer.cs)). From there, it is further sent to the two actual consumers.
+
+1. The static files system will attempt to run a script with the given [EventScriptAttribute](./EventScriptAttribute)'s `ScriptName`.
+1. The watchdog will send a mirror of the event via the DMAPI to be handled by game code.
+
+With these two endpoints, the behaviour of TGS is highly customizable as server operators can customize the entire process.
diff --git a/src/Tgstation.Server.Host/Components/Instance.cs b/src/Tgstation.Server.Host/Components/Instance.cs
index 68d5fdcd77..76d67ce595 100644
--- a/src/Tgstation.Server.Host/Components/Instance.cs
+++ b/src/Tgstation.Server.Host/Components/Instance.cs
@@ -9,6 +9,7 @@ using Tgstation.Server.Api.Rights;
using Tgstation.Server.Host.Components.Byond;
using Tgstation.Server.Host.Components.Chat;
using Tgstation.Server.Host.Components.Deployment;
+using Tgstation.Server.Host.Components.Events;
using Tgstation.Server.Host.Components.Repository;
using Tgstation.Server.Host.Components.Watchdog;
using Tgstation.Server.Host.Database;
diff --git a/src/Tgstation.Server.Host/Components/InstanceFactory.cs b/src/Tgstation.Server.Host/Components/InstanceFactory.cs
index 23aa1da429..844aa5c264 100644
--- a/src/Tgstation.Server.Host/Components/InstanceFactory.cs
+++ b/src/Tgstation.Server.Host/Components/InstanceFactory.cs
@@ -7,6 +7,7 @@ using Tgstation.Server.Host.Components.Byond;
using Tgstation.Server.Host.Components.Chat;
using Tgstation.Server.Host.Components.Chat.Commands;
using Tgstation.Server.Host.Components.Deployment;
+using Tgstation.Server.Host.Components.Events;
using Tgstation.Server.Host.Components.Interop.Bridge;
using Tgstation.Server.Host.Components.Repository;
using Tgstation.Server.Host.Components.Session;
diff --git a/src/Tgstation.Server.Host/Components/Interop/Topic/EventNotification.cs b/src/Tgstation.Server.Host/Components/Interop/Topic/EventNotification.cs
index e9183f5787..b6024c58a3 100644
--- a/src/Tgstation.Server.Host/Components/Interop/Topic/EventNotification.cs
+++ b/src/Tgstation.Server.Host/Components/Interop/Topic/EventNotification.cs
@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.Linq;
+using Tgstation.Server.Host.Components.Events;
namespace Tgstation.Server.Host.Components.Interop.Topic
{
diff --git a/src/Tgstation.Server.Host/Components/README.md b/src/Tgstation.Server.Host/Components/README.md
index 6d48a22aae..ff311c3f00 100644
--- a/src/Tgstation.Server.Host/Components/README.md
+++ b/src/Tgstation.Server.Host/Components/README.md
@@ -10,6 +10,7 @@ Component code is where the magic and tears of TGS are made. There are six main
There exist two more namespaces in here that don't directly fit in these 6 components.
+- [Events](./Events) deals with the TGS event system.
- [Interop](./Interop) deals with the bulk of DMAPI communication (Though it's not all contained here).
- [Session](./Session) contains the classes used for actually executing DreamDaemon, sending topic requests, receiving bridge requests, among other things.
@@ -19,4 +20,6 @@ While the database represents stored instance data, in component code an instanc
`IInstance`s are created via the [IInstanceFactory](./IInstanceFactory.cs) ([implementation](./InstanceFactory.cs)) and are generally controlled via the [IInstanceManager](./IInstanceManager.cs) ([implementation](./InstanceManager.cs)).
-Many classes in here implement [IHostedService](), `InstanceManager` being the only one that is called by the ASP.NET runtime. In the case of instances `StartAsync()` is called when an `Instance` is being brought online (from server startup or user request). The `Instance` handles calling `StartAsync()` on its various subcomponents that need it. When an `Instance` is being brought offline (from server shutdown/restart/update or user request) the same pattern is followed calling `StopAsync()`.
+Many classes in here implement [IHostedService](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-3.1&tabs=visual-studio), `InstanceManager` being the only one that is called by the ASP.NET runtime. In the case of instances `StartAsync()` is called when an `Instance` is being brought online (from server startup or user request). The `Instance` handles calling `StartAsync()` on its various subcomponents that need it. When an `Instance` is being brought offline (from server shutdown/restart/update or user request) the same pattern is followed calling `StopAsync()`.
+
+`IInstanceManager` is the sole point where the controllers talk to component code. It also dispatches bridge requests to their relevant instances.
diff --git a/src/Tgstation.Server.Host/Components/Repository/Repository.cs b/src/Tgstation.Server.Host/Components/Repository/Repository.cs
index 8afac9fe04..35a8928d4c 100644
--- a/src/Tgstation.Server.Host/Components/Repository/Repository.cs
+++ b/src/Tgstation.Server.Host/Components/Repository/Repository.cs
@@ -8,6 +8,7 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Tgstation.Server.Api.Models;
+using Tgstation.Server.Host.Components.Events;
using Tgstation.Server.Host.IO;
using Tgstation.Server.Host.Jobs;
diff --git a/src/Tgstation.Server.Host/Components/Repository/RepositoryManager.cs b/src/Tgstation.Server.Host/Components/Repository/RepositoryManager.cs
index 6b6c1b51b8..4c5fefc314 100644
--- a/src/Tgstation.Server.Host/Components/Repository/RepositoryManager.cs
+++ b/src/Tgstation.Server.Host/Components/Repository/RepositoryManager.cs
@@ -4,6 +4,7 @@ using System;
using System.Threading;
using System.Threading.Tasks;
using Tgstation.Server.Api.Models;
+using Tgstation.Server.Host.Components.Events;
using Tgstation.Server.Host.Core;
using Tgstation.Server.Host.IO;
using Tgstation.Server.Host.Jobs;
diff --git a/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs b/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs
index bcc44ee87f..a61ba8cea7 100644
--- a/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs
+++ b/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs
@@ -9,6 +9,7 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Tgstation.Server.Api.Models;
+using Tgstation.Server.Host.Components.Events;
using Tgstation.Server.Host.Core;
using Tgstation.Server.Host.IO;
using Tgstation.Server.Host.Jobs;
@@ -32,12 +33,18 @@ namespace Tgstation.Server.Host.Components.StaticFiles
const string CodeModificationsHeadFile = "HeadInclude.dm";
const string CodeModificationsTailFile = "TailInclude.dm";
- static readonly IReadOnlyDictionary EventTypeScriptFileNameMap = new Dictionary
- {
- { EventType.CompileStart, "PreCompile" },
- { EventType.CompileComplete, "PostCompile" },
- { EventType.RepoPreSynchronize, "PreSynchronize" }
- };
+ static readonly IReadOnlyDictionary EventTypeScriptFileNameMap = new Dictionary(
+ Enum.GetValues(typeof(EventType))
+ .OfType()
+ .Select(
+ eventType => new KeyValuePair(
+ eventType,
+ typeof(EventType)
+ .GetField(eventType.ToString())
+ .GetCustomAttributes(false)
+ .OfType()
+ .First()
+ .ScriptName)));
///
/// The for
diff --git a/src/Tgstation.Server.Host/Components/StaticFiles/IConfiguration.cs b/src/Tgstation.Server.Host/Components/StaticFiles/IConfiguration.cs
index ad88be4917..0cd29c0c5c 100644
--- a/src/Tgstation.Server.Host/Components/StaticFiles/IConfiguration.cs
+++ b/src/Tgstation.Server.Host/Components/StaticFiles/IConfiguration.cs
@@ -4,6 +4,7 @@ using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Tgstation.Server.Api.Models;
+using Tgstation.Server.Host.Components.Events;
using Tgstation.Server.Host.Security;
namespace Tgstation.Server.Host.Components.StaticFiles
diff --git a/src/Tgstation.Server.Host/Components/Watchdog/IWatchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/IWatchdog.cs
index 0f86a510f5..536096c499 100644
--- a/src/Tgstation.Server.Host/Components/Watchdog/IWatchdog.cs
+++ b/src/Tgstation.Server.Host/Components/Watchdog/IWatchdog.cs
@@ -3,6 +3,7 @@ using System;
using System.Threading;
using System.Threading.Tasks;
using Tgstation.Server.Api.Models.Internal;
+using Tgstation.Server.Host.Components.Events;
using Tgstation.Server.Host.Components.Session;
namespace Tgstation.Server.Host.Components.Watchdog
diff --git a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs
index d3067f29b7..9874ce67fa 100644
--- a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs
+++ b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs
@@ -11,6 +11,7 @@ using Tgstation.Server.Api.Models.Internal;
using Tgstation.Server.Api.Rights;
using Tgstation.Server.Host.Components.Chat;
using Tgstation.Server.Host.Components.Deployment;
+using Tgstation.Server.Host.Components.Events;
using Tgstation.Server.Host.Components.Interop.Topic;
using Tgstation.Server.Host.Components.Session;
using Tgstation.Server.Host.Core;
diff --git a/tests/Tgstation.Server.Host.Tests/Components/Events/TestEventScriptAttribute.cs b/tests/Tgstation.Server.Host.Tests/Components/Events/TestEventScriptAttribute.cs
new file mode 100644
index 0000000000..6652345fab
--- /dev/null
+++ b/tests/Tgstation.Server.Host.Tests/Components/Events/TestEventScriptAttribute.cs
@@ -0,0 +1,21 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System;
+
+
+namespace Tgstation.Server.Host.Components.Events.Tests
+{
+ ///
+ /// Tests for the .
+ ///
+ [TestClass]
+ public sealed class TestEventScriptAttribute
+ {
+ [TestMethod]
+ public void TestConstruction()
+ {
+ Assert.ThrowsException(() => new EventScriptAttribute(null));
+ var test = new EventScriptAttribute("test");
+ Assert.AreEqual("test", test.ScriptName);
+ }
+ }
+}
diff --git a/tests/Tgstation.Server.Host.Tests/Components/Events/TestEventType.cs b/tests/Tgstation.Server.Host.Tests/Components/Events/TestEventType.cs
new file mode 100644
index 0000000000..3e9ed9b8c0
--- /dev/null
+++ b/tests/Tgstation.Server.Host.Tests/Components/Events/TestEventType.cs
@@ -0,0 +1,28 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Tgstation.Server.Host.Components.Events.Tests
+{
+ [TestClass]
+ public sealed class TestEventType
+ {
+ [TestMethod]
+ public void TestAllEventTypesHaveUniqueEventScriptAttributes()
+ {
+ var allScripts = new HashSet();
+ foreach (var eventType in Enum.GetValues(typeof(EventType))) {
+ var list = typeof(EventType)
+ .GetField(eventType.ToString())
+ .GetCustomAttributes(false)
+ .OfType()
+ .ToList();
+ Assert.AreEqual(1, list.Count, $"EventType: {eventType}");
+
+ var attribute = list.First();
+ Assert.IsTrue(allScripts.Add(attribute.ScriptName), $"Non-unique script Name: {attribute.ScriptName}");
+ }
+ }
+ }
+}