Context: I have a websocket 'server.py' and a script that executes some tasks: 'worker.py'. I want to use the functions in server.py to send the results from that task in worker.py. But the thing is, when a client requests the worker to send results, i need to use a function from worker.py. How can I avoid circular dependies in this situation?
Server.py:
import eventlet
#eventlet.monkey_patch()
import socketio
from flask import Flask
from flask_cors import CORS
#The Worker file
import worker
sio = socketio.Server(cors_allowed_origins='http://localhost:8100')
#sio.on('connect')
def connectHandler(sid, environ):
print('[INFO] Incoming connection from: ' + environ['REMOTE_ADDR'])
sio.emit('response', {'data' : 'Connection established, you can now request classifications by firing the "requestClassification" event.'})
#sio.on('disconnect')
def disconnectHandler(sid):
print('disconnect ', sid)
#sio.on('requestClassification')
def requestHandler(data):
print('[INFO] recieved request to classify')
print(data)
#using a function in the worker module
worker.someFunc()
eventlet.wsgi.server(eventlet.listen(('127.0.0.1', 8080)), app)
worker.py:
import server
def work():
while True:
result = doSomeTask()
print(f'sending result: {str(i)}')
server.sio.emit('result', {'data' : result})
server.sio.sleep(1)
How can i properly use the imports without defining sio (the server) twice for example?
Related
Hey everyone I was tasked a few days ago to create an API style application that listens over a TCP socket for some commands then return some responses mainly success/failures (i know it's dumb but it's the client request) since I have some validation/database stuff I thought of flask directly but I am still stuck on how I am going to invoke the specific endpoints in code directly. here is a small snippet on how I am imagining things would be
from flask import Flask
import threading
data = 'foo'
app = Flask(__name__)
#app.route("/SomeCommand")
def SomeCommand():
return { 'Some' : 'Response'}
def flaskThread():
app.run()
def TcpListenner():
# logic that listens over tcp socket then invoks the flask app
# I was thinking about calling app.something() from here
pass
if __name__ == "__main__":
flaskApp = threading.Thread(target=flaskThread)
flaskApp.start()
listenner = threading.Thread(target=TcpListenner)
listenner.start()
any help/ideas would be much appreciated, thank you
You can use flask_socketio with which the flask app and socket i.e. tcp listener both start together...
Based on what I've understood, you can do something like this:
That the client will first make a connection to the flask socket.
Then, to send a command to the flask app, the client will send a message to the flask socket with the command in its message.
The flask socket will be listening for messages. So when it receives a message for the specific command, then it emits a response based on that command to the socket which will then be received by the client.
Below is an example code for the flask socket app:
import eventlet
eventlet.monkey_patch()
from flask import Flask
from flask_socketio import SocketIO, send, emit
app = Flask(__name__)
socketio = SocketIO(app, cors_allowed_origins="*", logger=True, engineio_logger=True)
# other flask APIs can come here and can be called by the client...
def someCommandOneResponse(): # function that sends response to client when flask socket gets command 1
commandOneResponse = 'Success'
socketio.emit('message', commandOneResponse)
def someCommandTwoResponse(): # function that sends response to client when flask socket gets command 2
commandTwoResponse = 'Failure'
socketio.emit('message', commandTwoResponse)
#socketio.on('message') # when any command is received on the socket from the client
def handleMessage(cmd):
print('\nCommand Received: ' + cmd + '\n')
if( cmd == 'SomeCommand1' ): # if the client has sent a message for command 1
print('Got Some Command 1')
someCommandOneResponse()
elif( cmd == 'SomeCommand2' ): # if the client has sent a message for command 2
print('Got Some Command 2')
someCommandTwoResponse
send(cmd, broadcast=True)
if __name__ == '__main__':
socketio.run(app, port=3000) # starts the flask socket (tcp listener) as well as the flask app
I have flask_socketIO Python server:
from flask import Flask
from flask_socketio import SocketIO
import time
app = Flask(__name__)
sio = SocketIO(app)
#sio.on("client_connect")
def client_connect():
sio.emit("test")
time.sleep(1) # Should be computationally complex code: for i in range(1000000): ...
sio.emit("test")
sio.run(app)
And socketio Python client:
from socketio import Client
import time
sio = Client()
sio.connect("http://localhost:5000")
#sio.event
def test():
print("TEST socket message", time.time())
sio.emit("client_connect")
So these steps should be performed:
Client connect to server
Client sends client_connect message to server
Server sends test message to client
Server waits 1 s
Server sends another test message to client
1 and 2 work, but instead of next steps server first waits 1 s and than sends test message twice in (almost) same time. So output of client is (both messages was received in the same second):
TEST socket message 1595397405
TEST socket message 1595397405
Am I doing something wrong?
So I have a simple flask server and wanted to listen to nsqd,(My nsqd and nsqlookupd dockers are running fine.) I'm using gnsq from python as a tool to achieve that
server.py:
from flask import Flask
import gnsq
consumer = gnsq.Consumer('test_topic', 'test_channel', '0.0.0.0:4161')
#consumer.on_message.connect
def handler(consumer, message):
print ('got message:', message.body)
consumer.start()
app = Flask(__name__)
#app.route("/")
def hello():
return "Flasky"
and when I run the server all I get is
[0.0.0.0:4161] connection failed (NSQSocketError(57, 'Socket is not connected'))
I tried changing ports as well but still persist.
I have stitched together a tornado websocket client code and using it in my python unit test case. This is my first time use of tornado websocket and not very familiar with its unit test API. Looking for some help to understand the use of tornado websocket asynchronous unit test code and the below case working.
Client class code:
import logging
import logging.config
import ssl
import time
import traceback
from tornado.concurrent import Future
from tornado import gen
from tornado.httpclient import HTTPError, HTTPRequest
from tornado.log import gen_log, app_log
from tornado.web import Application, RequestHandler
class TorWebSocketClient():
def __init__(self, ip_addr, port, cookie):
self.ip_addr = ip_addr
self.port = port
self.cookie = cookie
self.sockConnected = False
self.logger = logging.getLogger(__name__)
def Connect(self):
# Creating the websocket client for each test case.
url = "ws://{0}:{1}/socket{2}".format(str(self.ip_addr), str(self.port), self.cookie)
self.logger.debug('Websocket URL: ' + url)
sslopt={"cert_reqs": ssl.CERT_NONE,
"check_hostname": False,
"ssl_version": ssl.PROTOCOL_TLSv1}
self.logger.debug('New web socket connection is being establshed by the client')
self.ws = websocket.websocket_connect(HTTPRequest(url, headers=headers, ssl_options=sslopt), io_loop=self.io_loop)
# Start the websocket client thread. A wait is added till connection is established.
self.sockConnected = True
def send(self, data):
# Wait till websocket is connected.
if not self.ws.sock.connected:
self.logger.debug('Send failed; Websocket connection is not yet established')
return
self.logger.info('Sending data to the server: ' + data)
self.ws.write_message(data)
def recv(self, expValues):
# Read data from the response message.
resp = yield self.ws.read_message()
print '>>>> Response: ', resp
def stop(self):
self.logger.debug('Client closing the websocket connection with the server')
self.ws.close()
Unit test function is below:
import functools
import json
import logging
import logging.config
import time
# These are couple of custom classes.
import TorWebSocketClient
from infra.serverbase import Server
from tornado.testing import AsyncHTTPTestCase, gen_test, bind_unused_port, ExpectLog
class TornadoTest(AsyncHTTPTestCase):
def get_app(self):
app = tornado.web.Application([('/', EchoWebSocketHandler)])
return app
#gen_test
def testToradoWSConection(self):
# Login to the server to get the cookie.
logger = logging.getLogger(__name__)
server = Server(self.ipaddr, self.port, self.username, self.password)
result = server.Login()
self.assertEqual(result, True, 'login failed')
webSocClient = yield TorWebSocketClient(self.ipaddr, self.port, server.GetCookie())
result = webSocClient.Connect()
self.assertEqual(result, True, 'Websocket connection failed')
Error I am getting:
Traceback (most recent call last):
File "/users/usr1/pyvenv/venv/lib/python2.7/site-packages/tornado/testing.py", line 527, in post_coroutine
return self.io_loop.run_sync(
AttributeError: TornadoTest instance has no attribute 'io_loop'
----------------------------------------------------------------------
Ran 1 tests in 0.002s
FAILED (errors=1)
Did you have your own setUp function?
The io_loop is created under AsyncTestCase's setUp function, I think you need to call super's setUp function.
I am creating an Flask-socketio app, in which I want to send socket when an OSC message is received, in order to receive it into a web app thanks to socketio.js
from flask import Flask, render_template, copy_current_request_context, current_app
from flask_socketio import SocketIO, emit, send
from OSC import OSCClient, OSCMessage, OSCServer
import time, threading
app = Flask(__name__)
socketio = SocketIO(app)
client = OSCClient()
client.connect( ("localhost", 62345))
receive_address = ('localhost', 62346)
server = OSCServer(receive_address)
# simple callback functions
def answer_handler(addr, tags, stuff, source):
with app.app_context():
socketio.emit('tempo', 1)
# adding callback functions to listener
server.addMsgHandler("/puredata", answer_handler)
if __name__ == '__main__':
#Start OSCServer in extra thread
st = threading.Thread( target = server.serve_forever )
st.daemon = True
st.start()
print('OSC server is started')
socketio.run(app, host='0.0.0.0')
Even if I don't get error message, the socket is not receive from the javascript side, because the emit function is called in another thread, and there is conflicts with the request context.
I tried several things according to some other stackoverflow tickets :
socketio = SocketIO(app, async_mode='threading')
Adding this line before handler function
#copy_current_request_context
Or recreate a socketio instance into the callback
def answer_handler(addr, tags, stuff, source):
socketio_connection = SocketIO(app)
with app.app_context():
socketio_connection.emit('tempo', 1)
But none of these solution is working, and I need to integrate solve this 'context' problem into my thread.
Note that :
socketio.emit('tempo', 1)
is working great out of this thread , and received in the javascript part