-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhello_sockets.py
77 lines (57 loc) · 5.56 KB
/
hello_sockets.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
from flask import Flask, render_template, session, request
from flask_socketio import SocketIO, emit, disconnect
app = Flask(__name__)
app.debug = True # use this when testing
# app.debug = False # use this to fully use websockets
app.config['SECRET_KEY'] = 'obviously not a good secret key'
socketio = SocketIO(app)
@app.route('/')
def index():
return render_template('hello_sockets.html')
# SocketIO syntax is as follows: @socketio.on(your_event_name, namespace='/your_name_space')
# The first argument to the decorator, your_event_name, is of course, your custom event name.
# From the docs: Event names 'connect', 'disconnect', 'message' and 'json' are special events generated by SocketIO. Any other event names are considered custom events.
# The second argument is optional and lets you specify the namespace in which your event will run. Think of namespace as a specific chatroom in which you allow your event to run, i.e. this event will only run in the specified chatroom.
# If you do not define the namespace, the event will be allowed to be attached to the default global namespace (i.e. any chatroom/namespace will have access to it).
# From the docs: Events can be defined inside a namespace by adding the namespace optional argument to the socketio.on decorator. Namespaces allow a client to open multiple connections to the server that are multiplexed on a single socket. When a namespace is not specified the events are attached to the default global namespace.
# What does this mean? More accurately, when a namespace is not defined a default global namespace with the name '/' is used. So your events without a namespace defined can access said global namespace if you do not specify a "chatroom name".
# Quiz 1
# If this event handler, @socketio.on('my_event'), is a custom event name, then why are @socketio.on('message') and @socketio.on('json') unnamed events?
# Hint: Check the docs under "Receiving Messages".
# Answer: Events with the reserved event names of 'message' and 'json' are special events generated by SocketIO. Any other event names are considered custom events.
# In this workshop, to send events between our server and the client, and vice versa, we will be using the emit() function provided by Flask-SocketIO to send a message (under a custom event name).
# Quiz 2
# What is send() used for, and why do we not use it here?
# Hint: Check the docs under "Sending Messages".
# send() is used for reserved unnamed events only, viz. message and json. emit() is for named events.
# It is worth noting that messages are sent to and ONLY to the connected client by default (i.e. messages that John sends are obviously sent to himself, but not other users like Dick or Harry who may be in the same namespace/chatroom by default).
# But, if you specify broadcast=True (an optional argument), all clients connected to the namespace will receive the message (i.e. if we turn on broadcast=True, the messages that John sends will now be broadcasted to Dick and Harry who are connected to the same namespace/chatroom).
@socketio.on('connect', namespace='/test') # think of this as a listener
def test_connect():
emit('display_message', {'data': 'Connected', 'count': 0}) # when you are just connected, the message count will start from 0
@socketio.on('send_to_self', namespace='/test')
def test_message(message):
session['receive_count'] = session.get('receive_count', 0) + 1 # get() is actually a Python method - When get() is called, Python checks if the specified key exists in the dict. If it does, then get() returns the value of that key. If the key does not exist, then get() returns the value specified in the second argument to get(). For more information, check this out: https://blog.miguelgrinberg.com/post/flask-socketio-and-the-user-session
emit('display_message',
{'data': message['data'], 'count': session['receive_count']}) # thereafter, the message count (which is "remembered" in session) increases incrementally
@socketio.on('send_to_all', namespace='/test')
def test_broadcast_message(message):
session['receive_count'] = session.get('receive_count', 0) + 1
emit('display_message',
{'data': message['data'], 'count': session['receive_count']},
broadcast=True) # broadcast = True means sending data to everyone in the namespace/chatroom
if __name__ == '__main__':
# Check if eventlet is installed.
# This Flask websocket app would still work great without eventlet, but for the purposes of this workshop, we just want to make sure you have it installed first so that we can use it. (Else flask-socketio will use long-polling instead, which is exactly what we do NOT want to be doing.)
import pip
installed_packages = pip.get_installed_distributions()
package_names = [package.project_name for package in installed_packages]
print ('\nEVENTLET STATUS:')
if not 'eventlet' in package_names:
print ('eventlet not installed, aborting... please install using $ pip install eventlet\n')
else:
print ('eventlet is installed - you are good to go!\n')
# From the docs:
# The Flask-SocketIO extension is initialized in the usual way, but to simplify the start up of the server a custom run() method is provided by the extension. This method attempts to start a web server in the following order: eventlet, followed by gevent, and lastly the Flask development web server.
# The run() method takes optional host and port arguments, but by default it will listen on localhost:5000 like Flask's development web server.
socketio.run(app)