Closed nmz787-intel closed 1 year ago
There's no register_blueprint
in this extension. See the documentation for usage.
I indeed searched the docs, there was no result for blueprint
.
I also tried porting the register_blueprint
method and associated members from flask_sockets
, but while I got no errors, my client's websocket requests were not heard in the server.
Have you considered not using a blueprint for your websocket route, which is how this is designed to work with this extension?
As I said, blueprints are currently not implemented, but this shouldn't impose any big limitations. For a Flask route you would need to have a global app
object. This isn't the case for Flask-Sock, since your route is defined on the sock
object, not on app
.
Can you provide a quick 2-file example? One where your app and Sock
is setup, and another with the routes for the Sock
? In my current server, my main.py
file has the app and flask_socket
, and then I have many other files (blueprints) which have the actual routes and response logic. I have 2 separate files for different websocket pages/applications... which are currently registered with the main.py flask_socket
object. So unless I make all my blueprints into classes, and then instantiate them after I create a flask_sock Sock
object and pass that into their constructor, I'm at a loss for a quick and clean way to go about transitioning.
Here you go. Added to this repo to help others with the same question: https://github.com/miguelgrinberg/flask-sock/tree/main/examples/blueprints
Another solution is to change the code of flask-sock to support blueprints:
In flask_sock/__init__.py
:
1) Add a reference to Blueprints by changing line 2:
from flask import Flask, Blueprint, request, Response, current_app
2) change the init function of class Sockets
for this one:
def __init__(self, app=None):
self.app = None
self.bp = None
if app is None:
self.bp = Blueprint('__flask_sock', __name__)
else:
if isinstance(app, Flask):
self.app = app
self.init_app(app)
elif isinstance(app, Blueprint):
self.bp = app
else:
raise AssertionError("Unknown type for app argument (must be Flask or Blueprint)")
Then in your blueprint file you can simply write:
app = Blueprint('MyBlueprint', __name__)
sockets= Sockets(app)
...
@sockets.route('/handler.sock')
def handler_socket(ws):
...
This works for me.
@ceprio that is a really bad idea, unless you plan on maintaining your own fork of this package. You will not be able to install upgrade if you make custom changes. You are obviously free to do whatever you like, but for the vast majority of people this isn't a workable solution.
@miguelgrinberg, I can also make a pull request when I get time. It would be for after the holidays. Though you seem negative about it: Do you see any issues in this implementation?
@ceprio I'm negative about this change because it doesn't make this package better. There is no need to use a blueprint as the parent of this extension, that does not provide any benefit. The OP wasn't asking about this, they were asking about how to incorporate Flask-Sock in a multi-file app that has blueprints, not to initialize this extension inside of a blueprint.
I see that we will not agree on this one. For me keeping the socket handler in the blueprint solution is of the upmost importance as each blueprint must be independant of each other, attached to that blueprint and the socket should be able to use the facilities of the blueprint. For example, when a user enters my blueprint I want this user to be authenticated and approved for this perticular blueprint. Same goes for the socket, if the socket is at the app level, I cannot validate permissions, if it is at the blueprint level then I can use Blueprint.before_request
to validate that user can indeed use the socket.
Here is an example of this (with the changes to flask_sock described above):
from flask import Blueprint, Flask, render_template
from flask_sock import Sockets
app = Flask(__name__)
play = Blueprint('simple_page', 'simple_page')
play_socket = Sockets(play)
@app.route('/')
def first_hit():
return 'Welcome to Websockets sample!<br>' + \
'<a href="/play/">Go to the Blueprint</a>'
@play.route('/')
def hello():
return 'You are in the Blueprint!<br>' + \
'<a href="/play/echo_test">Run the test</a>'
@play.route('/echo_test', methods=['GET'])
def echo_test():
return render_template('echo_test.html')
@play.before_request
def validate():
print("Validate the user permissions here.")
@play_socket.route('/echo')
def echo_socket(ws):
print(ws.environ['QUERY_STRING'])
print("Socket opened")
try:
while True:
message = ws.receive()
ws.send(message[::-1])
except Exception as e:
print(f"ws.exception: {type(e)}")
finally:
if ws.connected:
ws.close()
print("Socket closed")
@play_socket.route('/status_ping')
def ping(ws):
while not ws.closed:
message = ws.receive()
response = json.dumps({"Message":message, "Response":"Message received"})
ws.send(response)
########### Register blueprints ###########
app.register_blueprint(play, url_prefix=r"/play")
if __name__ == '__main__':
app.run()
Thanks for the example. I will think about how to support this use case.
@ceprio Just released Flask-Sock 0.6.0 with the option to put the WebSocket route in a blueprint. Example:
app = Flask(__name__)
play = Blueprint('play', __name__)
sock = Sock(app)
@sock.route('/ws', bp=play)
def websocket(ws):
pass
Thank you, your implementation is different than mine. I wonder why you are initializing the socket with the app instead of directly using the blueprint? You then need to specify the socket at each @sock.route. Was there any thing wrong with my code that I did not see?
@ceprio Flask-Sock is a Flask extension. The normal way to use extensions is to initialize them on the application instance. Your solution does not agree with this standard way of initializing extensions, and would create complications if you want to use websocket routes in more than one blueprint.
I am trying to convert from flask-sockets but I used blueprints before, having so many routes in my project for normal webpages, and multiple uses of websockets.
I tried simply replacing my
flask-sockets
import withflask-sock
, but get this error:how can I proceed?