finish implementation

This commit is contained in:
zontreck 2024-06-16 20:13:35 -07:00
parent a17e0452a0
commit 23d93a7f9a
8 changed files with 90 additions and 55 deletions

View file

@ -4,6 +4,7 @@ import 'package:libac_dart/packets/packets.dart';
import 'package:libac_dart/utils/IOTools.dart'; import 'package:libac_dart/utils/IOTools.dart';
import 'package:servermanager/game.dart'; import 'package:servermanager/game.dart';
import 'package:servermanager/packets/ClientPackets.dart'; import 'package:servermanager/packets/ClientPackets.dart';
import 'package:servermanager/structs/SessionData.dart';
import 'package:servermanager/structs/settings.dart'; import 'package:servermanager/structs/settings.dart';
void main() async { void main() async {
@ -73,7 +74,12 @@ void main() async {
print("Starting up server manager server wrapper"); 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"); print("Server stopping");
} }

View file

@ -289,26 +289,33 @@ class C2SUploadSettingsPacket implements IPacket {
@override @override
Future<PacketResponse> handleServerPacket() async { Future<PacketResponse> handleServerPacket() async {
Settings settings = Settings(); Settings settings = Settings();
settings.deserialize(srvSettings);
settings.Write();
// Check if server is running, if not, stop immediately CompoundTag currentSettings = settings.serialize();
// 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 try {
SessionData.shutdownMessage = "Server wrapper updated. Restart required."; settings.deserialize(srvSettings);
SessionData.timer.apply(60); settings.Write();
SessionData.CURRENT_INTERVAL = WarnIntervals.NONE;
if (settings.subsys.currentState == States.Inactive) { // Check if server is running, if not, stop immediately
Timer.periodic(Duration(seconds: 10), (timer) { // 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.shutdownPending = true; SessionData.shutdownMessage = "Server wrapper updated. Restart required.";
// Stop packet server SessionData.timer.apply(60);
PacketServer.socket!.close(); SessionData.CURRENT_INTERVAL = WarnIntervals.NONE;
timer.cancel();
exit(0); if (settings.subsys.currentState == States.Inactive) {
}); // We give time to allow the server to shut down gracefully. 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 @override

View file

@ -11,16 +11,16 @@ class DiscordConfigPage extends StatefulWidget {
class DiscordConfigurationState extends State<DiscordConfigPage> { class DiscordConfigurationState extends State<DiscordConfigPage> {
TextEditingController ServerNameController = TextEditingController(); TextEditingController ServerNameController = TextEditingController();
TextEditingController URLController = TextEditingController(); TextEditingController URLController = TextEditingController();
bool enabled = false;
@override @override
void didChangeDependencies() { void didChangeDependencies() {
Settings settings = Settings(); Settings settings = Settings();
final discord = settings.inst!.discord; final discord = settings.inst!.discord;
if (discord != null) { ServerNameController.text = discord.serverName;
ServerNameController.text = discord.serverName; URLController.text = discord.url;
URLController.text = discord.url; enabled = discord.enabled;
}
} }
@override @override
@ -37,7 +37,8 @@ class DiscordConfigurationState extends State<DiscordConfigPage> {
"Discord Webhook has been successfully reset and will no longer be used"))); "Discord Webhook has been successfully reset and will no longer be used")));
Settings settings = Settings(); Settings settings = Settings();
settings.inst!.discord = null; settings.inst!.discord =
DiscordHookProps(url: "", serverName: "", enabled: false);
Navigator.pop(context); Navigator.pop(context);
}, },
@ -50,7 +51,8 @@ class DiscordConfigurationState extends State<DiscordConfigPage> {
context, context,
DiscordHookProps( DiscordHookProps(
url: URLController.text, url: URLController.text,
serverName: ServerNameController.text)); serverName: ServerNameController.text,
enabled: enabled));
}, },
child: Text("Submit"), child: Text("Submit"),
), ),
@ -82,6 +84,14 @@ class DiscordConfigurationState extends State<DiscordConfigPage> {
controller: URLController, controller: URLController,
)) ))
], ],
),
SwitchListTile(
value: enabled,
onChanged: (V) {
enabled = V;
setState(() {});
},
title: Text("Enabled"),
) )
], ],
), ),

View file

