Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Уведомления о обновлениях сервера через Discord webhook #920

Merged
merged 3 commits into from
Dec 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using Content.Shared.Administration;
using Robust.Shared.Console;
using Content.Server.Administration;
using Content.Server.ServerUpdates;

namespace Content.Server.ADT.Administration.Commands;


[AdminCommand(AdminFlags.Permissions)]
public sealed class SendUpdateServerCommand : LocalizedCommands
{
[Dependency] private readonly ServerUpdateManager _serverManager = default!;
public override string Command => "send_updateserver_devtest";

public override async void Execute(IConsoleShell shell, string argStr, string[] args)
{
var player = shell.Player;
if (player == null)
{
shell.WriteError(LocalizationManager.GetString("shell-target-player-does-not-exist"));
return;
}

_serverManager.SendDiscordWebHookUpdateMessage();
}
}
89 changes: 89 additions & 0 deletions Content.Server/ServerUpdates/ServerUpdateManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
using Robust.Shared.Enums;
using Robust.Shared.Player;
using Robust.Shared.Timing;
using Content.Shared.ADT.CCVar;
using Content.Server.Discord;
using Content.Server.GameTicking;

namespace Content.Server.ServerUpdates;

Expand All @@ -27,6 +30,8 @@ public sealed class ServerUpdateManager : IPostInjectInit
[Dependency] private readonly IBaseServer _server = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly ILogManager _logManager = default!;
[Dependency] private readonly DiscordWebhook _discord = default!;
[Dependency] private readonly IEntitySystemManager _entitySystemManager = default!;

private ISawmill _sawmill = default!;

Expand Down Expand Up @@ -102,6 +107,7 @@ private void WatchdogOnUpdateReceived()
_chatManager.DispatchServerAnnouncement(Loc.GetString("server-updates-received"));
_updateOnRoundEnd = true;
ServerEmptyUpdateRestartCheck("update notification");
SendDiscordWebHookUpdateMessage(); // ADT-Tweak
}

/// <summary>
Expand Down Expand Up @@ -148,4 +154,87 @@ void IPostInjectInit.PostInject()
{
_sawmill = _logManager.GetSawmill("restart");
}
// ADT-Tweak-start: Отправка сообщения в Discord при обновлении сервера
public async void SendDiscordWebHookUpdateMessage()
{
if (!string.IsNullOrWhiteSpace(_cfg.GetCVar(ADTDiscordWebhookCCVars.DiscordServerUpdateWebhook)))
{
var webhookUrl = _cfg.GetCVar(ADTDiscordWebhookCCVars.DiscordServerUpdateWebhook);
if (webhookUrl == null)
return;

if (await _discord.GetWebhook(webhookUrl) is not { } webhookData)
return;

// Получение данных сервера
var serverName = _cfg.GetCVar<string>("game.hostname");
var serverDesc = _cfg.GetCVar<string>("game.desc");
var engineVersion = _cfg.GetCVar<string>("build.engine_version");
var buildVersion = _cfg.GetCVar<string>("build.version");

// Сообщение о перезапуске сервера
var descContent = "Обновление получено, сервер автоматически перезапустится для обновления в конце этого раунда.";

// Определение состояния раунда
var gameTicker = _entitySystemManager.GetEntitySystem<GameTicker>();
var roundDescription = gameTicker.RunLevel switch
{
GameRunLevel.PreRoundLobby => gameTicker.RoundId == 0
? "pre-round lobby after server restart"
: $"pre-round lobby for round {gameTicker.RoundId + 1}",
GameRunLevel.InRound => $"round {gameTicker.RoundId}",
GameRunLevel.PostRound => $"post-round {gameTicker.RoundId}",
_ => throw new ArgumentOutOfRangeException(nameof(gameTicker.RunLevel), $"{gameTicker.RunLevel} was not matched."),
};

// Формирование структуры embed
var embed = new WebhookEmbed
{
Title = "Обновление пришло",
Description = descContent,
Color = 0x0e9c00,
Footer = new WebhookEmbedFooter
{
Text = $"{serverName} ({roundDescription})"
},
Fields = new List<WebhookEmbedField>()
};

// Добавление полей только если они не пустые
AddIfNotEmpty(embed.Fields, "Название сервера", serverName);
AddIfNotEmpty(embed.Fields, "Описание сервера", serverDesc);
AddIfNotEmpty(embed.Fields, "RobustToolbox version", engineVersion);
AddIfNotEmpty(embed.Fields, "Build version", buildVersion);

// Формирование полезной нагрузки
var payload = new WebhookPayload
{
Embeds = new List<WebhookEmbed> { embed },
Username = Loc.GetString("username-webhook-update")
};

// Проверка, нужно ли добавлять пинг
var shouldPingOnUpdate = _cfg.GetCVar(ADTDiscordWebhookCCVars.ShouldPingOnUpdate);
if (shouldPingOnUpdate)
{
// Добавляем пинг в поле Content. Это будет сообщение, которое будет сверху
payload.Content = "<@&1275740664264659017>"; // ID роли "Обновления"
}

// Отправка сообщения в Discord
var identifier = webhookData.ToIdentifier();
payload.AllowedMentions.AllowRoleMentions();
await _discord.CreateMessage(identifier, payload);
}
}

// Вспомогательный метод для добавления полей в embed
private void AddIfNotEmpty(List<WebhookEmbedField> fields, string fieldName, string? fieldValue)
{
if (!string.IsNullOrWhiteSpace(fieldValue))
{
fields.Add(new WebhookEmbedField { Name = fieldName, Value = fieldValue, Inline = true });
}
}
// ADT-Tweak-end
}
16 changes: 15 additions & 1 deletion Content.Shared/ADT/CCVar/CCVars.WebhookDiscord.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,19 @@ public sealed class ADTDiscordWebhookCCVars : CVars
/// URL of the Discord webhook which will relay adminwho info to the channel.
/// </summary>
public static readonly CVarDef<string> DiscordAdminwhoWebhook =
CVarDef.Create("discord.adminwho_webhook", string.Empty, CVar.SERVERONLY | CVar.CONFIDENTIAL);
CVarDef.Create("discord.adminwho_webhook", string.Empty, CVar.SERVERONLY | CVar.CONFIDENTIAL | CVar.ARCHIVE);

/// <summary>
/// This constant specifies a webhook that will send a message to Discord when a server updates.
/// </summary>
public static readonly CVarDef<string> DiscordServerUpdateWebhook =
CVarDef.Create("discord.server_update_webhook", string.Empty, CVar.SERVERONLY | CVar.CONFIDENTIAL | CVar.ARCHIVE);

/// <summary>
/// This constant specifies whether a ping should be sent to a specific Discord role
/// when the server update notification is triggered. If set to <c>true</c>, a ping will be sent to the role.
/// If set to <c>false</c>, no ping will be sent.
/// </summary>
public static readonly CVarDef<bool> ShouldPingOnUpdate =
CVarDef.Create("discord.server_update_webhook_ping", true, CVar.SERVERONLY | CVar.ARCHIVE);
}
Loading