How do I use ReverseProxyProtocol - python

I have the following:
My webserver running on twisted
My comet server, aka orbited
Note that 1 and 2 are different processes.
Basically, I want 1 and 2 to share the same port. Request that are http://mysite.com/a/b/c should go to the webserver and anything starting with http://mysite.com/orbited/ should go to the orbited server, i.e. (http://mysite.com/orbited/a/b/c => do a request to http://mysite.com:12345/a/b/c and return that).
This is what I have right now:
# Reverse Proxy
class OrbitedResource(Resource):
isLeaf = True
def __init__(self, orbited_url='http://127.0.0.1:12345'):
self.orbited = orbited_url
Resource.__init__(self)
def render_GET(self, request):
def callback(html):
request.write(html)
request.finish()
def errback(failure, *args):
request.setResponseCode(http.INTERNAL_SERVER_ERROR)
request.write(failure.getErrorMessage())
request.finish()
request.setHeader('Connection', 'close')
# TODO find cleaner way to do this:
# Currently request.uri is "/orbited/....", you must trim it
target_uri = request.uri.replace('/orbited', '')
final_uri = self.orbited + target_uri
print "final_uri is", final_uri
deferred = getPage(final_uri)
deferred.addCallbacks(callback, errback)
return server.NOT_DONE_YET
class SimpleRoutingResource(Resource):
isLeaf = False
def __init__(self, wsgiApp):
Resource.__init__(self)
self.WSGIApp = wsgiApp
self.orbitedResource = OrbitedResource()
def getChild(self, name, request):
if name == "orbited":
request.prepath.pop()
print "Simple request.path is", request.path
return self.orbitedResource
else:
request.prepath.pop()
request.postpath.insert(0,name)
return self.WSGIApp
# Attaching proxy + django
log_dir = './.log'
if not os.path.exists(log_dir):
os.makedirs(log_dir)
reactor.listenTCP(DJANGO_PORT, server.Site(SimpleRoutingResource(WSGIRoot),
logPath=os.path.join(log_dir, '.django.log')))
Currently this works . However, I see that there's a class called ReverseProxyProtocol, and I have been doing tried it with the following modification:
class SimpleRoutingResource(Resource):
isLeaf = False
def __init__(self, wsgiApp):
Resource.__init__(self)
self.WSGIApp = wsgiApp
def getChild(self, name, request):
if name == "orbited":
request.prepath.pop()
print "Simple request.path is", request.path, name
return ReverseProxyResource( 'http://localhost', 12345, name )
else:
request.prepath.pop()
request.postpath.insert(0,name)
return self.WSGIApp
This is NOT Working. I have inserted a lot of prints into the twisted's reverseProxyResource class, and I discovered the following:
Given http://mysite.com/orbited/a/b/c
OrbitedResource will keep calling ReverseProxyResource with getChild until c
by the time you get to c, the url is messed up and the client class calling the orbited server will be wrong
I tried setting isLeaf = True in the ReverseProxyResource, but to no avail.
Anybody can point me a more effecient way to write the getPage? Do I really need to use ReverseProxyResource if it's such a black box in nature?

The cleanest way is to put something like nginx in front of both servers.

Related

How do I make my function call stay in context?

I have a class that is trying to call an RPC from a server, using the name_me method defined on the server. It works fine if I call it in iPython using:
jsonrpcclient.request ('http://localhost:5000', 'name_me', N=6).data.result
but when I try to build it with my class, I get the error:
RuntimeError: Working outside of request context.
This typically means that you attempted to use functionality that needed
an active HTTP request. Consult the documentation on testing for
information about how to avoid this problem.
I'll put the client code in the code section.
class LyricCaller:
def __update_host_port (self, new_port):
self.__port = new_port
def __update_host_address (self, new_address):
self.__address = new_address
def __target (self):
return '{}:{}'.format (self.__address, self.__port)
def __init__(self, host_address = 'http://localhost:5000', host_port = 5000):
self.lyric = []
self.__Lyr_fn = 'name_me'
self.__update_host_address (host_address)
self.__update_host_port (host_port)
def __parse_choice (self, choice):
return abs (choice)
def sing(self):
print (self.lyric)
def fetch_lyric (self, choice):
C = self.__parse_choice (choice)
K = request (self.__target(), self.Lyr_fn, N=1)
I expect a returned string, which works when I just directly call
jsonrpcclient.request ('http://localhost:5000', 'name_me', N=6).data.result,
but instead I still get the context error. I've tried restarting the server, but still the same thing occurs.
for further reference, here's the server code:
'''
from flask import Flask, request, Response
from jsonrpcserver import method, dispatch
LServer = Flask(__name__)
#method
def name_me (N = 1):
K = ['How do we sleep while our beds are burning?',
'You label me, I label you, and so I dub thee Unforgiven',
'Carry on my wayward son!',
'Not dead which eternal lie, stranger aeons death may die',
'Let the bodies hit the floor',
'Wollt ihr das bed in flammen siehen']
#N = 4
if N <= len (K):
O = K[N-1]
else:
import random
n = random.randint (0, len(K)-1)
O = K[n]
return O
#LServer.route ('/', methods = ['POST'])
def index():
#with LServer.test_request_context():
req = request.get_data().decode()
response = dispatch(req)
return Response (str(response), response.http_status, mimetype="application/json")
if __name__ == '__main__':
LServer.run()
'''
The Flask documentation says:
If you see that error somewhere else in your code not related to testing, it most likely indicates that you should move that code into a view function.
So your code will be similar to this:
from flask.views import View
# ...
class Index(View):
def dispatch_request(self):
req = request.get_data().decode()
response = dispatch(req)
return Response (str(response), response.http_status, mimetype="application/json")
LServer.add_url_rule('/', 'index', view_func=Index.as_view('index'),methods=['POST'])

Incremental ID shared between classes

I'm coding a virtual assistant in Python, and I want to store each request, response and possible error in a database.
I'm using one class for request, another class for response and another class for error.
How can I create an ID variable that is shared for the respectives classes instances, for example:
First run of the program (the normal and correct running of the program):
request_id = 1
response_id = 1
Second run (an error occurred and stopped the program to proceed to the response class):
request_id = 2
error_id = 2
Third run (the program ran fine and the response class skipped the id 2 -
that is the behavior that I want):
request_id = 3
response_id = 3
Note that in the third run, that response_id received the id 3 and the response_id = 2 will never exist, cause in the second run the proccess started with request and stopped in the error.
The ID variable must be always unique, even when my program crashes and I must restart him. I know I could grab the last id in the database when my program runs, but there's a way to do it without envolving the database?
Since you are using database to store the request and response why don't you use database to generate this id for you.
This can be done by creating the table with primary key int auto increment. Every request/response should be inserted into database, and the database will generate an unique id for each record inserted.
a possible solution would be to use Pyro4 instead of a DB if you don't want it. You can use the following code:
Tracker.py
import Pyro4
#Pyro4.expose
#Pyro4.behavior(instance_mode="single")
class Tracker(object):
def __init__(self):
self._id = None
def setId(self, value):
print "set well :)", value
self._id = value
print self._id
def getId(self):
print "returning", self._id
return self._id
daemon = Pyro4.Daemon()
uri = daemon.register(Tracker)
print("URI: ", uri)
daemon.requestLoop()
Status.py
import Pyro4
class Status(object):
def __init__(self, id):
self._id = id
self._pyro = None
def connect(self, target):
self._pyro = Pyro4.Proxy(target)
def updateId(self):
if ( not self._pyro is None ):
self._pyro.setId(self._id)
print "updated"
else:
print "please connect"
def getId(self):
if ( not self._pyro is None ):
return self._pyro.getId()
else:
print "please connect"
Success.py
from Status import *
class Success(Status):
def __init__(self):
super(Success,self).__init__(1)
Wait.py
from Status import *
class Wait(Status):
def __init__(self):
super(Wait,self).__init__(1)
Error.py
from Status import *
class Error(Status):
def __init__(self):
super(Error,self).__init__(3)
run.py
from Success import *
from Wait import *
from Error import *
#just an example
s = Success()
w = Wait()
e = Error()
s.connect("PYRO:obj_c98931f8b95d486a9b52cf0edc61b9d6#localhost:51464")
s.updateId()
print s.getId()
w.connect("PYRO:obj_c98931f8b95d486a9b52cf0edc61b9d6#localhost:51464")
w.updateId()
print s.getId()
e.connect("PYRO:obj_c98931f8b95d486a9b52cf0edc61b9d6#localhost:51464")
e.updateId()
print s.getId()
Of course you would need to use a different URI but you should have a good idea now. using Pyro you could also specify a static URI name if needed.
The output should be:
$ c:\Python27\python.exe run.py
updated
1
updated
2
updated
3
HTH

pyramid: deduplicate similar routes

I have a problem with repeated code in the routes of our pyramid app. I'm pretty sure I'm doing it wrong, but don't know how to do better. Our app essentially has three "modes" which are represented as prefixes to the URL path. With no prefix, we're in "prod" mode, then we have "/mock" and "/old" prefixes which use the same views with different backends to fetch the data.
The code turns out looking like this:
def routes(config):
"""Add routes to the configuration."""
config.add_route('my_view:old', '/old/my_view')
config.add_route('my_view:prod', '/my_view')
config.add_route('my_view:mock', '/mock/my_view')
#view_config(route_name='my_view:mock', renderer='string')
def my_view_mock(request):
return my_view(request, data.mock)
#view_config(route_name='my_view:prod', renderer='string')
def my_view_prod(request):
return my_view(request, data.prod)
#view_config(route_name='my_view:old', renderer='string')
def my_view_old(request):
return my_view(request, data.old)
def my_view(request, data):
results = data.query(**request.json)
What's worse, is this pattern is repeated for all of our endpoints, resulting in a ton of nearly-duplicate boilerplate code.
How can I teach pyramid about my setup in some centralized manner and get rid of this boilerplate?
Well here's an option. It requires you to define a unique object for each view. The nice part is that you can define that object and then each route can create it differently ... imagine factory=lambda request: MyView(request, old=True) instead of using the exact same MyView(request) object for each route.
def routes(config):
"""Add routes to the configuration."""
config.add_directive('add_routed_resource', add_routed_resource)
config.add_routed_resource('my_view', MyView)
def add_routed_resource(config, name, factory):
routes = [
('%s:old', '/old/%s-errors', lambda request: factory(request, old=True)),
('%s:prod', '/%s', factory),
('%s:mock', '/mock/%s', lambda request: factory(request, mock=True)),
]
for name_fmt, pattern_fmt in routes:
config.add_route(
name_fmt % name,
pattern_fmt % name,
factory=factory,
use_global_views=True,
)
class MyView:
def __init__(self, request, old=False, mock=False):
self.request = request
self.old = old
self.mock = mock
#reify
def data(self):
# let's assume sqlalchemy query to load the data?
q = self.request.db.query(...)
if self.old:
q = q.filter_by(old=True)
return q.one()
#view_config(context=MyView, renderer='json')
def my_view(context, request):
return context.data

How to pass information to and from RequestHandler in socket server

I have a class that manages a socketserver. Information needs to be passed in both directions between it and the handler. There are some work arounds I can use to get the Handler to pass information to the game server, but not the other way around. It seems like a pretty common need. It's also possible that there's a better way to do this whole thing and that I'm violating some common practice, in which case I'd like to know so I can write my code in a more standard way (I'm not trying to do anything fancy).
class GameServer:
class GameServerUDPHandler(socketserver.BaseRequestHandler):
#... (other, irrelevant functions)
def handle(self):
data = self.request[0].strip()
data = str(data, 'utf-8')
print(data)
socket = self.request[1]
data = data.split('\n')
option = data[0]
print(option)
c_add = self.client_address
if option == "register" and not self.server.base.has_started:
self.handle_register(socket, c_add)
print("test")
elif option == "get_postion":
handle_get_postion(socket, c_add, data[1])
elif option == "change_postion":
hande_changed_postion(socket, c_add, data[1])
#temporary
if len(self.server.base.players) > 0:
self.server.base.start
def __init__(self, port):
self.server = socketserver.UDPServer(("localhost", port), self.GameServerUDPHandler)
def start_server(self):
threading.Thread(target=self.server.serve_forever).start()
def start_game():
self.has_started = True
self.server.RequestHandler.alert_start()

cherrypy handle all request with one function or class

i'd like to use cherrypy but i don't want to use the normal dispatcher, i'd like to have a function that catch all the requests and then perform my code. I think that i have to implement my own dispatcher but i can't find any valid example. Can you help me by posting some code or link ?
Thanks
make a default function:
import cherrypy
class server(object):
#cherrypy.expose
def default(self,*args,**kwargs):
return "It works!"
cherrypy.quickstart(server())
What you ask can be done with routes and defining a custom dispatcher
http://tools.cherrypy.org/wiki/RoutesUrlGeneration
Something like the following. Note the class instantiation assigned to a variable that is used as the controller for all routes, otherwise you will get multiple instances of your class. This differs from the example in the link, but I think is more what you want.
class Root:
def index(self):
<cherrpy stuff>
return some_variable
dispatcher = None
root = Root()
def setup_routes():
d = cherrypy.dispatch.RoutesDispatcher()
d.connect('blog', 'myblog/:entry_id/:action', controller=root)
d.connect('main', ':action', controller=root)
dispatcher = d
return dispatcher
conf = {'/': {'request.dispatch': setup_routes()}}
Hope that helps : )
Here's a quick example for CherryPy 3.2:
from cherrypy._cpdispatch import LateParamPageHandler
class SingletonDispatcher(object):
def __init__(self, func):
self.func = func
def set_config(self, path_info):
# Get config for the root object/path.
request = cherrypy.serving.request
request.config = base = cherrypy.config.copy()
curpath = ""
def merge(nodeconf):
if 'tools.staticdir.dir' in nodeconf:
nodeconf['tools.staticdir.section'] = curpath or "/"
base.update(nodeconf)
# Mix in values from app.config.
app = request.app
if "/" in app.config:
merge(app.config["/"])
for segment in path_info.split("/")[:-1]:
curpath = "/".join((curpath, segment))
if curpath in app.config:
merge(app.config[curpath])
def __call__(self, path_info):
"""Set handler and config for the current request."""
self.set_config(path_info)
# Decode any leftover %2F in the virtual_path atoms.
vpath = [x.replace("%2F", "/") for x in path_info.split("/") if x]
cherrypy.request.handler = LateParamPageHandler(self.func, *vpath)
Then just set it in config for the paths you intend:
[/single]
request.dispatch = myapp.SingletonDispatcher(myapp.dispatch_func)
...where "dispatch_func" is your "function that catches all the requests". It will be passed any path segments as positional arguments, and any querystring as keyword arguments.

Categories

Resources