DEV Community

Cover image for Implementing a Scalable Forex WebSocket Using a Python Proxy
Shridhar G Vatharkar
Shridhar G Vatharkar

Posted on

Implementing a Scalable Forex WebSocket Using a Python Proxy

This guide will teach you how to create a WebSocket proxy server in Python.

Here's what the server will do:

  • Verify client identity: Before allowing clients to connect, it will check whether each has a unique "user key (API Key)."
  • Connect to another WebSocket: The server will connect to a separate WebSocket server.
  • Relay messages: The server will receive messages from the connected WebSocket and send them to all verified clients.

Before you begin:

  • Make sure you have installed Python 3.6 or a newer version. WebSockets need Python 3.6 or higher.
  • Install the WebSockets library: You can install it using the following command in your terminal.
pip install websockets
Enter fullscreen mode Exit fullscreen mode

1. Getting Started

  • Create a new folder for your project.
  • Create a new Python file inside the folder and name it 'websocket_proxy_server.py.' This file will hold all the code for your server.

2. Create the WebSocket Server

  • Import the required libraries. You'll need the libraries you installed earlier.
  • Build the basic structure of your server. Use the WebSockets library to create the foundation for your server.
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)
Enter fullscreen mode Exit fullscreen mode

3. Connect and Verify Clients

  • Ensure that the server is all set to accept connections from clients.
  • Add a check to verify each client's identity. As a client tries to connect, the server should ask for a "user key." Only clients with the correct key will be allowed to connect.
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")
Enter fullscreen mode Exit fullscreen mode

4. Connect to the Source and Share Messages

  • Create a function that keeps the server connected to the original WebSocket.
  • This function should automatically send messages received from the original WebSocket to all successfully verified 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))
Enter fullscreen mode Exit fullscreen mode

5. Start the Server

  • Create a function to start the server and listen for connections.
  • Add code to run this function, starting your WebSocket proxy server.
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()

Enter fullscreen mode Exit fullscreen mode

In Summary

You have successfully developed a Python-based WebSocket proxy server. This server can authenticate client identities, maintain a persistent connection to a designated data source, and effectively distribute messages received from the source to all verified clients. This functionality proves invaluable for applications that necessitate the secure and instantaneous dissemination of data from a singular origin to a diverse user base.

Next Steps

Thorough server testing is crucial to ensure optimal performance and reliability. It verifies its proper handling of connections and message transmission. To enhance efficiency, consider implementing load-balancing mechanisms and customizing connection headers. Finally, it is advisable to deploy the server to a suitable environment for production deployment, such as a cloud service specifically designed to accommodate long-term network connections.

Also, please take a look at the originally published tutorial on our website: Scaling a Forex WebSocket with Python Proxy

Top comments (0)