Skip to content
This repository was archived by the owner on Jan 13, 2024. It is now read-only.

Commit cdd6f42

Browse files
author
DirectiveAthena
committed
Feat: Frequent oputput method
1 parent 5a51132 commit cdd6f42

File tree

5 files changed

+66
-9
lines changed

5 files changed

+66
-9
lines changed

src/AthenaTwitchBot/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# - Package Imports -
33
# ----------------------------------------------------------------------------------------------------------------------
44
from AthenaTwitchBot.decorators.command import commandmethod
5+
from AthenaTwitchBot.decorators.frequentoutput import frequentoutputmethod
56

67
from AthenaTwitchBot.models.twitch_bot import TwitchBot
78
from AthenaTwitchBot.models.twitch_bot_protocol import TwitchBotProtocol

src/AthenaTwitchBot/decorators/command.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ def wrapper(*args, **kwargs):
1717
return fnc(*args, **kwargs)
1818

1919
# store attributes for later use by the bot
20+
wrapper.is_command = True
2021
wrapper.command_name = name
2122

2223
return wrapper
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# ----------------------------------------------------------------------------------------------------------------------
2+
# - Package Imports -
3+
# ----------------------------------------------------------------------------------------------------------------------
4+
# General Packages
5+
from __future__ import annotations
6+
7+
# Custom Library
8+
9+
# Custom Packages
10+
11+
# ----------------------------------------------------------------------------------------------------------------------
12+
# - Code -
13+
# ----------------------------------------------------------------------------------------------------------------------
14+
def frequentoutputmethod(delay:int=3600): # defult is every hour
15+
"""
16+
Create a method that runs every couple of seconds.
17+
The delay parameter is defined in seconds
18+
:param delay:
19+
:return:
20+
"""
21+
22+
def decorator(fnc):
23+
def wrapper(*args, **kwargs):
24+
return fnc(*args, **kwargs)
25+
26+
# store attributes for later use by the bot
27+
# to be used by the protocol to assign it top an async call loop
28+
wrapper.is_frequent_ouput = True
29+
wrapper.delay = delay
30+
return wrapper
31+
return decorator

src/AthenaTwitchBot/models/twitch_bot.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ class TwitchBot:
3333

3434
# noinspection PyDataclass
3535
commands:dict[str: Callable]=field(init=False)
36+
frequent_outputs:list[tuple[Callable, int]]=field(init=False)
3637

3738
# non init slots
3839

@@ -42,13 +43,19 @@ class TwitchBot:
4243
def __new__(cls, *args, **kwargs):
4344
# Loop over own functions to see if any is decorated with the command setup
4445
cls.commands = {}
46+
cls.frequent_outputs = []
4547

4648
# create the actual instance
4749
# Which is to be used in the commands tuple
4850
obj = super(TwitchBot, cls).__new__(cls,*args,**kwargs)
51+
52+
# loop over the bot's metods and parse the different methods
4953
for k,v in cls.__dict__.items():
50-
if inspect.isfunction(v) and getattr(v, "command_name", False):
51-
cls.commands[v.command_name] = (v, obj)
54+
if inspect.isfunction(v):
55+
if "is_command" in (attributes := [attribute for attribute in dir(v) if not attribute.startswith("__")]):
56+
cls.commands[v.command_name] = v
57+
elif "is_frequent_ouput" in attributes:
58+
cls.frequent_outputs.append((v,v.delay))
5259

5360
return obj
5461

src/AthenaTwitchBot/models/twitch_bot_protocol.py

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ def __post_init__(self):
3636
else:
3737
raise NotImplementedError("This needs to be created")
3838

39+
# ----------------------------------------------------------------------------------------------------------------------
40+
# - Protocol neseccary -
41+
# ----------------------------------------------------------------------------------------------------------------------
3942
def connection_made(self, transport: asyncio.transports.Transport) -> None:
4043
self.transport = transport
4144
# first write the password then the nickname else the connection will fail
@@ -44,26 +47,40 @@ def connection_made(self, transport: asyncio.transports.Transport) -> None:
4447
self.transport.write(messages.join(channel=self.bot.channel))
4548
self.transport.write(messages.request_tags)
4649

50+
# add frequent_ouput methods to the coroutine loop
51+
loop = asyncio.get_running_loop()
52+
for callback, delay in self.bot.frequent_outputs:
53+
coro = loop.create_task(self.frequent_output_call(callback,delay))
54+
asyncio.ensure_future(coro, loop=loop)
55+
56+
async def frequent_output_call(self, callback,delay:int):
57+
context = TwitchMessageContext(
58+
message=TwitchMessage(channel=f"#{self.bot.channel}"),
59+
transport=self.transport
60+
)
61+
while True:
62+
await asyncio.sleep(delay)
63+
callback(
64+
self=self.bot,
65+
context=context)
66+
4767
def data_received(self, data: bytearray) -> None:
4868
for message in data.split(b"\r\n"):
4969
match (twitch_message := self.message_constructor(message, bot_name=self.bot.nickname)):
5070
# Keepalive messages : https://dev.twitch.tv/docs/irc#keepalive-messages
5171
case TwitchMessagePing():
5272
print(ForeNest.ForestGreen("PINGED BY TWITCH"))
53-
self.transport.write(pong_message := messages.pong(message=twitch_message.text))
54-
print(pong_message)
73+
self.transport.write(messages.pong(message=twitch_message.text))
5574

5675
# catch a message which starts with a command:
57-
case TwitchMessage(text=user_message) if user_message.startswith(f"{self.bot.prefix}"):
58-
user_message:str
76+
case TwitchMessage(text=str(user_message)) if user_message.startswith(f"{self.bot.prefix}"):
5977
print(ForeNest.ForestGreen("COMMAND CAUGHT"))
6078
try:
6179
user_cmd = user_message.replace(f"{self.bot.prefix}", "")
6280
# tuple unpacking because we have a callback
6381
# and the object instance where the command is placed in
64-
callback, orign_obj = self.bot.commands[user_cmd]
65-
callback(
66-
self=orign_obj,
82+
self.bot.commands[user_cmd](
83+
self=self.bot,
6784
# Assign a context so the user doesn't need to write the transport messages themselves
6885
# A user opnly has to write the text
6986
context=TwitchMessageContext(

0 commit comments

Comments
 (0)