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 | import sys
import lxml.html
from twisted.internet import reactor, task, defer, protocol
from twisted.python import log
from twisted.words.protocols import irc
from twisted.web.client import getPage
from twisted.application import internet, service
import engine
HOST, PORT = 'irc.rizon.net', 6667
nickname = ''
channels = [""]
eng = engine.Eng()
class MyFirstIRCProtocol(irc.IRCClient):
nickname = nickname
def signedOn(self):
for channel in self.factory.channels:
self.join(channel)
def extract_nicks(self, msg):
return
def say(self, msg, target):
self._send_message(msg, target)
#def say(self, msg, channel)
# Obviously, called when a PRIVMSG is received.
def privmsg(self, user, channel, message):
message = message.decode("utf8").strip()
msg = eng.administrate(message, nickname, user)
if msg:
msg = msg.encode("utf8")
self.say(msg, channel)
def _send_message(self, msg, target, nick=None):
if nick:
msg = '%s, %s' % (nick, msg)
self.msg(target, msg)
def _show_error(self, failure):
return failure.getErrorMessage()
def command_ping(self, rest):
return 'Pong.'
def command_saylater(self, rest):
when, sep, msg = rest.partition(' ')
when = int(when)
d = defer.Deferred()
# A small example of how to defer the reply from a command. callLater
# will callback the Deferred with the reply after so many seconds.
reactor.callLater(when, d.callback, msg)
# Returning the Deferred here means that it'll be returned from
# maybeDeferred in privmsg.
return d
def command_title(self, url):
d = getPage(url)
# Another example of using Deferreds. twisted.web.client.getPage returns
# a Deferred which is called back when the URL requested has been
# downloaded. We add a callback to the chain which will parse the page
# and extract only the title. If we just returned the deferred instead,
# the function would still work, but the reply would be the entire
# contents of the page.
# After that, we add a callback that will extract the title
# from the parsed tree lxml returns
d.addCallback(self._parse_pagetitle, url)
return d
def _parse_pagetitle(self, page_contents, url):
# Parses the page into a tree of elements:
pagetree = lxml.html.fromstring(page_contents)
# Extracts the title text from the lxml document using xpath
title = u' '.join(pagetree.xpath('//title/text()')).strip()
# Since lxml gives you unicode and unicode data must be encoded
# to send over the wire, we have to encode the title. Sadly IRC predates
# unicode, so there's no formal way of specifying the encoding of data
# transmitted over IRC. UTF-8 is our best bet, and what most people use.
title = title.encode('utf-8')
# Since we're returning this value from a callback, it will be passed in
# to the next callback in the chain (self._send_message).
return '%s -- "%s"' % (url, title)
class MyFirstIRCFactory(protocol.ReconnectingClientFactory):
protocol = MyFirstIRCProtocol
channels = channels
if __name__ == '__main__':
# This runs the program in the foreground. We tell the reactor to connect
# over TCP using a given factory, and once the reactor is started, it will
# open that connection.
reactor.connectTCP(HOST, PORT, MyFirstIRCFactory())
# Since we're running in the foreground anyway, show what's happening by
# logging to stdout.
log.startLogging(sys.stdout)
# And this starts the reactor running. This call blocks until everything is
# done, because this runs the whole twisted mainloop.
reactor.run()
# This runs the program in the background. __name__ is __builtin__ when you use
# twistd -y on a python module.
elif __name__ == '__builtin__':
# Create a new application to which we can attach our services. twistd wants
# an application object, which is how it knows what services should be
# running. This simplifies startup and shutdown.
application = service.Application('MyFirstIRCBot')
# twisted.application.internet.TCPClient is how to make a TCP client service
# which we can attach to the application.
ircService = internet.TCPClient(HOST, PORT, MyFirstIRCFactory())
ircService.setServiceParent(application)
# twistd -y looks for a global variable in this module named 'application'.
# Since there is one now, and it's all set up, there's nothing left to do.
|