Skip to content

Commit 661cc67

Browse files
committed
feat: add HTTP monitor and style
1 parent c87e58c commit 661cc67

File tree

10 files changed

+143
-6
lines changed

10 files changed

+143
-6
lines changed

discordgsm/games.csv

+1
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,7 @@ vietcong2,Vietcong 2,gamespy2,port=5001;port_query=19967
312312
vrising,V Rising,source,port=9876;port_query=9877
313313

314314
warsow,Warsow,quake3,port=44400
315+
http,Website,http,
315316
wheeloftime,Wheel of Time,gamespy1,port=7777;port_query_offset=1
316317
wolfenstein2009,Wolfenstein 2009,doom3,port=27666
317318
wolfensteinet,Wolfenstein: Enemy Territory,quake3,port_query=27960

discordgsm/main.py

+16-2
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ async def send_alert(server: Server, alert: Alert):
215215
content = None if not content else content
216216
username = 'Game Server Monitor Alert'
217217
avatar_url = 'https://avatars.githubusercontent.com/u/61296017'
218-
218+
219219
async with aiohttp.ClientSession() as session:
220220
webhook = Webhook.from_url(webhook_url, session=session)
221221
await webhook.send(content, username=username, avatar_url=avatar_url, embed=alert_embed(server, alert))
@@ -276,6 +276,17 @@ def query_server_modal(game: GamedigGame, locale: Locale):
276276
query_extra['password'] = TextInput(label='Password', placeholder='Query Password', default="User")
277277
modal.add_item(query_extra['username'])
278278
modal.add_item(query_extra['password'])
279+
elif game['id'] == "http":
280+
query_extra['website_name'] = TextInput(label="Display Name", placeholder="My Website")
281+
query_extra['status_code'] = TextInput(label="Response Status Code", placeholder=200, default=200)
282+
query_extra['response_content'] = TextInput(label="Response Content has... (regex)", placeholder=".*", default=".*")
283+
284+
modal.add_item(query_extra['website_name'])
285+
modal.add_item(query_extra['status_code'])
286+
modal.add_item(query_extra['response_content'])
287+
288+
modal.remove_item(query_param['port'])
289+
query_param['port']._value = '0'
279290

280291
return modal, query_param, query_extra
281292

@@ -322,6 +333,9 @@ async def modal_on_submit(interaction: Interaction):
322333
# Create new server object
323334
server = Server.new(interaction.guild_id, interaction.channel_id, game_id, address, query_port, query_extra, result)
324335
style = Styles.get(server, 'Medium')
336+
if game_id == 'http':
337+
style = Styles.get(server, 'Website')
338+
325339
server.style_id = style.id
326340
server.style_data = await style.default_style_data(None)
327341

@@ -1043,7 +1057,7 @@ async def query_distinct_server(servers: list[Server]):
10431057

10441058

10451059
async def get_hash_code(server: Server):
1046-
if server.game_id in ['discord', 'scpsl']:
1060+
if server.game_id in ['discord', 'scpsl', 'http']:
10471061
host = server.address
10481062
else:
10491063
try:

discordgsm/protocols/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -40,5 +40,6 @@
4040
from .ut3_lan import UT3_LAN
4141
from .vcmp import Vcmp
4242
from .won import WON
43+
from .http import HTTP
4344

4445
protocols = {str(protocol.name): protocol for protocol in Protocol.__subclasses__()}

