1234
This commit is contained in:
+110
-127
@@ -6,16 +6,16 @@
|
||||
|
||||
DATE:
|
||||
|
||||
Create: Saturday, 18th May, 2022
|
||||
Update: Thursday, 22nd Aug. 2024
|
||||
Create: Monday, 29th Sept., 2025
|
||||
|
||||
OBJECTIVE:
|
||||
|
||||
To provide an easy way to work with '.json' data and files.
|
||||
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:
|
||||
|
||||
1) https://www.w3schools.com/python/python_json.asp
|
||||
N/A
|
||||
|
||||
DOWNLOADS:
|
||||
|
||||
@@ -37,13 +37,21 @@ sys.path.append(".")
|
||||
sys.path.append("..")
|
||||
|
||||
# System-level activities:
|
||||
import io
|
||||
import os
|
||||
|
||||
# To work with the JSON standard:
|
||||
import json
|
||||
# To make HTTP calls:
|
||||
import httpx
|
||||
|
||||
# To work with files:
|
||||
from utils_v2.system import files
|
||||
# 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
|
||||
|
||||
|
||||
# *****************************************************************************************************************
|
||||
@@ -53,7 +61,30 @@ from utils_v2.system import files
|
||||
# *****************************************************************************************************************
|
||||
|
||||
|
||||
# --- Nothing Yet
|
||||
# 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 = []
|
||||
|
||||
|
||||
# *****************************************************************************************************************
|
||||
@@ -63,7 +94,15 @@ from utils_v2.system import files
|
||||
# *****************************************************************************************************************
|
||||
|
||||
|
||||
# --- Nothing Yet
|
||||
# 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))
|
||||
|
||||
|
||||
# *****************************************************************************************************************
|
||||
@@ -73,121 +112,7 @@ from utils_v2.system import files
|
||||
# *****************************************************************************************************************
|
||||
|
||||
|
||||
def from_string(json_data):
|
||||
|
||||
"""
|
||||
Decodes a JSON string to a pythonic variable like a dict.
|
||||
:param json_data: The JSON string to decode.
|
||||
:return: The decoded pythonic variable.
|
||||
"""
|
||||
|
||||
python_data = json.loads(json_data)
|
||||
return python_data
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
def to_string(
|
||||
python_data,
|
||||
indent = 4,
|
||||
default = None,
|
||||
separators = None,
|
||||
no_space = False
|
||||
):
|
||||
|
||||
"""
|
||||
Converts the given pythonic data to a JSON string.
|
||||
:param python_data: The input data like a dict.
|
||||
:param indent: The tab-width for pretty presentation.
|
||||
:param default: The function to use on something that cannot be directly parsed into a JSON string.
|
||||
:param separators: Custom separators to use.
|
||||
:param no_space: If you want a dense JSON string that saves memory by not using spaces or tabs or line-breaks. Not
|
||||
good for human readability, very good for saving memory. WARNING: THIS OVERRIDES EVERY OTHER PARAMETER EXCEPT
|
||||
'default'.
|
||||
:return: The JSON string representation of the input pythonic data.
|
||||
"""
|
||||
|
||||
if no_space:
|
||||
json_data = json.dumps(
|
||||
python_data,
|
||||
default = default,
|
||||
separators = (',', ':')
|
||||
)
|
||||
|
||||
else:
|
||||
json_data = json.dumps(
|
||||
python_data,
|
||||
indent = indent,
|
||||
default = default,
|
||||
separators = separators
|
||||
)
|
||||
|
||||
return json_data
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
def from_file(file):
|
||||
|
||||
"""
|
||||
Reads a JSON file and returns it as a pythonic variable like a dict.
|
||||
:param file: The path to the file on the disk or a file held in RAM as a BytesIO object.
|
||||
:return: The decoded pythonic variable.
|
||||
"""
|
||||
|
||||
if isinstance(file, io.BytesIO):
|
||||
file.seek(0)
|
||||
json_data = file.getvalue()
|
||||
else: json_data = files.read_file(file)
|
||||
python_data = from_string(json_data)
|
||||
return python_data
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
def to_file(
|
||||
file,
|
||||
python_data,
|
||||
indent = 4,
|
||||
default = None,
|
||||
separators = None,
|
||||
no_space = False
|
||||
):
|
||||
|
||||
"""
|
||||
|
||||
:param file: Either a path to a file on disk, or a buffer in RAM in the form of a BytesIO object.
|
||||
:param python_data: The pythonic data to be converted to the JSON string.
|
||||
:param indent: The tab-width for pretty presentation.
|
||||
:param default: The function to use on something that cannot be directly parsed into a JSON string.
|
||||
:param separators: Custom separators to use.
|
||||
:param no_space: If you want a dense JSON string that saves memory by not using spaces or tabs or line-breaks. Not
|
||||
good for human readability, very good for saving memory. WARNING: THIS OVERRIDES EVERY OTHER PARAMETER EXCEPT
|
||||
'default'.
|
||||
:return: True/False if a path was given, else the same BytesIO object with the written JSON data.
|
||||
"""
|
||||
|
||||
json_data = to_string(
|
||||
python_data,
|
||||
indent = indent,
|
||||
default = default,
|
||||
separators = separators,
|
||||
no_space = no_space
|
||||
)
|
||||
|
||||
if isinstance(file, io.BytesIO):
|
||||
file.write(json_data.encode("utf-8"))
|
||||
file.seek(0)
|
||||
return file
|
||||
|
||||
else:
|
||||
try:
|
||||
files.write_file(file, json_data, mode = "w")
|
||||
return True
|
||||
except: return False
|
||||
# --- Nothing Yet
|
||||
|
||||
|
||||
# *****************************************************************************************************************
|
||||
@@ -199,4 +124,62 @@ def to_file(
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
pass
|
||||
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
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user