-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathevent.py
188 lines (163 loc) · 6.48 KB
/
event.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# vim: tabstop=2 shiftwidth=2
import re
class Event:
"""
Allows event type definition. The definition accepts a regex.
Every event can be triggered by specific lines, messages, message_id or users.
Eventually (see time_event branch for proof-of-concept implementation) time-sensitive events will be triggerable as well.
Each line received by the bot is passed to each module in the modules_list. If the module determines the line matches what the event cares about,
the event calls each of its subscribers itself, which contains all the information the module needs to respond appropriately.
To use:
e = Event("__my_type__")
e.define("some_regex")
bot.register_event(e, calling_module)
"""
def __init__(self, _type):
"""
Define your own type here. Make sure if you're making a broad event (all messages, for example) you use a sane type, as other modules that care about this kind of event can subscribe to it.
Args:
_type: string. like "__youtube__" or "__weather__". Underscores are a convention.
"""
self._type = _type
self.subscribers = [] # this is a list of subscribers to notify
self.user = ""
self.definition = ""
self.msg_definition = ""
self.user_definition = ""
self.channel = ""
self.line = ""
self.msg = ""
self.verb = ""
self.mode = ""
self.is_pm = False
self.message_id = -1
self.case_insensitive = False
def subscribe(self, e):
"""
Append passed-in event to our list of subscribing modules.
Args:
e: event.
"""
self.subscribers.append(e)
def define(self, definition=None, msg_definition=None, user_definition=None,
message_id=None, mode=None, case_insensitive=False):
"""
Define ourself by general line (definition), msg_definition (what someone says in a channel or PM), user_definition (the user who said the thing), or message_id (like 376 for MOTD or 422 for no MOTD)
Currently, an event is defined by only one type of definition. If one were to remove the returns after each self. set, an event could be defined and triggered by any of several definitions.
Args:
definition: string. regex allowed.
msg_definition: string. regex allowed. this is what someone would say in a channel. like "hello, pybot".
user_definition: string. the user that said the thing. like 'hlmtre' or 'BoneKin'.
message_id: the numerical ID of low-level IRC protocol stuff. 376, for example, tells clients 'hey, this is the MOTD.'
"""
if definition is not None:
self.definition = definition
if msg_definition is not None:
self.msg_definition = msg_definition
if user_definition is not None:
self.user_definition = user_definition
if message_id is not None:
self.message_id = message_id
if mode is not None:
self.mode = mode
self.case_insensitive = case_insensitive
return
def matches(self, line):
"""
Fills out the event object per line, and returns True or False if the line matches one of our definitions.
Args:
line: string. The entire incoming line.
Return:
boolean; True or False.
"""
# perhaps TODO
# first try very simply
if len(self.definition) and self.definition in line:
return True
# grab message id. not always present
try:
temp = line.split(":")[1].split(" ")[1]
except IndexError:
pass
if len(self.mode):
try:
split_line = line.split()
temp_verb = split_line[1] # first nick, then verb
if self.mode == temp_verb.strip():
return True
except IndexError:
pass
try:
message_id = int(temp)
except (ValueError, UnboundLocalError):
message_id = 0
try:
msg = line.split(":", 2)[2]
except IndexError:
return
if len(self.msg_definition):
if self.case_insensitive:
return re.search(self.msg_definition, msg, re.IGNORECASE)
else:
return re.search(self.msg_definition, msg)
if len(self.definition):
if re.search(self.definition, line):
return True
if len(self.user_definition):
if line and "PRIVMSG" in line:
line_array = line.split()
user_and_mask = line_array[0][1:]
user = user_and_mask.split("!")[0]
if self.user_definition == user:
return True
if isinstance(self.message_id, int):
if self.message_id == message_id:
return True
return False
def notifySubscribers(self, line):
"""
Fills out the object with all necessary information, then notifies subscribers with itself (an event with all the line information parsed out) as an argument.
Args:
line: string
"""
self.line = line
if line == "null":
for s in self.subscribers:
s.handle(self)
return
self.user = line.split(":")[1].rsplit(
"!")[0] # nick is first thing on line
if "JOIN" in line or "QUIT" in line:
self.user = line.split("!")[0].replace(":", "")
try:
temp = line.split(":")[1].split(" ")[1]
except IndexError:
pass
try:
self.msg = line.split(":", 2)[2]
except IndexError:
self.msg = ""
l = line.split()
self.channel = ""
self.verb = ""
ind = 0
for e in l:
ind += 1
if e == "PRIVMSG":
pass
if e.startswith("#"):
self.channel = e
break
for v in l:
if v.strip() in ["JOIN", "PART", "QUIT", "NICK", "KICK",
"PRIVMSG", "TOPIC", "NOTICE", "PING", "PONG", "MODE"]:
self.verb = v
break
# channel is unset if it does not begin with #
if self.verb == "PRIVMSG" and not len(self.channel):
self.is_pm = True
for s in self.subscribers:
try:
s.handle(self)
except AttributeError:
pass