discordgsm/protocols/http.py

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import time
2+
import re
3+
from typing import TYPE_CHECKING
4+
5+
import aiohttp
6+
7+
from discordgsm.logger import Logger
8+
9+
from discordgsm.protocols.protocol import Protocol
10+
11+
if TYPE_CHECKING:
12+
from discordgsm.gamedig import GamedigResult
13+
14+
15+
class HTTP(Protocol):
16+
name = "http"
17+
18+
async def query(self):
19+
url, status_code, response_content, website_name = (
20+
str(self.kv["host"]),
21+
int(str(self.kv["status_code"])),
22+
str(self.kv["response_content"]),
23+
str(self.kv["website_name"]),
24+
)
25+
26+
start = time.time()
27+
async with aiohttp.ClientSession() as session:
28+
async with session.get(url) as response:
29+
status = response.status
30+
content = await response.text()
31+
end = time.time()
32+
33+
if not status == status_code:
34+
raise Exception(f"Received unexpected status code {status}")
35+
36+
if not re.search(response_content, content):
37+
raise Exception("Response body did not match provided regex!")
38+
39+
result: GamedigResult = {
40+
"name": website_name,
41+
"map": "",
42+
"password": False,
43+
"numplayers": 0,
44+
"numbots": 0,
45+
"maxplayers": -1,
46+
"players": None,
47+
"bots": None,
48+
"connect": f"{url}",
49+
"ping": int((end - start) * 1000),
50+
"raw": {
51+
status_code: status,
52+
response_content: content
53+
},
54+
}
55+
56+
return result

discordgsm/styles/__init__.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@
55
from .large import Large
66
from .medium import Medium
77
from .small import Small
8+
from .website import Website
89
from .style import Style
910

1011
if __name__ == '__main__':
1112
from server import Server
1213
else:
1314
from discordgsm.server import Server
1415

15-
styles: List[Type[Style]] = [ExtraSmall, Small, Medium, Large, ExtraLarge]
16+
styles: List[Type[Style]] = [ExtraSmall, Small, Medium, Large, ExtraLarge, Website]
1617
_styles = {style.__name__: style for style in styles}
1718

1819

discordgsm/styles/style.py

+6
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,9 @@ async def default_style_data(self, locale: Optional[Locale]):
8989
elif gamedig.default_port(self.server.game_id) == 27015 and gamedig.game_port(self.server.result) == int(self.server.query_port):
9090
style_data['description'] = t('embed.description.connect', self.locale).format(url=f'steam://connect/{self.server.address}:{self.server.query_port}')
9191

92+
if self.server.game_id == 'http':
93+
return style_data
94+
9295
try:
9396
async with aiohttp.ClientSession() as session:
9497
async with session.get(f'https://ipinfo.io/{socket.gethostbyname(self.server.address)}/country') as response:
@@ -128,6 +131,9 @@ def add_address_field(self, embed: Embed):
128131
if self.server.game_id == 'discord':
129132
name = t('modal.text_input.guild_id.label', self.locale)
130133
embed.add_field(name=name, value=f'`{self.server.address}`', inline=True)
134+
elif self.server.game_id == 'http':
135+
name = t("modal.text_input.http.label", self.locale)
136+
embed.add_field(name=name, value=f'`{self.server.address}`', inline=True)
131137
elif game_port is None or game_port == int(self.server.query_port):
132138
name = t('embed.field.address:port.name', self.locale)
133139
embed.add_field(name=name, value=f'`{self.server.address}:{self.server.query_port}`', inline=True)

discordgsm/styles/website.py

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
from typing import Dict
2+
3+
from discord.ui import TextInput
4+
from discord import Color, Embed, Emoji, Locale, PartialEmoji, TextStyle
5+
6+
from discordgsm.styles.style import Style
7+
from discordgsm.translator import t
8+
9+
10+
class Website(Style):
11+
"""Website style"""
12+
13+
@property
14+
def display_name(self) -> str:
15+
return t('style.website.display_name', self.locale)
16+
17+
@property
18+
def description(self) -> str:
19+
return t('style.website.description', self.locale)
20+
21+
@property
22+
def default_edit_fields(self) -> Dict[str, TextInput]:
23+
return {
24+
'description': TextInput(
25+
label=t('embed.text_input.description.label', self.locale),
26+
style=TextStyle.long,
27+
placeholder=t('embed.text_input.description.placeholder', self.locale),
28+
default=self.server.style_data.get('description', ''),
29+
required=False,
30+
max_length=1024
31+
),
32+
'fullname': TextInput(
33+
label=t('embed.text_input.fullname.label', self.locale),
34+
placeholder=t('embed.text_input.fullname.placeholder', self.locale),
35+
default=self.server.style_data.get('fullname', ''),
36+
)
37+
}
38+
39+
def embed(self) -> Embed:
40+
title, description, color = self.embed_data()
41+
embed = Embed(title=title, description=description, color=color)
42+
43+
self.add_status_field(embed)
44+
self.add_address_field(embed)
45+
self.add_game_field(embed)
46+
47+
self.set_footer(embed)
48+
49+
return embed

