Created
February 12, 2014 18:13
-
-
Save mpapierski/8961288 to your computer and use it in GitHub Desktop.
Python Twisted + sendfile(2)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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