@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../structs/autorestarts.dart'; import '../structs/autorestarts.dart';
import '../structs/discordHookHelper.dart';
import '../structs/serversettings.dart'; import '../structs/serversettings.dart';
import '../structs/settings.dart'; import '../structs/settings.dart';
@ -80,6 +81,23 @@ class GameServerPageState extends State<GameServerPage> {
}); });
}, },
), ),
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( SwitchListTile(
value: settings.inst!.pterodactylMode, value: settings.inst!.pterodactylMode,
onChanged: (B) { onChanged: (B) {

View file

@ -1,6 +1,4 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:servermanager/structs/discordHookHelper.dart';
import 'package:servermanager/structs/settings.dart';
import '../structs/serversettings.dart'; import '../structs/serversettings.dart';
@ -108,28 +106,6 @@ class ServerSettingsState extends State<ServerSettingsPage> {
)), )),
], ],
), ),
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( Row(
children: [ children: [
ElevatedButton( ElevatedButton(

View file

@ -359,6 +359,18 @@ class StateMachine {
print( print(
"Scheduling restart for mod updates: ${updatedMods.join(', ')}"); "Scheduling restart for mod updates: ${updatedMods.join(', ')}");
SessionData.enableRestartTimer = true; 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");
} }
}); });
} }

View file

@ -1,13 +1,14 @@
import 'dart:convert'; import 'dart:convert';
import 'package:dio/dio.dart'; 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/CompoundTag.dart';
import 'package:libac_dart/nbt/impl/StringTag.dart'; import 'package:libac_dart/nbt/impl/StringTag.dart';
class DiscordHookHelper { class DiscordHookHelper {
static Future<void> sendWebHook(DiscordHookProps? props, int colorCode, static Future<void> sendWebHook(DiscordHookProps props, int colorCode,
String title, String content) async { 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({ var js = json.encode({
"content": "", "content": "",
"embeds": [ "embeds": [
@ -29,13 +30,16 @@ class DiscordHookHelper {
class DiscordHookProps { class DiscordHookProps {
String url; String url;
String serverName; 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 serialize() {
CompoundTag ct = CompoundTag(); CompoundTag ct = CompoundTag();
ct.put(TAG_URL, StringTag.valueOf(url)); ct.put(TAG_URL, StringTag.valueOf(url));
ct.put(TAG_SERVER_NAME, StringTag.valueOf(serverName)); ct.put(TAG_SERVER_NAME, StringTag.valueOf(serverName));
NbtUtils.writeBoolean(ct, TAG_ENABLED, enabled);
return ct; return ct;
} }
@ -43,12 +47,14 @@ class DiscordHookProps {
static DiscordHookProps deserialize(CompoundTag ct) { static DiscordHookProps deserialize(CompoundTag ct) {
return DiscordHookProps( return DiscordHookProps(
url: ct.get(TAG_URL)!.asString(), 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_URL = "url";
static const String TAG_SERVER_NAME = "serverName"; static const String TAG_SERVER_NAME = "serverName";
static const String TAG_NAME = "discord"; static const String TAG_NAME = "discord";
static const String TAG_ENABLED = "enabled";
static const int ONLINE_ALERT = 1869056; static const int ONLINE_ALERT = 1869056;
static const int OFFLINE_ALERT = 8716288; static const int OFFLINE_ALERT = 8716288;

View file

@ -11,7 +11,8 @@ import 'package:servermanager/structs/serversettings.dart';
class SettingsEntry { class SettingsEntry {
List<Mod> mods = []; List<Mod> mods = [];
DiscordHookProps? discord; DiscordHookProps discord =
DiscordHookProps(url: "", serverName: "", enabled: false);
Credentials? steam_creds; Credentials? steam_creds;
bool pterodactylMode = true; // Default is to be compatible bool pterodactylMode = true; // Default is to be compatible
AutomaticRestartInfo timer = AutomaticRestartInfo timer =
@ -61,8 +62,7 @@ class SettingsEntry {
} }
tag.put("mods", lMods); tag.put("mods", lMods);
if (discord != null) tag.put(DiscordHookProps.TAG_NAME, discord.serialize());
tag.put(DiscordHookProps.TAG_NAME, discord!.serialize());
return tag; return tag;
} }