-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathircbot.py
executable file
·151 lines (116 loc) · 5.4 KB
/
ircbot.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
#! /usr/bin/env python2.7
import sys
import signal
import concurrent.futures
import logging
import os
import ircbot.config
import ircbot.parser
import ircbot.helpers
from ircbot.functions import *
def run(socket, channels, cmds, nick):
# buffer for some command received
buff = ''
num_workers = sum(len(v) for k, v in cmds.iteritems())
# TODO: what happens if I use all the workers?
# TODO: don't let commands to run for more than one minute
with concurrent.futures.ProcessPoolExecutor(max_workers=num_workers) as executor:
while len(channels):
receive = socket.recv(4096)
buff = buff + receive
response = ''
if receive:
logging.debug(receive + \
('' if '\n' == receive[len(receive)-1] else '\n'))
if -1 != buff.find('\n'):
# get a full command from the buffer
command = buff[0 : buff.find('\n')]
buff = buff[buff.find('\n')+1 : ]
# command's components after parsing
components = ircbot.parser.parse_command(command)
to = send_to(command)
if 'PING' == components['action']:
response = []
response.append('PONG')
response.append(':' + components['arguments'])
elif 'PRIVMSG' == components['action']:
if '!' == components['arguments'][0]:
# a command from a user only makes sense if it starts
# with an exclamation mark
pos = components['arguments'].find(' ')
if -1 == pos:
pos = len(components['arguments'])
# get the command issued to the bot without the "!"
cmd = components['arguments'][1:pos]
callable_cmd = get_cmd(cmd, cmds['user'])
if callable_cmd:
run_cmd(socket, executor, to, callable_cmd,
components)
else:
callable_cmd = get_cmd(cmd, cmds['core'])
if callable_cmd:
try:
response = callable_cmd(socket, components)
except Exception as e:
response = ircbot.helpers.C_EXCEPTION.format(
callable_cmd.__name__)
logging.error(str(e))
# run auto commands
for cmd in ircbot.config.cmds['auto']:
callable_cmd = get_cmd(cmd, cmds['auto'])
if callable_cmd:
run_cmd(socket, executor, to, callable_cmd,
components)
elif 'KICK' == components['action'] and \
nick == components['action_args'][1]:
channels.remove(components['action_args'][0])
elif 'QUIT' == components['action'] and \
-1 != components['arguments'].find('Ping timeout: '):
channels[:] = []
# this call is still necessary in case that a PONG response or a
# core command response should be sent, every other response is
# sent when the futures finish working from their respective
# thread
send_response(response, to, socket)
buff = ''
def main():
valid_cfg = check_cfg(ircbot.config.owner, ircbot.config.server, ircbot.config.nicks,
ircbot.config.real_name, ircbot.config.log, ircbot.config.cmds)
if not valid_cfg:
sys.exit(ircbot.helpers.INVALID_CFG)
if not os.path.isdir(ircbot.config.log):
try:
os.makedirs(ircbot.config.log)
except os.error as e:
print "Log directory creation failed: " + str(e)
sys.exit(1)
else:
print "Log directory created"
logfile = get_datetime()['date'] + '.log'
try:
logging.basicConfig(filename=os.path.join(ircbot.config.log, logfile),
level=ircbot.config.logging_level,
format='%(asctime)s - %(levelname)s - %(message)s',
datefmt='%Y-%m-%d %H:%M:%S')
except IOError as e:
print "Couldn't set up logging: " + str(e)
sys.exit(1)
if not check_channel(ircbot.config.channels):
sys.exit(ircbot.helpers.INVALID_CHANNELS)
signal.signal(signal.SIGINT, sigint_handler)
socket = create_socket()
if socket and connect_to((ircbot.config.server, ircbot.config.port), socket):
content = 'Connected to {0}:{1}'.format(ircbot.config.server, ircbot.config.port)
logging.info(content)
print content
ircbot.config.current_nick = name_bot(socket, ircbot.config.nicks, ircbot.config.real_name)
joined = join_channels(config.channels, socket)
if joined:
run(socket, ircbot.config.channels, ircbot.config.cmds, ircbot.config.current_nick)
quit_bot(socket)
socket.close()
content = 'Disconnected from {0}:{1}'.format(ircbot.config.server, ircbot.config.port)
logging.info(content)
print content
if '__main__' == __name__: #pragma: no cover
main()