i'm trying to create a web extension using native messaging that can interact with a Web API. So the idea is when someone sends a message through the API, the extension also receive it.
I follow the steps of the firefox example. So far so good, i was able to communicate between the host and the extension.
Here is my host code, using the flask framework:
import json
import sys
import struct
import threading
import os
from flask import Flask, request, jsonify, Response, abort
# Read a message from stdin and decode it.
def get_message():
raw_length = sys.stdin.read(4)
if not raw_length:
sys.exit(0)
message_length = struct.unpack('=I', raw_length)[0]
message = sys.stdin.read(message_length)
return json.loads(message)
# Encode a message for transmission, given its content.
def encode_message(message_content):
encoded_content = json.dumps(message_content)
encoded_length = struct.pack('=I', len(encoded_content))
return {'length': encoded_length, 'content': encoded_content}
# Send an encoded message to stdout.
def send_message(encoded_message):
sys.stdout.write(encoded_message['length'])
sys.stdout.write(encoded_message['content'])
sys.stdout.flush()
def get_message_background():
while True:
message = get_message()
if message == "ping":
send_message(encode_message("pong"))
thread = threading.Thread(target=get_message_background)
thread.daemon = True
thread.start()
app = Flask(__name__)
#app.route("/test", methods=['GET'])
def test():
send_message(encode_message('testing'))
return 'testing'
app.run('localhost', 5001, debug=True)
With this code i receive a ping and respond a pong.
The problem is when i try to run that code on the terminal.
The native messaging communicates over stdio and when i'm run my script on the terminal, the terminal became the standard input and output.
If i just load the extension, the flask not start.
Someone has solved this problem?
PS: Sorry for my english
Related
i am experimenting with flask and have a basic web page setup that gives me a data field to fill in. it all works ok, but i am having a problem with sending data via a socket connection to a server. the code is below:
from flask import Flask, render_template, request
import socket
import sys
app = Flask(__name__)
app.static_folder = 'static'
HOST, PORT = '', 8888
#app.route('/')
def index():
return render_template("index.html")
#app.route('/success', methods=['POST'])
def success():
if request.method == 'POST':
if request.form['Update'] == 'Update':
messsage_name = request.form["message_name"]
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as soc:
# connect to server if we have a post
soc.connect((HOST, PORT))
soc.sendall(bytes(messsage_name + "\n", "utf-8"))
return render_template("index.html")
if __name__ == '__main__':
app.debug = True
app.run()
I want to open the socket once then send data via it each time the update button is pressed, at present the only way i can get it to work is keep opening the socket as in the above code in success. I don't want the socket to close until the flask app quits.
whats the best way to achieve my goal
thanks
I think your title is wrong. In your example there is no use of socketIO library.
For using socketIO in your flask application, you need to install the library like this:
pip install flask-socketio
And then you can import it in your python file as:
from flask_socketio import SocketIO, emit
You can then use socketIO and emit some messages/data to your web page.
By the way your sockets, initialized as before, will live as long as your Flask server is on. More information available over there.
If your goal is to use the Python sockets, then you have to edit your question title.
I'm trying to create a python app that can send message from server to client. Currently I'm using this sample code from here. It's a chat app and it's working fine. I tried to modified the app and add a new function in the server side python code that will print a message "Dummy" into the client but seems like it didn't work.
Here's my html code:
index.html
<body>
<ul id="messages"></ul>
<ul id="output"></ul>
<form action="">
<input id="m" autocomplete="off" /><button>Send</button>
</form>
<script src="{{url_for('static', filename='assets/vendor/socket.io.min.js')}}"></script>
<script src="{{url_for('static', filename='assets/vendor/jquery.js')}}"></script>
<script>
var socket = io.connect('http://127.0.0.1:5000/chat');
$('form').submit(function(){
socket.emit('chat message', $('#m').val());
$('#m').val('');
return false;
});
socket.on('chat message', function(msg){
$('#messages').html($('<li>').text(msg));
});
socket.on('output', function(msg){
alert(msg)
$('#messages').html($('<li>').text(msg));
});
</script>
Here's my backend code:
web_app.py
from flask import Flask
from flask import render_template
from flask_socketio import SocketIO
from flask_socketio import emit
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app)
connected = False
def socket_onload(json):
socketio.emit('output', str(json), namespace='/chat')
print('received message: ' + str(json))
#socketio.on('chat message', namespace='/chat')
def handle_chat_message(json):
print('received message: ' + str(json))
emit('chat message', str(json), broadcast=True)
#socketio.on('connect') # global namespace
def handle_connect():
global connected
connected = True
print('Client connected')
#socketio.on('connect', namespace='/chat')
def handle_chat_connect():
print('Client connected to chat namespace')
emit('chat message', 'welcome!')
#socketio.on('disconnect', namespace='/chat')
def test_disconnect():
print('Client disconnected')
#app.route('/')
def index():
return render_template('index.html')
#app.route('/blah/')
def blah():
return render_template('blah.html')
main.py
import web_app
import threading
import time
def main():
import web_app
webapp_thread = threading.Thread(target=run_web_app)
webapp_thread.start()
# webapp_thread = threading.Thread(target=run_web_app, args=(i,))
while web_app.connected==False:
print "waiting for client to connect"
time.sleep(1)
pass
print "Connected..."
time.sleep(3)
print "Trying to print dummy message..."
web_app.socket_onload("Dummy")
def run_web_app():
web_app.socketio.run(web_app.app)
if __name__ == '__main__':
main()
I can see "received message: Dummy" in the terminal but nothing's change on the web browser.
You have two mistakes which prevent you from doing so:
First, you are trying to emit an event with socket.io outside from the socket context.
When a function is wraped with #socketio.on decorator, it becomes an Event-Handlers.
While an event is fired on the server-side it will search for the right handler to handle the event and initialize the context to the specific client that emitted the event.
Without this context initializing, your socketio.emit('output', str(json), namespace='/chat') will do nothing because the server doesn't know to whom it should emit back the response.
Anyway, there is a little trick for emitting events manually to a specific client (even if you are not in its context). Each time a socket has opened, the server assign it to a "private" room with the same name as the socket id (sid). So in order to send a message to the client outside from the client context, you can create a list of connected client's ids and call the emit function with the room=<id> argument.
For example:
web_app.py:
...
from flask import Flask, request
clients = []
#socketio.on('connect')
def handle_connect():
print('Client connected')
clients.append(request.sid)
#socketio.on('disconnect')
def handle_disconnect():
print('Client disconnected')
clients.remove(request.sid)
def send_message(client_id, data):
socketio.emit('output', data, room=client_id)
print('sending message "{}" to client "{}".'.format(data, client_id))
...
Then you would probably use this as follow:
main.py:
import web_app
import threading
import time
def main():
webapp_thread = threading.Thread(target=run_web_app)
webapp_thread.start()
while not web_app.clients:
print "waiting for client to connect"
time.sleep(1)
print "Connected..."
time.sleep(3)
print "Trying to print dummy message..."
web_app.send_message(web_app.clients[0], "Dummy")
...
But even if you try this, it will not work (which brings us to the second mistake).
Second, you are mixing eventlet with regular Python threads and it's not a good idea. the green threads that eventlet uses do not work well with regular threads. Instead, you should use green threads for all your threading needs.
One option which I found in the internet, is to monkey patch the Python standard library, so that threading, sockets, etc. are replaced with eventlet friendly versions. You can do this at the very top of your main.py script:
import eventlet
eventlet.monkey_patch()
After that it should work fine (I tried it on my own). Let me know if you have another problems...
These decorators are there for simply loading the pages index.html and blah.html these don't do anything --- don't pass any variable or don't write anything to the template they just render it, meanwhile all the things you are doing are there for the command line if you have to print or pass anything it would have to be in these functions :
#app.route('/')
def index():
return render_template('index.html')
#app.route('/blah/')
def blah():
return render_template('blah.html')
My question is related to having an Arduino Uno communicate data through a socket to another client app. [A buzzer system communicating to a Jeopardy!-esque game frontend] To goal is to have the 'lockout' event emit.
Currently, the Arduino is running on its own thread and the Flask-SocketIO server is running as the main process. All code works, including the print statement saying "Emitting Socket", except for the line emitting the socket data after.
I feel like this is just a multithreading issue, but my experience with multithreading is minimal.
Suggestions?
# https://pymotw.com/2/threading/
# https://flask-socketio.readthedocs.org/en/latest/
import serial, time, threading
from flask import Flask, render_template
from flask_socketio import SocketIO
ser = serial.Serial('/dev/tty.usbmodem3d11', 9600, dsrdtr=1)
PORT = 3000
# Needed b/c Macs & DTR
time.sleep(5)
def getSerialData():
while True:
stuff = str(ser.readline().decode("utf-8"))
doEmit(1)
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app)
def doEmit(pNo):
print("Emitting Socket")
socketio.emit('lockout', {'playerNo': 1})
serialThread = threading.Thread(name='serialThread', target=getSerialData)
serialThread.start()
#socketio.on("questionRead")
def on_questionRead(data):
print("-------Start-------")
ser.write(b'y\r')
#socketio.on("resetLockout")
def on_resetLockout(data):
resetLockout()
def resetLockout():
print("--------Reset--------")
ser.write(b'n\r')
if __name__ == '__main__':
socketio.run(app, '127.0.0.1', PORT)
You emit a 'lockout' message here:
def doEmit(pNo):
print("Emitting Socket")
socketio.emit('lockout', {'playerNo': 1})
I don't see where you're providing the function to receive this emitted code. Perhaps adding something like this with the appropriate adjustments:
#socketio.on("lockout")
def on_lockout(data):
print("-------Lockout Player", data['playerNo'] , "-------")
So here's the deal : I'm writing a simple lightweight IRC app, hosted locally, that basically does the same job as Xchat and works in your browser, just as Sabnzbd. I display search results in the browser as an html table, and using an AJAX GET request with an on_click event, the download is launched. I use another AJAX GET request in a 1 second loop to request the download information (status, progress, speed, ETA, etc.). I hit a bump with the simultaneous AJAX requests, since my CGI handler seems to only be able to handle one thread at a time : indeed, the main thread processes the download, while requests for download status are sent too.
Since I had a Django app somewhere, I tried implementing this IRC app and everything works fine. Simultaneous requests are handled properly.
So is there something I have to know with the HTTP handler ? Is it not possible with the basic CGI handle to deal with simultaneous requests ?
I use the following for my CGI IRC app :
from http.server import BaseHTTPRequestHandler, HTTPServer, CGIHTTPRequestHandler
If it's not about theory but about my code, I can gladly post various python scripts if it helps.
A little bit deeper into the documentation:
These four classes process requests synchronously; each request must be completed before the next request can be started.
TL;DR: Use a real web server.
So, after further research, here's my code, whick works :
from http.server import BaseHTTPRequestHandler, HTTPServer, CGIHTTPRequestHandler
from socketserver import ThreadingMixIn
import threading
import cgitb; cgitb.enable() ## This line enables CGI error reporting
import webbrowser
class HTTPRequestHandler(CGIHTTPRequestHandler):
"""Handle requests in a separate thread."""
def do_GET(self):
if "shutdown" in self.path:
self.send_head()
print ("shutdown")
server.stop()
else:
self.send_head()
class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
allow_reuse_address = True
daemon_threads = True
def shutdown(self):
self.socket.close()
HTTPServer.shutdown(self)
class SimpleHttpServer():
def __init__(self, ip, port):
self.server = ThreadedHTTPServer((ip,port), HTTPRequestHandler)
self.status = 1
def start(self):
self.server_thread = threading.Thread(target=self.server.serve_forever)
self.server_thread.daemon = True
self.server_thread.start()
def waitForThread(self):
self.server_thread.join()
def stop(self):
self.server.shutdown()
self.waitForThread()
if __name__=='__main__':
HTTPRequestHandler.cgi_directories = ["/", "/ircapp"]
server = SimpleHttpServer('localhost', 8020)
print ('HTTP Server Running...........')
webbrowser.open_new_tab('http://localhost:8020/ircapp/search.py')
server.start()
server.waitForThread()
I am attempting to pass binary data over websockets, more specifically compressed strings over websockets. In my current setup I use tornado as the server with a websocket client transmitting the binary data. The binary data is formed by compressing the data with zlib. Both client and server are as simple as they get and are shown below.
Server:
import tornado.websocket
import tornado.httpserver
import tornado.ioloop
import tornado.web
class WebSocketServer(tornado.websocket.WebSocketHandler):
def open(self):
print 'OPEN'
def on_message(self, message):
print 'len = {}'.format(len(message))
print 'GOT MESSAGE: {}'.format(message.decode('zlib'))
def on_close(self):
print 'CLOSE'
app = tornado.web.Application([
(r'/', WebSocketServer)
])
http_server = tornado.httpserver.HTTPServer(app)
http_server.listen(9500)
tornado.ioloop.IOLoop.instance().start()
Client:
import websocket
host = 'localhost'
port_ws = 9500
ws = websocket.create_connection('ws://{}:{}/'.format(host, port_ws))
message = 'this is my message'.encode('zlib')
print 'Length of message is {}'.format(len(message))
ws.send(message)
The client does not throw any errors, it prints out that the message: Length of message is 24. The message is encoded as a str as per the zlib standard. The server on the other end does not show that it received any messages, it just understands that a client had connected, and then disconnected. Does anyone know where the problem is? I am not sure if the problem lays within tornado or the websockets library. Any suggestions?
EDIT: In response to the comment below (#plg), I modified the scripts above to show that:
Non-encoded messages can be send from client to the tornado server
Tornado can reply with an encoded message
Server:
import tornado.websocket
import tornado.httpserver
import tornado.ioloop
import tornado.web
class WebSocketServer(tornado.websocket.WebSocketHandler):
def open(self):
print 'OPEN'
def on_message(self, message):
print 'len = {}'.format(len(message))
print 'GOT MESSAGE: {}'.format(message)
self.write_message(message.encode('zlib'))
def on_close(self):
print 'CLOSE'
app = tornado.web.Application([
(r'/', WebSocketServer)
])
http_server = tornado.httpserver.HTTPServer(app)
http_server.listen(9500)
tornado.ioloop.IOLoop.instance().start()
Client:
import websocket
host = 'localhost'
port_ws = 9500
ws = websocket.create_connection('ws://{}:{}/'.format(host, port_ws))
#message = 'this is my message'.encode('zlib')
message = 'this is my message'
print 'Length of message is {}'.format(len(message))
ws.send(message)
assert ws.recv().decode('zlib') == message
The system works just fine. The assert does not throw an error. The decoded message matches the send message. So I guess there is a problem with either:
Sending an encoded message from the client
Tornado receiving encoded messages
To be quite honest, I do believe that the first option is more probable than tornado. In my opinion, I believe tornado would alert me if an incoming message is not properly decoded as per the websocket standard. Any more suggestions?
EDIT: More development on who is at fault. Instead of using my own server to relay back and fourth my connection, I relayed the connection to ws://echo.websocket.org/. My testing application is as shows:
import websocket
host = 'localhost'
port_ws = 9500
ws = websocket.create_connection('ws://echo.websocket.org/')
message = 'this is my message'
ws.send(message.encode('zlib'))
got = ws.recv().decode('zlib')
print 'GOT: {}'.format(got)
assert got == message
This actually passed the test, the data was received just fine. So I guess there is something wrong with tornado receiving the data?
After looking though the source code of the websocket library, I found that by default it is formatting the packets as text. By changing the line:
ws.send('message')
# to:
ws.send('message', opcode=websocket.ABNF.OPCODE_BINARY)
# or better yet:
ws.send_binary('message')
The packet will be sent over just fine. Tornado I guess was just ignoring the fake binary packets since they were marked as text and contained binary.
Thanks to this commit tornado supports websocket compression extensions.