eventlet-0.13.0/ 0000755 0001750 0001750 00000000000 12164600754 014266 5 ustar temoto temoto 0000000 0000000 eventlet-0.13.0/eventlet.egg-info/ 0000755 0001750 0001750 00000000000 12164600754 017606 5 ustar temoto temoto 0000000 0000000 eventlet-0.13.0/eventlet.egg-info/not-zip-safe 0000644 0001750 0001750 00000000001 12163276741 022040 0 ustar temoto temoto 0000000 0000000
eventlet-0.13.0/eventlet.egg-info/PKG-INFO 0000644 0001750 0001750 00000006117 12164600737 020711 0 ustar temoto temoto 0000000 0000000 Metadata-Version: 1.1
Name: eventlet
Version: 0.13.0
Summary: Highly concurrent networking library
Home-page: http://eventlet.net
Author: Linden Lab
Author-email: eventletdev@lists.secondlife.com
License: UNKNOWN
Description: Eventlet is a concurrent networking library for Python that allows you to change how you run your code, not how you write it.
It uses epoll or libevent for highly scalable non-blocking I/O. Coroutines ensure that the developer uses a blocking style of programming that is similar to threading, but provide the benefits of non-blocking I/O. The event dispatch is implicit, which means you can easily use Eventlet from the Python interpreter, or as a small part of a larger application.
It's easy to get started using Eventlet, and easy to convert existing
applications to use it. Start off by looking at the `examples`_,
`common design patterns`_, and the list of `basic API primitives`_.
.. _examples: http://eventlet.net/doc/examples.html
.. _common design patterns: http://eventlet.net/doc/design_patterns.html
.. _basic API primitives: http://eventlet.net/doc/basic_usage.html
Quick Example
===============
Here's something you can try right on the command line::
% python
>>> import eventlet
>>> from eventlet.green import urllib2
>>> gt = eventlet.spawn(urllib2.urlopen, 'http://eventlet.net')
>>> gt2 = eventlet.spawn(urllib2.urlopen, 'http://secondlife.com')
>>> gt2.wait()
>>> gt.wait()
Getting Eventlet
==================
The easiest way to get Eventlet is to use easy_install or pip::
easy_install eventlet
pip install eventlet
The development `tip`_ is available via easy_install as well::
easy_install 'eventlet==dev'
pip install 'eventlet==dev'
.. _tip: http://bitbucket.org/eventlet/eventlet/get/tip.zip#egg=eventlet-dev
Building the Docs Locally
=========================
To build a complete set of HTML documentation, you must have Sphinx, which can be found at http://sphinx.pocoo.org/ (or installed with `easy_install sphinx`)
cd doc
make html
The built html files can be found in doc/_build/html afterward.
Platform: UNKNOWN
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python
Classifier: Operating System :: MacOS :: MacOS X
Classifier: Operating System :: POSIX
Classifier: Operating System :: Microsoft :: Windows
Classifier: Programming Language :: Python :: 2.4
Classifier: Programming Language :: Python :: 2.5
Classifier: Programming Language :: Python :: 2.6
Classifier: Programming Language :: Python :: 2.7
Classifier: Topic :: Internet
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Intended Audience :: Developers
Classifier: Development Status :: 4 - Beta
eventlet-0.13.0/eventlet.egg-info/requires.txt 0000644 0001750 0001750 00000000017 12164600737 022205 0 ustar temoto temoto 0000000 0000000 greenlet >= 0.3 eventlet-0.13.0/eventlet.egg-info/dependency_links.txt 0000644 0001750 0001750 00000000001 12164600737 023655 0 ustar temoto temoto 0000000 0000000
eventlet-0.13.0/eventlet.egg-info/top_level.txt 0000644 0001750 0001750 00000000011 12164600737 022331 0 ustar temoto temoto 0000000 0000000 eventlet
eventlet-0.13.0/eventlet.egg-info/SOURCES.txt 0000644 0001750 0001750 00000012362 12164600737 021477 0 ustar temoto temoto 0000000 0000000 AUTHORS
LICENSE
MANIFEST.in
NEWS
README
README.twisted
setup.py
doc/Makefile
doc/authors.rst
doc/basic_usage.rst
doc/common.txt
doc/conf.py
doc/design_patterns.rst
doc/environment.rst
doc/examples.rst
doc/history.rst
doc/hubs.rst
doc/index.rst
doc/modules.rst
doc/patching.rst
doc/ssl.rst
doc/testing.rst
doc/threading.rst
doc/zeromq.rst
doc/images/threading_illustration.png
doc/modules/backdoor.rst
doc/modules/corolocal.rst
doc/modules/db_pool.rst
doc/modules/debug.rst
doc/modules/event.rst
doc/modules/greenpool.rst
doc/modules/greenthread.rst
doc/modules/pools.rst
doc/modules/queue.rst
doc/modules/semaphore.rst
doc/modules/timeout.rst
doc/modules/websocket.rst
doc/modules/wsgi.rst
doc/modules/zmq.rst
eventlet/__init__.py
eventlet/api.py
eventlet/backdoor.py
eventlet/convenience.py
eventlet/corolocal.py
eventlet/coros.py
eventlet/db_pool.py
eventlet/debug.py
eventlet/event.py
eventlet/greenio.py
eventlet/greenpool.py
eventlet/greenthread.py
eventlet/patcher.py
eventlet/pool.py
eventlet/pools.py
eventlet/proc.py
eventlet/processes.py
eventlet/queue.py
eventlet/saranwrap.py
eventlet/semaphore.py
eventlet/timeout.py
eventlet/tpool.py
eventlet/util.py
eventlet/websocket.py
eventlet/wsgi.py
eventlet.egg-info/PKG-INFO
eventlet.egg-info/SOURCES.txt
eventlet.egg-info/dependency_links.txt
eventlet.egg-info/not-zip-safe
eventlet.egg-info/requires.txt
eventlet.egg-info/top_level.txt
eventlet/green/BaseHTTPServer.py
eventlet/green/CGIHTTPServer.py
eventlet/green/MySQLdb.py
eventlet/green/Queue.py
eventlet/green/SimpleHTTPServer.py
eventlet/green/SocketServer.py
eventlet/green/__init__.py
eventlet/green/_socket_nodns.py
eventlet/green/asynchat.py
eventlet/green/asyncore.py
eventlet/green/ftplib.py
eventlet/green/httplib.py
eventlet/green/os.py
eventlet/green/profile.py
eventlet/green/select.py
eventlet/green/socket.py
eventlet/green/ssl.py
eventlet/green/subprocess.py
eventlet/green/thread.py
eventlet/green/threading.py
eventlet/green/time.py
eventlet/green/urllib.py
eventlet/green/urllib2.py
eventlet/green/zmq.py
eventlet/green/OpenSSL/SSL.py
eventlet/green/OpenSSL/__init__.py
eventlet/green/OpenSSL/crypto.py
eventlet/green/OpenSSL/rand.py
eventlet/green/OpenSSL/tsafe.py
eventlet/green/OpenSSL/version.py
eventlet/hubs/__init__.py
eventlet/hubs/epolls.py
eventlet/hubs/hub.py
eventlet/hubs/kqueue.py
eventlet/hubs/poll.py
eventlet/hubs/pyevent.py
eventlet/hubs/selects.py
eventlet/hubs/timer.py
eventlet/hubs/twistedr.py
eventlet/support/__init__.py
eventlet/support/greendns.py
eventlet/support/greenlets.py
eventlet/support/psycopg2_patcher.py
eventlet/support/pylib.py
eventlet/support/stacklesspypys.py
eventlet/support/stacklesss.py
eventlet/twistedutil/__init__.py
eventlet/twistedutil/join_reactor.py
eventlet/twistedutil/protocol.py
eventlet/twistedutil/protocols/__init__.py
eventlet/twistedutil/protocols/basic.py
examples/chat_bridge.py
examples/chat_server.py
examples/connect.py
examples/distributed_websocket_chat.py
examples/echoserver.py
examples/feedscraper-testclient.py
examples/feedscraper.py
examples/forwarder.py
examples/producer_consumer.py
examples/recursive_crawler.py
examples/webcrawler.py
examples/websocket.html
examples/websocket.py
examples/websocket_chat.html
examples/websocket_chat.py
examples/wsgi.py
examples/zmq_chat.py
examples/zmq_simple.py
examples/twisted/twisted_client.py
examples/twisted/twisted_http_proxy.py
examples/twisted/twisted_portforward.py
examples/twisted/twisted_server.py
examples/twisted/twisted_srvconnector.py
examples/twisted/twisted_xcap_proxy.py
tests/__init__.py
tests/api_test.py
tests/backdoor_test.py
tests/convenience_test.py
tests/coros_test.py
tests/db_pool_test.py
tests/debug_test.py
tests/env_test.py
tests/event_test.py
tests/fork_test.py
tests/greenio_test.py
tests/greenpipe_test_with_statement.py
tests/greenpool_test.py
tests/greenthread_test.py
tests/hub_test.py
tests/mock.py
tests/mysqldb_test.py
tests/nosewrapper.py
tests/parse_results.py
tests/patcher_psycopg_test.py
tests/patcher_test.py
tests/pools_test.py
tests/processes_test.py
tests/queue_test.py
tests/saranwrap_test.py
tests/semaphore_test.py
tests/ssl_test.py
tests/subprocess_test.py
tests/test__coros_queue.py
tests/test__event.py
tests/test__greenness.py
tests/test__pool.py
tests/test__proc.py
tests/test__refcount.py
tests/test__socket_errors.py
tests/test__twistedutil.py
tests/test__twistedutil_protocol.py
tests/test_server.crt
tests/test_server.key
tests/thread_test.py
tests/timeout_test.py
tests/timeout_test_with_statement.py
tests/timer_test.py
tests/tpool_test.py
tests/websocket_test.py
tests/wsgi_test.py
tests/zmq_test.py
tests/stdlib/all.py
tests/stdlib/all_modules.py
tests/stdlib/all_monkey.py
tests/stdlib/test_SimpleHTTPServer.py
tests/stdlib/test_asynchat.py
tests/stdlib/test_asyncore.py
tests/stdlib/test_ftplib.py
tests/stdlib/test_httplib.py
tests/stdlib/test_httpservers.py
tests/stdlib/test_os.py
tests/stdlib/test_queue.py
tests/stdlib/test_select.py
tests/stdlib/test_socket.py
tests/stdlib/test_socket_ssl.py
tests/stdlib/test_socketserver.py
tests/stdlib/test_ssl.py
tests/stdlib/test_subprocess.py
tests/stdlib/test_thread.py
tests/stdlib/test_thread__boundedsem.py
tests/stdlib/test_threading.py
tests/stdlib/test_threading_local.py
tests/stdlib/test_timeout.py
tests/stdlib/test_urllib.py
tests/stdlib/test_urllib2.py
tests/stdlib/test_urllib2_localnet.py eventlet-0.13.0/MANIFEST.in 0000644 0001750 0001750 00000000305 12164577340 016026 0 ustar temoto temoto 0000000 0000000 recursive-include tests *.py *.crt *.key
recursive-include doc *.rst *.txt *.py Makefile *.png
recursive-include examples *.py *.html
include MANIFEST.in README.twisted NEWS AUTHORS LICENSE README
eventlet-0.13.0/AUTHORS 0000644 0001750 0001750 00000006505 12164577340 015350 0 ustar temoto temoto 0000000 0000000 Maintainer (i.e., Who To Hassle If You Find Bugs)
-------------------------------------------------
Sergey Shepelev, temoto on Freenode, temotor@gmail.com
Original Authors
----------------
* Bob Ippolito
* Donovan Preston
Contributors
------------
* AG Projects
* Chris AtLee
* R\. Tyler Ballance
* Denis Bilenko
* Mike Barton
* Patrick Carlisle
* Ben Ford
* Andrew Godwin
* Brantley Harris
* Gregory Holt
* Joe Malicki
* Chet Murthy
* Eugene Oden
* radix
* Scott Robinson
* Tavis Rudd
* Sergey Shepelev
* Chuck Thier
* Nick V
* Daniele Varrazzo
* Ryan Williams
* Geoff Salmon
* Edward George
* Floris Bruynooghe
Linden Lab Contributors
-----------------------
* John Beisley
* Tess Chu
* Nat Goodspeed
* Dave Kaprielian
* Kartic Krishnamurthy
* Bryan O'Sullivan
* Kent Quirk
* Ryan Williams
Thanks To
---------
* AdamKG, giving the hint that invalid argument errors were introduced post-0.9.0
* Luke Tucker, bug report regarding wsgi + webob
* Taso Du Val, reproing an exception squelching bug, saving children's lives ;-)
* Luci Stanescu, for reporting twisted hub bug
* Marcus Cavanaugh, for test case code that has been incredibly useful in tracking down bugs
* Brian Brunswick, for many helpful questions and suggestions on the mailing list
* Cesar Alaniz, for uncovering bugs of great import
* the grugq, for contributing patches, suggestions, and use cases
* Ralf Schmitt, for wsgi/webob incompatibility bug report and suggested fix
* Benoit Chesneau, bug report on green.os and patch to fix it
* Slant, better iterator implementation in tpool
* Ambroff, nice pygtk hub example
* Michael Carter, websocket patch to improve location handling
* Marcin Bachry, nice repro of a bug and good diagnosis leading to the fix
* David Ziegler, reporting issue #53
* Favo Yang, twisted hub patch
* Schmir, patch that fixes readline method with chunked encoding in wsgi.py, advice on patcher
* Slide, for open-sourcing gogreen
* Holger Krekel, websocket example small fix
* mikepk, debugging MySQLdb/tpool issues
* Malcolm Cleaton, patch for Event exception handling
* Alexey Borzenkov, for finding and fixing issues with Windows error detection (#66, #69), reducing dependencies in zeromq hub (#71)
* Anonymous, finding and fixing error in websocket chat example (#70)
* Edward George, finding and fixing an issue in the [e]poll hubs (#74), and in convenience (#86)
* Ruijun Luo, figuring out incorrect openssl import for wrap_ssl (#73)
* rfk, patch to get green zmq to respect noblock flag.
* Soren Hansen, finding and fixing issue in subprocess (#77)
* Stefano Rivera, making tests pass in absence of postgres (#78)
* Joshua Kwan, fixing busy-wait in eventlet.green.ssl.
* Nick Vatamaniuc, Windows SO_REUSEADDR patch (#83)
* Clay Gerrard, wsgi handle socket closed by client (#95)
* Eric Windisch, zmq getsockopt(EVENTS) wake correct threads (pull request 22)
* Raymond Lu, fixing busy-wait in eventlet.green.ssl.socket.sendall()
* Thomas Grainger, webcrawler example small fix, "requests" library import bug report, Travis integration
* Peter Portante, save syscalls in socket.dup(), environ[REMOTE_PORT] in wsgi
* Peter Skirko, fixing socket.settimeout(0) bug
* Derk Tegeler, Pre-cache proxied GreenSocket methods (Bitbucket #136)
* Jakub Stasiak, Travis integration, wsgi fix
* Paul Oppenheim, bug reports
* David Malcolm, optional "timeout" argument to the subprocess module (Bitbucket #89)
eventlet-0.13.0/setup.cfg 0000644 0001750 0001750 00000000073 12164600754 016107 0 ustar temoto temoto 0000000 0000000 [egg_info]
tag_build =
tag_date = 0
tag_svn_revision = 0
eventlet-0.13.0/examples/ 0000755 0001750 0001750 00000000000 12164600754 016104 5 ustar temoto temoto 0000000 0000000 eventlet-0.13.0/examples/websocket.py 0000644 0001750 0001750 00000002366 12164577340 020457 0 ustar temoto temoto 0000000 0000000 import eventlet
from eventlet import wsgi
from eventlet import websocket
# demo app
import os
import random
@websocket.WebSocketWSGI
def handle(ws):
""" This is the websocket handler function. Note that we
can dispatch based on path in here, too."""
if ws.path == '/echo':
while True:
m = ws.wait()
if m is None:
break
ws.send(m)
elif ws.path == '/data':
for i in xrange(10000):
ws.send("0 %s %s\n" % (i, random.random()))
eventlet.sleep(0.1)
def dispatch(environ, start_response):
""" This resolves to the web page or the websocket depending on
the path."""
if environ['PATH_INFO'] == '/data':
return handle(environ, start_response)
else:
start_response('200 OK', [('content-type', 'text/html')])
return [open(os.path.join(
os.path.dirname(__file__),
'websocket.html')).read()]
if __name__ == "__main__":
# run an example app from the command line
listener = eventlet.listen(('127.0.0.1', 7000))
print "\nVisit http://localhost:7000/ in your websocket-capable browser.\n"
wsgi.server(listener, dispatch)
eventlet-0.13.0/examples/websocket.html 0000644 0001750 0001750 00000002512 12164577340 020764 0 ustar temoto temoto 0000000 0000000
Plot
(Only tested in Chrome)
eventlet-0.13.0/examples/websocket_chat.py 0000644 0001750 0001750 00000002106 12164577340 021446 0 ustar temoto temoto 0000000 0000000 import os
import eventlet
from eventlet import wsgi
from eventlet import websocket
PORT = 7000
participants = set()
@websocket.WebSocketWSGI
def handle(ws):
participants.add(ws)
try:
while True:
m = ws.wait()
if m is None:
break
for p in participants:
p.send(m)
finally:
participants.remove(ws)
def dispatch(environ, start_response):
"""Resolves to the web page or the websocket depending on the path."""
if environ['PATH_INFO'] == '/chat':
return handle(environ, start_response)
else:
start_response('200 OK', [('content-type', 'text/html')])
html_path = os.path.join(os.path.dirname(__file__), 'websocket_chat.html')
return [open(html_path).read() % {'port': PORT}]
if __name__ == "__main__":
# run an example app from the command line
listener = eventlet.listen(('127.0.0.1', PORT))
print "\nVisit http://localhost:7000/ in your websocket-capable browser.\n"
wsgi.server(listener, dispatch)
eventlet-0.13.0/examples/wsgi.py 0000644 0001750 0001750 00000001150 12164577340 017430 0 ustar temoto temoto 0000000 0000000 """This is a simple example of running a wsgi application with eventlet.
For a more fully-featured server which supports multiple processes,
multiple threads, and graceful code reloading, see:
http://pypi.python.org/pypi/Spawning/
"""
import eventlet
from eventlet import wsgi
def hello_world(env, start_response):
if env['PATH_INFO'] != '/':
start_response('404 Not Found', [('Content-Type', 'text/plain')])
return ['Not Found\r\n']
start_response('200 OK', [('Content-Type', 'text/plain')])
return ['Hello, World!\r\n']
wsgi.server(eventlet.listen(('', 8090)), hello_world)
eventlet-0.13.0/examples/zmq_simple.py 0000644 0001750 0001750 00000001306 12164577340 020642 0 ustar temoto temoto 0000000 0000000 from eventlet.green import zmq
import eventlet
CTX = zmq.Context(1)
def bob_client(ctx, count):
print "STARTING BOB"
bob = zmq.Socket(CTX, zmq.REQ)
bob.connect("ipc:///tmp/test")
for i in range(0, count):
print "BOB SENDING"
bob.send("HI")
print "BOB GOT:", bob.recv()
def alice_server(ctx, count):
print "STARTING ALICE"
alice = zmq.Socket(CTX, zmq.REP)
alice.bind("ipc:///tmp/test")
print "ALICE READY"
for i in range(0, count):
print "ALICE GOT:", alice.recv()
print "ALIC SENDING"
alice.send("HI BACK")
alice = eventlet.spawn(alice_server, CTX, 10)
bob = eventlet.spawn(bob_client, CTX, 10)
bob.wait()
alice.wait()
eventlet-0.13.0/examples/webcrawler.py 0000644 0001750 0001750 00000001474 12164577340 020625 0 ustar temoto temoto 0000000 0000000 #!/usr/bin/env python
"""
This is a simple web "crawler" that fetches a bunch of urls using a pool to
control the number of outbound connections. It has as many simultaneously open
connections as coroutines in the pool.
The prints in the body of the fetch function are there to demonstrate that the
requests are truly made in parallel.
"""
import eventlet
from eventlet.green import urllib2
urls = [
"https://www.google.com/intl/en_ALL/images/logo.gif",
"http://python.org/images/python-logo.gif",
"http://us.i1.yimg.com/us.yimg.com/i/ww/beta/y3.gif",
]
def fetch(url):
print "opening", url
body = urllib2.urlopen(url).read()
print "done with", url
return url, body
pool = eventlet.GreenPool(200)
for url, body in pool.imap(fetch, urls):
print "got body from", url, "of length", len(body)
eventlet-0.13.0/examples/feedscraper.py 0000644 0001750 0001750 00000002147 12164577340 020751 0 ustar temoto temoto 0000000 0000000 """A simple web server that accepts POSTS containing a list of feed urls,
and returns the titles of those feeds.
"""
import eventlet
feedparser = eventlet.import_patched('feedparser')
# the pool provides a safety limit on our concurrency
pool = eventlet.GreenPool()
def fetch_title(url):
d = feedparser.parse(url)
return d.feed.get('title', '')
def app(environ, start_response):
if environ['REQUEST_METHOD'] != 'POST':
start_response('403 Forbidden', [])
return []
# the pile collects the result of a concurrent operation -- in this case,
# the collection of feed titles
pile = eventlet.GreenPile(pool)
for line in environ['wsgi.input'].readlines():
url = line.strip()
if url:
pile.spawn(fetch_title, url)
# since the pile is an iterator over the results,
# you can use it in all sorts of great Pythonic ways
titles = '\n'.join(pile)
start_response('200 OK', [('Content-type', 'text/plain')])
return [titles]
if __name__ == '__main__':
from eventlet import wsgi
wsgi.server(eventlet.listen(('localhost', 9010)), app) eventlet-0.13.0/examples/zmq_chat.py 0000644 0001750 0001750 00000003177 12164577340 020300 0 ustar temoto temoto 0000000 0000000 import eventlet, sys
from eventlet.green import socket, zmq
from eventlet.hubs import use_hub
use_hub('zeromq')
ADDR = 'ipc:///tmp/chat'
ctx = zmq.Context()
def publish(writer):
print "connected"
socket = ctx.socket(zmq.SUB)
socket.setsockopt(zmq.SUBSCRIBE, "")
socket.connect(ADDR)
eventlet.sleep(0.1)
while True:
msg = socket.recv_pyobj()
str_msg = "%s: %s" % msg
writer.write(str_msg)
writer.flush()
PORT=3001
def read_chat_forever(reader, pub_socket):
line = reader.readline()
who = 'someone'
while line:
print "Chat:", line.strip()
if line.startswith('name:'):
who = line.split(':')[-1].strip()
try:
pub_socket.send_pyobj((who, line))
except socket.error, e:
# ignore broken pipes, they just mean the participant
# closed its connection already
if e[0] != 32:
raise
line = reader.readline()
print "Participant left chat."
try:
print "ChatServer starting up on port %s" % PORT
server = eventlet.listen(('0.0.0.0', PORT))
pub_socket = ctx.socket(zmq.PUB)
pub_socket.bind(ADDR)
eventlet.spawn_n(publish,
sys.stdout)
while True:
new_connection, address = server.accept()
print "Participant joined chat."
eventlet.spawn_n(publish,
new_connection.makefile('w'))
eventlet.spawn_n(read_chat_forever,
new_connection.makefile('r'),
pub_socket)
except (KeyboardInterrupt, SystemExit):
print "ChatServer exiting." eventlet-0.13.0/examples/websocket_chat.html 0000644 0001750 0001750 00000001462 12164577340 021766 0 ustar temoto temoto 0000000 0000000
Chat!
(Only tested in Chrome)
eventlet-0.13.0/examples/producer_consumer.py 0000644 0001750 0001750 00000003612 12164577340 022222 0 ustar temoto temoto 0000000 0000000 """This is a recursive web crawler. Don't go pointing this at random sites;
it doesn't respect robots.txt and it is pretty brutal about how quickly it
fetches pages.
This is a kind of "producer/consumer" example; the fetch function produces
jobs, and the GreenPool itself is the consumer, farming out work concurrently.
It's easier to write it this way rather than writing a standard consumer loop;
GreenPool handles any exceptions raised and arranges so that there's a set
number of "workers", so you don't have to write that tedious management code
yourself.
"""
from __future__ import with_statement
from eventlet.green import urllib2
import eventlet
import re
# http://daringfireball.net/2009/11/liberal_regex_for_matching_urls
url_regex = re.compile(r'\b(([\w-]+://?|www[.])[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/)))')
def fetch(url, outq):
"""Fetch a url and push any urls found into a queue."""
print "fetching", url
data = ''
with eventlet.Timeout(5, False):
data = urllib2.urlopen(url).read()
for url_match in url_regex.finditer(data):
new_url = url_match.group(0)
outq.put(new_url)
def producer(start_url):
"""Recursively crawl starting from *start_url*. Returns a set of
urls that were found."""
pool = eventlet.GreenPool()
seen = set()
q = eventlet.Queue()
q.put(start_url)
# keep looping if there are new urls, or workers that may produce more urls
while True:
while not q.empty():
url = q.get()
# limit requests to eventlet.net so we don't crash all over the internet
if url not in seen and 'eventlet.net' in url:
seen.add(url)
pool.spawn_n(fetch, url, q)
pool.waitall()
if q.empty():
break
return seen
seen = producer("http://eventlet.net")
print "I saw these urls:"
print "\n".join(seen)
eventlet-0.13.0/examples/distributed_websocket_chat.py 0000644 0001750 0001750 00000007473 12164577340 024064 0 ustar temoto temoto 0000000 0000000 """This is a websocket chat example with many servers. A client can connect to
any of the servers and their messages will be received by all clients connected
to any of the servers.
Run the examples like this:
$ python examples/chat_bridge.py tcp://127.0.0.1:12345 tcp://127.0.0.1:12346
and the servers like this (changing the port for each one obviously):
$ python examples/distributed_websocket_chat.py -p tcp://127.0.0.1:12345 -s tcp://127.0.0.1:12346 7000
So all messages are published to port 12345 and the device forwards all the
messages to 12346 where they are subscribed to
"""
import os, sys
import eventlet
from collections import defaultdict
from eventlet import spawn_n, sleep
from eventlet import wsgi
from eventlet import websocket
from eventlet.green import zmq
from eventlet.hubs import get_hub, use_hub
from uuid import uuid1
use_hub('zeromq')
ctx = zmq.Context()
class IDName(object):
def __init__(self):
self.id = uuid1()
self.name = None
def __str__(self):
if self.name:
return self.name
else:
return str(self.id)
def pack_message(self, msg):
return self, msg
def unpack_message(self, msg):
sender, message = msg
sender_name = 'you said' if sender.id == self.id \
else '%s says' % sender
return "%s: %s" % (sender_name, message)
participants = defaultdict(IDName)
def subscribe_and_distribute(sub_socket):
global participants
while True:
msg = sub_socket.recv_pyobj()
for ws, name_id in participants.items():
to_send = name_id.unpack_message(msg)
if to_send:
try:
ws.send(to_send)
except:
del participants[ws]
@websocket.WebSocketWSGI
def handle(ws):
global pub_socket
name_id = participants[ws]
ws.send("Connected as %s, change name with 'name: new_name'" % name_id)
try:
while True:
m = ws.wait()
if m is None:
break
if m.startswith('name:'):
old_name = str(name_id)
new_name = m.split(':', 1)[1].strip()
name_id.name = new_name
m = 'Changed name from %s' % old_name
pub_socket.send_pyobj(name_id.pack_message(m))
sleep()
finally:
del participants[ws]
def dispatch(environ, start_response):
"""Resolves to the web page or the websocket depending on the path."""
global port
if environ['PATH_INFO'] == '/chat':
return handle(environ, start_response)
else:
start_response('200 OK', [('content-type', 'text/html')])
return [open(os.path.join(
os.path.dirname(__file__),
'websocket_chat.html')).read() % dict(port=port)]
port = None
if __name__ == "__main__":
usage = 'usage: websocket_chat -p pub address -s sub address port number'
if len (sys.argv) != 6:
print usage
sys.exit(1)
pub_addr = sys.argv[2]
sub_addr = sys.argv[4]
try:
port = int(sys.argv[5])
except ValueError:
print "Error port supplied couldn't be converted to int\n", usage
sys.exit(1)
try:
pub_socket = ctx.socket(zmq.PUB)
pub_socket.connect(pub_addr)
print "Publishing to %s" % pub_addr
sub_socket = ctx.socket(zmq.SUB)
sub_socket.connect(sub_addr)
sub_socket.setsockopt(zmq.SUBSCRIBE, "")
print "Subscribing to %s" % sub_addr
except:
print "Couldn't create sockets\n", usage
sys.exit(1)
spawn_n(subscribe_and_distribute, sub_socket)
listener = eventlet.listen(('127.0.0.1', port))
print "\nVisit http://localhost:%s/ in your websocket-capable browser.\n" % port
wsgi.server(listener, dispatch)
eventlet-0.13.0/examples/recursive_crawler.py 0000644 0001750 0001750 00000003413 12164577340 022211 0 ustar temoto temoto 0000000 0000000 """This is a recursive web crawler. Don't go pointing this at random sites;
it doesn't respect robots.txt and it is pretty brutal about how quickly it
fetches pages.
The code for this is very short; this is perhaps a good indication
that this is making the most effective use of the primitves at hand.
The fetch function does all the work of making http requests,
searching for new urls, and dispatching new fetches. The GreenPool
acts as sort of a job coordinator (and concurrency controller of
course).
"""
from __future__ import with_statement
from eventlet.green import urllib2
import eventlet
import re
# http://daringfireball.net/2009/11/liberal_regex_for_matching_urls
url_regex = re.compile(r'\b(([\w-]+://?|www[.])[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/)))')
def fetch(url, seen, pool):
"""Fetch a url, stick any found urls into the seen set, and
dispatch any new ones to the pool."""
print "fetching", url
data = ''
with eventlet.Timeout(5, False):
data = urllib2.urlopen(url).read()
for url_match in url_regex.finditer(data):
new_url = url_match.group(0)
# only send requests to eventlet.net so as not to destroy the internet
if new_url not in seen and 'eventlet.net' in new_url:
seen.add(new_url)
# while this seems stack-recursive, it's actually not:
# spawned greenthreads start their own stacks
pool.spawn_n(fetch, new_url, seen, pool)
def crawl(start_url):
"""Recursively crawl starting from *start_url*. Returns a set of
urls that were found."""
pool = eventlet.GreenPool()
seen = set()
fetch(start_url, seen, pool)
pool.waitall()
return seen
seen = crawl("http://eventlet.net")
print "I saw these urls:"
print "\n".join(seen)
eventlet-0.13.0/examples/forwarder.py 0000644 0001750 0001750 00000001556 12164577340 020464 0 ustar temoto temoto 0000000 0000000 """ This is an incredibly simple port forwarder from port 7000 to 22 on
localhost. It calls a callback function when the socket is closed, to
demonstrate one way that you could start to do interesting things by
starting from a simple framework like this.
"""
import eventlet
def closed_callback():
print "called back"
def forward(source, dest, cb = lambda: None):
"""Forwards bytes unidirectionally from source to dest"""
while True:
d = source.recv(32384)
if d == '':
cb()
break
dest.sendall(d)
listener = eventlet.listen(('localhost', 7000))
while True:
client, addr = listener.accept()
server = eventlet.connect(('localhost', 22))
# two unidirectional forwarders make a bidirectional one
eventlet.spawn_n(forward, client, server, closed_callback)
eventlet.spawn_n(forward, server, client)
eventlet-0.13.0/examples/echoserver.py 0000644 0001750 0001750 00000001607 12164577340 020633 0 ustar temoto temoto 0000000 0000000 #! /usr/bin/env python
"""\
Simple server that listens on port 6000 and echos back every input to
the client. To try out the server, start it up by running this file.
Connect to it with:
telnet localhost 6000
You terminate your connection by terminating telnet (typically Ctrl-]
and then 'quit')
"""
import eventlet
def handle(fd):
print "client connected"
while True:
# pass through every non-eof line
x = fd.readline()
if not x: break
fd.write(x)
fd.flush()
print "echoed", x,
print "client disconnected"
print "server socket listening on port 6000"
server = eventlet.listen(('0.0.0.0', 6000))
pool = eventlet.GreenPool()
while True:
try:
new_sock, address = server.accept()
print "accepted", address
pool.spawn_n(handle, new_sock.makefile('rw'))
except (SystemExit, KeyboardInterrupt):
break
eventlet-0.13.0/examples/chat_bridge.py 0000644 0001750 0001750 00000001035 12164577340 020714 0 ustar temoto temoto 0000000 0000000 import sys
from zmq import FORWARDER, PUB, SUB, SUBSCRIBE
from zmq.devices import Device
if __name__ == "__main__":
usage = 'usage: chat_bridge sub_address pub_address'
if len (sys.argv) != 3:
print usage
sys.exit(1)
sub_addr = sys.argv[1]
pub_addr = sys.argv[2]
print "Recieving on %s" % sub_addr
print "Sending on %s" % pub_addr
device = Device(FORWARDER, SUB, PUB)
device.bind_in(sub_addr)
device.setsockopt_in(SUBSCRIBE, "")
device.bind_out(pub_addr)
device.start()
eventlet-0.13.0/examples/chat_server.py 0000644 0001750 0001750 00000002242 12164577340 020767 0 ustar temoto temoto 0000000 0000000 import eventlet
from eventlet.green import socket
PORT=3001
participants = set()
def read_chat_forever(writer, reader):
line = reader.readline()
while line:
print "Chat:", line.strip()
for p in participants:
try:
if p is not writer: # Don't echo
p.write(line)
p.flush()
except socket.error, e:
# ignore broken pipes, they just mean the participant
# closed its connection already
if e[0] != 32:
raise
line = reader.readline()
participants.remove(writer)
print "Participant left chat."
try:
print "ChatServer starting up on port %s" % PORT
server = eventlet.listen(('0.0.0.0', PORT))
while True:
new_connection, address = server.accept()
print "Participant joined chat."
new_writer = new_connection.makefile('w')
participants.add(new_writer)
eventlet.spawn_n(read_chat_forever,
new_writer,
new_connection.makefile('r'))
except (KeyboardInterrupt, SystemExit):
print "ChatServer exiting."
eventlet-0.13.0/examples/twisted/ 0000755 0001750 0001750 00000000000 12164600754 017567 5 ustar temoto temoto 0000000 0000000 eventlet-0.13.0/examples/twisted/twisted_http_proxy.py 0000644 0001750 0001750 00000004343 12164577340 024134 0 ustar temoto temoto 0000000 0000000 """Listen on port 8888 and pretend to be an HTTP proxy.
It even works for some pages.
Demonstrates how to
* plug in eventlet into a twisted application (join_reactor)
* call green functions from places where blocking calls
are not allowed (deferToGreenThread)
* use eventlet.green package which provides [some of] the
standard library modules that don't block other greenlets.
"""
import re
from twisted.internet.protocol import Factory
from twisted.internet import reactor
from twisted.protocols import basic
from eventlet.twistedutil import deferToGreenThread
from eventlet.twistedutil import join_reactor
from eventlet.green import httplib
class LineOnlyReceiver(basic.LineOnlyReceiver):
def connectionMade(self):
self.lines = []
def lineReceived(self, line):
if line:
self.lines.append(line)
elif self.lines:
self.requestReceived(self.lines)
self.lines = []
def requestReceived(self, lines):
request = re.match('^(\w+) http://(.*?)(/.*?) HTTP/1..$', lines[0])
#print request.groups()
method, host, path = request.groups()
headers = dict(x.split(': ', 1) for x in lines[1:])
def callback(result):
self.transport.write(str(result))
self.transport.loseConnection()
def errback(err):
err.printTraceback()
self.transport.loseConnection()
d = deferToGreenThread(http_request, method, host, path, headers=headers)
d.addCallbacks(callback, errback)
def http_request(method, host, path, headers):
conn = httplib.HTTPConnection(host)
conn.request(method, path, headers=headers)
response = conn.getresponse()
body = response.read()
print method, host, path, response.status, response.reason, len(body)
return format_response(response, body)
def format_response(response, body):
result = "HTTP/1.1 %s %s" % (response.status, response.reason)
for k, v in response.getheaders():
result += '\r\n%s: %s' % (k, v)
if body:
result += '\r\n\r\n'
result += body
result += '\r\n'
return result
class MyFactory(Factory):
protocol = LineOnlyReceiver
print __doc__
reactor.listenTCP(8888, MyFactory())
reactor.run()
eventlet-0.13.0/examples/twisted/twisted_client.py 0000644 0001750 0001750 00000001605 12164577340 023170 0 ustar temoto temoto 0000000 0000000 """Example for GreenTransport and GreenClientCreator.
In this example reactor is started implicitly upon the first
use of a blocking function.
"""
from twisted.internet import ssl
from twisted.internet.error import ConnectionClosed
from eventlet.twistedutil.protocol import GreenClientCreator
from eventlet.twistedutil.protocols.basic import LineOnlyReceiverTransport
from twisted.internet import reactor
# read from TCP connection
conn = GreenClientCreator(reactor).connectTCP('www.google.com', 80)
conn.write('GET / HTTP/1.0\r\n\r\n')
conn.loseWriteConnection()
print conn.read()
# read from SSL connection line by line
conn = GreenClientCreator(reactor, LineOnlyReceiverTransport).connectSSL('sf.net', 443, ssl.ClientContextFactory())
conn.write('GET / HTTP/1.0\r\n\r\n')
try:
for num, line in enumerate(conn):
print '%3s %r' % (num, line)
except ConnectionClosed, ex:
print ex
eventlet-0.13.0/examples/twisted/twisted_server.py 0000644 0001750 0001750 00000002623 12164577340 023221 0 ustar temoto temoto 0000000 0000000 """Simple chat demo application.
Listen on port 8007 and re-send all the data received to other participants.
Demonstrates how to
* plug in eventlet into a twisted application (join_reactor)
* how to use SpawnFactory to start a new greenlet for each new request.
"""
from eventlet.twistedutil import join_reactor
from eventlet.twistedutil.protocol import SpawnFactory
from eventlet.twistedutil.protocols.basic import LineOnlyReceiverTransport
class Chat:
def __init__(self):
self.participants = []
def handler(self, conn):
peer = conn.getPeer()
print 'new connection from %s' % (peer, )
conn.write("Welcome! There're %s participants already\n" % (len(self.participants)))
self.participants.append(conn)
try:
for line in conn:
if line:
print 'received from %s: %s' % (peer, line)
for buddy in self.participants:
if buddy is not conn:
buddy.sendline('from %s: %s' % (peer, line))
except Exception, ex:
print peer, ex
else:
print peer, 'connection done'
finally:
conn.loseConnection()
self.participants.remove(conn)
print __doc__
chat = Chat()
from twisted.internet import reactor
reactor.listenTCP(8007, SpawnFactory(chat.handler, LineOnlyReceiverTransport))
reactor.run()
eventlet-0.13.0/examples/twisted/twisted_srvconnector.py 0000644 0001750 0001750 00000002146 12164577340 024440 0 ustar temoto temoto 0000000 0000000 from twisted.internet import reactor
from twisted.names.srvconnect import SRVConnector
from gnutls.interfaces.twisted import X509Credentials
from eventlet.twistedutil.protocol import GreenClientCreator
from eventlet.twistedutil.protocols.basic import LineOnlyReceiverTransport
class NoisySRVConnector(SRVConnector):
def pickServer(self):
host, port = SRVConnector.pickServer(self)
print 'Resolved _%s._%s.%s --> %s:%s' % (self.service, self.protocol, self.domain, host, port)
return host, port
cred = X509Credentials(None, None)
creator = GreenClientCreator(reactor, LineOnlyReceiverTransport)
conn = creator.connectSRV('msrps', 'ag-projects.com',
connectFuncName='connectTLS', connectFuncArgs=(cred,),
ConnectorClass=NoisySRVConnector)
request = """MSRP 49fh AUTH
To-Path: msrps://alice@intra.example.com;tcp
From-Path: msrps://alice.example.com:9892/98cjs;tcp
-------49fh$
""".replace('\n', '\r\n')
print 'Sending:\n%s' % request
conn.write(request)
print 'Received:'
for x in conn:
print repr(x)
if '-------' in x:
break
eventlet-0.13.0/examples/twisted/twisted_xcap_proxy.py 0000644 0001750 0001750 00000002027 12164577340 024105 0 ustar temoto temoto 0000000 0000000 from twisted.internet.protocol import Factory
from twisted.internet import reactor
from twisted.protocols import basic
from xcaplib.green import XCAPClient
from eventlet.twistedutil import deferToGreenThread
from eventlet.twistedutil import join_reactor
class LineOnlyReceiver(basic.LineOnlyReceiver):
def lineReceived(self, line):
print 'received: %r' % line
if not line:
return
app, context, node = (line + ' ').split(' ', 3)
context = {'u' : 'users', 'g': 'global'}.get(context, context)
d = deferToGreenThread(client._get, app, node, globaltree=context=='global')
def callback(result):
self.transport.write(str(result))
def errback(error):
self.transport.write(error.getTraceback())
d.addCallback(callback)
d.addErrback(errback)
class MyFactory(Factory):
protocol = LineOnlyReceiver
client = XCAPClient('https://xcap.sipthor.net/xcap-root', 'alice@example.com', '123')
reactor.listenTCP(8007, MyFactory())
reactor.run()
eventlet-0.13.0/examples/twisted/twisted_portforward.py 0000644 0001750 0001750 00000002206 12164577340 024261 0 ustar temoto temoto 0000000 0000000 """Port forwarder
USAGE: twisted_portforward.py local_port remote_host remote_port"""
import sys
from twisted.internet import reactor
from eventlet.twistedutil import join_reactor
from eventlet.twistedutil.protocol import GreenClientCreator, SpawnFactory, UnbufferedTransport
from eventlet import proc
def forward(source, dest):
try:
while True:
x = source.recv()
if not x:
break
print 'forwarding %s bytes' % len(x)
dest.write(x)
finally:
dest.loseConnection()
def handler(local):
client = str(local.getHost())
print 'accepted connection from %s' % client
remote = GreenClientCreator(reactor, UnbufferedTransport).connectTCP(remote_host, remote_port)
a = proc.spawn(forward, remote, local)
b = proc.spawn(forward, local, remote)
proc.waitall([a, b], trap_errors=True)
print 'closed connection to %s' % client
try:
local_port, remote_host, remote_port = sys.argv[1:]
except ValueError:
sys.exit(__doc__)
local_port = int(local_port)
remote_port = int(remote_port)
reactor.listenTCP(local_port, SpawnFactory(handler))
reactor.run()
eventlet-0.13.0/examples/connect.py 0000644 0001750 0001750 00000001315 12164577340 020113 0 ustar temoto temoto 0000000 0000000 """Spawn multiple workers and collect their results.
Demonstrates how to use the eventlet.green.socket module.
"""
import eventlet
from eventlet.green import socket
def geturl(url):
c = socket.socket()
ip = socket.gethostbyname(url)
c.connect((ip, 80))
print '%s connected' % url
c.sendall('GET /\r\n\r\n')
return c.recv(1024)
urls = ['www.google.com', 'www.yandex.ru', 'www.python.org']
pile = eventlet.GreenPile()
for x in urls:
pile.spawn(geturl, x)
# note that the pile acts as a collection of return values from the functions
# if any exceptions are raised by the function they'll get raised here
for url, result in zip(urls, pile):
print '%s: %s' % (url, repr(result)[:50])
eventlet-0.13.0/examples/feedscraper-testclient.py 0000644 0001750 0001750 00000001452 12164577340 023123 0 ustar temoto temoto 0000000 0000000 from eventlet.green import urllib2
big_list_of_feeds = """
http://blog.eventlet.net/feed/
http://rss.slashdot.org/Slashdot/slashdot
http://feeds.boingboing.net/boingboing/iBag
http://feeds.feedburner.com/RockPaperShotgun
http://feeds.penny-arcade.com/pa-mainsite
http://achewood.com/rss.php
http://raysmuckles.blogspot.com/atom.xml
http://rbeef.blogspot.com/atom.xml
http://journeyintoreason.blogspot.com/atom.xml
http://orezscu.blogspot.com/atom.xml
http://feeds2.feedburner.com/AskMetafilter
http://feeds2.feedburner.com/Metafilter
http://stackoverflow.com/feeds
http://feeds.feedburner.com/codinghorror
http://www.tbray.org/ongoing/ongoing.atom
http://www.zeldman.com/feed/
http://ln.hixie.ch/rss/html
"""
url = 'http://localhost:9010/'
result = urllib2.urlopen(url, big_list_of_feeds)
print result.read() eventlet-0.13.0/PKG-INFO 0000644 0001750 0001750 00000006117 12164600754 015370 0 ustar temoto temoto 0000000 0000000 Metadata-Version: 1.1
Name: eventlet
Version: 0.13.0
Summary: Highly concurrent networking library
Home-page: http://eventlet.net
Author: Linden Lab
Author-email: eventletdev@lists.secondlife.com
License: UNKNOWN
Description: Eventlet is a concurrent networking library for Python that allows you to change how you run your code, not how you write it.
It uses epoll or libevent for highly scalable non-blocking I/O. Coroutines ensure that the developer uses a blocking style of programming that is similar to threading, but provide the benefits of non-blocking I/O. The event dispatch is implicit, which means you can easily use Eventlet from the Python interpreter, or as a small part of a larger application.
It's easy to get started using Eventlet, and easy to convert existing
applications to use it. Start off by looking at the `examples`_,
`common design patterns`_, and the list of `basic API primitives`_.
.. _examples: http://eventlet.net/doc/examples.html
.. _common design patterns: http://eventlet.net/doc/design_patterns.html
.. _basic API primitives: http://eventlet.net/doc/basic_usage.html
Quick Example
===============
Here's something you can try right on the command line::
% python
>>> import eventlet
>>> from eventlet.green import urllib2
>>> gt = eventlet.spawn(urllib2.urlopen, 'http://eventlet.net')
>>> gt2 = eventlet.spawn(urllib2.urlopen, 'http://secondlife.com')
>>> gt2.wait()
>>> gt.wait()
Getting Eventlet
==================
The easiest way to get Eventlet is to use easy_install or pip::
easy_install eventlet
pip install eventlet
The development `tip`_ is available via easy_install as well::
easy_install 'eventlet==dev'
pip install 'eventlet==dev'
.. _tip: http://bitbucket.org/eventlet/eventlet/get/tip.zip#egg=eventlet-dev
Building the Docs Locally
=========================
To build a complete set of HTML documentation, you must have Sphinx, which can be found at http://sphinx.pocoo.org/ (or installed with `easy_install sphinx`)
cd doc
make html
The built html files can be found in doc/_build/html afterward.
Platform: UNKNOWN
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python
Classifier: Operating System :: MacOS :: MacOS X
Classifier: Operating System :: POSIX
Classifier: Operating System :: Microsoft :: Windows
Classifier: Programming Language :: Python :: 2.4
Classifier: Programming Language :: Python :: 2.5
Classifier: Programming Language :: Python :: 2.6
Classifier: Programming Language :: Python :: 2.7
Classifier: Topic :: Internet
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Intended Audience :: Developers
Classifier: Development Status :: 4 - Beta
eventlet-0.13.0/eventlet/ 0000755 0001750 0001750 00000000000 12164600754 016114 5 ustar temoto temoto 0000000 0000000 eventlet-0.13.0/eventlet/websocket.py 0000644 0001750 0001750 00000023666 12164577340 020475 0 ustar temoto temoto 0000000 0000000 import collections
import errno
import string
import struct
from socket import error as SocketError
try:
from hashlib import md5
except ImportError: #pragma NO COVER
from md5 import md5
import eventlet
from eventlet import semaphore
from eventlet import wsgi
from eventlet.green import socket
from eventlet.support import get_errno
ACCEPTABLE_CLIENT_ERRORS = set((errno.ECONNRESET, errno.EPIPE))
__all__ = ["WebSocketWSGI", "WebSocket"]
class WebSocketWSGI(object):
"""Wraps a websocket handler function in a WSGI application.
Use it like this::
@websocket.WebSocketWSGI
def my_handler(ws):
from_browser = ws.wait()
ws.send("from server")
The single argument to the function will be an instance of
:class:`WebSocket`. To close the socket, simply return from the
function. Note that the server will log the websocket request at
the time of closure.
"""
def __init__(self, handler):
self.handler = handler
self.protocol_version = None
def __call__(self, environ, start_response):
if not (environ.get('HTTP_CONNECTION') == 'Upgrade' and
environ.get('HTTP_UPGRADE') == 'WebSocket'):
# need to check a few more things here for true compliance
start_response('400 Bad Request', [('Connection','close')])
return []
# See if they sent the new-format headers
if 'HTTP_SEC_WEBSOCKET_KEY1' in environ:
self.protocol_version = 76
if 'HTTP_SEC_WEBSOCKET_KEY2' not in environ:
# That's bad.
start_response('400 Bad Request', [('Connection','close')])
return []
else:
self.protocol_version = 75
# Get the underlying socket and wrap a WebSocket class around it
sock = environ['eventlet.input'].get_socket()
ws = WebSocket(sock, environ, self.protocol_version)
# If it's new-version, we need to work out our challenge response
if self.protocol_version == 76:
key1 = self._extract_number(environ['HTTP_SEC_WEBSOCKET_KEY1'])
key2 = self._extract_number(environ['HTTP_SEC_WEBSOCKET_KEY2'])
# There's no content-length header in the request, but it has 8
# bytes of data.
environ['wsgi.input'].content_length = 8
key3 = environ['wsgi.input'].read(8)
key = struct.pack(">II", key1, key2) + key3
response = md5(key).digest()
# Start building the response
scheme = 'ws'
if environ.get('wsgi.url_scheme') == 'https':
scheme = 'wss'
location = '%s://%s%s%s' % (
scheme,
environ.get('HTTP_HOST'),
environ.get('SCRIPT_NAME'),
environ.get('PATH_INFO')
)
qs = environ.get('QUERY_STRING')
if qs is not None:
location += '?' + qs
if self.protocol_version == 75:
handshake_reply = ("HTTP/1.1 101 Web Socket Protocol Handshake\r\n"
"Upgrade: WebSocket\r\n"
"Connection: Upgrade\r\n"
"WebSocket-Origin: %s\r\n"
"WebSocket-Location: %s\r\n\r\n" % (
environ.get('HTTP_ORIGIN'),
location))
elif self.protocol_version == 76:
handshake_reply = ("HTTP/1.1 101 WebSocket Protocol Handshake\r\n"
"Upgrade: WebSocket\r\n"
"Connection: Upgrade\r\n"
"Sec-WebSocket-Origin: %s\r\n"
"Sec-WebSocket-Protocol: %s\r\n"
"Sec-WebSocket-Location: %s\r\n"
"\r\n%s"% (
environ.get('HTTP_ORIGIN'),
environ.get('HTTP_SEC_WEBSOCKET_PROTOCOL', 'default'),
location,
response))
else: #pragma NO COVER
raise ValueError("Unknown WebSocket protocol version.")
sock.sendall(handshake_reply)
try:
self.handler(ws)
except socket.error, e:
if get_errno(e) not in ACCEPTABLE_CLIENT_ERRORS:
raise
# Make sure we send the closing frame
ws._send_closing_frame(True)
# use this undocumented feature of eventlet.wsgi to ensure that it
# doesn't barf on the fact that we didn't call start_response
return wsgi.ALREADY_HANDLED
def _extract_number(self, value):
"""
Utility function which, given a string like 'g98sd 5[]221@1', will
return 9852211. Used to parse the Sec-WebSocket-Key headers.
"""
out = ""
spaces = 0
for char in value:
if char in string.digits:
out += char
elif char == " ":
spaces += 1
return int(out) / spaces
class WebSocket(object):
"""A websocket object that handles the details of
serialization/deserialization to the socket.
The primary way to interact with a :class:`WebSocket` object is to
call :meth:`send` and :meth:`wait` in order to pass messages back
and forth with the browser. Also available are the following
properties:
path
The path value of the request. This is the same as the WSGI PATH_INFO variable, but more convenient.
protocol
The value of the Websocket-Protocol header.
origin
The value of the 'Origin' header.
environ
The full WSGI environment for this request.
"""
def __init__(self, sock, environ, version=76):
"""
:param socket: The eventlet socket
:type socket: :class:`eventlet.greenio.GreenSocket`
:param environ: The wsgi environment
:param version: The WebSocket spec version to follow (default is 76)
"""
self.socket = sock
self.origin = environ.get('HTTP_ORIGIN')
self.protocol = environ.get('HTTP_WEBSOCKET_PROTOCOL')
self.path = environ.get('PATH_INFO')
self.environ = environ
self.version = version
self.websocket_closed = False
self._buf = ""
self._msgs = collections.deque()
self._sendlock = semaphore.Semaphore()
@staticmethod
def _pack_message(message):
"""Pack the message inside ``00`` and ``FF``
As per the dataframing section (5.3) for the websocket spec
"""
if isinstance(message, unicode):
message = message.encode('utf-8')
elif not isinstance(message, str):
message = str(message)
packed = "\x00%s\xFF" % message
return packed
def _parse_messages(self):
""" Parses for messages in the buffer *buf*. It is assumed that
the buffer contains the start character for a message, but that it
may contain only part of the rest of the message.
Returns an array of messages, and the buffer remainder that
didn't contain any full messages."""
msgs = []
end_idx = 0
buf = self._buf
while buf:
frame_type = ord(buf[0])
if frame_type == 0:
# Normal message.
end_idx = buf.find("\xFF")
if end_idx == -1: #pragma NO COVER
break
msgs.append(buf[1:end_idx].decode('utf-8', 'replace'))
buf = buf[end_idx+1:]
elif frame_type == 255:
# Closing handshake.
assert ord(buf[1]) == 0, "Unexpected closing handshake: %r" % buf
self.websocket_closed = True
break
else:
raise ValueError("Don't understand how to parse this type of message: %r" % buf)
self._buf = buf
return msgs
def send(self, message):
"""Send a message to the browser.
*message* should be convertable to a string; unicode objects should be
encodable as utf-8. Raises socket.error with errno of 32
(broken pipe) if the socket has already been closed by the client."""
packed = self._pack_message(message)
# if two greenthreads are trying to send at the same time
# on the same socket, sendlock prevents interleaving and corruption
self._sendlock.acquire()
try:
self.socket.sendall(packed)
finally:
self._sendlock.release()
def wait(self):
"""Waits for and deserializes messages.
Returns a single message; the oldest not yet processed. If the client
has already closed the connection, returns None. This is different
from normal socket behavior because the empty string is a valid
websocket message."""
while not self._msgs:
# Websocket might be closed already.
if self.websocket_closed:
return None
# no parsed messages, must mean buf needs more data
delta = self.socket.recv(8096)
if delta == '':
return None
self._buf += delta
msgs = self._parse_messages()
self._msgs.extend(msgs)
return self._msgs.popleft()
def _send_closing_frame(self, ignore_send_errors=False):
"""Sends the closing frame to the client, if required."""
if self.version == 76 and not self.websocket_closed:
try:
self.socket.sendall("\xff\x00")
except SocketError:
# Sometimes, like when the remote side cuts off the connection,
# we don't care about this.
if not ignore_send_errors: #pragma NO COVER
raise
self.websocket_closed = True
def close(self):
"""Forcibly close the websocket; generally it is preferable to
return from the handler method."""
self._send_closing_frame()
self.socket.shutdown(True)
self.socket.close()
eventlet-0.13.0/eventlet/hubs/ 0000755 0001750 0001750 00000000000 12164600754 017055 5 ustar temoto temoto 0000000 0000000 eventlet-0.13.0/eventlet/hubs/pyevent.py 0000644 0001750 0001750 00000012517 12164577340 021133 0 ustar temoto temoto 0000000 0000000 import sys
import traceback
import event
import types
from eventlet.support import greenlets as greenlet
from eventlet.hubs.hub import BaseHub, FdListener, READ, WRITE
class event_wrapper(object):
def __init__(self, impl=None, seconds=None):
self.impl = impl
self.seconds = seconds
def __repr__(self):
if self.impl is not None:
return repr(self.impl)
else:
return object.__repr__(self)
def __str__(self):
if self.impl is not None:
return str(self.impl)
else:
return object.__str__(self)
def cancel(self):
if self.impl is not None:
self.impl.delete()
self.impl = None
@property
def pending(self):
return bool(self.impl and self.impl.pending())
class Hub(BaseHub):
SYSTEM_EXCEPTIONS = (KeyboardInterrupt, SystemExit)
def __init__(self):
super(Hub,self).__init__()
event.init()
self.signal_exc_info = None
self.signal(
2,
lambda signalnum, frame: self.greenlet.parent.throw(KeyboardInterrupt))
self.events_to_add = []
def dispatch(self):
loop = event.loop
while True:
for e in self.events_to_add:
if e is not None and e.impl is not None and e.seconds is not None:
e.impl.add(e.seconds)
e.seconds = None
self.events_to_add = []
result = loop()
if getattr(event, '__event_exc', None) is not None:
# only have to do this because of bug in event.loop
t = getattr(event, '__event_exc')
setattr(event, '__event_exc', None)
assert getattr(event, '__event_exc') is None
raise t[0], t[1], t[2]
if result != 0:
return result
def run(self):
while True:
try:
self.dispatch()
except greenlet.GreenletExit:
break
except self.SYSTEM_EXCEPTIONS:
raise
except:
if self.signal_exc_info is not None:
self.schedule_call_global(
0, greenlet.getcurrent().parent.throw, *self.signal_exc_info)
self.signal_exc_info = None
else:
self.squelch_timer_exception(None, sys.exc_info())
def abort(self, wait=True):
self.schedule_call_global(0, self.greenlet.throw, greenlet.GreenletExit)
if wait:
assert self.greenlet is not greenlet.getcurrent(), "Can't abort with wait from inside the hub's greenlet."
self.switch()
def _getrunning(self):
return bool(self.greenlet)
def _setrunning(self, value):
pass # exists for compatibility with BaseHub
running = property(_getrunning, _setrunning)
def add(self, evtype, fileno, real_cb):
# this is stupid: pyevent won't call a callback unless it's a function,
# so we have to force it to be one here
if isinstance(real_cb, types.BuiltinMethodType):
def cb(_d):
real_cb(_d)
else:
cb = real_cb
if evtype is READ:
evt = event.read(fileno, cb, fileno)
elif evtype is WRITE:
evt = event.write(fileno, cb, fileno)
return super(Hub,self).add(evtype, fileno, evt)
def signal(self, signalnum, handler):
def wrapper():
try:
handler(signalnum, None)
except:
self.signal_exc_info = sys.exc_info()
event.abort()
return event_wrapper(event.signal(signalnum, wrapper))
def remove(self, listener):
super(Hub, self).remove(listener)
listener.cb.delete()
def remove_descriptor(self, fileno):
for lcontainer in self.listeners.itervalues():
listener = lcontainer.pop(fileno, None)
if listener:
try:
listener.cb.delete()
except self.SYSTEM_EXCEPTIONS:
raise
except:
traceback.print_exc()
def schedule_call_local(self, seconds, cb, *args, **kwargs):
current = greenlet.getcurrent()
if current is self.greenlet:
return self.schedule_call_global(seconds, cb, *args, **kwargs)
event_impl = event.event(_scheduled_call_local, (cb, args, kwargs, current))
wrapper = event_wrapper(event_impl, seconds=seconds)
self.events_to_add.append(wrapper)
return wrapper
schedule_call = schedule_call_local
def schedule_call_global(self, seconds, cb, *args, **kwargs):
event_impl = event.event(_scheduled_call, (cb, args, kwargs))
wrapper = event_wrapper(event_impl, seconds=seconds)
self.events_to_add.append(wrapper)
return wrapper
def _version_info(self):
baseversion = event.__version__
return baseversion
def _scheduled_call(event_impl, handle, evtype, arg):
cb, args, kwargs = arg
try:
cb(*args, **kwargs)
finally:
event_impl.delete()
def _scheduled_call_local(event_impl, handle, evtype, arg):
cb, args, kwargs, caller_greenlet = arg
try:
if not caller_greenlet.dead:
cb(*args, **kwargs)
finally:
event_impl.delete()
eventlet-0.13.0/eventlet/hubs/timer.py 0000644 0001750 0001750 00000006174 12164577340 020563 0 ustar temoto temoto 0000000 0000000 from eventlet.support import greenlets as greenlet
from eventlet.hubs import get_hub
""" If true, captures a stack trace for each timer when constructed. This is
useful for debugging leaking timers, to find out where the timer was set up. """
_g_debug = False
class Timer(object):
def __init__(self, seconds, cb, *args, **kw):
"""Create a timer.
seconds: The minimum number of seconds to wait before calling
cb: The callback to call when the timer has expired
*args: The arguments to pass to cb
**kw: The keyword arguments to pass to cb
This timer will not be run unless it is scheduled in a runloop by
calling timer.schedule() or runloop.add_timer(timer).
"""
self.seconds = seconds
self.tpl = cb, args, kw
self.called = False
if _g_debug:
import traceback, cStringIO
self.traceback = cStringIO.StringIO()
traceback.print_stack(file=self.traceback)
@property
def pending(self):
return not self.called
def __repr__(self):
secs = getattr(self, 'seconds', None)
cb, args, kw = getattr(self, 'tpl', (None, None, None))
retval = "Timer(%s, %s, *%s, **%s)" % (
secs, cb, args, kw)
if _g_debug and hasattr(self, 'traceback'):
retval += '\n' + self.traceback.getvalue()
return retval
def copy(self):
cb, args, kw = self.tpl
return self.__class__(self.seconds, cb, *args, **kw)
def schedule(self):
"""Schedule this timer to run in the current runloop.
"""
self.called = False
self.scheduled_time = get_hub().add_timer(self)
return self
def __call__(self, *args):
if not self.called:
self.called = True
cb, args, kw = self.tpl
try:
cb(*args, **kw)
finally:
try:
del self.tpl
except AttributeError:
pass
def cancel(self):
"""Prevent this timer from being called. If the timer has already
been called or canceled, has no effect.
"""
if not self.called:
self.called = True
get_hub().timer_canceled(self)
try:
del self.tpl
except AttributeError:
pass
# No default ordering in 3.x. heapq uses <
# FIXME should full set be added?
def __lt__(self, other):
return id(self)