Add discord webhooks

This commit is contained in:
zontreck 2024-06-16 16:42:50 -07:00
parent cbf0279c42
commit a17e0452a0
6 changed files with 208 additions and 2 deletions

View file

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:libac_dart/packets/packets.dart'; import 'package:libac_dart/packets/packets.dart';
import 'package:servermanager/packets/ClientPackets.dart'; import 'package:servermanager/packets/ClientPackets.dart';
import 'package:servermanager/pages/Constants.dart'; import 'package:servermanager/pages/Constants.dart';
import 'package:servermanager/pages/DiscordConfigPage.dart';
import 'package:servermanager/pages/GameServerPage.dart'; import 'package:servermanager/pages/GameServerPage.dart';
import 'package:servermanager/pages/ModManager.dart'; import 'package:servermanager/pages/ModManager.dart';
import 'package:servermanager/pages/autorestart.dart'; import 'package:servermanager/pages/autorestart.dart';
@ -33,6 +34,7 @@ class MyApp extends StatelessWidget {
"/server/ports": (context) => ServerSettingsPage(), "/server/ports": (context) => ServerSettingsPage(),
"/server/mods": (context) => ModManager(settings: appSettings), "/server/mods": (context) => ModManager(settings: appSettings),
"/server/mods/edit": (context) => ModPage(), "/server/mods/edit": (context) => ModPage(),
"/server/discord": (context) => DiscordConfigPage()
}); });
} }
} }

View file

@ -0,0 +1,91 @@
import 'package:flutter/material.dart';
import 'package:servermanager/pages/Constants.dart';
import 'package:servermanager/structs/discordHookHelper.dart';
import 'package:servermanager/structs/settings.dart';
class DiscordConfigPage extends StatefulWidget {
@override
State<StatefulWidget> createState() => DiscordConfigurationState();
}
class DiscordConfigurationState extends State<DiscordConfigPage> {
TextEditingController ServerNameController = TextEditingController();
TextEditingController URLController = TextEditingController();
@override
void didChangeDependencies() {
Settings settings = Settings();
final discord = settings.inst!.discord;
if (discord != null) {
ServerNameController.text = discord.serverName;
URLController.text = discord.url;
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Conan Exiles Server Manager - Discord Hook Settings"),
backgroundColor: Constants.TITLEBAR_COLOR,
actions: [
IconButton(
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(
"Discord Webhook has been successfully reset and will no longer be used")));
Settings settings = Settings();
settings.inst!.discord = null;
Navigator.pop(context);
},
icon: Icon(Icons.clear_all))
],
),
floatingActionButton: ElevatedButton(
onPressed: () {
Navigator.pop(
context,
DiscordHookProps(
url: URLController.text,
serverName: ServerNameController.text));
},
child: Text("Submit"),
),
body: SingleChildScrollView(
child: Column(
children: [
Row(
children: [
SizedBox(
width: 256,
child: ListTile(
title: Text("Server Name"),
)),
Expanded(
child: TextField(
controller: ServerNameController,
))
],
),
Row(
children: [
SizedBox(
width: 256,
child: ListTile(
title: Text("URL"),
)),
Expanded(
child: TextField(
controller: URLController,
))
],
)
],
),
),
);
}
}

View file

@ -1,4 +1,6 @@
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';
@ -106,6 +108,28 @@ 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

