186 lines
6.5 KiB
Python
186 lines
6.5 KiB
Python
"""
|
|
|
|
AUTHOR:
|
|
|
|
Khushal P Soonderji
|
|
|
|
DATE:
|
|
|
|
Create: Monday, 29th Sept., 2025
|
|
|
|
OBJECTIVE:
|
|
|
|
To have a centralized Socket.IO app from where several namespaces can be registered. This is kind of like how
|
|
you can have one Quart app and register several blueprints.
|
|
|
|
REFERENCES:
|
|
|
|
N/A
|
|
|
|
DOWNLOADS:
|
|
|
|
N/A
|
|
|
|
"""
|
|
|
|
|
|
# *****************************************************************************************************************
|
|
# ***** ****
|
|
# *** IMPORT ***
|
|
# ***** ****
|
|
# *****************************************************************************************************************
|
|
|
|
|
|
# To make sibling directories accessible for imports:
|
|
import sys
|
|
sys.path.append(".")
|
|
sys.path.append("..")
|
|
|
|
# System-level activities:
|
|
import os
|
|
|
|
# To make HTTP calls:
|
|
import httpx
|
|
|
|
# To work with SocketIO:
|
|
import socket
|
|
import socketio
|
|
|
|
# To maintain the app's state:
|
|
from wsio_v2.app_state import AppState
|
|
from wsio_v2.test.echo import EchoNamespace
|
|
|
|
# Debugging:
|
|
from icecream import IceCreamDebugger
|
|
|
|
|
|
# *****************************************************************************************************************
|
|
# ***** ****
|
|
# *** MACROS / ONE-TIME INIT ***
|
|
# ***** ****
|
|
# *****************************************************************************************************************
|
|
|
|
|
|
# A custom class to maintain the app's state:
|
|
app_state = AppState()
|
|
|
|
# Debugging:
|
|
app_state.printer = IceCreamDebugger(prefix = "WSIO | ", includeContext = True)
|
|
app_state.no_context_printer = IceCreamDebugger(prefix = "WSIO | ", includeContext = False)
|
|
|
|
# To make API calls:
|
|
app_state.http_client = httpx.AsyncClient(
|
|
limits = httpx.Limits(
|
|
max_connections = 100, # ............ Maximum number of connections allowed in the pool.
|
|
max_keepalive_connections = 50, # ... Maximum number of connections that can be kept alive.
|
|
),
|
|
timeout = httpx.Timeout(
|
|
pool = 120.0, # .... Time to wait for a free connection from the pool.
|
|
connect = 2.5, # ... Time to wait for establishing a connection to the server.
|
|
write = 10.0, # .... Time to wait for sending data.
|
|
read = 9.9 # ....... Time to wait for receiving data.
|
|
)
|
|
)
|
|
|
|
# General:
|
|
app_state.SERVER_HOSTNAME = str(socket.gethostname())
|
|
app_state.ALLOWED_ORIGINS = []
|
|
|
|
|
|
# *****************************************************************************************************************
|
|
# ***** ****
|
|
# *** VARIABLES ***
|
|
# ***** ****
|
|
# *****************************************************************************************************************
|
|
|
|
|
|
# For SocketIO:
|
|
sio = socketio.AsyncServer(
|
|
cors_allowed_origins = "*",
|
|
async_mode = "asgi"
|
|
)
|
|
app = socketio.ASGIApp(sio)
|
|
|
|
# Register the namespaces:
|
|
sio.register_namespace(EchoNamespace(namespace = "/test", app_state = app_state))
|
|
|
|
|
|
# *****************************************************************************************************************
|
|
# ***** ****
|
|
# *** FUNCTIONS ***
|
|
# ***** ****
|
|
# *****************************************************************************************************************
|
|
|
|
|
|
# --- Nothing Yet
|
|
|
|
|
|
# *****************************************************************************************************************
|
|
# ***** ****
|
|
# *** MAIN PROGRAM ***
|
|
# ***** ****
|
|
# *****************************************************************************************************************
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
app_state.printer("Main.")
|
|
|
|
# To get args from the terminal:
|
|
import argparse
|
|
|
|
# To run the ASGI:
|
|
import uvicorn
|
|
from multiprocessing import freeze_support
|
|
|
|
# Get the config from the command-line:
|
|
parser = argparse.ArgumentParser(description = f"SocketIO to serve live market data (and a general passthrough).")
|
|
parser.add_argument(
|
|
"-w", "--workers",
|
|
type = int,
|
|
help = "The no. of threads to spin up for this instance!",
|
|
default = 2
|
|
)
|
|
parser.add_argument(
|
|
"-a", "--host",
|
|
type = str,
|
|
help = "The host for the app. e.g.: '0.0.0.0' or '127.0.0.1'.",
|
|
default = "0.0.0.0"
|
|
)
|
|
parser.add_argument(
|
|
"-p", "--port",
|
|
type = int,
|
|
help = "The port no. to bind the app to.",
|
|
default = 8080
|
|
)
|
|
parser.add_argument(
|
|
"-s", "--script-id",
|
|
type = str,
|
|
help = "The id of this script (will affect the loaded config)."
|
|
)
|
|
parser.add_argument(
|
|
"-d", "--debug",
|
|
action = "store_true",
|
|
help = "Whether, or not, you want to see debugging messages in the terminal.",
|
|
default = False
|
|
)
|
|
args = parser.parse_args()
|
|
|
|
# Note down the config;
|
|
os.environ["SCRIPT_ID"] = args.script_id
|
|
os.environ["DEBUG"] = str(args.debug)
|
|
|
|
# Startup message:
|
|
app_state.printer.enable()
|
|
app_state.printer(str(args.debug))
|
|
if str(args.debug).lower().find("false") >= 0: app_state.printer.disable()
|
|
|
|
# Run the gateway:
|
|
freeze_support()
|
|
uvicorn.run(
|
|
app = "app:app",
|
|
workers = args.workers,
|
|
host = args.host,
|
|
port = args.port
|
|
)
|