mirror of
https://github.com/tgstation/tgstation-server.git
synced 2026-08-26 06:27:19 +01:00
Merge pull request #1720 from tgstation/v5180Rel [TGSDeploy]
v5.18.0: Fixes and release
This commit is contained in:
@@ -468,11 +468,11 @@ jobs:
|
||||
sleep 10
|
||||
set +e
|
||||
test_output=$(dotnet test -c ${{ matrix.configuration }} --no-build --filter TestCategory=RequiresDatabase --logger "GitHubActions;summary.includePassedTests=true;summary.includeSkippedTests=true" --collect:"XPlat Code Coverage" --settings ../../build/ci.runsettings --results-directory ../../TestResults)
|
||||
succeeded=$?
|
||||
retval=$?
|
||||
set -e
|
||||
cd ../..
|
||||
echo $test_output > ./test_output.txt
|
||||
if [[ $retVal -ne 0 ]]; then
|
||||
if [[ $retval -ne 0 ]]; then
|
||||
echo "succeeded=NO" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "succeeded=YES" >> $GITHUB_OUTPUT
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ WORKDIR /repo/build
|
||||
COPY build/Common.props Common.props
|
||||
COPY build/NugetCommon.props NugetCommon.props
|
||||
COPY build/Version.props Version.props
|
||||
COPY build/ControlPanelVersion.props ControlPanelVersion.props
|
||||
COPY build/WebpanelVersion.props WebpanelVersion.props
|
||||
COPY build/SrcCommon.props SrcCommon.props
|
||||
|
||||
WORKDIR /repo/src/Tgstation.Server.Host
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<!-- Usage: Hard to say what exactly this is for, but not including it removes the test icon and breaks vstest.console.exe for some reason -->
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.7.2" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||
<!-- Usage: Dependency mocking for tests -->
|
||||
<!-- Pinned: Be VERY careful about updating https://github.com/moq/moq/issues/1372 -->
|
||||
<PackageReference Include="Moq" Version="4.20.69" />
|
||||
|
||||
+7
-7
@@ -1,16 +1,16 @@
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<!-- This is the authorative version list -->
|
||||
<!-- Integration tests will ensure they match across the board -->
|
||||
<Import Project="ControlPanelVersion.props" />
|
||||
<Import Project="WebpanelVersion.props" />
|
||||
<PropertyGroup>
|
||||
<TgsCoreVersion>5.17.3</TgsCoreVersion>
|
||||
<TgsCoreVersion>5.18.0</TgsCoreVersion>
|
||||
<TgsConfigVersion>4.7.1</TgsConfigVersion>
|
||||
<TgsApiVersion>9.13.0</TgsApiVersion>
|
||||
<TgsApiVersion>9.14.0</TgsApiVersion>
|
||||
<TgsCommonLibraryVersion>7.0.0</TgsCommonLibraryVersion>
|
||||
<TgsApiLibraryVersion>12.0.1</TgsApiLibraryVersion>
|
||||
<TgsClientVersion>14.1.0</TgsClientVersion>
|
||||
<TgsDmapiVersion>6.6.2</TgsDmapiVersion>
|
||||
<TgsInteropVersion>5.6.2</TgsInteropVersion>
|
||||
<TgsApiLibraryVersion>12.2.0</TgsApiLibraryVersion>
|
||||
<TgsClientVersion>14.2.0</TgsClientVersion>
|
||||
<TgsDmapiVersion>6.7.0</TgsDmapiVersion>
|
||||
<TgsInteropVersion>5.7.0</TgsInteropVersion>
|
||||
<TgsHostWatchdogVersion>1.4.0</TgsHostWatchdogVersion>
|
||||
<TgsContainerScriptVersion>1.2.1</TgsContainerScriptVersion>
|
||||
<TgsMigratorVersion>1.0.2</TgsMigratorVersion>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<!-- This is in it's own file to help incremental building, changing it causes a complete rebuild of the web panel -->
|
||||
<TgsControlPanelVersion>4.26.2</TgsControlPanelVersion>
|
||||
<TgsWebpanelVersion>5.1.0</TgsWebpanelVersion>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -87,4 +87,5 @@ tgstation-server is a BYOND server managment suite. It includes all the followin
|
||||
- Functions with all 3 DreamDaemon security levels
|
||||
- Provides notifications of TGS side events
|
||||
- Allows specifying the .dmb's minimum required security level
|
||||
- Broadcast messages to clients
|
||||
*/
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
// tgstation-server DMAPI
|
||||
|
||||
#define TGS_DMAPI_VERSION "6.6.2"
|
||||
#define TGS_DMAPI_VERSION "6.7.0"
|
||||
|
||||
// All functions and datums outside this document are subject to change with any version and should not be relied on.
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
"5.6.2"
|
||||
"5.7.0"
|
||||
|
||||
@@ -80,6 +80,7 @@
|
||||
#define DMAPI5_TOPIC_COMMAND_WATCHDOG_REATTACH 8
|
||||
#define DMAPI5_TOPIC_COMMAND_SEND_CHUNK 9
|
||||
#define DMAPI5_TOPIC_COMMAND_RECEIVE_CHUNK 10
|
||||
#define DMAPI5_TOPIC_COMMAND_RECEIVE_BROADCAST 11
|
||||
|
||||
#define DMAPI5_TOPIC_PARAMETER_COMMAND_TYPE "commandType"
|
||||
#define DMAPI5_TOPIC_PARAMETER_CHAT_COMMAND "chatCommand"
|
||||
@@ -89,6 +90,7 @@
|
||||
#define DMAPI5_TOPIC_PARAMETER_NEW_INSTANCE_NAME "newInstanceName"
|
||||
#define DMAPI5_TOPIC_PARAMETER_CHAT_UPDATE "chatUpdate"
|
||||
#define DMAPI5_TOPIC_PARAMETER_NEW_SERVER_VERSION "newServerVersion"
|
||||
#define DMAPI5_TOPIC_PARAMETER_BROADCAST_MESSAGE "broadcastMessage"
|
||||
|
||||
#define DMAPI5_TOPIC_RESPONSE_COMMAND_RESPONSE "commandResponse"
|
||||
#define DMAPI5_TOPIC_RESPONSE_COMMAND_RESPONSE_MESSAGE "commandResponseMessage"
|
||||
|
||||
@@ -94,7 +94,7 @@
|
||||
if(DMAPI5_TOPIC_COMMAND_CHANGE_PORT)
|
||||
var/new_port = topic_parameters[DMAPI5_TOPIC_PARAMETER_NEW_PORT]
|
||||
if (!isnum(new_port) || !(new_port > 0))
|
||||
return TopicResponse("Invalid or missing [DMAPI5_TOPIC_PARAMETER_NEW_PORT]]")
|
||||
return TopicResponse("Invalid or missing [DMAPI5_TOPIC_PARAMETER_NEW_PORT]")
|
||||
|
||||
if(event_handler != null)
|
||||
event_handler.HandleEvent(TGS_EVENT_PORT_SWAP, new_port)
|
||||
@@ -141,7 +141,7 @@
|
||||
if(DMAPI5_TOPIC_COMMAND_SERVER_PORT_UPDATE)
|
||||
var/new_port = topic_parameters[DMAPI5_TOPIC_PARAMETER_NEW_PORT]
|
||||
if (!isnum(new_port) || !(new_port > 0))
|
||||
return TopicResponse("Invalid or missing [DMAPI5_TOPIC_PARAMETER_NEW_PORT]]")
|
||||
return TopicResponse("Invalid or missing [DMAPI5_TOPIC_PARAMETER_NEW_PORT]")
|
||||
|
||||
server_port = new_port
|
||||
return TopicResponse()
|
||||
@@ -157,7 +157,7 @@
|
||||
var/error_message = null
|
||||
if (new_port != null)
|
||||
if (!isnum(new_port) || !(new_port > 0))
|
||||
error_message = "Invalid [DMAPI5_TOPIC_PARAMETER_NEW_PORT]]"
|
||||
error_message = "Invalid [DMAPI5_TOPIC_PARAMETER_NEW_PORT]"
|
||||
else
|
||||
server_port = new_port
|
||||
|
||||
@@ -165,7 +165,7 @@
|
||||
if (!istext(new_version_string))
|
||||
if(error_message != null)
|
||||
error_message += ", "
|
||||
error_message += "Invalid or missing [DMAPI5_TOPIC_PARAMETER_NEW_SERVER_VERSION]]"
|
||||
error_message += "Invalid or missing [DMAPI5_TOPIC_PARAMETER_NEW_SERVER_VERSION]"
|
||||
else
|
||||
var/datum/tgs_version/new_version = new(new_version_string)
|
||||
if (event_handler)
|
||||
@@ -267,4 +267,16 @@
|
||||
|
||||
return chunk_to_send
|
||||
|
||||
if(DMAPI5_TOPIC_COMMAND_RECEIVE_BROADCAST)
|
||||
var/message = topic_parameters[DMAPI5_TOPIC_PARAMETER_BROADCAST_MESSAGE]
|
||||
if (!istext(message))
|
||||
return TopicResponse("Invalid or missing [DMAPI5_TOPIC_PARAMETER_BROADCAST_MESSAGE]")
|
||||
|
||||
TGS_WORLD_ANNOUNCE(message)
|
||||
return TopicResponse()
|
||||
|
||||
return TopicResponse("Unknown command: [command]")
|
||||
|
||||
/datum/tgs_api/v5/proc/WorldBroadcast(message)
|
||||
set waitfor = FALSE
|
||||
TGS_WORLD_ANNOUNCE(message)
|
||||
|
||||
@@ -78,6 +78,9 @@
|
||||
#undef DMAPI5_TOPIC_COMMAND_SERVER_PORT_UPDATE
|
||||
#undef DMAPI5_TOPIC_COMMAND_HEALTHCHECK
|
||||
#undef DMAPI5_TOPIC_COMMAND_WATCHDOG_REATTACH
|
||||
#undef DMAPI5_TOPIC_COMMAND_SEND_CHUNK
|
||||
#undef DMAPI5_TOPIC_COMMAND_RECEIVE_CHUNK
|
||||
#undef DMAPI5_TOPIC_COMMAND_RECEIVE_BROADCAST
|
||||
|
||||
#undef DMAPI5_TOPIC_PARAMETER_COMMAND_TYPE
|
||||
#undef DMAPI5_TOPIC_PARAMETER_CHAT_COMMAND
|
||||
@@ -87,6 +90,7 @@
|
||||
#undef DMAPI5_TOPIC_PARAMETER_NEW_INSTANCE_NAME
|
||||
#undef DMAPI5_TOPIC_PARAMETER_CHAT_UPDATE
|
||||
#undef DMAPI5_TOPIC_PARAMETER_NEW_SERVER_VERSION
|
||||
#undef DMAPI5_TOPIC_PARAMETER_BROADCAST_MESSAGE
|
||||
|
||||
#undef DMAPI5_TOPIC_RESPONSE_COMMAND_RESPONSE
|
||||
#undef DMAPI5_TOPIC_RESPONSE_COMMAND_RESPONSE_MESSAGE
|
||||
|
||||
@@ -629,6 +629,10 @@ namespace Tgstation.Server.Api.Models
|
||||
[Description("The deployment took longer than the configured timeout!")]
|
||||
DeploymentTimeout,
|
||||
|
||||
// This comment is here to remind you that there is one more unused error code above and you should use it first
|
||||
/// <summary>
|
||||
/// Sending a broadcast message failed.
|
||||
/// </summary>
|
||||
[Description("Could not send broadcast to the DMAPI. This can happen either due to there being an insufficient DMAPI version, a communication failure, or the server being offline.")]
|
||||
BroadcastFailure,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,5 +7,9 @@ namespace Tgstation.Server.Api.Models.Request
|
||||
/// </summary>
|
||||
public sealed class DreamDaemonRequest : DreamDaemonApiBase
|
||||
{
|
||||
/// <summary>
|
||||
/// A <see cref="string"/> to send to the running server's DMAPI for broadcasting. How this is displayed is up to how the DMAPI is integrated in the codebase. Requires interop version >=5.7.0.
|
||||
/// </summary>
|
||||
public string? BroadcastMessage { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,5 +112,10 @@ namespace Tgstation.Server.Api.Rights
|
||||
/// User can change <see cref="Models.Internal.DreamDaemonLaunchParameters.MapThreads"/>.
|
||||
/// </summary>
|
||||
SetMapThreads = 1 << 19,
|
||||
|
||||
/// <summary>
|
||||
/// User can use <see cref="Models.Request.DreamDaemonRequest.BroadcastMessage"/>.
|
||||
/// </summary>
|
||||
BroadcastMessage = 1 << 20,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,5 +62,10 @@ namespace Tgstation.Server.Host.Components.Interop.Topic
|
||||
/// Receive additional data for a previous response.
|
||||
/// </summary>
|
||||
ReceiveChunk,
|
||||
|
||||
/// <summary>
|
||||
/// Sending a broadcast message.
|
||||
/// </summary>
|
||||
Broadcast,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,11 @@ namespace Tgstation.Server.Host.Components.Interop.Topic
|
||||
/// </summary>
|
||||
public string NewInstanceName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The message to broadcast for <see cref="TopicCommandType.Broadcast"/> requests.
|
||||
/// </summary>
|
||||
public string BroadcastMessage { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="Interop.ChatUpdate"/> for <see cref="TopicCommandType.ChatChannelsUpdate"/> requests.
|
||||
/// </summary>
|
||||
@@ -68,6 +73,7 @@ namespace Tgstation.Server.Host.Components.Interop.Topic
|
||||
or TopicCommandType.ChangeRebootState
|
||||
or TopicCommandType.InstanceRenamed
|
||||
or TopicCommandType.ChatChannelsUpdate
|
||||
or TopicCommandType.Broadcast
|
||||
or TopicCommandType.ServerRestarted => true,
|
||||
TopicCommandType.ChatCommand
|
||||
or TopicCommandType.HealthCheck
|
||||
@@ -76,6 +82,26 @@ namespace Tgstation.Server.Host.Components.Interop.Topic
|
||||
_ => throw new InvalidOperationException($"Invalid value for {nameof(CommandType)}: {CommandType}"),
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TopicParameters"/> class.
|
||||
/// </summary>
|
||||
/// <param name="newInstanceName">The value of <see cref="NewInstanceName"/>.</param>
|
||||
/// <returns>The created <see cref="TopicParameters"/>.</returns>
|
||||
public static TopicParameters CreateInstanceRenamedTopicParameters(string newInstanceName)
|
||||
=> new (
|
||||
newInstanceName ?? throw new ArgumentNullException(nameof(newInstanceName)),
|
||||
TopicCommandType.InstanceRenamed);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TopicParameters"/> class.
|
||||
/// </summary>
|
||||
/// <param name="broadcastMessage">The value of <see cref="BroadcastMessage"/>.</param>
|
||||
/// <returns>The created <see cref="TopicParameters"/>.</returns>
|
||||
public static TopicParameters CreateBroadcastParameters(string broadcastMessage)
|
||||
=> new (
|
||||
broadcastMessage ?? throw new ArgumentNullException(nameof(broadcastMessage)),
|
||||
TopicCommandType.Broadcast);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TopicParameters"/> class.
|
||||
/// </summary>
|
||||
@@ -116,16 +142,6 @@ namespace Tgstation.Server.Host.Components.Interop.Topic
|
||||
NewRebootState = newRebootState;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TopicParameters"/> class.
|
||||
/// </summary>
|
||||
/// <param name="newInstanceName">The value of <see cref="NewInstanceName"/>.</param>
|
||||
public TopicParameters(string newInstanceName)
|
||||
: this(TopicCommandType.InstanceRenamed)
|
||||
{
|
||||
NewInstanceName = newInstanceName ?? throw new ArgumentNullException(nameof(newInstanceName));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TopicParameters"/> class.
|
||||
/// </summary>
|
||||
@@ -175,5 +191,28 @@ namespace Tgstation.Server.Host.Components.Interop.Topic
|
||||
{
|
||||
CommandType = commandType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TopicParameters"/> class.
|
||||
/// </summary>
|
||||
/// <param name="stringCommand">The <see cref="string"/> parameter for the property designated by <paramref name="stringCommandType"/>.</param>
|
||||
/// <param name="stringCommandType">The value of <see cref="CommandType"/>.</param>
|
||||
TopicParameters(string stringCommand, TopicCommandType stringCommandType)
|
||||
: this(stringCommandType)
|
||||
{
|
||||
#pragma warning disable IDE0010 // Add missing cases
|
||||
switch (stringCommandType)
|
||||
{
|
||||
case TopicCommandType.InstanceRenamed:
|
||||
NewInstanceName = stringCommand;
|
||||
break;
|
||||
case TopicCommandType.Broadcast:
|
||||
BroadcastMessage = stringCommand;
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException($"Invalid string TopicCommandType: {stringCommandType}");
|
||||
}
|
||||
#pragma warning restore IDE0010 // Add missing cases
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -583,7 +583,9 @@ namespace Tgstation.Server.Host.Components.Session
|
||||
public async ValueTask InstanceRenamed(string newInstanceName, CancellationToken cancellationToken)
|
||||
{
|
||||
ReattachInformation.RuntimeInformation.InstanceName = newInstanceName;
|
||||
await SendCommand(new TopicParameters(newInstanceName), cancellationToken);
|
||||
await SendCommand(
|
||||
TopicParameters.CreateInstanceRenamedTopicParameters(newInstanceName),
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -88,5 +88,13 @@ namespace Tgstation.Server.Host.Components.Watchdog
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>A <see cref="ValueTask"/> representing the running operation.</returns>
|
||||
ValueTask CreateDump(CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Send a broadcast <paramref name="message"/> to the DMAPI.
|
||||
/// </summary>
|
||||
/// <param name="message">The message to broadcast.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>A <see cref="ValueTask{TResult}"/> resulting in <see langword="true"/> if the broadcast succeeded., <see langword="false"/> otherwise.</returns>
|
||||
ValueTask<bool> Broadcast(string message, CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -457,6 +457,43 @@ namespace Tgstation.Server.Host.Components.Watchdog
|
||||
await session.CreateDump(dumpFileName, cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async ValueTask<bool> Broadcast(string message, CancellationToken cancellationToken)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(message);
|
||||
|
||||
var activeServer = GetActiveController();
|
||||
if (activeServer == null)
|
||||
{
|
||||
Logger.LogInformation("Attempted broadcast failed, no active server!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!activeServer.DMApiAvailable)
|
||||
{
|
||||
Logger.LogInformation("Attempted broadcast failed, no DMAPI!");
|
||||
return false;
|
||||
}
|
||||
|
||||
var minimumRequiredVersion = new Version(5, 7, 0);
|
||||
if (activeServer.DMApiVersion < minimumRequiredVersion)
|
||||
{
|
||||
Logger.LogInformation(
|
||||
"Attempted broadcast failed, insufficient interop version: {interopVersion}. Requires {minimumRequiredVersion}!",
|
||||
activeServer.DMApiVersion,
|
||||
minimumRequiredVersion);
|
||||
return false;
|
||||
}
|
||||
|
||||
Logger.LogInformation("Broadcasting: {message}", message);
|
||||
|
||||
var response = await activeServer.SendCommand(
|
||||
TopicParameters.CreateBroadcastParameters(message),
|
||||
cancellationToken);
|
||||
|
||||
return response != null && response.ErrorMessage == null;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
async ValueTask IEventConsumer.HandleEvent(EventType eventType, IEnumerable<string> parameters, bool deploymentPipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
|
||||
@@ -148,7 +148,8 @@ namespace Tgstation.Server.Host.Controllers
|
||||
| DreamDaemonRights.SetVisibility
|
||||
| DreamDaemonRights.SetProfiler
|
||||
| DreamDaemonRights.SetLogOutput
|
||||
| DreamDaemonRights.SetMapThreads)]
|
||||
| DreamDaemonRights.SetMapThreads
|
||||
| DreamDaemonRights.BroadcastMessage)]
|
||||
[ProducesResponseType(typeof(DreamDaemonResponse), 200)]
|
||||
[ProducesResponseType(typeof(ErrorMessageResponse), 410)]
|
||||
#pragma warning disable CA1502 // TODO: Decomplexify
|
||||
@@ -208,36 +209,41 @@ namespace Tgstation.Server.Host.Controllers
|
||||
return false;
|
||||
}
|
||||
|
||||
if (CheckModified(x => x.AllowWebClient, DreamDaemonRights.SetWebClient)
|
||||
|| CheckModified(x => x.AutoStart, DreamDaemonRights.SetAutoStart)
|
||||
|| CheckModified(x => x.Port, DreamDaemonRights.SetPort)
|
||||
|| CheckModified(x => x.SecurityLevel, DreamDaemonRights.SetSecurity)
|
||||
|| CheckModified(x => x.Visibility, DreamDaemonRights.SetVisibility)
|
||||
|| (model.SoftRestart.HasValue && !AuthenticationContext.InstancePermissionSet.DreamDaemonRights.Value.HasFlag(DreamDaemonRights.SoftRestart))
|
||||
|| (model.SoftShutdown.HasValue && !AuthenticationContext.InstancePermissionSet.DreamDaemonRights.Value.HasFlag(DreamDaemonRights.SoftShutdown))
|
||||
|| (!String.IsNullOrWhiteSpace(model.BroadcastMessage) && !AuthenticationContext.InstancePermissionSet.DreamDaemonRights.Value.HasFlag(DreamDaemonRights.BroadcastMessage))
|
||||
|| CheckModified(x => x.StartupTimeout, DreamDaemonRights.SetStartupTimeout)
|
||||
|| CheckModified(x => x.HealthCheckSeconds, DreamDaemonRights.SetHealthCheckInterval)
|
||||
|| CheckModified(x => x.DumpOnHealthCheckRestart, DreamDaemonRights.CreateDump)
|
||||
|| CheckModified(x => x.TopicRequestTimeout, DreamDaemonRights.SetTopicTimeout)
|
||||
|| CheckModified(x => x.AdditionalParameters, DreamDaemonRights.SetAdditionalParameters)
|
||||
|| CheckModified(x => x.StartProfiler, DreamDaemonRights.SetProfiler)
|
||||
|| CheckModified(x => x.LogOutput, DreamDaemonRights.SetLogOutput)
|
||||
|| CheckModified(x => x.MapThreads, DreamDaemonRights.SetMapThreads))
|
||||
return Forbid();
|
||||
|
||||
return await WithComponentInstance(
|
||||
async instance =>
|
||||
{
|
||||
var watchdog = instance.Watchdog;
|
||||
var rebootState = watchdog.RebootState;
|
||||
var oldSoftRestart = rebootState == RebootState.Restart;
|
||||
var oldSoftShutdown = rebootState == RebootState.Shutdown;
|
||||
|
||||
if (CheckModified(x => x.AllowWebClient, DreamDaemonRights.SetWebClient)
|
||||
|| CheckModified(x => x.AutoStart, DreamDaemonRights.SetAutoStart)
|
||||
|| CheckModified(x => x.Port, DreamDaemonRights.SetPort)
|
||||
|| CheckModified(x => x.SecurityLevel, DreamDaemonRights.SetSecurity)
|
||||
|| CheckModified(x => x.Visibility, DreamDaemonRights.SetVisibility)
|
||||
|| (model.SoftRestart.HasValue && !AuthenticationContext.InstancePermissionSet.DreamDaemonRights.Value.HasFlag(DreamDaemonRights.SoftRestart))
|
||||
|| (model.SoftShutdown.HasValue && !AuthenticationContext.InstancePermissionSet.DreamDaemonRights.Value.HasFlag(DreamDaemonRights.SoftShutdown))
|
||||
|| CheckModified(x => x.StartupTimeout, DreamDaemonRights.SetStartupTimeout)
|
||||
|| CheckModified(x => x.HealthCheckSeconds, DreamDaemonRights.SetHealthCheckInterval)
|
||||
|| CheckModified(x => x.DumpOnHealthCheckRestart, DreamDaemonRights.CreateDump)
|
||||
|| CheckModified(x => x.TopicRequestTimeout, DreamDaemonRights.SetTopicTimeout)
|
||||
|| CheckModified(x => x.AdditionalParameters, DreamDaemonRights.SetAdditionalParameters)
|
||||
|| CheckModified(x => x.StartProfiler, DreamDaemonRights.SetProfiler)
|
||||
|| CheckModified(x => x.LogOutput, DreamDaemonRights.SetLogOutput)
|
||||
|| CheckModified(x => x.MapThreads, DreamDaemonRights.SetMapThreads))
|
||||
return Forbid();
|
||||
if (!String.IsNullOrWhiteSpace(model.BroadcastMessage)
|
||||
&& !await watchdog.Broadcast(model.BroadcastMessage, cancellationToken))
|
||||
return Conflict(new ErrorMessageResponse(ErrorCode.BroadcastFailure));
|
||||
|
||||
await DatabaseContext.Save(cancellationToken);
|
||||
|
||||
// run this second because current may be modified by it
|
||||
// slight race condition with request cancellation, but I CANNOT be assed right now
|
||||
await watchdog.ChangeSettings(current, cancellationToken);
|
||||
|
||||
var rebootState = watchdog.RebootState;
|
||||
var oldSoftRestart = rebootState == RebootState.Restart;
|
||||
var oldSoftShutdown = rebootState == RebootState.Shutdown;
|
||||
if (!oldSoftRestart && model.SoftRestart == true && watchdog.Status == WatchdogStatus.Online)
|
||||
await watchdog.Restart(true, cancellationToken);
|
||||
else if (!oldSoftShutdown && model.SoftShutdown == true)
|
||||
|
||||
@@ -558,7 +558,7 @@ namespace Tgstation.Server.Host.Core
|
||||
logger.LogTrace("Configuration version: {configVersion}", GeneralConfiguration.CurrentConfigVersion);
|
||||
logger.LogTrace("DMAPI Interop version: {interopVersion}", DMApiConstants.InteropVersion);
|
||||
if (controlPanelConfiguration.Enable)
|
||||
logger.LogTrace("Web control panel version: {webCPVersion}", MasterVersionsAttribute.Instance.RawControlPanelVersion);
|
||||
logger.LogTrace("Webpanel version: {webCPVersion}", MasterVersionsAttribute.Instance.RawWebpanelVersion);
|
||||
|
||||
logger.LogDebug("Starting hosting on port {httpApiPort}...", serverPortProvider.HttpApiPort);
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace Tgstation.Server.Host.Properties
|
||||
/// <summary>
|
||||
/// The <see cref="Version"/> <see cref="string"/> of the control panel version built.
|
||||
/// </summary>
|
||||
public string RawControlPanelVersion { get; }
|
||||
public string RawWebpanelVersion { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="Version"/> <see cref="string"/> of the control panel version built.
|
||||
@@ -46,19 +46,19 @@ namespace Tgstation.Server.Host.Properties
|
||||
/// </summary>
|
||||
/// <param name="rawConfigurationVersion">The value of <see cref="RawConfigurationVersion"/>.</param>
|
||||
/// <param name="rawInteropVersion">The value of <see cref="RawInteropVersion"/>.</param>
|
||||
/// <param name="rawControlPanelVersion">The value of <see cref="RawControlPanelVersion"/>.</param>
|
||||
/// <param name="rawWebpanelVersion">The value of <see cref="RawWebpanelVersion"/>.</param>
|
||||
/// <param name="rawHostWatchdogVersion">The value of <see cref="RawHostWatchdogVersion"/>.</param>
|
||||
/// <param name="rawMariaDBRedistVersion">The value of <see cref="RawMariaDBRedistVersion"/>.</param>
|
||||
public MasterVersionsAttribute(
|
||||
string rawConfigurationVersion,
|
||||
string rawInteropVersion,
|
||||
string rawControlPanelVersion,
|
||||
string rawWebpanelVersion,
|
||||
string rawHostWatchdogVersion,
|
||||
string rawMariaDBRedistVersion)
|
||||
{
|
||||
RawConfigurationVersion = rawConfigurationVersion ?? throw new ArgumentNullException(nameof(rawConfigurationVersion));
|
||||
RawInteropVersion = rawInteropVersion ?? throw new ArgumentNullException(nameof(rawInteropVersion));
|
||||
RawControlPanelVersion = rawControlPanelVersion ?? throw new ArgumentNullException(nameof(rawControlPanelVersion));
|
||||
RawWebpanelVersion = rawWebpanelVersion ?? throw new ArgumentNullException(nameof(rawWebpanelVersion));
|
||||
RawHostWatchdogVersion = rawHostWatchdogVersion ?? throw new ArgumentNullException(nameof(rawHostWatchdogVersion));
|
||||
RawMariaDBRedistVersion = rawMariaDBRedistVersion ?? throw new ArgumentNullException(nameof(rawMariaDBRedistVersion));
|
||||
}
|
||||
|
||||
@@ -22,17 +22,17 @@
|
||||
<DefineConstants>$(DefineConstants);NO_WEBPANEL</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<Target Condition="'$(TGS_HOST_NO_WEBPANEL)' != 'true'" Name="ClientInstall" BeforeTargets="ResolveAssemblyReferences" Inputs="../../build/ControlPanelVersion.props" Outputs="$(NpmInstallStampFile)">
|
||||
<Target Condition="'$(TGS_HOST_NO_WEBPANEL)' != 'true'" Name="ClientInstall" BeforeTargets="ResolveAssemblyReferences" Inputs="../../build/WebpanelVersion.props" Outputs="$(NpmInstallStampFile)">
|
||||
<Message Text="Pulling web control panel..." Importance="high" />
|
||||
<RemoveDir Directories="ClientApp" />
|
||||
<Exec Command="git clone https://github.com/tgstation/tgstation-server-webpanel --branch v$(TgsControlPanelVersion) --depth 1 ClientApp" />
|
||||
<Exec Command="git clone https://github.com/tgstation/tgstation-server-webpanel --branch v$(TgsWebpanelVersion) --depth 1 ClientApp" />
|
||||
<RemoveDir Directories="ClientApp/.git" /> <!-- Allows git clean to clean it out -->
|
||||
<Message Text="Restoring yarn packages..." Importance="high" />
|
||||
<Exec WorkingDirectory="ClientApp" Command="npx --yes yarn@$(TgsYarnVersion) install --immutable" />
|
||||
<Touch Files="$(NpmInstallStampFile)" AlwaysCreate="true" />
|
||||
</Target>
|
||||
|
||||
<Target Condition="'$(TGS_HOST_NO_WEBPANEL)' != 'true'" Name="NpmBuild" BeforeTargets="BeforeBuild" DependsOnTargets="ClientInstall" Inputs="../../build/ControlPanelVersion.props" Outputs="wwwroot\index.html">
|
||||
<Target Condition="'$(TGS_HOST_NO_WEBPANEL)' != 'true'" Name="NpmBuild" BeforeTargets="BeforeBuild" DependsOnTargets="ClientInstall" Inputs="../../build/WebpanelVersion.props" Outputs="wwwroot\index.html">
|
||||
<Message Text="Building web control panel..." Importance="high" />
|
||||
<Exec WorkingDirectory="ClientApp" Command="npx --yes yarn@$(TgsYarnVersion) run msbuild" />
|
||||
</Target>
|
||||
@@ -47,7 +47,7 @@
|
||||
<AssemblyAttributes Include="Tgstation.Server.Host.Properties.MasterVersionsAttribute">
|
||||
<_Parameter1>$(TgsConfigVersion)</_Parameter1>
|
||||
<_Parameter2>$(TgsInteropVersion)</_Parameter2>
|
||||
<_Parameter3>$(TgsControlPanelVersion)</_Parameter3>
|
||||
<_Parameter3>$(TgsWebpanelVersion)</_Parameter3>
|
||||
<_Parameter4>$(TgsHostWatchdogVersion)</_Parameter4>
|
||||
<_Parameter5>$(TgsMariaDBRedistVersion)</_Parameter5>
|
||||
</AssemblyAttributes>
|
||||
@@ -107,7 +107,7 @@
|
||||
<!-- Usage: Async logging plugin -->
|
||||
<PackageReference Include="Serilog.Sinks.Async" Version="1.5.0" />
|
||||
<!-- Usage: Console logging plugin -->
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="5.0.0" />
|
||||
<!-- Usage: Elasticsearch logging plugin -->
|
||||
<PackageReference Include="Serilog.Sinks.Elasticsearch" Version="9.0.3" />
|
||||
<!-- Usage: File logging plugin -->
|
||||
|
||||
@@ -174,6 +174,10 @@ var/run_bridge_test
|
||||
if(tactics8)
|
||||
return received_health_check ? "received health check" : "did not receive health check"
|
||||
|
||||
var/tactics_broadcast = data["tgs_integration_test_tactics_broadcast"]
|
||||
if(tactics_broadcast)
|
||||
return last_tgs_broadcast || "!!NULL!!"
|
||||
|
||||
var/legalize_nuclear_bombs = data["shadow_wizard_money_gang"]
|
||||
if(legalize_nuclear_bombs)
|
||||
text2file("I expect this to remain here for a while", "kajigger.txt")
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
#define TGS_READ_GLOBAL(Name) global.##Name
|
||||
#define TGS_WRITE_GLOBAL(Name, Value) global.##Name = ##Value
|
||||
#define TGS_PROTECT_DATUM(Path)
|
||||
#define TGS_WORLD_ANNOUNCE(message) world << ##message
|
||||
var/last_tgs_broadcast
|
||||
#define TGS_WORLD_ANNOUNCE(message) if(TRUE) { var/__tgs_announce_message_local = ##message; world << __tgs_announce_message_local; last_tgs_broadcast = __tgs_announce_message_local; }
|
||||
#define TGS_WARNING_LOG(message) world.log << "Warn: [##message]"
|
||||
#define TGS_NOTIFY_ADMINS(event)
|
||||
#define TGS_CLIENT_COUNT 0
|
||||
|
||||
+1
-6
@@ -1,16 +1,11 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="../../build/Common.props" />
|
||||
<Import Project="../../build/TestCommon.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>$(TgsFrameworkVersion)</TargetFramework>
|
||||
<OutputType>Exe</OutputType>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Moq" Version="4.18.4" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="3.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Tgstation.Server.Host\Tgstation.Server.Host.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -211,12 +211,46 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
await RunTest(false);
|
||||
}
|
||||
|
||||
async ValueTask BroadcastTest(CancellationToken cancellationToken)
|
||||
{
|
||||
var topicRequestResult = await topicClient.SendTopic(
|
||||
IPAddress.Loopback,
|
||||
$"tgs_integration_test_tactics_broadcast=1",
|
||||
ddPort,
|
||||
cancellationToken);
|
||||
|
||||
Assert.IsNotNull(topicRequestResult);
|
||||
Assert.AreEqual("!!NULL!!", topicRequestResult.StringData);
|
||||
|
||||
const string TestBroadcastMessage = "TGS: THIS IS A TEST OF THE EMERGENCY BROADCAST SYSTEM!";
|
||||
await instanceClient.DreamDaemon.Update(new DreamDaemonRequest
|
||||
{
|
||||
BroadcastMessage = TestBroadcastMessage,
|
||||
}, cancellationToken);
|
||||
|
||||
topicRequestResult = await topicClient.SendTopic(
|
||||
IPAddress.Loopback,
|
||||
$"tgs_integration_test_tactics_broadcast=1",
|
||||
ddPort,
|
||||
cancellationToken);
|
||||
|
||||
Assert.IsNotNull(topicRequestResult);
|
||||
Assert.AreEqual(TestBroadcastMessage, topicRequestResult.StringData);
|
||||
}
|
||||
|
||||
async Task InteropTestsForLongRunningDme(CancellationToken cancellationToken)
|
||||
{
|
||||
await RegressionTest1686(cancellationToken);
|
||||
|
||||
await ApiAssert.ThrowsException<ConflictException, DreamDaemonResponse>(() => instanceClient.DreamDaemon.Update(new DreamDaemonRequest
|
||||
{
|
||||
BroadcastMessage = "ksjfdksjf",
|
||||
}, cancellationToken), ErrorCode.BroadcastFailure);
|
||||
|
||||
await StartAndLeaveRunning(cancellationToken);
|
||||
|
||||
await BroadcastTest(cancellationToken);
|
||||
|
||||
await RegressionTest1550(cancellationToken);
|
||||
|
||||
var deleteJobTask = TestDeleteByondInstallErrorCasesAndQueing(cancellationToken);
|
||||
|
||||
@@ -284,11 +284,11 @@ namespace Tgstation.Server.Tests
|
||||
[TestMethod]
|
||||
public void TestControlPanelVersion()
|
||||
{
|
||||
var doc = XDocument.Load("../../../../../build/ControlPanelVersion.props");
|
||||
var doc = XDocument.Load("../../../../../build/WebpanelVersion.props");
|
||||
var project = doc.Root;
|
||||
var controlPanelXmlNamespace = project.GetDefaultNamespace();
|
||||
var controlPanelVersionsPropertyGroup = project.Elements().First(x => x.Name == controlPanelXmlNamespace + "PropertyGroup");
|
||||
var versionString = controlPanelVersionsPropertyGroup.Element(controlPanelXmlNamespace + "TgsControlPanelVersion").Value;
|
||||
var versionString = controlPanelVersionsPropertyGroup.Element(controlPanelXmlNamespace + "TgsWebpanelVersion").Value;
|
||||
Assert.IsNotNull(versionString);
|
||||
Assert.IsTrue(Version.TryParse(versionString, out var expected));
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{6FF654E6
|
||||
build\BuildDox.ps1 = build\BuildDox.ps1
|
||||
build\ci.runsettings = build\ci.runsettings
|
||||
build\Common.props = build\Common.props
|
||||
build\ControlPanelVersion.props = build\ControlPanelVersion.props
|
||||
build\Dockerfile = build\Dockerfile
|
||||
build\GenerateMigrations.sh = build\GenerateMigrations.sh
|
||||
build\logo.svg = build\logo.svg
|
||||
@@ -39,6 +38,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{6FF654E6
|
||||
build\tgstation-server.service = build\tgstation-server.service
|
||||
build\uac_elevation_manifest.xml = build\uac_elevation_manifest.xml
|
||||
build\Version.props = build\Version.props
|
||||
build\WebpanelVersion.props = build\WebpanelVersion.props
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tgstation.Server.Api", "src\Tgstation.Server.Api\Tgstation.Server.Api.csproj", "{8B4A208D-A48A-4A5D-8B94-E2661138865D}"
|
||||
|
||||
@@ -223,7 +223,7 @@ namespace Tgstation.Server.ReleaseNotes
|
||||
|
||||
string prefix;
|
||||
const string PropsPath = "build/Version.props";
|
||||
const string ControlPanelPropsPath = "build/ControlPanelVersion.props";
|
||||
const string ControlPanelPropsPath = "build/WebpanelVersion.props";
|
||||
|
||||
var doc = XDocument.Load(PropsPath);
|
||||
var project = doc.Root;
|
||||
@@ -246,7 +246,7 @@ namespace Tgstation.Server.ReleaseNotes
|
||||
var configVersion = Version.Parse(versionsPropertyGroup.Element(xmlNamespace + "TgsConfigVersion").Value);
|
||||
var dmApiVersion = Version.Parse(versionsPropertyGroup.Element(xmlNamespace + "TgsDmapiVersion").Value);
|
||||
var interopVersion = Version.Parse(versionsPropertyGroup.Element(xmlNamespace + "TgsInteropVersion").Value);
|
||||
var webControlVersion = Version.Parse(controlPanelVersionsPropertyGroup.Element(controlPanelXmlNamespace + "TgsControlPanelVersion").Value);
|
||||
var webControlVersion = Version.Parse(controlPanelVersionsPropertyGroup.Element(controlPanelXmlNamespace + "TgsWebpanelVersion").Value);
|
||||
var hostWatchdogVersion = Version.Parse(versionsPropertyGroup.Element(xmlNamespace + "TgsHostWatchdogVersion").Value);
|
||||
|
||||
if (webControlVersion.Major == 0)
|
||||
@@ -608,14 +608,14 @@ namespace Tgstation.Server.ReleaseNotes
|
||||
dict.Add(Component.NugetApi, Parse("TgsApiLibraryVersion"));
|
||||
dict.Add(Component.NugetClient, Parse("TgsClientVersion"));
|
||||
|
||||
var webVersion = Parse("TgsControlPanelVersion");
|
||||
var webVersion = Parse("TgsWebpanelVersion");
|
||||
if (webVersion != null)
|
||||
{
|
||||
dict.Add(Component.WebControlPanel, webVersion);
|
||||
}
|
||||
else
|
||||
{
|
||||
var controlPanelVersionBytes = await RLR(() => client.Repository.Content.GetRawContentByRef(RepoOwner, RepoName, "build/ControlPanelVersion.props", mergeCommit));
|
||||
var controlPanelVersionBytes = await RLR(() => client.Repository.Content.GetRawContentByRef(RepoOwner, RepoName, "build/WebpanelVersion.props", mergeCommit));
|
||||
using (var ms = new MemoryStream(controlPanelVersionBytes))
|
||||
doc = XDocument.Load(ms);
|
||||
|
||||
@@ -623,7 +623,7 @@ namespace Tgstation.Server.ReleaseNotes
|
||||
project = doc.Root;
|
||||
var controlPanelXmlNamespace = project.GetDefaultNamespace();
|
||||
var controlPanelVersionsPropertyGroup = project.Elements().First(x => x.Name == controlPanelXmlNamespace + "PropertyGroup");
|
||||
dict.Add(Component.WebControlPanel, Version.Parse(controlPanelVersionsPropertyGroup.Element(controlPanelXmlNamespace + "TgsControlPanelVersion").Value));
|
||||
dict.Add(Component.WebControlPanel, Version.Parse(controlPanelVersionsPropertyGroup.Element(controlPanelXmlNamespace + "TgsWebpanelVersion").Value));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<!-- Usage: GitHub Discussions interop -->
|
||||
<PackageReference Include="Octokit.GraphQL" Version="0.2.1-beta" />
|
||||
<PackageReference Include="Octokit.GraphQL" Version="0.3.0-beta" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
Reference in New Issue
Block a user