Skip to content
This repository was archived by the owner on Dec 23, 2020. It is now read-only.

Commit bd4d92c

Browse files
committed
Update __init__.py, cached_messaging.py, and 5 more files...
1 parent 9da4b7a commit bd4d92c

File tree

7 files changed

+249
-25
lines changed

7 files changed

+249
-25
lines changed

SourceQueryBot/__init__.py

Lines changed: 158 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,34 @@
11
import discord
2+
from discord import Embed, Color, Status, Game
23
from discord.ext import tasks
34

5+
import asyncio
6+
import sys
7+
import logging
8+
9+
from aioquery.exceptions import InvalidServer, DidNotReceive, UnableToConnect
10+
411
from .translations import TranslationBase, English
512
from .messages import Messages
13+
from .cached_messaging import CachedMessaging
614

715

816
__version__ = "0.0.1"
917

1018

19+
logging.basicConfig(level=logging.INFO)
20+
21+
1122
class SourceQueryBot(discord.Client):
12-
refresh_rate = 0.0
23+
_refresh_rate = 0.0
24+
_presence_completed = True
25+
_total_servers = 0
1326

1427
def __init__(self, catagories: list, refresh_rate: float = 30.0,
1528
lanague: TranslationBase = English,
1629
messages: Messages = Messages(),
17-
*args, **kwargs):
30+
smart_presence: bool = False,
31+
*args, **kwargs) -> None:
1832
"""
1933
Pass any discord bot client args / paramters.
2034
@@ -26,24 +40,157 @@ def __init__(self, catagories: list, refresh_rate: float = 30.0,
2640
Defaults to english.
2741
messages: Messages
2842
Handles message caching.
43+
smart_presence: bool
44+
Defaults to false, if enabled presence will rotate between maps.
2945
"""
3046

47+
super().__init__(*args, **kwargs)
48+
3149
self.lanague = lanague
32-
self.refresh_rate = refresh_rate
50+
self._refresh_rate = refresh_rate
51+
self.catagories = catagories
52+
self.messages = messages
3353

34-
super().__init__(*args, **kwargs)
54+
if not sys.version_info[1] >= 7 and smart_presence:
55+
self.smart_presence = False
56+
logging.log(
57+
logging.INFO,
58+
lanague.invalid_py_version.format(
59+
sys.version
60+
)
61+
)
62+
else:
63+
self.smart_presence = smart_presence
3564

36-
async def on_ready(self):
65+
self.query_task.start()
66+
67+
async def on_ready(self) -> None:
3768
print(self.lanague.on_ready.format(self.user))
3869

39-
async def close(self):
70+
async def close(self) -> None:
4071
print(self.lanague.shutdown)
72+
73+
await super().close()
4174
self.query_task.cancel()
4275

