BackWebSocket Proxy

Scaling a Forex WebSocket with Python Proxy

30 November 2023


In this tutorial, you'll develop a WebSocket proxy server using Python. The server will authenticate client requests with a specific user key, maintain a connection to a source WebSocket, and broadcast messages from the source to authenticated clients.

Prerequisites

Ensure you have Python 3.6 or newer installed, as WebSockets require this version or later. You’ll also need to install the WebSockets library, which you can do using pip:

pip install websockets


Step 1: Set Up Your Project

Create a new directory for your project and a Python file named websocket_proxy_server.py. This file will contain all your server code.

Step 2: Implement the WebSocket Server

Start by importing the necessary modules and setting up your basic server framework using the Web Sockets library:

import asyncio
import websockets
import json

class WebSocketProxy:

    def init(self, source_url, symbols):

        self.source_url = source_url
        self.clients = set()
        self.symbols = symbols
        self.valid_user_key = "yourValidUserKey"  # Single valid user key for authentication

    async def on_open(self, ws):

        print("Connected to source")
        symbols_str = ",".join(self.symbols.keys())
        init_message = f"{{"userKey":"your_api_key", "symbol":"{symbols_str}"}}"
        await ws.send(init_message)



Step 3: Handle Client Connections and Authentication

Extend your server to handle client connections. Implement authentication by checking the user key provided by the client upon connection:

async def client_handler(self, websocket, path):

        try:

            # Wait for a message that should contain the authentication key
            auth_message = await asyncio.wait_for(websocket.recv(), timeout=10)
            auth_data = json.loads(auth_message)
            user_key = auth_data.get("userKey")

            if user_key == self.valid_user_key:
                self.clients.add(websocket)
                print(f"Client authenticated with key: {user_key}")

                try:
                    await websocket.wait_closed()

                finally:
                    self.clients.remove(websocket)

            else:

                print("Authentication failed")
                await websocket.close(reason="Authentication failed")
        except (asyncio.TimeoutError, json.JSONDecodeError, KeyError):
            print("Failed to authenticate")
            await websocket.close(reason="Failed to authenticate")



Step 4: Connect to the Source WebSocket and Broadcast Messages

Set up a method to maintain a connection to the source WebSocket and broadcast any received messages to all authenticated clients:

  async def source_handler(self):
        async with websockets.connect(self.source_url) as websocket:
            await self.on_open(websocket)
            async for message in websocket:
                await self.broadcast(message)

    async def broadcast(self, message):
        if self.clients:
            await asyncio.gather(*(client.send(message) for client in self.clients))



Step 5: Running the Server

Complete your server setup by adding a function to start the server and a block to run it:

def run(self, host="localhost", port=8765):
        start_server = websockets.serve(self.client_handler, host, port)
        asyncio.get_event_loop().run_until_complete(start_server)
        asyncio.get_event_loop().run_until_complete(self.source_handler())
        asyncio.get_event_loop().run_forever()

if name == "main":
    symbols = {"EURUSD": {}, "GBPUSD": {}, "USDJPY": {}, "AUDUSD": {}, "USDCAD": {}}
    source_url = "ws://example.com/source"
    proxy = WebSocketProxy(source_url, symbols)
    proxy.run()



Conclusion

You've created a functional WebSocket proxy server in Python. This server authenticates clients, maintains a connection to the data feed, and broadcasts messages to authenticated clients using the WebSocket protocol. This is particularly useful for applications that require secure, real-time data distribution from a central source to multiple clients.


Testing and Deployment

Test the server locally to ensure it handles connections and broadcasts as expected. Implement load balancing and customize your connection headers. You can also use reverse proxy servers. Once verified, you can deploy the server to a more permanent environment for handling WebSocket connections, such as a cloud service supporting long-lived network connections.