2 from slides import Slide, Bullet, SubBullet, URL, Image, PRE
3 from twslides import Lecture
6 def __init__(self, content):
9 return '<pre class="python">%s</pre>' % (self.content,)
12 def __init__(self, content):
13 self.content = content
15 return self.content + '\n'
18 "Applications of Twisted",
19 Slide("Twisted.names",
20 Bullet("Domain Name Server", SubBullet(
21 Bullet("Authoritative"),
25 Bullet("Domain Name Client"),
27 Slide("Mostly Functional",
28 Bullet("All common records support; 22 supported total", SubBullet(
29 Bullet("A, NS, CNAME, SOA, PTR, HINFO, MX, TXT"),
30 Bullet("IPv6 records AAAA and A6"),
32 Bullet("No DNSSEC support"),
33 Bullet("Server and Client functionality"),
35 Slide("Rapidly Developed",
36 Bullet("One month initial development period", SubBullet(
37 Bullet("Python is good for rapid development"),
38 Bullet("Twisted handles all the boring network details"),
40 Bullet("Easily extended", SubBullet(
41 Bullet("Doesn't choke on unrecognized record types"),
42 Bullet("Support for a new record type can be added in "
43 "just a few minutes"),
44 Bullet(PythonSource("""\
45 from twisted.protocols import dns
48 __implements__ = (dns.IEncodable,)
49 TYPE = dns.QUERY_TYPES['A'] = 1
51 def __init__(self, address = '0.0.0.0'):
52 self.address = socket.inet_aton(address)
54 def encode(self, strio, compDict = None):
55 strio.write(self.address)
57 def decode(self, strio, length = None):
58 self.address = readPrecisely(strio, 4)
63 Slide("Easily Configured",
64 Bullet("BIND zonefile syntax"),
65 Bullet("Python source", SubBullet(
66 Bullet(PythonSource("""\
68 AAAA('intarweb.us', '3ffe:b80:1886:1::1'),
69 SRV('_http._tcp.www.intarweb.us', 0, 0, 8080, 'intarweb.us'),
70 MX('intarweb.us', 10, 'mail.intarweb.us')
75 Bullet("Twisted's mktap and twistd tools", SubBullet(
76 PRE("mktap dns --pyzone a.domain.zonefile --recursive --cache"),
77 PRE("twistd -f dns.tap"),
81 Bullet("Asynchronous", SubBullet(
82 Bullet("All lookup functions return Deferred objects"),
86 from twisted.names import client
88 def addressFor(service, protocol, domain):
89 d = client.theResolver.lookupService(
90 '_%s._%s.%s' % (service, protocol, domain)
93 def grabPayload((answers, authority, additional)):
94 return [r.payload for r in answers]
96 def randomAnswer(results):
97 if len(results) == 1 and results[0] == '.':
98 raise RuntimeException, "No service records found"
99 return random.choice(results)
101 return d.addCallback(grabPayload).addCallback(randomAnswer)
107 Bullet("Service Records", SubBullet(
108 Bullet("Potential to simplify user experience"),
109 Bullet("Not widely accessible"),
110 Bullet("Names' client API makes accessing them trivial"),
113 Slide("Pynfo: A Network Information 'Bot",
114 Bullet("A 'bot with the goal of integrating access to miscellaneous data inputs"),
116 Slide("Architecture",
117 Bullet("Factories", SubBullet(
118 Bullet("Takes care of connecting to different services"),
119 Bullet("Acts as a central storage for shared data"),
120 Bullet("Currently only IRC is supported"),
121 Bullet("Planned support for web, IM, and PB interfaces")
123 Bullet("Protocols", SubBullet(
124 Bullet("Created by Factories"),
125 Bullet("Handles all service-specific interaction"),
126 Bullet("Refers back to the factory for shared data"),
127 Bullet("Current support for IRC only")
129 Image("pynfo-chart.png"),
130 Bullet("Separation of Factory and Protocols", SubBullet(
131 Bullet("Per-protocol data separate, per-robot data shared"),
132 Bullet("Protocols destroyed on disconnect, factory manage reconnecting"),
136 Bullet("Plugins are modules plus some metadata", SubBullet(
137 Bullet("A plugin name"),
138 Bullet("A plugin description"),
139 Bullet("A plugin type"),
140 Bullet("Any other data appropriate for the type"),
142 Bullet("Initialization / Finalization hooks"),
143 Bullet("Input filtering, for behaviors like ignore"),
144 Bullet("An example", SubBullet(
145 Bullet(PythonSource("""
146 from twisted.names import client
147 def info_LOOKUP(bot, user, channel, query):
148 def tellUserResponse((ans, auth, add)):
149 bot.reply(user, "%s: %s" % (query, [str(a.payload) for a in ans]))
151 def tellUserError(failure):
152 bot.reply(user, "Host lookup failed.")
154 client.lookupAddress(query).addCallbacks(
155 tellUserResponse, tellUserError
161 Slide("But where do they come from?",
162 Bullet("Twisted's plugin module", SubBullet(
163 Bullet(PythonSource("""\
164 from twisted.python import plugin
165 class InfoBotFactory:
167 def loadPlugins(self):
169 p = plugin.getPlugIns('infobot')
176 Bullet("Addresses to connect to and protocols to use"),
177 Bullet("Administrators, passwords, keys"),
178 Bullet("Connection statistics"),
179 Bullet("Plugins can store objects for later retrieval")
182 Bullet("Shared and pluggable behavior is implemented as Adapters for Interfaces", SubBullet(
183 Bullet("IScheduler, IStorage, IAuthenticator"),
185 Bullet("Plugins can register their own adapters for the factory", SubBullet(
186 Bullet("Gracefully add new capabilities without __class__ hacks"),
187 Bullet("Share capabilities with other plugins"),
188 Bullet("Avoids namespace collisions"),
192 Bullet("Commands and responses are issued through normal protocol actions"),
193 Bullet('Three levels of command "security"'),
194 Bullet("Access to some commands is unrestricted",
196 SubBullet("<exarkun> pyn: networks"),
197 SubBullet("<pyn> Connected to: oftc -> ('irc.oftc.net', 6667), fn -> ('irc.freenode.net', 6667)"),
200 Bullet("Access to others is granted via an ACL",
202 SubBullet("<exarkun> pyn: rebuild"),
203 SubBullet("<pyn> You aren't allowed to do that."),
206 Bullet("Still further access is granted by the possession of a secret key",
208 SubBullet("<exarkun> pyn: spill self.transport.getHost()"),
209 SubBullet("<pyn> Command queued. Challenge: BBKSkYCRCGQETx4kTmceUg==%"),
210 SubBullet("<exarkun> pyn: respond 2lwcgSVnJPzrW6Yvq7sg+g==%"),
211 SubBullet("<pyn> ('INET', '192.168.123.137', 45539)"),
215 Slide("Network Bridging",
216 Bullet("Pass messages between networks",
218 SubBullet("<pyn> Yosomono (~fake@hostmask) has joined on efnet"),
219 SubBullet("<pyn> <Yosomono@efnet> hello"),
222 Bullet("Requesting user information across networks",
224 SubBullet("<exarkun> pyn: whois Yosomono@efnet"),
225 SubBullet("<pyn> Hostmask: Yosomono!fake@hostmask"),
226 SubBullet("<pyn> Channels: @#python"),
230 Slide("Conversation Logging",
231 Bullet("The 'conversation' command", SubBullet(
233 SubBullet("<exar[con]> pyn: conversation begin PyCon example conversation"),
234 SubBullet("<pyn> Beginning tagged conversation 'PyCon example conversation'."),
235 SubBullet("<exar[con]> Hello, PyCon"),
236 SubBullet("<exar[con]> Enjoy the example!"),
237 SubBullet("<exar[con]> pyn: conversation end PyCon example conversation"),
238 SubBullet("<pyn> Ended tagged conversation 'PyCon example conversation'."),
241 Bullet("Web interface", SubBullet(
242 URL("http://c.intarweb.us:8008/%23tanstaafl/PyCon%20example%20conversation"),
244 Bullet("Search previous logs and add conversation tags"),
246 Slide("Various other plugins",
247 Bullet("PyPI monitor and querying"),
248 Bullet("Network specific operations - IRC operator module"),
249 Bullet("Freshmeat and Google querying"),
250 Bullet("Link shortener"),
251 Bullet("PyMetar plugin"),
257 lecture.renderHTML(".", "applications-%d.html", css="stylesheet.css")