Receive data from client without using "dataReceived" function in Twisted - python

How to receive the data from the client, bypassing the standard class function Protocol? For example,
class TW(protocol.Protocol):
def get_data(delim = '\n'):
#some code
return data
I.e, without using the function "dataReceived", and not freezing all other the server clients?

You can't bypass dataReceived unless you like doing things the hard way :D. You can do what ever you're doing in get_data() in dataReceived(). Alternatively, you could add a data param in your get_data() and do a callback form dataReceived.
class TW(Protocol):
def get_data(data, delim='\n'):
# some code
return result
def dataReceived(self, data):
result = self.get_data(data, delim='\r\n')
# do some more stuff

Related

Store value of a callback function in Python

I am trying to store the content of a callback function, in order to access and manipulate the data within the script.
As far as I am concerned, the given function .subscribe() in my code below does not return anything (None). My function is only passed as a reference to the function as an argument. Is there a way to return the data from the function that calls my function?
My code is a simple example with roslibpy (a library for Python that interacts with the open-source robotics framework ROS through Websockets). It is mentioned, that the data is published as a stream via a Websocket each time a message is published into the topic /turtle1/pose. My goal here is to return the data that is being published into the topic. The print command provides a nice visualization of the data, which just works fine.
import roslibpy
client = roslibpy.Ros(host='localhost', port=9090)
client.run()
def myfunc(msg):
print(msg)
listener = roslibpy.Topic(client, '/turtle1/pose', 'turtlesim/Pose')
#my function is passed as an argument
listener.subscribe(myfunc)
try:
while True:
pass
except KeyboardInterrupt:
client.terminate()
The subscribe() method in the roslibpy library is defined as follows:
def subscribe(self, callback):
"""Register a subscription to the topic.
Every time a message is published for the given topic,
the callback will be called with the message object.
Args:
callback: Function to be called when messages of this topic are published.
"""
# Avoid duplicate subscription
if self._subscribe_id:
return
self._subscribe_id = 'subscribe:%s:%d' % (
self.name, self.ros.id_counter)
self.ros.on(self.name, callback)
self._connect_topic(Message({
'op': 'subscribe',
'id': self._subscribe_id,
'type': self.message_type,
'topic': self.name,
'compression': self.compression,
'throttle_rate': self.throttle_rate,
'queue_length': self.queue_length
}))
Is there common way to deal with such problems? Does it make more sense to store the output as an external source (e.g. .txt) and then access the source trough the script?
You can define a Python class that acts like a function, that can modify its own state when called, by defining the magic __call__ method. When obj(whatever) is done on a non-function obj, Python will run obj.__call__(whatever). subscribe only needs its input to be callable; whether it is an actual function or an object with a __call__ method does not matter to subscribe.
Here's an example of what you could do:
class MessageRecorder():
def __init__(self):
self.messages = []
# Magic python 'dunder' method
# Whenever a MessageRecorder is called as a function
# This function defined here will be called on it
# In this case, adds the message to a list of received messages
def __call__(self, msg):
self.messages.append(msg)
recorder = MessageRecorder()
# recorder can be called like a function
recorder("Hello")
listener.subscribe(recorder)
try:
while True:
pass
except KeyboardInterrupt:
client.terminate()
"""Now you can do whatever you'd like with recorder.messages,
which contains all messages received before termination,
in order of reception. If you wanted to print all of them, do:"""
for m in recorder.messages:
print(m)

where do i add code in tornado websocket server?

