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

Commit 5a51132

Browse files
author
DirectiveAthena
committed
Feat: Twitch Message Context handler
1 parent 3d66fd4 commit 5a51132

File tree

5 files changed

+84
-20
lines changed

5 files changed

+84
-20
lines changed

src/AthenaTwitchBot/functions/twitch_message_constructors.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ def twitch_message_constructor_tags(message_bytes:bytearray, bot_name:str) -> Tw
8484
message=message,
8585
message_type=irc_message,
8686
channel=channel,
87+
user=user,
8788
text=" ".join(text).replace(":", "", 1) #only remove the first ":"
8889
)
8990

src/AthenaTwitchBot/models/twitch_bot.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,17 @@ class TwitchBot:
4242
def __new__(cls, *args, **kwargs):
4343
# Loop over own functions to see if any is decorated with the command setup
4444
cls.commands = {}
45+
46+
# create the actual instance
47+
# Which is to be used in the commands tuple
48+
obj = super(TwitchBot, cls).__new__(cls,*args,**kwargs)
4549
for k,v in cls.__dict__.items():
4650
if inspect.isfunction(v) and getattr(v, "command_name", False):
47-
cls.commands[v.command_name] = v
51+
cls.commands[v.command_name] = (v, obj)
4852

49-
# create the actual instance
50-
return super(TwitchBot, cls).__new__(cls,*args,**kwargs)
53+
return obj
5154

5255
def __post_init__(self, predefined_commands: dict[str: Callable]=None):
5356
if predefined_commands is not None:
54-
self.commands |= predefined_commands
55-
56-
57+
# the self instance isn't assigned on the predefined_commands input
58+
self.commands |= {k:(v,self) for k, v in predefined_commands.items()}

src/AthenaTwitchBot/models/twitch_bot_protocol.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
from AthenaTwitchBot.models.twitch_message import TwitchMessage, TwitchMessagePing
1818
from AthenaTwitchBot.models.twitch_bot import TwitchBot
19+
from AthenaTwitchBot.models.twitch_message_context import TwitchMessageContext
1920

2021
# ----------------------------------------------------------------------------------------------------------------------
2122
# - Code -
@@ -36,7 +37,6 @@ def __post_init__(self):
3637
raise NotImplementedError("This needs to be created")
3738

3839
def connection_made(self, transport: asyncio.transports.Transport) -> None:
39-
# todo make some sort of connector to make t
4040
self.transport = transport
4141
# first write the password then the nickname else the connection will fail
4242
self.transport.write(messages.password(oauth_token=self.bot.oauth_token))
@@ -59,7 +59,18 @@ def data_received(self, data: bytearray) -> None:
5959
print(ForeNest.ForestGreen("COMMAND CAUGHT"))
6060
try:
6161
user_cmd = user_message.replace(f"{self.bot.prefix}", "")
62-
self.bot.commands[user_cmd](self=self.bot,message=twitch_message,transport=self.transport)
62+
# tuple unpacking because we have a callback
63+
# 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,
67+
# Assign a context so the user doesn't need to write the transport messages themselves
68+
# A user opnly has to write the text
69+
context=TwitchMessageContext(
70+
message=twitch_message,
71+
transport=self.transport
72+
)
73+
)
6374
except KeyError:
6475
pass
6576

src/AthenaTwitchBot/models/twitch_message.py

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,30 +14,38 @@
1414
# ----------------------------------------------------------------------------------------------------------------------
1515
# - Code -
1616
# ----------------------------------------------------------------------------------------------------------------------
17+
EMPTY_STR = ""
18+
1719
@dataclass(slots=True, eq=True, match_args=True)
1820
class TwitchMessage:
19-
message:str="" # complete message without the sufix: "\r\n"
20-
message_type:str=""
21-
channel:str=""
22-
text:str=""
21+
message:str=EMPTY_STR # complete message without the sufix: "\r\n"
22+
message_type:str=EMPTY_STR
23+
channel:str=EMPTY_STR
24+
text:str=EMPTY_STR
25+
user:str=EMPTY_STR
26+
username:str=field(init=False) # decoupled after init
2327

2428
# optional info if tags is enabled
25-
badge_info:str=""
29+
badge_info:str=EMPTY_STR
2630
badges:list[str]=field(default_factory=list)
27-
client_nonce:str=""
31+
client_nonce:str=EMPTY_STR
2832
color:HEX=field(default_factory=HEX)
29-
display_name:str=""
33+
display_name:str=EMPTY_STR
3034
first_msg:bool=False
31-
message_id:str=""
35+
message_id:str=EMPTY_STR
3236
mod:bool=False
33-
room_id:str=""
37+
room_id:str=EMPTY_STR
3438
subscriber:bool=False
3539
tmi_sent_ts:int=0
3640
turbo:bool=False
3741
user_id:int=0
38-
emotes:str=""
39-
flags:str=""
40-
user_type:str=""
42+
emotes:str=EMPTY_STR
43+
flags:str=EMPTY_STR
44+
user_type:str=EMPTY_STR
45+
46+
def __post_init__(self):
47+
self.username = self.user.split("!")[0][1:]
48+
4149
# ----------------------------------------------------------------------------------------------------------------------
4250
# - Special message types -
4351
# ----------------------------------------------------------------------------------------------------------------------
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# ----------------------------------------------------------------------------------------------------------------------
2+
# - Package Imports -
3+
# ----------------------------------------------------------------------------------------------------------------------
4+
# General Packages
5+
from __future__ import annotations
6+
from dataclasses import dataclass, field
7+
import asyncio
8+
9+
# Custom Library
10+
11+
# Custom Packages
12+
from AthenaTwitchBot.models.twitch_message import TwitchMessage
13+
14+
# ----------------------------------------------------------------------------------------------------------------------
15+
# - Code -
16+
# ----------------------------------------------------------------------------------------------------------------------
17+
@dataclass(slots=True,eq=False,order=False,match_args=True)
18+
class TwitchMessageContext:
19+
message:TwitchMessage
20+
transport:asyncio.Transport
21+
22+
# things not to be defined on init
23+
username:str=field(init=False)
24+
25+
def __post_init__(self):
26+
self.username = f"@{self.message.username}"
27+
28+
def reply(self, text:str):
29+
"""
30+
a "reply" method does reply to the user's message that invoked the command
31+
"""
32+
self.transport.write(
33+
f"@reply-parent-msg-id={self.message.message_id} PRIVMSG {self.message.channel} :{text}\r\n".encode("UTF_8")
34+
)
35+
36+
def write(self, text:str):
37+
"""
38+
a "write" method does not reply to the message that invoked the command, but simply writes the text to the channel
39+
"""
40+
self.transport.write(
41+
f"PRIVMSG {self.message.channel} :{text}\r\n".encode("UTF_8")
42+
)

0 commit comments

Comments
 (0)