43-
@tasks.loop(seconds=refresh_rate)
44-
async def query_task(self):
45-
pass
76+
async def _smart_presence(self, players, max_players,
77+
map_name, loop_index) -> None:
78+
79+
if loop_index == self._total_servers:
80+
self._presence_completed = False
81+
82+
await asyncio.sleep(loop_index * 10)
83+
84+
await self.change_presence(
85+
status=Status.online,
86+
activity=Game(
87+
self.lanague.smart_presence.format(
88+
players,
89+
max_players,
90+
map_name
91+
)
92+
)
93+
)
94+
95+
if loop_index == self._total_servers:
96+
self._presence_completed = True
97+
98+
@tasks.loop(seconds=30.0)
99+
async def query_task(self) -> None:
100+
total_players = 0
101+
total_max_players = 0
102+
103+
loop_index = -1
104+
105+
for catgory in self.catagories:
106+
embed = Embed(
107+
title=catgory.name,
108+
color=Color(catgory.color)
109+
)
110+
111+
for server in catgory.servers:
112+
try:
113+
info = await server.interact.info()
114+
115+
embed.add_field(
116+
name=server.alt_name if server.alt_name else
117+
info.hostname[:catgory.server_name_limit] + "...",
118+
value=self.lanague.server.format(
119+
info.map,
120+
info.players,
121+
info.max_players,
122+
"{}:{}".format(server.ip, server.port)
123+
),
124+
inline=catgory.inline
125+
)
126+
127+
total_players += info.players
128+
total_max_players += info.max_players
129+
130+
if self.smart_presence and self._presence_completed:
131+
loop_index += 1
132+
133+
asyncio.create_task(
134+
self._smart_presence(
135+
info.players,
136+
info.max_players,
137+
info.map,
138+
loop_index
139+
)
140+
)
141+
142+
except (InvalidServer, DidNotReceive, UnableToConnect):
143+
embed.add_field(
144+
name=server.alt_name if server.alt_name else
145+
self.lanague.offline_title,
146+
value=self.lanague.offline_msg
147+
)
148+
149+
await asyncio.sleep(0.0001)
150+
151+
sent_message = await CachedMessaging(
152+
catgory, self.get_channel(catgory.channel), embed=embed
153+
).send_edit()
154+
155+
await self.messages.save("{}:{}".format(
156+
catgory.channel, sent_message.id
157+
))
158+
159+
await asyncio.sleep(0.0001)
160+
161+
if not self.smart_presence:
162+
await self.change_presence(
163+
status=Status.online,
164+
activity=Game(
165+
self.lanague.normal_presence.format(
166+
total_players,
167+
total_max_players
168+
)
169+
)
170+
)
46171

47172
@query_task.before_loop
48-
async def before_query_task(self):
49-
pass
173+
async def before_query_task(self) -> None:
174+
"""
175+
Handles deleting old messages & caching config details.
176+
"""
177+
178+
await self.wait_until_ready()
179+
180+
async for message in self.messages.get():
181+
try:
182+
channel_id, message_id = message.split(":")
183+
except ValueError:
184+
pass
185+
else:
186+
channel = self.get_channel(int(channel_id))
187+
if channel:
188+
message_obj = await channel.fetch_message(int(message_id))
189+
if message_obj:
190+
await message_obj.delete()
191+
192+
for catgory in self.catagories:
193+
for server in catgory.servers:
194+
self._total_servers += 1
195+
196+
await asyncio.sleep(0.00001)

SourceQueryBot/cached_messaging.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
from .settings import Category
2+
from .exceptions import InvalidChannel
3+
4+
from discord import channel
5+
6+
7+
CACHED_CATAGORIES = {}
8+
9+
10+
class CachedMessaging:
11+
def __init__(self, catgory: Category, channel: channel,
12+
*args, **kwargs) -> None:
13+
self.catgory = catgory
14+
self.args = args
15+
self.kwargs = kwargs
16+
self.channel = channel
17+
18+
async def send_edit(self) -> channel:
19+
if self.catgory in CACHED_CATAGORIES:
20+
message = await CACHED_CATAGORIES[self.catgory].edit(**self.kwargs)
21+
else:
22+
if self.channel:
23+
message = await self.channel.send(**self.kwargs)
24+
25+
CACHED_CATAGORIES[self.catgory] = message
26+
else:
27+
raise InvalidChannel()
28+
29+
return CACHED_CATAGORIES[self.catgory]

SourceQueryBot/exceptions.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,11 @@ class NoSuchConfigFile(Exception):
44
"""
55

66
pass
7+
8+
9+
class InvalidChannel(Exception):
10+
"""
11+
Raised when a channel ID is invalid or can't be accessed.
12+
"""
13+
14+
pass

SourceQueryBot/messages.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
import aiofiles
22
import typing
33

4-
from os import path
4+
from os import path, getcwd
55

66
from .exceptions import NoSuchConfigFile
77

88

99
class Messages:
10+
_saved_messages = []
11+
1012
def __init__(self,
11-
location: str = path.join(
12-
path.dirname(path.realpath(__file__)),
13-
"messages.txt")) -> None:
13+
location: str = path.join(getcwd(), "messages.txt")) -> None:
1414

1515
self.location = location
1616

@@ -34,12 +34,11 @@ async def get(self) -> list:
3434
"""
3535

3636
if path.exists(self.location):
37-
async with aiofiles.open(self.location) as file:
38-
data = await file.read()
37+
async with aiofiles.open(self.location, "r+") as file:
38+
async for line in file:
39+
yield line
3940

4041
await file.truncate(0)
41-
42-
return data.split("\n")
4342
else:
4443
raise NoSuchConfigFile()
4544

@@ -53,5 +52,8 @@ async def save(self, line: typing.Any) -> None:
5352
line to save.
5453
"""
5554

56-
async with aiofiles.open(self.location, mode="a") as file:
57-
await file.write(str(line))
55+
if line not in self._saved_messages:
56+
self._saved_messages.append(line)
57+
58+
async with aiofiles.open(self.location, mode="a") as file:
59+
await file.write("{}\n".format(line))

SourceQueryBot/settings.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import aioquery
2+
3+
14
class Server:
25
def __init__(self, ip: str, port: int = 27015,
36
alt_name: str = None) -> None:
@@ -18,10 +21,13 @@ def __init__(self, ip: str, port: int = 27015,
1821
self.port = port
1922
self.alt_name = alt_name
2023

24+
self.interact = aioquery.client(ip, port)
25+
2126

2227
class Category:
23-
def __init__(self, name: str, channel: int,
24-
servers: list, server_name_limit: int = 20) -> None:
28+
def __init__(self, name: str, channel: int, color: hex,
29+
servers: list, server_name_limit: int = 20,
30+
inline: bool = False) -> None:
2531
"""
2632
Handles server commands.
2733
@@ -33,11 +39,17 @@ def __init__(self, name: str, channel: int,
3339
Limits how many characters the server name can be.
3440
channel: int
3541
Discord channel ID for this category.
42+
color: hex
43+
Hex color code.
3644
servers: list
3745
List of Server objects.
46+
inline: bool
47+
Defaults to false, if servers should be inline.
3848
"""
3949

4050
self.name = name
4151
self.server_name_limit = server_name_limit
4252
self.channel = channel
4353
self.servers = servers
54+
self.color = color
55+
self.inline = inline

SourceQueryBot/translations.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,22 @@
11
class TranslationBase:
22
shutdown: str
33
on_ready: str
4+
server: str
5+
offline_title: str
6+
offline_msg: str
7+
normal_presence: str
8+
smart_presence: str
9+
invalid_py_version: str
410

511

612
class English(TranslationBase):
713
shutdown = "The bot is shutting down, please DO NOT press ctrl + C"
814
on_ready = "Logged on as {}"
15+
server = """**Map:** {}\n**Players:** {}/{}
16+
**Connect:**\nsteam://connect/{}"""
17+
offline_title = "Unknown"
18+
offline_msg = "**This server is offline.**"
19+
normal_presence = "{}/{} on our servers."
20+
smart_presence = "{}/{} on {}"
21+
invalid_py_version = "Python 3.7 or above is required for" + \
22+
" smart presence, you're running {}"

run.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,23 @@
77
Category(
88
"Retake",
99
705852327550124062,
10+
0xffffff,
1011
[
11-
Server("216.52.148.47")
12+
Server("216.52.148.47"),
13+
Server("54.37.111.216"),
14+
Server("92.119.148.18"),
15+
]
16+
),
17+
Category(
18+
"Bhop",
19+
705852327550124062,
20+
0x444444,
21+
[
22+
Server("92.119.148.31")
1223
]
1324
)
14-
]
25+
],
26+
smart_presence=True
1527
)
1628

1729
if __name__ == "__main__":

0 commit comments

Comments
 (0)