How to pass information to and from RequestHandler in socket server - python

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()

Related

How to use the value of a variable as an argument

I am trying to use the value of a variable, which is a string, as an argument and I keep getting "'Str' not callable' error. I haven't used str as a variable name I can make the code work with eval, however, I've read dire warnings about eval, so am unsure what to do. My code is below.
from time import sleep
from binance.client import Client
from binance.websockets import BinanceSocketManager
class s33():
def __init__(self):
self.client = Client("", "")
self.bm = BinanceSocketManager(self.client)
def process_trade_message(self, message):
global count, conn_key
print(count)
if count >= 10:
print('closing socket')
# use either stop_socket or close, or both
self.bm.stop_socket(conn_key)
self.bm.close()
# reset the count
count = 0
def go(self, sockb):
global count, conn_key
print(sockb['1'])
sock = 'self.bm.'+sockb['1']
print(sock)
count = 0
conn_key = sock(self.process_trade_message)
self.bm.start()
if __name__ == '__main__':
while True:
s = s33()
socka = {'1':'start_miniticker_socket'}
s.go(socka)
sleep(20)
print('sleeping')
I have read people recommend using a dict, So I passed the dict as the arg and tried to extract the string in the function,which is the code below. I tried to extract the string and pass that as an arg to the function. s.go(socka['1'], I tried passing the just the variable as an arg, socka = 'start_miniticker_socket' and I can get that to work if I use eval('self.bm'+socka) I tried the percentage sign with no luck. Not sure how to do this without using eval. I am still fairly new and can't find an alternative answer after several hours of searching that works. any help would be appreciated.
I think what people meant when suggesting a dict is something like this:
class s33():
# Codes...
def go(self, func_name):
global count, conn_key
print(func_name)
mapper = {
'start_miniticker_socket': self.bm.start_miniticker_socket
}
# Get self.bm.start_miniticker or None
sock = mapper.get(func_name)
print(sock)
if sock:
count = 0
conn_key = sock(self.process_trade_message)
self.bm.start()
else:
pass # Handle when sock is None
if __name__ == '__main__':
while True:
s = s33()
socka = 'start_miniticker_socket'
s.go(socka)
sleep(20)
print('sleeping')

Python : Iterate a list which is shared by several method in a class

I'm using tornado.websocket, where class-methods are overrides of the WebSocketHandler methods. Anyway, my code look like that:
class SocketHandler(tornado.websocket.WebSocketHandler):
current_ninja_pool = enumerate(return_dependency_lvl_0())
current_ninja = next(current_ninja_pool)
file_to_upload = []
def check_origin(self, origin):
return True
def open(self):
logging.info("A client connected.")
self.run()
def run(self):
if condition:
do_this()
else:
do_that()
self.current_ninja = next(self.current_ninja_pool)
self.run()
def on_message(self, message):
do_a_lot_of_stuff()
if message == 'next one':
self.current_ninja = next(self.current_ninja_pool)
def on_close(self):
logging.info("A client disconnected")
So, what I want is to be able to iterate my enumerate, so that every element can be processed in the methods run or on_message depending on how my client-websocket will answer. The problem is that I want to iterate under particular conditions, and I don't have a clue on how to do this. Since I'm not very familiar with the way you manipulate class- and instance-variables, I'm probably missing a point here.
Thank you
You need an iterator. Luckily, enumerate already returns an iterator; you just need to access that, rather than storing the current item.
I also suspect that current_ninja_pool should be an instance variable, not a class one (which would be shared across all instances of the class).
class SocketHandler(tornado.websocket.WebSocketHandler):
def __init__(self, *args, **kwargs)
self.current_ninja_pool = enumerate(return_dependency_lvl_0())
file_to_upload = []
def run(self):
item = next(self.current_ninja_pool)
do_something_with(item)

using object in whole module. Python

When I create an object in some method, I can't use it in any other method. So the use of the object is limited just to that method. But I would like to create the object somehow, that could use it in my whole module.
Here is the code of the module in which I want to create the object so I could use it in every method. (It's not so important what it should do, but for those who cares, it'll be network configurator which using netlink socket to communicate with the kernel).
In the method configureBridge() (the 4th method from the beginning) I tried to create an object and use it (ip = IPRoute() ... ip.release()) and it worked, but I couldn't use the object variable ip in any other function apart from configureBridge(). Could someone help me with that?
class PyrouteTwo(Configurator):
def __init__(self, inRollback=False):
super(PyrouteTwo, self).__init__(ConfigApplier(), inRollback)
self.runningConfig = RunningConfig()
logging.debug("testmark.PyR2.init")
def begin(self):
if self.configApplier is None:
self.configApplier = ConfigApplier()
if self.runningConfig is None:
self.runningConfig = RunningConfig()
logging.debug("testmark.PyR2.begin")
def commit(self):
self.configApplier = None
self.runningConfig.save()
self.runningConfig = None
logging.debug("testmark.PyR2.commit")
def configureBridge(self, bridge, **opts):
self.configApplier.addBridge(bridge)
if bridge.port:
bridge.port.configure(**opts)
self.configApplier.addBridgePort(bridge)
self.configApplier.setIfaceConfigAndUp(bridge)
logging.debug("testmark.PyR2.confBridge..")
# I am using the object here:
ip = IPRoute(fork=True)
dev = ip.link_lookup(ifname='em1')[0]
logging.debug("pyroute2 link_lookup output: %d", dev)
ip.release()
# there are some similar functions like configureVAN etc. in which I want
# to use the object
class ConfigApplier(object):
def _setIpConfig(self, iface):
ipConfig = iface.ipConfig
logging.debug("testmark.PyR2.ConfApplier.setIpConf.")
if ipConfig.ipaddr:
self.removeIpConfig(iface)
ipwrapper.addrAdd(iface.name, ipConfig.ipaddr,
ipConfig.netmask)
if ipConfig.gateway and ipConfig.defaultRoute:
ipwrapper.routeAdd(['default', 'via', ipConfig.gateway])
def removeIpConfig(self, iface):
ipwrapper.addrFlush(iface.name)
def setIfaceMtu(self, iface, mtu):
ipwrapper.linkSet(iface, ['mtu', str(mtu)])
def ifup(self, iface):
ipwrapper.linkSet(iface.name, ['up'])
if iface.ipConfig.bootproto == 'dhcp':
dhclient = DhcpClient(iface.name)
dhclient.start(iface.ipConfig.async)
def ifdown(self, iface):
ipwrapper.linkSet(iface.name, ['down'])
dhclient = DhcpClient(iface.name)
dhclient.shutdown()
def setIfaceConfigAndUp(self, iface):
if iface.ip:
self._setIpConfig(iface)
if iface.mtu:
self.setIfaceMtu(iface.name, iface.mtu)
self.ifup(iface)
def addBridge(self, bridge):
rc, _, err = execCmd([EXT_BRCTL, 'addbr', bridge.name])
if rc != 0:
raise ConfigNetworkError(ERR_FAILED_IFUP, err)
def addBridgePort(self, bridge):
rc, _, err = execCmd([EXT_BRCTL, 'addif', bridge.name,
bridge.port.name])
if rc != 0:
raise ConfigNetworkError(ERR_FAILED_IFUP, err)
def removeBridge(self, bridge):
rc, _, err = execCmd([EXT_BRCTL, 'delbr', bridge.name])
if rc != 0:
raise ConfigNetworkError(ERR_FAILED_IFDOWN, err)
logging.debug("testmarkPyR2.ConfApplier.remBridge")
# ...
def createLibvirtNetwork(self, network, bridged, iface, qosInbound=None,
qosOutbound=None):
netXml = libvirtCfg.createNetworkDef(network, bridged, iface,
qosInbound, qosOutbound)
libvirtCfg.createNetwork(netXml)
logging.debug("testmarkPyR2.ConfApplier.createLibvirtNetwork")
def removeLibvirtNetwork(self, network):
libvirtCfg.removeNetwork(network)
logging.debug("testmarkPyR2.ConfApplier.remLibvirtNetwork")
You can either declare it as object specific attibute by doing -
self.ip = value # Now its a object specific variable
or make it a class veriable before assign it a value.
class PyrouteTwo(Configurator):
ip = None # Now its a class variable

Python - how can I use generators more succinctly?

(Python 3)
I am using a Python generator to read messages from a queue.
After the consumer reads a queue message, it needs to be able to tell the generator to delete the queue message if it was successfully processed.
In order to .send() to a Python generator, it seems I must first .send(None) to the generator. This is making my code fatter than I think it should be.
Can anyone suggest a way for qconsumer.py to drive the generator with fewer lines of code? I have identified which lines below I am hoping to eliminate.
In short, how can I make the code below more compact, any suggestions for how I can delete lines?
Code below is qconsumer.py:
from qserver import Qserver
myqserver = Qserver()
myproducer = myqserver.producer() # trying to eliminate this line
# first send to a generator must be None
myproducer.send(None) # trying to eliminate this line
for msg in myproducer:
# do something with message
print(msg)
if messageprocessok:
myproducer.send('delete')
Code below is qserver.py:
# -*- coding: utf-8 -*-
import boto
from boto.sqs.connection import SQSConnection
from boto.sqs.message import Message
QNAME = 'qinbound'
SQSREGION = 'us-west-1'
class Qserver():
"""A simple Q server."""
def __init__(self, qname=None, sqsregion=None):
self.qname = qname or QNAME
self.sqsregion = sqsregion or SQSREGION
self.sqsconn = boto.sqs.connect_to_region(self.sqsregion)
self.q_in = self.sqsconn.get_queue(self.qname)
def producer(self):
while True:
qmessage = self.q_in.read(wait_time_seconds=20)
if qmessage is None:
continue
action = (yield qmessage.get_body())
if action == 'delete':
# if processing completed ok, clear message from this queue
self.q_in.delete_message(qmessage)
Your current consumer is throwing away messages because each send call returns one. You should do this instead:
myqserver = Qserver()
myproducer = myqserver.producer()
messageprocessok = False
while True:
msg = myproducer.send('delete' if messageprocessok else None)
# do something with message
print(msg)
or alternatively:
myqserver = Qserver()
myproducer = myqserver.producer()
msg = next(myproducer)
while True:
# do something with message
print(msg)
msg = myproducer.send('delete' if messageprocessok else None)
The fact that you need separate calls to Qserver() and myqserver.producer() is simply because you made prouducer a method of a class. Alternatively you could use a stand-alone function, or make a wrapper function that simply returns Qserver().producer(). Here's the stand-alone version:
def producer(qname=None, sqsregion=None):
qname = qname or QNAME
sqsregion = sqsregion or SQSREGION
sqsconn = boto.sqs.connect_to_region(sqsregion)
q_in = sqsconn.get_queue(qname)
while True:
qmessage = q_in.read(wait_time_seconds=20)
if qmessage is None:
continue
action = (yield qmessage.get_body())
if action == 'delete':
# if processing completed ok, clear message from this queue
q_in.delete_message(qmessage)
Having understood what you're trying to do, I think I would avoid mixing send with iteration. Having the myqserver class be an iterator itself seems to make more sense to me:
# -*- coding: utf-8 -*-
import boto
from boto.sqs.connection import SQSConnection
from boto.sqs.message import Message
QNAME = 'qinbound'
SQSREGION = 'us-west-1'
class Qserver():
"""A simple Q server."""
_current_message = None
def __init__(self, qname=None, sqsregion=None):
self.qname = qname or QNAME
self.sqsregion = sqsregion or SQSREGION
self.sqsconn = boto.sqs.connect_to_region(self.sqsregion)
self.q_in = self.sqsconn.get_queue(self.qname)
def __iter__(self):
return self
def __next__(self):
while True:
qmessage = self.q_in.read(wait_time_seconds=20)
if qmessage is not None:
self._current_message = qmessage
return qmessage
next = __next__
def delete_current(self):
if self._current_message is not None:
self.q_in.delete_message(self._current_message)
And usage will be something like:
from qserver import Qserver
myqserver = Qserver()
for msg in myqserver:
# do something with message
print(msg)
if messageprocessok:
myqserver.delete_current()

How do I use ReverseProxyProtocol

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.

Categories

Resources