/usr/lib/python2.7/dist-packages/praw/multiprocess.py is in python-praw 3.3.0-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | """Provides a request server to be used with the multiprocess handler."""
from __future__ import print_function, unicode_literals
import socket
import sys
from optparse import OptionParser
from praw import __version__
from praw.handlers import DefaultHandler
from requests import Session
from six.moves import cPickle, socketserver # pylint: disable=F0401
from threading import Lock
class ThreadingTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
# pylint: disable=R0903,W0232
"""A TCP server that creates new threads per connection."""
allow_reuse_address = True
@staticmethod
def handle_error(_, client_addr):
"""Mute tracebacks of common errors."""
exc_type, exc_value, _ = sys.exc_info()
if exc_type is socket.error and exc_value[0] == 32:
pass
elif exc_type is cPickle.UnpicklingError:
sys.stderr.write('Invalid connection from {0}\n'
.format(client_addr[0]))
else:
raise
class RequestHandler(socketserver.StreamRequestHandler):
# pylint: disable=W0232
"""A class that handles incoming requests.
Requests to the same domain are cached and rate-limited.
"""
ca_lock = Lock() # lock around cache and timeouts
cache = {} # caches requests
http = Session() # used to make requests
last_call = {} # Stores a two-item list: [lock, previous_call_time]
rl_lock = Lock() # lock used for adding items to last_call
timeouts = {} # store the time items in cache were entered
do_evict = DefaultHandler.evict # Add in the evict method
@staticmethod
def cache_hit_callback(key):
"""Output when a cache hit occurs."""
print('HIT {0} {1}'.format('POST' if key[1][1] else 'GET', key[0]))
@DefaultHandler.with_cache
@DefaultHandler.rate_limit
def do_request(self, request, proxies, timeout, **_):
"""Dispatch the actual request and return the result."""
print('{0} {1}'.format(request.method, request.url))
response = self.http.send(request, proxies=proxies, timeout=timeout,
allow_redirects=False)
response.raw = None # Make pickleable
return response
def handle(self):
"""Parse the RPC, make the call, and pickle up the return value."""
data = cPickle.load(self.rfile) # pylint: disable=E1101
method = data.pop('method')
try:
retval = getattr(self, 'do_{0}'.format(method))(**data)
except Exception as retval: # pylint: disable=W0703
# All exceptions should be passed to the client
pass
cPickle.dump(retval, self.wfile, # pylint: disable=E1101
cPickle.HIGHEST_PROTOCOL)
def run():
"""The entry point from the praw-multiprocess utility."""
parser = OptionParser(version='%prog {0}'.format(__version__))
parser.add_option('-a', '--addr', default='localhost',
help=('The address or host to listen on. Specify -a '
'0.0.0.0 to listen on all addresses. '
'Default: localhost'))
parser.add_option('-p', '--port', type='int', default='10101',
help=('The port to listen for requests on. '
'Default: 10101'))
options, _ = parser.parse_args()
try:
server = ThreadingTCPServer((options.addr, options.port),
RequestHandler)
except (socket.error, socket.gaierror) as exc: # Handle bind errors
print(exc)
sys.exit(1)
print('Listening on {0} port {1}'.format(options.addr, options.port))
try:
server.serve_forever() # pylint: disable=E1101
except KeyboardInterrupt:
server.socket.close() # pylint: disable=E1101
RequestHandler.http.close()
print('Goodbye!')
|