@ -6,6 +6,7 @@ import 'package:libac_dart/utils/IOTools.dart';
import 'package:libac_dart/utils/TimeUtils.dart'; import 'package:libac_dart/utils/TimeUtils.dart';
import 'package:servermanager/game.dart'; import 'package:servermanager/game.dart';
import 'package:servermanager/structs/SessionData.dart'; import 'package:servermanager/structs/SessionData.dart';
import 'package:servermanager/structs/discordHookHelper.dart';
import 'package:servermanager/structs/mod.dart'; import 'package:servermanager/structs/mod.dart';
import 'package:servermanager/structs/settings.dart'; import 'package:servermanager/structs/settings.dart';
import 'package:servermanager/wine.dart'; import 'package:servermanager/wine.dart';
@ -130,6 +131,12 @@ class StateMachine {
PacketServer.socket!.close(); PacketServer.socket!.close();
}); });
DiscordHookHelper.sendWebHook(
settings.inst!.discord,
DiscordHookProps.OFFLINE_ALERT,
"Server is now offline",
"The server is shutting down");
changeState(States.Inactive); changeState(States.Inactive);
} else if (currentState == States.Starting) { } else if (currentState == States.Starting) {
// Server startup in progress // Server startup in progress
@ -213,6 +220,12 @@ class StateMachine {
SessionData.timer = settings.inst!.timer.time.copy(); SessionData.timer = settings.inst!.timer.time.copy();
changeState(States.PreStart); changeState(States.PreStart);
DiscordHookHelper.sendWebHook(
settings.inst!.discord,
DiscordHookProps.ONLINE_ALERT,
"Server is now starting up",
"The server is starting up now, it should appear on the server list in a few minutes");
resetKillswitch(); resetKillswitch();
SessionData.enableRestartTimer = settings.inst!.timer.enabled; SessionData.enableRestartTimer = settings.inst!.timer.enabled;
@ -284,14 +297,24 @@ class StateMachine {
if (send && SessionData.enableRestartTimer) { if (send && SessionData.enableRestartTimer) {
// Send the alert message // Send the alert message
SessionData.CURRENT_INTERVAL = current; SessionData.CURRENT_INTERVAL = current;
int alertColor = 0;
if (current.type == WarnType.Intrusive) { if (current.type == WarnType.Intrusive) {
print("Sending alert '${current.warning}'"); print("Sending alert '${current.warning}'");
settings.sendRconCommand("broadcast ${current.warning}"); settings.sendRconCommand("broadcast ${current.warning}");
// Set discord alert color
alertColor = DiscordHookProps.ALERT_INTRUSIVE;
} else if (current.type == WarnType.NonIntrusive) { } else if (current.type == WarnType.NonIntrusive) {
print("Sending chat message '${current.warning}'"); print("Sending chat message '${current.warning}'");
settings.sendRconCommand( //settings.sendRconCommand(
"ast chat \"global\" \"${current.warning}\""); // "ast chat \"global\" \"${current.warning}\"");
// Set discord alert color
alertColor = DiscordHookProps.ALERT;
} }
DiscordHookHelper.sendWebHook(settings.inst!.discord, alertColor,
"Server Restart Alert", "${current.warning}");
} }
// Check Shutdown Pending // Check Shutdown Pending

View file

@ -0,0 +1,57 @@
import 'dart:convert';
import 'package:dio/dio.dart';
import 'package:libac_dart/nbt/impl/CompoundTag.dart';
import 'package:libac_dart/nbt/impl/StringTag.dart';
class DiscordHookHelper {
static Future<void> sendWebHook(DiscordHookProps? props, int colorCode,
String title, String content) async {
if (props == null) return; // The webhook setting is not yet set up
var js = json.encode({
"content": "",
"embeds": [
{
"title": title,
"description": content,
"color": colorCode,
"author": {"name": props.serverName}
}
],
"attachments": []
});
Dio dio = Dio();
dio.post(props.url, data: js);
}
}
class DiscordHookProps {
String url;
String serverName;
DiscordHookProps({required this.url, required this.serverName});
CompoundTag serialize() {
CompoundTag ct = CompoundTag();
ct.put(TAG_URL, StringTag.valueOf(url));
ct.put(TAG_SERVER_NAME, StringTag.valueOf(serverName));
return ct;
}
static DiscordHookProps deserialize(CompoundTag ct) {
return DiscordHookProps(
url: ct.get(TAG_URL)!.asString(),
serverName: ct.get(TAG_SERVER_NAME)!.asString());
}
static const String TAG_URL = "url";
static const String TAG_SERVER_NAME = "serverName";
static const String TAG_NAME = "discord";
static const int ONLINE_ALERT = 1869056;
static const int OFFLINE_ALERT = 8716288;
static const int ALERT = 21893; // non-intrusive
static const int ALERT_INTRUSIVE = 6291589;
}

View file

@ -5,11 +5,13 @@ import 'package:libac_dart/nbt/impl/ListTag.dart';
import 'package:libac_dart/utils/TimeUtils.dart'; import 'package:libac_dart/utils/TimeUtils.dart';
import 'package:servermanager/structs/autorestarts.dart'; import 'package:servermanager/structs/autorestarts.dart';
import 'package:servermanager/structs/credentials.dart'; import 'package:servermanager/structs/credentials.dart';
import 'package:servermanager/structs/discordHookHelper.dart';
import 'package:servermanager/structs/mod.dart'; import 'package:servermanager/structs/mod.dart';
import 'package:servermanager/structs/serversettings.dart'; import 'package:servermanager/structs/serversettings.dart';
class SettingsEntry { class SettingsEntry {
List<Mod> mods = []; List<Mod> mods = [];
DiscordHookProps? discord;
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 =
@ -33,6 +35,10 @@ class SettingsEntry {
st.pterodactylMode = NbtUtils.readBoolean(tag, "pterodactyl"); st.pterodactylMode = NbtUtils.readBoolean(tag, "pterodactyl");
} }
if (tag.containsKey(DiscordHookProps.TAG_NAME))
st.discord = DiscordHookProps.deserialize(
tag.get(DiscordHookProps.TAG_NAME)!.asCompoundTag());
st.mods.clear(); st.mods.clear();
ListTag lMods = tag.get("mods") as ListTag; ListTag lMods = tag.get("mods") as ListTag;
for (Tag tag in lMods.value) { for (Tag tag in lMods.value) {
@ -55,6 +61,9 @@ class SettingsEntry {
} }
tag.put("mods", lMods); tag.put("mods", lMods);
if (discord != null)
tag.put(DiscordHookProps.TAG_NAME, discord!.serialize());
return tag; return tag;
} }
} }