discordgsm/translations/de.json

+4-1
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
"modal.text_input.guild_id.label": "Gilden-ID",
5959
"modal.text_input.webhook_url.label": "Webhook URL",
6060
"modal.text_input.webhook_content.label": "Webhook-Inhalt",
61+
"modal.text_input.http.label": "URL",
6162
"embed.alert.description.test": "🧪 Dies ist ein Testalarm!",
6263
"embed.alert.description.online": "✅ Server ist wieder online!",
6364
"embed.alert.description.offline": "🚨 Server scheint ausgefallen zu sein!",
@@ -97,5 +98,7 @@
9798
"style.large.display_name": "Groß",
9899
"style.large.description": "Ein großformatiger Stil, der Serverinformationen und eine Spielerliste anzeigt.",
99100
"style.extra_large.display_name": "Extra Groß",
100-
"style.extra_large.description": "Ein extra großformatiger Stil, der mit Bot-Liste angezeigt wird."
101+
"style.extra_large.description": "Ein extra großformatiger Stil, der mit Bot-Liste angezeigt wird.",
102+
"style.website.display_name": "Webseite",
103+
"style.website.description": "Ein spezieller Style der nur mit dem Typ \"http\" genutzt werden sollte."
101104
}

discordgsm/translations/en-GB.json

+4-1
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
"modal.text_input.guild_id.label": "Guild ID",
5959
"modal.text_input.webhook_url.label": "Webhook URL",
6060
"modal.text_input.webhook_content.label": "Webhook Content",
61+
"modal.text_input.http.label": "URL",
6162
"embed.alert.description.test": "🧪 This is a test alert!",
6263
"embed.alert.description.online": "✅ Your server is back online!",
6364
"embed.alert.description.offline": "🚨 Your server seems to be down!",
@@ -97,5 +98,7 @@
9798
"style.large.display_name": "Large",
9899
"style.large.description": "A large-sized style that shows server info and player list.",
99100
"style.extra_large.display_name": "Extra Large",
100-
"style.extra_large.description": "An extra large-sized style that shows with bot list."
101+
"style.extra_large.description": "An extra large-sized style that shows with bot list.",
102+
"style.website.display_name": "Website",
103+
"style.website.description": "A special type that should only being used with type \"http\"."
101104
}

discordgsm/translations/en-US.json

+4-1
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
"modal.text_input.guild_id.label": "Guild ID",
5959
"modal.text_input.webhook_url.label": "Webhook URL",
6060
"modal.text_input.webhook_content.label": "Webhook Content",
61+
"modal.text_input.http.label": "URL",
6162
"embed.alert.description.test": "🧪 This is a test alert!",
6263
"embed.alert.description.online": "✅ Your server is back online!",
6364
"embed.alert.description.offline": "🚨 Your server seems to be down!",
@@ -97,5 +98,7 @@
9798
"style.large.display_name": "Large",
9899
"style.large.description": "A large-sized style that shows server info and player list.",
99100
"style.extra_large.display_name": "Extra Large",
100-
"style.extra_large.description": "An extra large-sized style that shows with bot list."
101+
"style.extra_large.description": "An extra large-sized style that shows with bot list.",
102+
"style.website.display_name": "Website",
103+
"style.website.description": "A special type that should only being used with type \"http\"."
101104
}

0 commit comments

Comments
 (0)