From 23d93a7f9a6a430dd6600b25cf958f86fc508811 Mon Sep 17 00:00:00 2001 From: zontreck Date: Sun, 16 Jun 2024 20:13:35 -0700 Subject: [PATCH] finish implementation --- bin/server.dart | 8 +++++- lib/packets/ClientPackets.dart | 41 +++++++++++++++++------------- lib/pages/DiscordConfigPage.dart | 22 +++++++++++----- lib/pages/GameServerPage.dart | 18 +++++++++++++ lib/pages/ServerSettings.dart | 24 ----------------- lib/statemachine.dart | 12 +++++++++ lib/structs/discordHookHelper.dart | 14 +++++++--- lib/structs/settingsEntry.dart | 6 ++--- 8 files changed, 90 insertions(+), 55 deletions(-) diff --git a/bin/server.dart b/bin/server.dart index 97a9475..92d2231 100644 --- a/bin/server.dart +++ b/bin/server.dart @@ -4,6 +4,7 @@ import 'package:libac_dart/packets/packets.dart'; import 'package:libac_dart/utils/IOTools.dart'; import 'package:servermanager/game.dart'; import 'package:servermanager/packets/ClientPackets.dart'; +import 'package:servermanager/structs/SessionData.dart'; import 'package:servermanager/structs/settings.dart'; void main() async { @@ -73,7 +74,12 @@ void main() async { print("Starting up server manager server wrapper"); - await PacketServer.start(settings.inst?.serverSettings.WrapperPort ?? 25306); + while (!SessionData.shutdownPending) { + try { + await PacketServer.start( + settings.inst?.serverSettings.WrapperPort ?? 25306); + } catch (E) {} + } print("Server stopping"); } diff --git a/lib/packets/ClientPackets.dart b/lib/packets/ClientPackets.dart index c00250a..19e93b0 100644 --- a/lib/packets/ClientPackets.dart +++ b/lib/packets/ClientPackets.dart @@ -289,26 +289,33 @@ class C2SUploadSettingsPacket implements IPacket { @override Future handleServerPacket() async { Settings settings = Settings(); - settings.deserialize(srvSettings); - settings.Write(); - // Check if server is running, if not, stop immediately - // If server is running, schedule restart for 1 minute and send a alert to all players, then perform stop or restart depending on if running in Pterodactyl Compatibility mode - SessionData.shutdownMessage = "Server wrapper updated. Restart required."; - SessionData.timer.apply(60); - SessionData.CURRENT_INTERVAL = WarnIntervals.NONE; + CompoundTag currentSettings = settings.serialize(); + try { + settings.deserialize(srvSettings); + settings.Write(); - if (settings.subsys.currentState == States.Inactive) { - Timer.periodic(Duration(seconds: 10), (timer) { - SessionData.shutdownPending = true; - // Stop packet server - PacketServer.socket!.close(); - timer.cancel(); - exit(0); - }); // We give time to allow the server to shut down gracefully. + // Check if server is running, if not, stop immediately + // If server is running, schedule restart for 1 minute and send a alert to all players, then perform stop or restart depending on if running in Pterodactyl Compatibility mode + SessionData.shutdownMessage = "Server wrapper updated. Restart required."; + SessionData.timer.apply(60); + SessionData.CURRENT_INTERVAL = WarnIntervals.NONE; + + if (settings.subsys.currentState == States.Inactive) { + Timer.periodic(Duration(seconds: 10), (timer) { + SessionData.shutdownPending = true; + // Stop packet server + PacketServer.socket!.close(); + timer.cancel(); + exit(0); + }); // We give time to allow the server to shut down gracefully. + } + + return PacketResponse.nil; + } catch (E) { + settings.deserialize(currentSettings); + return PacketResponse.nil; } - - return PacketResponse.nil; } @override diff --git a/lib/pages/DiscordConfigPage.dart b/lib/pages/DiscordConfigPage.dart index f6a4bca..c31e3f1 100644 --- a/lib/pages/DiscordConfigPage.dart +++ b/lib/pages/DiscordConfigPage.dart @@ -11,16 +11,16 @@ class DiscordConfigPage extends StatefulWidget { class DiscordConfigurationState extends State { TextEditingController ServerNameController = TextEditingController(); TextEditingController URLController = TextEditingController(); + bool enabled = false; @override void didChangeDependencies() { Settings settings = Settings(); final discord = settings.inst!.discord; - if (discord != null) { - ServerNameController.text = discord.serverName; - URLController.text = discord.url; - } + ServerNameController.text = discord.serverName; + URLController.text = discord.url; + enabled = discord.enabled; } @override @@ -37,7 +37,8 @@ class DiscordConfigurationState extends State { "Discord Webhook has been successfully reset and will no longer be used"))); Settings settings = Settings(); - settings.inst!.discord = null; + settings.inst!.discord = + DiscordHookProps(url: "", serverName: "", enabled: false); Navigator.pop(context); }, @@ -50,7 +51,8 @@ class DiscordConfigurationState extends State { context, DiscordHookProps( url: URLController.text, - serverName: ServerNameController.text)); + serverName: ServerNameController.text, + enabled: enabled)); }, child: Text("Submit"), ), @@ -82,6 +84,14 @@ class DiscordConfigurationState extends State { controller: URLController, )) ], + ), + SwitchListTile( + value: enabled, + onChanged: (V) { + enabled = V; + setState(() {}); + }, + title: Text("Enabled"), ) ], ), diff --git a/lib/pages/GameServerPage.dart b/lib/pages/GameServerPage.dart index 557af0f..cf316e4 100644 --- a/lib/pages/GameServerPage.dart +++ b/lib/pages/GameServerPage.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import '../structs/autorestarts.dart'; +import '../structs/discordHookHelper.dart'; import '../structs/serversettings.dart'; import '../structs/settings.dart'; @@ -80,6 +81,23 @@ class GameServerPageState extends State { }); }, ), + ListTile( + title: Text("Discord WebHook"), + onTap: () async { + var response = + await Navigator.pushNamed(context, "/server/discord"); + + if (response == null) + return; + else { + DiscordHookProps editResult = response as DiscordHookProps; + Settings settings = Settings(); + settings.inst!.discord = editResult; + + setState(() {}); + } + }, + ), SwitchListTile( value: settings.inst!.pterodactylMode, onChanged: (B) { diff --git a/lib/pages/ServerSettings.dart b/lib/pages/ServerSettings.dart index f263886..eadc2ed 100644 --- a/lib/pages/ServerSettings.dart +++ b/lib/pages/ServerSettings.dart @@ -1,6 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:servermanager/structs/discordHookHelper.dart'; -import 'package:servermanager/structs/settings.dart'; import '../structs/serversettings.dart'; @@ -108,28 +106,6 @@ class ServerSettingsState extends State { )), ], ), - Row( - children: [ - ListTile( - title: Text("Discord WebHook"), - onTap: () async { - var response = - await Navigator.pushNamed(context, "/server/discord"); - - if (response == null) - return; - else { - DiscordHookProps editResult = - response as DiscordHookProps; - Settings settings = Settings(); - settings.inst!.discord = editResult; - - setState(() {}); - } - }, - ) - ], - ), Row( children: [ ElevatedButton( diff --git a/lib/statemachine.dart b/lib/statemachine.dart index 5ceaff6..76cc971 100644 --- a/lib/statemachine.dart +++ b/lib/statemachine.dart @@ -359,6 +359,18 @@ class StateMachine { print( "Scheduling restart for mod updates: ${updatedMods.join(', ')}"); SessionData.enableRestartTimer = true; + + // Send discord alert! + DiscordHookHelper.sendWebHook( + settings.inst!.discord, + DiscordHookProps.ALERT_INTRUSIVE, + "Mods have been updated", + "The server is going to restart because the following mods have been updated: \n${updatedMods.join(', ')}"); + DiscordHookHelper.sendWebHook( + settings.inst!.discord, + DiscordHookProps.ALERT, + "Server Restart Alert", + "The server will restart in 5 minutes"); } }); } diff --git a/lib/structs/discordHookHelper.dart b/lib/structs/discordHookHelper.dart index 870cc0a..7c8cd9f 100644 --- a/lib/structs/discordHookHelper.dart +++ b/lib/structs/discordHookHelper.dart @@ -1,13 +1,14 @@ import 'dart:convert'; import 'package:dio/dio.dart'; +import 'package:libac_dart/nbt/NbtUtils.dart'; import 'package:libac_dart/nbt/impl/CompoundTag.dart'; import 'package:libac_dart/nbt/impl/StringTag.dart'; class DiscordHookHelper { - static Future sendWebHook(DiscordHookProps? props, int colorCode, + static Future sendWebHook(DiscordHookProps props, int colorCode, String title, String content) async { - if (props == null) return; // The webhook setting is not yet set up + if (!props.enabled) return; // The webhook setting is not yet set up var js = json.encode({ "content": "", "embeds": [ @@ -29,13 +30,16 @@ class DiscordHookHelper { class DiscordHookProps { String url; String serverName; + bool enabled = false; - DiscordHookProps({required this.url, required this.serverName}); + DiscordHookProps( + {required this.url, required this.serverName, required this.enabled}); CompoundTag serialize() { CompoundTag ct = CompoundTag(); ct.put(TAG_URL, StringTag.valueOf(url)); ct.put(TAG_SERVER_NAME, StringTag.valueOf(serverName)); + NbtUtils.writeBoolean(ct, TAG_ENABLED, enabled); return ct; } @@ -43,12 +47,14 @@ class DiscordHookProps { static DiscordHookProps deserialize(CompoundTag ct) { return DiscordHookProps( url: ct.get(TAG_URL)!.asString(), - serverName: ct.get(TAG_SERVER_NAME)!.asString()); + serverName: ct.get(TAG_SERVER_NAME)!.asString(), + enabled: NbtUtils.readBoolean(ct, TAG_ENABLED)); } static const String TAG_URL = "url"; static const String TAG_SERVER_NAME = "serverName"; static const String TAG_NAME = "discord"; + static const String TAG_ENABLED = "enabled"; static const int ONLINE_ALERT = 1869056; static const int OFFLINE_ALERT = 8716288; diff --git a/lib/structs/settingsEntry.dart b/lib/structs/settingsEntry.dart index ee2817d..8d50146 100644 --- a/lib/structs/settingsEntry.dart +++ b/lib/structs/settingsEntry.dart @@ -11,7 +11,8 @@ import 'package:servermanager/structs/serversettings.dart'; class SettingsEntry { List mods = []; - DiscordHookProps? discord; + DiscordHookProps discord = + DiscordHookProps(url: "", serverName: "", enabled: false); Credentials? steam_creds; bool pterodactylMode = true; // Default is to be compatible AutomaticRestartInfo timer = @@ -61,8 +62,7 @@ class SettingsEntry { } tag.put("mods", lMods); - if (discord != null) - tag.put(DiscordHookProps.TAG_NAME, discord!.serialize()); + tag.put(DiscordHookProps.TAG_NAME, discord.serialize()); return tag; }