Skip to content

Instantly share code, notes, and snippets.

@mpapierski
Created February 12, 2014 18:13
Show Gist options
  • Save mpapierski/8961288 to your computer and use it in GitHub Desktop.
Save mpapierski/8961288 to your computer and use it in GitHub Desktop.
Python Twisted + sendfile(2)
# coding: utf-8
import os
import sys
from cffi import FFI
from twisted.internet.defer import Deferred
from twisted.internet import reactor
from twisted.python import log
from twisted.web.server import Site, NOT_DONE_YET
from twisted.web.resource import Resource
from twisted.internet.endpoints import TCP4ServerEndpoint
ffi = FFI()
ffi.cdef("""
typedef long off_t;
ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
""")
lib = ffi.verify("""
#include <sys/sendfile.h>
""")
class _Sender(object):
def __init__(self, consumer, fileobj, size):
self.consumer = consumer
self.fileno = fileobj.fileno()
self.size = size
self.dfd = Deferred()
def resumeProducing(self):
offset = ffi.new('off_t*', 0)
lib.sendfile(self.consumer.fileno(), self.fileno, offset, self.size)
self.consumer.unregisterProducer()
self.dfd.callback(None)
def stopProducing(self):
pass
def doSendfile(req, fileobj):
fileno = fileobj.fileno()
size = os.fstat(fileno).st_size
sender = _Sender(req.transport, fileobj, size)
req.setHeader('content-length', size)
# kickstart this shit, will call sender.resumeProducing
req.write('')
req.transport.producer = sender
return sender.dfd
class Res(Resource):
isLeaf = True
def render_GET(self, req):
f = open('foo.txt')
(doSendfile(req, f)
.addCallback(lambda i: req.finish())
.addCallback(lambda i: f.close())
)
return NOT_DONE_YET
with open('foo.txt', 'w') as f:
f.write('asdasdasasd\n')
site = Site(Res())
TCP4ServerEndpoint(reactor, 8080).listen(site)
log.startLogging(sys.stderr)
reactor.run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment