Closed byaka closed 9 years ago
I think the most elegant way is to set the client IP as a parameter of the called method.
You can do this by defining a _dispatch
method in your request handler. That method is looked for in the request parsing process, but is not defined by default.
=> You don't have to override the do_POST
method, as it only give the JSON data to the dispatcher.
The custom _dispatch
method will be called once the request has been parsed, instead of the dispatch method of the SimpleJSONRPCDispatcher
.
=> You will be able to get the client IP in this method (see the sample)
Then, you will be able to call the default method by using the server
member of your request handler, because the SimpleJSONRPCServer
class inherits from SimpleJSONRPCDispatcher
.
The next step is to add the client IP parameter, but only when calling methods that wants it.
I prefer to add a custom field to the method object for that (here, needs_ip
), as it's really easy to check, and you can use a decorator to set it.
Here is a working example:
from __future__ import print_function
from jsonrpclib.SimpleJSONRPCServer import SimpleJSONRPCServer
from jsonrpclib.SimpleJSONRPCServer import SimpleJSONRPCRequestHandler
import jsonrpclib.utils
try:
import xmlrpc.server as xmlrpcserver
except ImportError:
import SimpleXMLRPCServer as xmlrpcserver
class myRequestHandler(SimpleJSONRPCRequestHandler):
rpc_paths = ('/adWolf-accApi')
def _dispatch(self, method, params):
try:
# You can look into self.server.funcs to get the method object
called_method = self.server.funcs[method]
except KeyError:
# Try with the installed instance
try:
called_method = xmlrpcserver.resolve_dotted_attribute(
self.server.instance, method, True)
except AttributeError:
# No installed instance: the method is either unknown,
# or dispatched with a specific method
called_method = None
if hasattr(called_method, "needs_ip"):
# Add client IP to parameters
clientIp, _ = self.client_address
if isinstance(params, jsonrpclib.utils.ListType):
params.append(clientIp)
else:
params['client_ip'] = clientIp
return self.server._dispatch(method, params)
def needs_ip(method):
# Nice way to request an IP: define a decorator that will set the needs_ip
# flag
method.needs_ip = True
return method
class mySharedMethods:
def test1(self):
print("Test 1 called")
def test2(self, client_ip):
print("Test 2 IP=", client_ip)
# Not readable, but valid; set the flag manually
test2.needs_ip = True
@needs_ip
def test3(self, a, b, client_ip):
# Using the decorator
print("Test 3 IP=", client_ip)
if __name__ == '__main__':
server = SimpleJSONRPCServer(("0.0.0.0", 8013),
requestHandler=myRequestHandler,
logRequests=False)
server.register_instance(mySharedMethods())
server.serve_forever()
It's really beauty, Thx u!
now i'm do this:
It's ugly and i'm think it's doesn't work properly with threaded version of server (when more then one clients per time connected, global variable "clientIp" will be shared and contain IP of last client only).
More elegant way?