I am using ws4py / CherryPy for websockets support, and would like to implement WAMP on top of it.
I thought of using autobahn but it only seems to support Twisted and asyncio out of the box.
Is possible to use autobahn functionality to extend ws4py, or is there an alternative way?
#oberstet is right. This is a quick showcase on how to run a CherryPy app:
import cherrypy
from twisted.web.wsgi import WSGIResource
from twisted.internet import reactor
# Our CherryPy application
class Root(object):
#cherrypy.expose
def index(self):
return "hello world"
# Create our WSGI app from the CherryPy application
# it will respond to the /blog path
wsgiapp = cherrypy.tree.mount(Root(), '/blog', {'/': {'tools.etags.on': True}})
# Configure the CherryPy's app server
# Disable the autoreload which won't play well
cherrypy.config.update({'engine.autoreload.on': False})
# We will be using Twisted HTTP server so let's
# disable the CherryPy's HTTP server entirely
cherrypy.server.unsubscribe()
# If you'd rather use CherryPy's signal handler
# Uncomment the next line. I don't know how well this
# will play with Twisted however
#cherrypy.engine.signals.subscribe()
# Tie our app to Twisted
reactor.addSystemEventTrigger('after', 'startup', cherrypy.engine.start)
reactor.addSystemEventTrigger('before', 'shutdown', cherrypy.engine.exit)
resource = WSGIResource(reactor, reactor.getThreadPool(), wsgiapp)
Assuming you save this snippet into a module called: "cptw.py", you can now serve your CherryPy application as follow:
twistd -n web --wsgi cptw.wsgiapp
This works with Twisted 13.2 and CherryPy 3.2.6+
As you have already noted, Autobahn|Python supports running under either Twisted or asyncio. It includes a full-featured WebSocket implementation, and WAMP on top of that. So there is no need for ws4py, and we have no plans of porting the WAMP layer that Autobahn|Python includes to ws4py.
Twisted also supports running any WSGI compliant application. So in principle, you should be able to run CherryPy under Twisted. I have not tested that - I only tested (and regularily use) Flask on Twisted.
Related
I am running a RabbitMQ instance that provides MQTT over websockets via the rabbitmq_web_mqtt plugin.
For legacy reasons, I need to support a non-default WebSocket URL.
I saw in the documentation it is possible to change the port via the { port, 1234 } config, but I could not find any way to change the WebSocket URL. It is currently set to the default path of /ws
Is it possible to change the WebSocket URL without modifying the plugin?
This has been made configurable back September 2018. See already mentioned ticket.
Add line:
# echo 'web_mqtt.ws_path = /mqtt' >> /etc/rabbitmq/rabbitmq.conf
# service rabbitmq-server restart
Now being accessible by (compliant) MQTT Clients. For instance at:
ws://192.168.210.84:15675/mqtt
UPDATE: RabbitMQ now allows configuration of the WebSocket URL. See this answer.
After some research, I found out that the path is not configurable
I'm trying to replicate the functionality provided by the Map Remote feature in Charles using MITMPROXY on OS X 10.9. What I want to do is replace any request for desiredurl.com with a request for desiredurl.ca (I'm open to any answer which tells me how to replicate the given functionality in Charles using free software).
I found this answer and this question which both looked like they should help, and I wrote the below script.
#!/usr/bin/env python
def redirect_request(context, flow):
host = flow.get_url()
if 'desiredurl' in host:
flow.set_url(host.replace('com','ca'))
I mitmdump -s path/to/script.py on my iMac and then connect my iPad to my iMac on port 8080 as usual, and see the traffic flying by in the Terminal window, but visiting desiredurl.com still takes me to desiredurl.com rather than desiredurl.ca. Thus, I tried the following:
#!/usr/bin/env python
def response(context, flow):
if 'desiredurl' in flow.request.host:
flow.request.host.replace('com','ca')
However, the requests still go to desiredurl.com rather than desiredurl.ca. Why is this?
Essentially, what I'm hoping to achieve is a canvas based web interface to control an Arduino, via a Raspberry Pi. The use case is that a user navigates to raspberrypi:8080 which displays a canvas. Then upon moving a slider, a websocket message is sent to the Tornado server on the Raspberry Pi. Tornado then sends a serial message to the Arduino which changes the RGB value of an LED. So far so good, I've been able to do this with the help of the documentation by a developer, Raspberry Pi Android HTML5 Realtime Servo Control.
However, the communication is only one-way from Raspberry Pi to Arduino. I'd like Tornado to also monitor the serial port to get any sensor data back to the front-end. Here's where I'm unsure about how to proceed. I was able to accomplish something like this using Node.js, which monitors for both websocket messages as well as serial messages asynchronously.
Should an asynchronous process be spawned which constantly monitors the port? I've seen a couple of options for this sort of solution.
Some people suggest tornado.gen.Task, but for single HTTP requests, not for constant serial data.
tornado.ioloop.PeriodicCallback which I could set up to check for serial data every millisecond, but that sounds like a lot of overhead.
I've also seen separate tools such as Swirl. (Swirl is outdated according to it's Github repo)
Or should I set up a separate Python application which monitors serial and then communicates to the Tornado application on something it can understand like the following?
websocket messages using a websocket client
ZeroMQ (working example: pyzmq / examples / eventloop / web.py)
So there are lots of options... What are some recommendations and some reasons to try out or avoid any of the above options?
Here's what I have and need to add serial monitoring to:
import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web
import tornado.websocket
from tornado.options import define, options
define("port", default=8080, help="run on the given port", type=int)
class IndexHandler(tornado.web.RequestHandler):
def get(self):
self.render('index.html')
class WebSocketHandler(tornado.websocket.WebSocketHandler):
def open(self):
print 'new connection'
self.write_message("connected")
def on_message(self, message):
print 'message received %s' % message
self.write_message('message received %s' % message)
def on_close(self):
print 'connection closed'
if __name__ == "__main__":
tornado.options.parse_command_line()
app = tornado.web.Application(
handlers=[
(r"/", IndexHandler),
(r"/ws", WebSocketHandler)
]
)
httpServer = tornado.httpserver.HTTPServer(app)
httpServer.listen(options.port)
print "Listening on port:", options.port
tornado.ioloop.IOLoop.instance().start()
Here are my 2 cents. I would advocate for the Python -> websockets-client route. The Tornado server software is made and tuned to handle web client requests. Let it do it's job. Any attempt to shoehorn it into another role (like monitoring local hardware) is going to cause more overhead than something which is either (a) designed to do such a job (like a C/C++ program) or (b) flexible enough to handle such a task with fairly little overhead (like a Python script).
Relevant Experience: Have programmed for both Raspberry Pi and Arduino. Officer in local robotics club.
I am trying to install the IPython html notebook server
on dotCloud. The IPython server uses tornado with websockets (and other internal communications using zeromq on tcp sockets).
Hhere's my dotcloud.yml:
www:
type: custom
buildscript: builder
ports:
nbserver: tcp
I am following the custom port recipes given here and here. As the logs show, I run the tornado server on 127.0.0.1:$DOTCLOUD_WWW_NBSERVER_PORT:
/var/log/supervisor/www.log:
[NotebookApp] The IPython Notebook is running at: 'http://127.0.0.1:35928/'
[NotebookApp] Use Control-C to stop this server and shut down all kernels.
But when I push, the dotCloud CLI tells me:
WARNING: The service crashed at startup or is listening to the wrong port. It failed to >respond on port "nbserver" (42801) within 30 seconds. Please check the application logs.
...
Deployment finished. Your application is available at the following URLs
No URL found. That's ok, it means that your application does not include a webservice."
There's nothing on my-app.dotcloud.com or my-app.dotcloud.com:DOTCLOUD_WWW_NBSERVER_PORT
What am I missing here? Thanks for your help.
UPDATE
Issue solved. The usual HTTP port works fine with websockets so the custom port recipes are not required. This is my new dotcloud.yml:
www:
type: custom
buildscript: builder
ports:
web: http
works with the following in ipython_notebook_config.py:
c.NotebookApp.ip = '*'
This makes it so that the tornado webserver listens to all ip addresses.
WARNING: setup security and authentication first!
See Running a Public Notebook Server for more information.
Glad you got it working!
In the future, and for other readers, you actually want your app to listen on $PORT_NBSERVER and then connect to it on DOTCLOUD_WWW_NBSERVER_PORT. $PORT_NBSERVER is the local port while the latter is the port that's exposed to the outside world through our routing/NAT layer.
If you have any other issue, don't hesitate to reach out to us at http://support.dotcloud.com
Source: I'm a dotCloud employee.
My aim is to do some automated testing over HTTP and HTTPS/SSL, via Rack, without recourse to a proxy server setup or anything like that. I have a gem that I want to test and I'd like for others to be able to run tests on too, so I'd like it to be as self contained as possible.
The code for App runs fine when run on it's own, so it's not included here, the problem is with the Rack part.
I'd like to do something like this:
app = Rack::Builder.app do
map "/" do
Rack::Handler::WEBrick.run App, Port: 3000
end
map "/ssl" do
Rack::Handler::WEBrick.run App, Port: 3001 # more options for SSL here...
end
end
run app
I've tried several combinations of the code above, like:
http = Rack::Builder.app do
map "/" do
run App
end
end
https = Rack::Builder.app do
map "/ssl" do
run App
end
end
Rack::Handler::WEBrick.run http, Port: 3000
Rack::Handler::WEBrick.run https, Port: 3001 # more options for SSL here...
With the two server setup up I tend to get one server run on the first port listed, then on interrupt it will run the second server on the next port listed - and then, on the next interrupt, either another server on 9292 or it shuts down.
I'm obviously doing something not quite right.
This is quite close, but ends up running the two servers via two different command line commands:
Starting thin server on different ports
Any help is much appreciated.
Current Thin does not support this -- I checked the source code.
Thin v2 is still pre-release, but the config code looks like it supports this via declaring multiple listeners in the config file.
But Thin v2 is still alpha software.
You can also switch to another server like Unicorn that does explicitly support binding to multiple ports or addresses.