##// END OF EJS Templates
hgweb: create dedicated type for WSGI responses...
hgweb: create dedicated type for WSGI responses We have refactored the request side of WSGI processing into a dedicated type. Now let's do the same thing for the response side. We invent a ``wsgiresponse`` type. It takes an instance of a request (for consulation) and the WSGI application's "start_response" handler. The type basically allows setting the HTTP status line, response headers, and the response body. The WSGI application calls sendresponse() to start sending output. Output is emitted as a generator to be fed through the WSGI application. According to PEP 3333, this is the preferred way for output to be transmitted. (Our legacy ``wsgirequest`` exposed a write() to send data. We do not wish to support this API because it isn't recommended by PEP 3333.) The wire protocol code has been ported to use the new API. Differential Revision: https://phab.mercurial-scm.org/D2775

File last commit:

r34734:115efdd9 default
r36877:a88d68dc default
Show More
peer.py
100 lines | 3.2 KiB | text/x-python | PythonLexer
Peter Arrenbrecht
peer: introduce real peer classes...
r17192 # peer.py - repository base classes for mercurial
#
# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
# Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
Gregory Szorc
peer: use absolute_import
r25965 from __future__ import absolute_import
from . import (
error,
Augie Fackler
peer: ensure command names are always ascii bytestrs...
r34734 pycompat,
Gregory Szorc
peer: use absolute_import
r25965 util,
)
Augie Fackler
batching: migrate basic noop batching into peer.peer...
r25912
# abstract batching support
class future(object):
'''placeholder for a value to be set later'''
def set(self, value):
if util.safehasattr(self, 'value'):
raise error.RepoError("future is already set")
self.value = value
class batcher(object):
'''base class for batches of commands submittable in a single request
All methods invoked on instances of this class are simply queued and
return a a future for the result. Once you call submit(), all the queued
calls are performed and the results set in their respective futures.
'''
def __init__(self):
self.calls = []
def __getattr__(self, name):
def call(*args, **opts):
resref = future()
Augie Fackler
peer: when collecting method names for batch calls, bytes-ify __name__...
r34728 # Please don't invent non-ascii method names, or you will
# give core hg a very sad time.
self.calls.append((name.encode('ascii'), args, opts, resref,))
Augie Fackler
batching: migrate basic noop batching into peer.peer...
r25912 return resref
return call
def submit(self):
Augie Fackler
peer: raise NotImplementedError for abstract submit() method...
r28434 raise NotImplementedError()
Augie Fackler
batching: migrate basic noop batching into peer.peer...
r25912
Augie Fackler
peer: add an iterbatcher interface...
r28436 class iterbatcher(batcher):
def submit(self):
raise NotImplementedError()
def results(self):
raise NotImplementedError()
class localiterbatcher(iterbatcher):
def __init__(self, local):
super(iterbatcher, self).__init__()
self.local = local
def submit(self):
# submit for a local iter batcher is a noop
pass
def results(self):
for name, args, opts, resref in self.calls:
Gregory Szorc
wireproto: overhaul iterating batcher code (API)...
r33761 resref.set(getattr(self.local, name)(*args, **opts))
yield resref.value
Augie Fackler
peer: add an iterbatcher interface...
r28436
Augie Fackler
batching: migrate basic noop batching into peer.peer...
r25912 def batchable(f):
'''annotation for batchable methods
Such methods must implement a coroutine as follows:
@batchable
def sample(self, one, two=None):
# Build list of encoded arguments suitable for your wire protocol:
encargs = [('one', encode(one),), ('two', encode(two),)]
# Create future for injection of encoded result:
encresref = future()
# Return encoded arguments and future:
yield encargs, encresref
# Assuming the future to be filled with the result from the batched
# request now. Decode it:
yield decode(encresref.value)
The decorator returns a function which wraps this coroutine as a plain
method, but adds the original method as an attribute called "batchable",
which is used by remotebatch to split the call into separate encoding and
decoding phases.
'''
def plain(*args, **opts):
batchable = f(*args, **opts)
timeless
py3: convert to next() function...
r29216 encargsorres, encresref = next(batchable)
Augie Fackler
batching: migrate basic noop batching into peer.peer...
r25912 if not encresref:
return encargsorres # a local result in this case
self = args[0]
Augie Fackler
peer: ensure command names are always ascii bytestrs...
r34734 cmd = pycompat.bytesurl(f.__name__) # ensure cmd is ascii bytestr
encresref.set(self._submitone(cmd, encargsorres))
timeless
py3: convert to next() function...
r29216 return next(batchable)
Augie Fackler
batching: migrate basic noop batching into peer.peer...
r25912 setattr(plain, 'batchable', f)
return plain