twisted-internet.py [plain text]
from slides import Lecture, Slide, Image, Bullet, PRE, URL, SubBullet, NumSlide, toHTML
import os
class Bad:
"""Marks the text in red."""
def __init__(self, text):
self.text = text
def toHTML(self):
return '<font color="red">%s</font>' % toHTML(self.text)
class Lecture(Lecture):
def getFooter(self):
return '<div class="footer"><hr noshade />Presented by <b>ZOTECA </b></div>'
EVENT_LOOP_CODE = """\
# pseudo-code reactor
class Reactor:
def run(self):
while 1:
e = self.getNextEvent()
e.run()
"""
PROTOCOL_CODE = """\
from twisted.internet.protocol import Protocol
class Echo(Protocol):
def connectionMade(self):
print 'connection made with', self.transport.getPeer()
def dataReceived(self, data):
self.transport.write(data)
def connectionLost(self, reason):
print 'connection was lost, alas'
"""
SERVER_CODE = """\
from twisted.internet.protocol import ServerFactory
class EchoFactory(ServerFactory):
def buildProtocol(self, addr):
p = Echo()
p.factory = self
return p
"""
RUNNING_SERVER_CODE = """\
from twisted.internet import reactor
f = EchoFactory()
reactor.listenTCP(7771, f)
reactor.run()
"""
CLIENT_PROTOCOL_CODE = """\
from twisted.internet.protocol import Protocol
class MyClientProtocol(Protocol):
buffer = ''
def connectionMade(self):
self.transport.write('hello world')
def dataReceived(self, data):
self.buffer += data
if self.buffer == 'hello world':
self.transport.loseConnection()
"""
CLIENT_FACTORY_CODE = """\
from twisted.internet.protocol import ClientFactory
class MyFactory(ClientFactory):
protocol = MyClientProtocol
def startedConnecting(self, connector):
pass # we could connector.stopConnecting()
def clientConnectionMade(self, connector):
pass # we could connector.stopConnecting()
def clientConnectionLost(self, connector, reason):
connector.connect() # reconnect
def clientConnectionFailed(self, connector, reason):
print "connection failed"
reactor.stop()
"""
CLIENT_CONNECT_CODE = """\
from twisted.internet import reactor
reactor.connectTCP('localhost', 7771, MyFactory(), timeout=30)
reactor.run()
"""
PULL_PRODUCER_CODE = """\
class FileProducer:
def __init__(self, file, size, transport):
self.file = file; self.size = size
self.transport = transport # the consumer
transport.registerProducer(self, 0)
def resumeProducing(self):
if not self.transport: return
self.transport.write(self.file.read(16384))
if self.file.tell() == self.size:
self.transport.unregisterProducer()
self.transport = None
def pauseProducing(self): pass
def stopProducing(self):
self.file.close()
self.request = None
"""
PUSH_PRODUCER_CODE = """\
from twisted.internet import reactor
class GarbageProducer:
def __init__(self, transport):
self.paused = 0; self.stopped = 0
self.transport = transport
transport.registerProducer(self, 1)
self.produce()
def produce(self):
if not self.paused:
self.transport.write('blabla')
if not self.stopped:
reactor.callLater(0.1, self.produce)
def stopProducing(self):
self.stopped = 1
def pauseProducing(self):
self.paused = 1
def resumeProducing(self):
self.paused = 0
"""
SCHEDULING_CODE = """\
from twisted.internet import reactor
def f(x, y=1):
print x, y
i = reactor.callLater(0.1, f, 2, y=4)
i.delay(2)
i.reset(1)
i.cancel()
"""
FACTORY_START_CODE = """\
from twisted.internet.protocol import ServerFactory
class LogFactory(ServerFactory):
def startFactory(self):
self.log = open('log.txt', 'w')
def stopFactory(self):
self.log.close()
"""
LOGGING_CODE = """\
from twisted.python import log
# by default only errors are logged, to stderr
logFile = open('log.txt', 'a')
log.startLogging(logFile)
log.msg('Something has occurred')
"""
LOGGING_ERRORS_CODE = """
from twisted.python import log, failure
e = ValueError('ONO')
log.err(failure.Failure(e))
try:
doSomethingElse()
except:
log.deferr()
"""
SERVICE_CODE = """\
from twisted.internet import app
class FooService(app.ApplicationService):
def startService(self):
# do startup stuff
def stopService(self):
# do shutdown stuff
def foobrizate(self):
# business logic!
application = app.Application('foobnator')
svc = FooService('foo', application)
application.getServiceNamed('foo') is svc # True
"""
RUNNABLE_APP_CODE = """\
# this is web.py
from twisted.internet import app
from twisted.web import static, server
application = app.Application('web')
application.listenTCP(8080, server.Site(static.File('/var/www')))
if __name__ == '__main__':
application.run(save=0)
"""
TWISTD_CODE = """\
$ twistd -y web.py
$ lynx http://localhost:8080
$ kill `cat twistd.pid`
"""
GUI_CODE = """\
from twisted.internet import gtkreactor
gtkreactor.install()
import gtk
w = gtk.GtkWindow(gtk.WINDOW_TOPLEVEL)
w.show_all()
from twisted.internet import reactor
reactor.run()
"""
lecture = Lecture(
"The twisted.internet Tutorial of Doom",
Slide("Part 1 - Introduction"),
Slide("Choosing a networking paradigm for the enterprise",
Bullet("Event driven"),
Bullet(Bad("Threads")),
Bullet("Others which we will ignore (processes, SEDA, ...)")),
Slide("Applied Bistromathics 101",
Bullet("Consider a restaurant as a network application"),
Bullet("Clients come in, make requests to the waiters"),
Bullet("Waiters act on clients' choices")),
Slide("The event driven waiter",
Bullet("One waiter, serving all tables"),
Bullet("Waiter takes orders from tables to kitchen"),
Bullet("Waiter takes food from kitchen to tables")),
Slide("Threads (a caricature)",
Bullet(Bad("One waiter per table")),
SubBullet("Problems:",
Bullet(Bad("Expensive")),
Bullet(Bad("Waiters need to be careful not bump into each other")),
)),
Slide("When do we want threads?",
Bullet("Long running, blocking operations"),
Bullet("Classic example: database access")),
Slide("Twisted: The Framework of Your Internet",
Image("twisted-overview.png")),
Slide("Project Stats",
Bullet("URL: ", URL("http://www.twistedmatrix.com")),
Bullet("License: LGPL"),
Bullet("Number of developers: approximately 20"),
Bullet("Version: 1.0.3"),
Bullet("Platforms: Unix, Win32"),
Bullet("Started in January 2000 by Glyph Lefkowitz")),
Slide("Part 2 - Basic Networking With Twisted"),
Slide("Internet!",
Bullet("Network of interconnected machines"),
Bullet("Each machine has one (or more) IP addresses"),
Bullet("DNS maps names ('www.yahoo.com') to IPs (216.109.125.69)"),
Bullet("TCP runs on top of IP, servers listen on of of 65536 ports,"
" e.g. HTTP on port 80"),),
Slide("Basic Definitions - Reactor",
Bullet("An object implementing the event loop",
PRE(EVENT_LOOP_CODE))),
Slide("Basic Definitions - Transport",
Bullet("Moves data from one location to another"),
Bullet("Main focus of talk are ordered, reliable byte stream transports"),
Bullet("Examples: TCP, SSL, Unix sockets"),
Bullet("UDP is a different kind of transport")),
Slide("Basic Definitions - Protocol",
Bullet("Defines the rules for communication between two hosts"),
Bullet("Protocols communicate using a transport"),
Bullet("Typically there is a client, and server"),
Bullet("Examples: HTTP, SSH, DNS")),
Slide("All Together Now",
Bullet("The reactor gets events from the transports (read from network, write to network)"),
Bullet("The reactor passes events to protocol (connection lost, data received)"),
Bullet("The protocol tells the transport to do stuff (write data, lose connection)")),
Slide("How To Implement A Protocol",
Bullet("Hopefully, you don't.")),
NumSlide("How To Not Implement A Protocol",
Bullet("Use an existing Twisted implementation of the protocol"),
Bullet("Use XML-RPC"),
Bullet("Use Perspective Broker, a remote object protocol")),
Slide("How To Really Implement A Protocol",
PRE(PROTOCOL_CODE)),
Slide("Factories",
Bullet("A protocol instance only exists as long as the connection is there"),
Bullet("Protocols want to share state"),
Bullet("Solution: a factory object that creates protocol instances")),
Slide("A Server Factory",
PRE(SERVER_CODE)),
Slide("Connecting A Factory To A TCP Port",
PRE(RUNNING_SERVER_CODE)),
Slide("Transport Independence",
Bullet("Notice how none of the protocol code was TCP specific"),
Bullet("We can reuse same protocol with different transports"),
Bullet("We could use listenUNIX for unix sockets with same code"),
Bullet("Likewise listenSSL for SSL or TLS")),
Slide("Client Side Protocol",
PRE(CLIENT_PROTOCOL_CODE)),
Slide("Client Side Factories",
Bullet("Different requirements than server"),
Bullet("Failure to connect"),
Bullet("Automatic reconnecting"),
Bullet("Cancelling and timing out connections")),
Slide("Client Side Factories 2",
PRE(CLIENT_FACTORY_CODE)),
Slide("Connection API",
PRE(CLIENT_CONNECT_CODE)),
Slide("Buffering",
Bullet("When we write to transport, data is buffered"),
Bullet("loseConnection will wait until all buffered data is sent, and producer (if any) is finished")),
Slide("Factory Resources",
Bullet("Factories may want to create/clean up resources"),
Bullet("startFactory() - called on start of listening/connect"),
Bullet("stopFactory() - called on end of listening/connect"),
Bullet("Called once even if factory listening/connecting multiple ports")),
Slide("Factory Resources 2",
PRE(FACTORY_START_CODE)),
Slide("Producers and Consumers",
Bullet("What if we want to send out lots of data?"),
Bullet("Can't write it out all at once"),
Bullet("We don't want to write too fast")),
Slide("Producers",
Bullet("Produce data for a consumer, in this case by calling transport's write()"),
Bullet("Pausable (should implement pauseProducing and resumeProducing methods)"),
Bullet("Push - keeps producing unless told to pause"),
Bullet("Pull - produces only when consumer tells it to")),
Slide("Consumers",
Bullet("registerProducer(producer, streaming)"),
Bullet("Will notify producer to pause if buffers are full")),
Slide("Sample Pull Producer",
PRE(PULL_PRODUCER_CODE)),
Slide("Sample Push Producer",
PRE(PUSH_PRODUCER_CODE)),
Slide("Scheduling",
PRE(SCHEDULING_CODE)),
Slide("Choosing a Reactor - Why?",
Bullet("GUI toolkits have their own event loop"),
Bullet("Platform specific event loops")),
Slide("Choosing a Reactor",
Bullet("Twisted supports multiple reactors"),
Bullet("Default, gtk, gtk2, qt, win32 and others"),
Bullet("Tk and wxPython as non-reactors"),
Bullet("Reactor installation should be first thing code does")),
Slide("Example GTK Program",
PRE(GUI_CODE)),
Slide("Learning more about networking and scheduling",
Bullet("twisted.internet.interfaces"),
Bullet("http://twistedmatrix.com/document/howtos/")),
Slide("Part 3 - Building Applications With Twisted"),
Slide("Applications",
Bullet("Reactor is a concept of event loop"),
Bullet("Application is higher-level"),
Bullet("Configuration, services, persistence"),
Bullet("Like reactor, you can listenTCP, connectTCP, etc.")),
Slide("Services",
Bullet("Services can be registered with Application"),
Bullet("A service encapsulates 'business logic'"),
Bullet("Infrastructure outside the scope of protocols"),
Bullet("Examples: authentication, mail storage")),
Slide("Services 2",
PRE(SERVICE_CODE)),
Slide("Logging",
PRE(LOGGING_CODE)),
Slide("Logging Errors",
PRE(LOGGING_ERRORS_CODE)),
Slide("twistd - Application Runner",
Bullet("Single access point for running applications"),
Bullet("Separate configuration from deployment")),
Slide("twistd Features",
Bullet("Daemonization"),
Bullet("Log file selection (including to syslog)"),
Bullet("Choosing reactor"),
Bullet("Running under debugger"),
Bullet("Profiling"),
Bullet("uid, gid"),
Bullet("Future: WinNT Services")),
Slide("Making a runnable application",
PRE(RUNNABLE_APP_CODE)),
Slide("Running twistd",
PRE(TWISTD_CODE)),
Slide("Part 4: Further Bits and Pieces"),
Slide("Other twisted.internet Features",
Bullet("UDP, Multicast, Unix sockets, Serial"),
Bullet("Thread integration")),
Slide("Deferreds",
Bullet("Deferred - a promise of a result"),
Bullet("Supports callback chains for results and exceptions"),
Bullet("Used across the whole framework"),
Bullet("Make event-driven programming much easier"),
Bullet("Can work with asyncore too, not just Twisted")),
Slide("Protocol implementations",
Bullet("Low-level implementations, without policies"),
Bullet("SSH, HTTP, SMTP, IRC, POP3, telnet, FTP, TOC, OSCAR, SOCKSv4, finger, DNS, NNTP, IMAP, LDAP"),
Bullet("Common GPS modem protocols")),
Slide("Frameworks",
Bullet("twisted.web - Web server framework"),
Bullet("twisted.news - NNTP server framework"),
Bullet("twisted.words - messaging framework"),
Bullet("twisted.names - DNS server")),
Slide("Perspective Broker",
Bullet("Object publishing protocol"),
Bullet("Fast, efficient and extendable"),
Bullet("Two-way, asynchronous"),
Bullet("Secure and encourages secure model"),
Bullet("Implemented in Python for Twisted, and Java")),
Slide("Lore",
Bullet("Simple documentation system"),
Bullet("Simple subset of XHTML"),
Bullet("Generates LaTeX, XHTML")),
Slide("Reality",
Bullet("Multiplayer text simulation framework"),
Bullet("Original source of Twisted project"),
Bullet("Now a totally different project")),
)
if __name__ == '__main__':
lecture.renderHTML(".", "twisted_internet-%02d.html", css="main.css")