The words Under construction in black text on a yellow background with diagonal black stipes surrounding it
I'm in the process of moving my site. It's still a work in progress. Please excuse the mess and broken links.

Setup A Python Flask Web Server With WebSockets

TODO: Pull subtitle into page object

### Overview

When you search `flask websockets` the first thing that comes up is Flask-SocketIO. Turns on, SocketIO and WebSockets aren't the same thing. Took me a while to figure that out. Once I did, I put together this example file of how to get flask and websockets running together via a single script. It:

- spins up a flask web server on port 5050 - spins up websockets on port 5051 - sets up the websockets so that incomings messages go to each client except the one that sent the original message - provides an index file at the root of the flask server that contains an example page (at http://localhost:5000/ that you can load multiple times to see the communication take place - Note that the way I'm excluding the client that sends the original message might not work all the time. I've seen it not send to other clients as well. Not sure about the behavior. If you have problems, see the note below about how to send to every client (including the one that sent the original message). (Maybe a single browser can use the same web socket for multiple tabs? If you know, let me know on [Twitter](https://twitter.com/TheIdOfAlan ))

code_start_default_section code_end_default_section

That's it. Happy Web Socketing!

Debugging Stuff

I'm moving stuff around right now. All this below is helping me figure out where to put stuff

        -- title

Setup A Python Flask Web Server With WebSockets

-- p

### Overview

-- p

When you search `flask websockets` the first thing that comes up is <<link|Flask-SocketIO|https://flask-socketio.readthedocs.io/en/latest/>>. Turns on, SocketIO and WebSockets aren't the same thing. Took me a while to figure that out. Once I did, I put together this example file of how to get flask and websockets running together via a single script. It:

-- p

- spins up a flask web server on port 5050
- spins up websockets on port 5051
- sets up the websockets so that incomings messages go to each client except the one that sent the original message
- provides an index file at the root of the flask server that contains an example page (at <<link|http://localhost:5000/|http://localhost:5000/)>> that you can load multiple times to see the communication take place
- Note that the way I'm excluding the client that sends the original message might not work all the time. I've seen it not send to other clients as well. Not sure about the behavior. If you have problems, see the note below about how to send to every client (including the one that sent the original message). (Maybe a single browser can use the same web socket for multiple tabs? If you know, let me know on [Twitter](https://twitter.com/TheIdOfAlan
))

-- code/
-- python

#!/usr/bin/env python3

import asyncio
import os
import subprocess
import sys
import time
import websockets

from flask import Flask, request, Response

python_path = sys.executable
script_path = os.path.realpath(__file__) 
domain = 'localhost'
http_port = '5050'
ws_port = '5051'

### Flask Stuff
app = Flask(__name__)

html_page = '''<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>WebSocket Example</title>
</head>
<body>
<input id="textField" />
<p id="outputField" />
<script>
'''

html_page += f'websocket = new WebSocket("ws://{domain}:{ws_port}/");'

html_page += '''
textField = document.getElementById('textField');
outputField = document.getElementById('outputField');
textField.addEventListener('input', () => {
    currentText = textField.value;  
    websocket.send(currentText);
});

websocket.addEventListener('message', (event) => {
    outputField.innerHTML = event.data
})


</script>
</body>
</html> 
'''

@app.route('/', methods=['GET'])
def respond2():
    return Response(
        status=200,
        response=html_page
    )

### Websocket stuff 

CONNECTIONS =  set()

async def register(websocket):
    CONNECTIONS.add(websocket)

async def unregister(websocket):
    CONNECTIONS.remove(websocket)

async def notify_users(message, websocket):
    connection_list = []
    for connection in CONNECTIONS:
        if connection != websocket:
            connection_list.append(connection)

    await asyncio.wait([
        connection.send(message) for connection in connection_list
    ])

async def message_control(websocket, path):
    await register(websocket)
    try:
        await websocket.send("Connected")
        async for message in websocket:
            print(message)
            await notify_users(message, websocket)
    finally:
        await unregister(websocket)


if len(sys.argv) == 2: 
    if sys.argv[1] == 'run_socket':
        print("\nStarting websocker server")
        start_server = websockets.serve(message_control, domain, ws_port)

        asyncio.get_event_loop().run_until_complete(start_server)
        asyncio.get_event_loop().run_forever()

else:
    time.sleep(1)
    print("Triggering websocket server")
    return_value = (subprocess.Popen([
        python_path,
        script_path,
        'run_socket'
    ]))

    print("Starting flask server")
    app.run(port=http_port)

-- /code

-- p

If you want the messages to be sent to all clients (including the one that originally sent the message), then change this:

-- code/
-- python

async def notify_users(message, websocket):
    connection_list = []
    for connection in CONNECTIONS:
        if connection != websocket:
            connection_list.append(connection)

    await asyncio.wait([
        connection.send(message) for connection in connection_list
    ])

-- /code

-- p

to this:

-- code/
-- python

async def notify_users(message, websocket):
    connection_list = []
    for connection in CONNECTIONS:
        connection_list.append(connection)

    await asyncio.wait([
        connection.send(message) for connection in connection_list
    ])

-- /code

-- p

That's it. Happy Web Socketing!


-- categories
-- Miscellaneous

-- metadata
-- date: 2021-05-29 00:00:00
-- id: 20eo3p4t
-- status: published
-- type: post
-- SCRUBBED_NEO: false
-- site: aws