I just jump into websocket programing with basic knowledge of "Asynchronous" and "Threads", i have something like this
import tornado.httpserver
import tornado.websocket
import tornado.ioloop
import tornado.web
import socket
import uuid
import json
import datetime
class WSHandler(tornado.websocket.WebSocketHandler):
clients = []
def open(self):
self.id = str(uuid.uuid4())
self.user_info = self.request.remote_ip +' - '+ self.id
print (f'[{self.user_info}] Conectado')
client = {"sess": self, "id" : self.id}
self.clients.append(client.copy())
def on_message(self, message):
print (f'[{self.user_info}] Mensaje Recivido: {message}')
print (f'[{self.user_info}] Respuesta al Cliente: {message[::-1]}')
self.write_message(message[::-1])
self.comm(message)
def on_close(self):
print (f'[{self.user_info}] Desconectado')
for x in self.clients:
if x["id"] == self.id :
self.clients.remove(x)
def check_origin(self, origin):
return True
application = tornado.web.Application([
(r'/', WSHandler),
])
if __name__ == "__main__":
http_server = tornado.httpserver.HTTPServer(application)
http_server.listen(80)
myIP = socket.gethostbyname(socket.gethostname())
print ('*** Websocket Server Started at %s***' % myIP)
tornado.ioloop.IOLoop.instance().start()
my question is where do I add code ?, should I add everything inside the WShandler class, or outside, or in another file ? and when to use #classmethod?. for now there is no problem with the code when i add code inside the handler but i have just few test clients.
maybe not the full solution but just a few thoughts..
You can maybe look at the tornado websocket chat example,
here.
First good change is, that their clients (waiters) is a set()
which makes sure that every client is only contained once by default. And it is defined and accessed as a class variable. So you don't use self.waiters but cls.waiters or ClassName.waiters (in this case ChatSocketHandler.waiters) to access it.
class ChatSocketHandler(tornado.websocket.WebSocketHandler):
waiters = set()
Second change is that they update every client (you could choose here
to send the update not to all but only some) as a #classmethod, since
they dont want to receive the instance (self) but the class (cls) and
refer to the class variables (in their case waiters, cache and cach_size)
We can forget about the cache and cache size here.
So like this:
#classmethod
def send_updates(cls, chat):
logging.info("sending message to %d waiters", len(cls.waiters))
for waiter in cls.waiters:
try:
waiter.write_message(chat)
except:
logging.error("Error sending message", exc_info=True)
On every API call a new instance of your handler will be created, refered to as self. And every parameter in self is really unique to the instance and related to the actual client, calling your methods. This is good to identify a client on each call.
So a instance based client list like (self.clients) would always be empty on each call. And adding a client would only add it to this instance's view of the world.
But sometimes you want to have some variables like the list of clients the same for all instances created from your class.
This is where class variables (the ones you define directly under the class definition) and the #classmethod decorator come into play.
#classmethod makes the method call independant from the a instance. This means that you can only access class variables in those methods. But in the case of a
message broker this is pretty much what we want:
add clients to the class variable which is the same for all instances of your handler. And since it is defined as a set, each client is unique.
when receiving messages, send them out to all (or a subset of clients)
so on_message is a "normal" instance method but it calls something like: send_updates() which is a #classmethod in the end.
send_updates() iterates over all (or a subset) of clients (waiters) and uses this to send the actual updates in the end.
From the example:
#classmethod
def send_updates(cls, chat):
logging.info("sending message to %d waiters", len(cls.waiters))
for waiter in cls.waiters:
try:
waiter.write_message(chat)
except:
logging.error("Error sending message", exc_info=True)
Remember that you added waiters with waiters.append(self) so every waiter is really an instance and you are "simply" calling the instances (the instance is representing a caller) write_message() method. So this is not broadcasted but send to every caller one by one. This would be the place where you can separate by some criteria like topics or groups ...
So in short: use #classmethod for methods that are independant from a specific instance (like caller or client in your case) and you want to make actions for "all" or a subset of "all" of your clients. But you can only access class variables in those methods. Which should be fine since it's their purpose ;)

[Python][Tornado] Is it possible to have multi websocket with different port & message in one python program?

I am a newbie in Python. I am now having a project that using a raspberry pi to connect to local web, a web server & a mobile apps via websocket. Both of them are interactive. I can now communicate with each of them separately with 3 different program. But I face some problems when I want to integrate them into 1.
I read a number of post in here & find that all answers suggest to use a list to store each websocket and all of them sending the same message. Is it possible to send different message? Maybe something this
import tornado.ioloop
import tornado.web
import tornado.websocket
class WebSocketHandler_web(tornado.websocket.WebSocketHandler):
def __init__(self, application, **kwargs):
pass
def open(self):
# do something
def on_message(self, msg):
# do something
def on_close(self):
# do something
class WebSocketHandler_mobile(tornado.websocket.WebSocketHandler):
def __init__(self, application, **kwargs):
pass
def open(self):
# do something
def on_message(self, msg):
# do something
def on_close(self):
# do something
class WebSocketHandler_server(tornado.websocket.WebSocketHandler):
def __init__(self, application, **kwargs):
pass
def open(self):
# do something
def on_message(self, msg):
# do something
def on_close(self):
# do something
app_web = tornado.web.Application([(r'/ws/', WebSocketHandler_web),])
app_mobile = tornado.web.Application([(r'/ws/', WebSocketHandler_mobile),])
app_server = tornado.web.Application([(r'/ws/', WebSocketHandler_server),])
def main_task():
# do something
if(mode == 1):
webSocket_web.write_message("Mode 1")
elif(mode == 2):
webSocket_mobile.write_message("Mode 2")
elif(mode == 3):
webSocket_server.write_message("Mode 3")
# do something
if __name__ == "__main__":
app_web.listen(7777)
app_mobile.listen(8888)
app_server.listen(9999)
webSocket_web = WebSocketHandler_web(app_web)
webSocket_mobile = WebSocketHandler_mobile(app_mobile)
webSocket_server = WebSocketHandler_server(app_server)
tornado.ioloop.PeriodicCallback(main_task,1000).start()
tornado.ioloop.IOLoop.instance.start()
But seems that websocket.init needs a parameter request. What is that?
Is it possible to send different message Just iterate over a list of stored websockets and send different message, simple as that.
init needs a parameter request Tornado on each incoming request creates an instance of a request handler, and request is passed to init to bind a handler to request. When you override an init method in your handler you should follow parent's method interface. Don't worry about value of request argument, tornado will pass it for you.

