I need some help regarding some minor problems in this chat server I've written. As you can see, I am using a global variable 'chat' to store newly submitted messages. This is because I can't find a working pubsub module for MongoDB (or I just don't know how to use one). Because of this, when 2 people send message almost at the exact same time, only the newer message is being outputted. Here is my current code:
#!/usr/bin/env python
import gevent
import gevent.monkey; gevent.monkey.patch_all()
from gevent.event import Event
from gevent.pywsgi import WSGIServer
from flask import Flask, request, Response, render_template, jsonify
import time
from pymongo import MongoClient
app = Flask(__name__)
app.config['DEBUG'] = True
a = Event()
chat = {}
def logchat(data):
client = MongoClient()
db = client.chatlog
db.bences.insert(data)
#app.route('/output')
def sse_request():
a.wait()
return jsonify(chat)
#app.route('/processchat', methods=['POST'])
def processchat():
global chat
ms = int(round(time.time() * 1000))
chat = {'name': request.form['chatname'], 'msg': request.form['chatmsg'], 'ts': ms}
a.set(); a.clear()
logchat(chat)
return jsonify(success=True)
#app.route('/')
def page():
return render_template('chat.html')
if __name__ == '__main__':
http_server = WSGIServer(('0.0.0.0', 80), app)
http_server.serve_forever()
What can you suggest for me to do? Thanks a lot!
Related
Good day to you all.
I have a project and need to use websocket to get the json data in realtime.
That external json with HTTPBasicAuth protected.
I want to use the current login id and password to do the authentication.
But got error.
Anyone can help?
Thank you.
Error Message :
RuntimeError: Working outside of request context.
This typically means that you attempted to use functionality that needed
an active HTTP request. Consult the documentation on testing for
information about how to avoid this problem.
from flask_socketio import SocketIO, emit
from flask import Flask, render_template, redirect, request, session,url_for, copy_current_request_context
from flask_session import Session
from flask import request
from random import random
from time import sleep
from threading import Thread, Event
import urllib.request, json
import json
import asyncio
import websockets
import requests
from requests.auth import HTTPBasicAuth
from flask_mysqldb import MySQL
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
app.config['DEBUG'] = True
#turn the flask app into a socketio app
socketio = SocketIO(app, async_mode=None, logger=True, engineio_logger=True)
#random number Generator Thread
thread = Thread()
thread_stop_event = Event()
def randomNumberGenerator():
user=session['email']
pass=session['password']
res = requests.get('https://json.source.com', verify=False, auth=HTTPBasicAuth(user, password))
socketio.emit('newnumber', {'data': res.json()}, namespace='/test')
socketio.sleep(1)
#app.route("/")
def index():
# check if the users exist or not
if not session.get("email"):
# if not there in the session then redirect to the login page
return redirect("/login")
return render_template('index.html', email=session['email'])
#app.route("/login", methods=["POST", "GET"])
def login():
# if form is submited
if request.method == "POST":
# record the user name
session["email"] = request.form.get("email")
session["password"] = request.form.get("password")
# redirect to the main page
return redirect("/")
return render_template("login.html")
#app.route("/logout")
def logout():
session["email"] = None
return redirect("/")
#socketio.on('connect', namespace='/test')
def test_connect():
# need visibility of the global thread object
global thread
print('Client connected')
#Start the random number generator thread only if the thread has not been started before.
if not thread.is_alive():
print("Starting Thread")
thread = socketio.start_background_task(randomNumberGenerator)
#socketio.on('disconnect', namespace='/test')
def test_disconnect():
print('Client disconnected')
if __name__ == '__main__':
socketio.run(app)
I was trying to make a slack bot using slackeventsapi running on ngrok for now.
It can send messages properly but slack events adaptor doesn't seem to be working properly. It gives the code 200 every time a message is sent but the payload doesn't come. I tried printing it but the printing it shows nothing.
There was another post asking a similar question whose solution in the end was to make a new app on slack API but it doesn't seem to fix my issue. I have made another app but the issue persists.
I was following a tutorial so I have tried to match his code exactly but it doesn't seem to work even then. In case it will be helpful - https://www.youtube.com/watch?v=6gHvqXrfjuo&list=PLzMcBGfZo4-kqyzTzJWCV6lyK-ZMYECDc&index=2.
The slack API scopes
Slack API Subscriptions
import slack
import os
from pathlib import Path
from dotenv import load_dotenv
from flask import Flask
from slackeventsapi import SlackEventAdapter
env_path = Path('.')/'.env'
load_dotenv(dotenv_path=env_path)
client = slack.WebClient(token=os.environ['TEST2_SLACK_TOKEN'])
BOT_ID = client.api_call("auth.test")['user_id']
app = Flask(__name__)
slack_event_adaptor = SlackEventAdapter(os.environ['SIGNING_SECRET2'], '/slack/events', app)
client.chat_postMessage(channel=f'#new', text="Hello")
if __name__ == "__main__":
app.run(debug=True)
#slack_event_adaptor.on('message')
def message(payload):
print(payload)
event = payload.get('event',{})
channel_id = event.get('channel')
user_id = event.get('user')
text = event.get('text')
if BOT_ID != user_id:
client.chat_postMessage(channel= channel_id, text = text)
I had similar problem when I used slack_event_adaptor and then I tried slack_bolt and everything works well. Let me share example you may try if you want:
import re
from config import config
from flask import Flask, request
from slack_sdk import WebClient
from slack_bolt import App
from slack_bolt.adapter.flask import SlackRequestHandler
app = Flask(__name__)
slack_token = config.slack_token
client = WebClient(slack_token)
bolt_app = App(token=slack_token, signing_secret=config.signing_secret)
handler = SlackRequestHandler(bolt_app)
#bolt_app.message(re.compile("Hello bot",re.IGNORECASE))
def reply_in_thread(payload: dict):
""" This will reply in thread instead of creating a new thread """
response = client.chat_postMessage(channel=payload.get('channel'),
thread_ts=payload.get('ts'),
text=f"Hello<#{payload['user']}>")
#app.route("/datalake/events", methods=["POST"])
def slack_events():
""" Declaring the route where slack will post a request """
return handler.handle(request)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)
When you write "Hello bot" bot will respond you accordingly.
Is there a way to return multiple responses to 1 get request?
I have a basic flask app where I am trying to make it run another python app and send the terminal logs to the client side.
I can return a json value but I can't return any text or the output of the terminal.
Here is the server side:
from flask import Flask, stream_with_context, request, Response
from flask_restful import Api, Resource
from flask_socketio import SocketIO
import intermedia_choose_action_flask
import subprocess
app = Flask(__name__)
api = Api(app)
socketio = SocketIO(app)
class spamblacklistsend(Resource):
def get(self):
imapp = subprocess.Popen(["python3", "/home/tech/scripts/Intermedia_automate/intermedia_choose_action.py", "--addblockeveryone", "--ed", "test#fakeu.com"], bufsize=10, errors='replace')
imapp.app_context().push()
# p = subprocess.Popen(["python3", "/home/tech/scripts/Intermedia_automate/intermedia_choose_action.py", "--addblockeveryone", "--ed", "test#fakeu.com"], bufsize=10, errors='replace')
return imapp.app_context().push()
api.add_resource(spamblacklistsend, "/spamblacklistsend")
if __name__ == "__main__":
app.run(debug=True)
Here is the client side:
from flask import json
import requests
BASE = "http://127.0.0.1:5000/"
response = requests.get(BASE + "spamblacklistsend")
print(imapp.app_context().push())
I know that return stops the function. Is there anyway to return and continue?
I'm working in a web based app to my company. Recently I've gotten stuck with a 'basic' problem to make SQL scripts to a database (OracleDB).
I'm using Flask-SocketIO webserver with async-mode='gevent', and apparentely when you execute the cx_Oracle.connection.cursor.execute(), is blocking my entire app, until the response returns (webserver stops receiving others requests).
I have searching a answer to the question, and I realized that the cx_Oracle isn't running parallel the others clients and requests.
Example of the problem:
from gevent import monkey; monkey.patch_all()
from flask_socketio import SocketIO
from flask import Flask
import cx_Oracle
app = Flask(__name__, template_folder='templates')
app.secret_key = 'testing'
app.config['DEBUG'] = False
socketio = SocketIO(app, async_mode='gevent')
#app.route('/')
def index():
sql_query = 'select * from blabla'
connection = cx_Oracle.connect(user, password, host, threaded=True)
cursor = connection.cursor()
cursor.execute(sql_query)
transacoes = cursor.fetchall()
socketio.run(app, host='localhost', port=5005)
When I make more than 1 request to http://localhost/, my app doesn't response the 2+ requisitions until the first has done.
I tried to implement a gevent.ThreadPool to make more than 1 query in parallel, but i have faced the problem:
Example of the code with gevent.ThreadPool:
from gevent import monkey; monkey.patch_all()
from gevent.threadpool import ThreadPool
from flask_socketio import SocketIO
from flask import Flask
import cx_Oracle
app = Flask(__name__, template_folder='templates')
app.secret_key = 'testing'
app.config['DEBUG'] = False
socketio = SocketIO(app, async_mode='gevent')
def receive_data(user, password, host, sql_query):
connection = cx_Oracle.connect(user, password, host, threaded=True)
cursor = connection.cursor()
cursor.execute(sql_query)
response = cursor.fecthall()
cursor.close()
connection.close()
return response
#app.route('/')
def index():
sql_query = 'select * from blabla'
pool = ThreadPool(1) # I tried with more than 100
async_result = pool.apply_async(receive_data,
args=(user, password, host, sql_query))
transacoes = async_result.get()
socketio.run(app, host='localhost', port=5005)
I get the error when multiple requests is made in receive_data():
RuntimeError: Working outside of application context.
This typically means that you attempted to use functionality that
needed to interface with the current application object in a way. To
solve this set up an application context with app.app_context(). See
the documentation for more information.
And:
'LoopExit: This operation would block forever
To resolve this, I change the async_mode='gevent' to async_mode='threading' and remove the monkey_patch().
I don't know what impacting in my app, but all the system aparently runs ok.
I found another solution for this problem.
When a module doesn't support monkey_path, the eventlet sugests you to use eventlet.tpool http://eventlet.net/doc/threading.html.
Example:
from eventlet import tpool
cur = tpool.execute(cx_Oracle.connect, connection_string, *args, **kwargs)
This solves the main problem, and now I can use socketio whith "async_mode=eventlet".
I am receiving some socket.io event. After the event is handled I would like to redirect the user to some page. However, the redirection doesn't work. I don't know what is wrong. Below is my code:
from flask import Flask, render_template, send_from_directory, redirect, url_for
from flask_socketio import SocketIO, emit
import base64
import os
import random, string
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app)
#app.route('/')
def index():
try:
image_names = os.listdir('./images')
print image_names
return render_template("gallery.html", image_names=image_names)
except Exception as ex:
print ex
#socketio.on('takephoto')
def takePhoto(*args):
try:
decoded = base64.b64decode(args[0])
filename = ''.join(random.choice(string.lowercase) for x in range(6)) + '.jpg'
with open("./images/" + filename, "wb") as fh:
fh.write(args[0].decode('base64'))
except Exception, ex:
print ex
redirect(url_for('index')) #This doesnt work
#how can i go to index from this point?
if __name__ == '__main__':
from gevent import pywsgi
from geventwebsocket.handler import WebSocketHandler
app.debug = True
server = pywsgi.WSGIServer(('', 5001), app, handler_class=WebSocketHandler)
server.serve_forever()
I think you are missing the return statement.
return redirect(url_for('index'))
A little late to the party, but I just ran into this. Emitting a 'redirect' event and sending url_for('index') all via sockets is your best bet.
Server side:
emit('redirect', url_for('auth.login'), namespace=request.namespace, room=[request.sid])
Client side:
socket.on('redirect', (dest) => {
window.location.href = dest;
});