KDB/Q Websocket example, getting `badmsg error: How to serialize my data when sending it over to my KDB server?

Lately, I've been trying to stream data from KDB to python.
I'm now using websockets and have gone through the doc https://code.kx.com/q/wp/kdb_and_websockets.pdf
On the python side, I've been trying ws4py, autobahn and websocket-client.
All do work fine, essentially my problem resides in the format of the message sent to the server to subscribe to the feed.
A little (open source) example:
class DummyClient(WebSocketClient):
def opened(self):
self.send(*what should I put here?*, binary=True)
def closed(self, code, reason=None):
print("Closed down", code, reason)
def received_message(self, m):
# not yet implemented
if __name__ == '__main__':
try:
ws = DummyClient('ws://host:port/', protocols=['http-only', 'chat'])
ws.connect()
ws.run_forever()
except KeyboardInterrupt:
ws.close()
When opening, I'm supposed to subscribe to the feed by calling the server function loadPage.
I've tried different things when to encode the list containing the function name and the argument, without success.
What I've tried:
np.array("['loadPage',[]]").tobytes()
"['loadPage',[]]".encode('utf8')
json formating
hexadecimal formating
Any help would be much appreciated!
Best,
Yael
I think what you'll need to do in this case is define .z.ws in your kdb server. This function will be called with whatever you pass over the websocket as an argument, so for example if you defined .z.ws like so:
.z.ws:{show x}
and then send a message over the WebSocket like so:
var ws = new WebSocket("ws://localhost:1234")
ws.send("Hello World")
This will be output in your kdb session e.g.
λ q
KDB+ 3.6 2018.06.14 Copyright (C) 1993-2018 Kx Systems
w64/ 4(16)core 8082MB jonat laptop-o8a8co1o 10.255.252.249 EXPIRE 2019.05.21 jonathon.mcmurray#aquaq.co.uk KOD #4160315
q).z.ws:{show x}
q)\p 1234
q)"Hello World"
So in your case if you want to call loadPage, it might be as simple as defining .z.ws like so:
.z.ws:loadPage
Then whatever you pass over the socket will be passed into loadPage (note this is will not update if you change loadPage elsewhere, you can instead use .z.ws:{loadPage x} if you need to be able to update it dynamically). For a niladic function, this will just ignore whatever is passed in

How to consolidate two Python classes containing methods with identical signatures?

I'm working on a REST client library, and recently started working on adding support for sending batch messages.
However, I don't like the current design. It requires you to maintain large Client and RequestMessage classes with identical method signatures.
I am looking for a way to consolidate the two classes.
The original Client class's methods contained all the code needed to prepare and send the request:
class Client(object):
def __init__(self, config):
self.request = Request(config, "application/json")
def create_vertex(self, data):
path = "vertices"
params = remove_null_values(data)
self.request.post(path, params)
To add support for batch messages, I pulled out the guts of the code inside the each Client method, and put it into a separate RequestMessage class so that you can add the messages to the batch without sending it, until you're ready:
class Client(object):
def __init__(self, config):
self.request = Request(config, "application/json")
self.message = RequestMessage(config)
def create_vertex(self, data):
message = self.message.create_vertex(data)
return self.request.send(message)
# ...more REST client methods...
def batch(self, messages):
path = "batch"
params = messages
return self.request.post(path, params)
class RequestMessage(object):
def __init__(self, config):
self.config = config
def create_vertex(self, data):
path = "vertices"
params = remove_null_values(data)
return POST, path, params
# ...more REST client methods...
But I don't like the design because now you have to maintain the Client and RequestMessage class -- two large classes with identical signatures.
Here's what the Batch class looks like:
class Batch(object):
def __init__(self, client):
self.client = client
self.messages = []
def add(self, message):
self.messages.append(message)
def send(self):
return self.client.batch(self.messages)
Here's example usage for creating a vertex on the server:
>>> client = Client(config)
>>> vertex = client.create_vertex({'name':'James'})
Here's example usage for creating a batch of vertices on the server:
>>> message1 = client.message.create_vertex({'name':'James'})
>>> message2 = client.message.create_vertex({'name':'Julie'})
>>> batch = Batch(client)
>>> batch.add(message1)
>>> batch.add(message2)
>>> batch.send()
Batch is used less frequently than Client so I want to make the normal Client interface easiest to use.
Here's one idea, but I'm not quite sure how to achieve it or if something else would be better:
>>> vertex = client.create_vertex(data)
>>> message = client.create_vertex(data).message()
My personal preference is an API like:
client.create_vertex({'name':'James'}) # single
client.create_vertex([{'name':'James'}, {'name':'Julie'}]) # batch
That way you use the exact same function, you're just giving it more data. Typical usage would probably look more like:
batch = []
batch.append({'name':'James'})
batch.append({'name':'Julie'})
client.create_vertex(batch)
I would agree with #Karl with some modifications
client.create_vertex({'name':'James'}) # single
client.create_vertex({'name':'James'}, {'name':'Julie'}) # batch
batch = []
batch.append({'name':'James'})
batch.append({'name':'Julie'})
client.create_vertex(*batch)
That way you don't have to check the type of your input. Easier to write, easier to use.

Categories

Resources