(20241228) Payments module revamped!

This commit is contained in:
2024-12-28 16:34:57 +05:30
parent 7ddae1707f
commit 5c17eb28ae
18 changed files with 1477 additions and 156 deletions
+120 -12
View File
@@ -106,8 +106,11 @@ EVENT_TICKS = "ticks"
# *****************************************************************************************************************
# For locking user-noting operations:
lock = asyncio.Semaphore(1)
# Session-awareness:
pass
connected_clients = {}
# Script-local:
flags = {
@@ -123,13 +126,20 @@ flags = {
@sio.on(event = EVENT_CONNECT, namespace = NAMESPACE_MODULE)
async def handle_connect(sid, environ):
async def handle_connect(sid, environ) -> bool:
# Start the common background processes:
if not flags.get("initDone"):
flags["initDone"] = True
asyncio.create_task(init())
# Note down user changes:
async with lock:
connected_clients[sid] = {
"user": None,
"rooms": []
}
# Allow/reject requests:
printer(sid)
print("ENVIRON:", json.to_string(environ, default = str))
@@ -140,7 +150,7 @@ async def handle_connect(sid, environ):
@sio.on(event = EVENT_DISCONNECT, namespace = NAMESPACE_MODULE)
async def handle_disconnect(sid, reason):
async def handle_disconnect(sid, reason) -> None:
printer(sid, reason)
@@ -148,7 +158,7 @@ async def handle_disconnect(sid, reason):
@sio.on(event = EVENT_ECHO, namespace = NAMESPACE_MODULE)
async def handle_echo(sid, data):
async def handle_echo(sid, data) -> None:
"""
For testing. This is a quick way to check if the module is up.
@@ -168,6 +178,88 @@ async def handle_echo(sid, data):
# ---------------------------------------------------------------------------------------------------------------------
async def send_passthrough(
to: str | List[str],
event: str,
namespace: str,
data: dict | list
) -> None:
"""
To send out the arbitrary passthrough message
:param to: The recipient of the message. This can be set to the 'sid' of a client to address only that client, or to
any custom room created by the application to address all the clients in that room, or to a list of custom
room names. If null, the event is broadcasted to all connected clients.
:param event: Any name for the event that the recipients are listening to. The strings 'connect', 'disconnect', and
'message' are reserved. Everything else is fair game.
:param namespace: The namespace (path) to send the data to.
:param data: The data to send to the target recipients.
:return: None.
"""
# Send out the event:
try: await sio.emit(
event = event,
data = data,
to = to,
namespace = namespace
)
except Exception as exception:
printer(exception)
# ---------------------------------------------------------------------------------------------------------------------
async def passthrough_from_kafka(
consumer: ConsumerKafka,
fetch_count: int = 100,
fetch_timeout: float = 1.0
) -> None:
"""
This function must run in the background forever and just keep listening for any passthrough messages from the
backend. The backend message must give the following kind of JSON:
{
"to": <sid>,
"event": <event-name>,
"namespace": <path>,
"data": <json-data>
}
:param consumer: The preconfigured Kafka consumer that can listen for ticks in asynchronous mode.
:param fetch_count: How many messages to consume in one go.
:param fetch_timeout: How long to wait (in seconds) while consuming messages from Kafka.
:return: None
"""
# Do the next part infinitely:
while True:
# Get messages form Kafka:
messages = await consumer.consume(
count = fetch_count,
timeout = fetch_timeout
)
# If there are no updates to give:
if not messages: continue
# Each message is a passthrough to be sent to the connected clients:
tasks = [
send_passthrough(
to = message["value"].get("to", None),
event = message["value"].get("event", None),
namespace = message["value"].get("namespace", "/"),
data = message["value"].get("data", {})
) for message in messages
]
results = await asyncio.gather(*tasks)
printer(len(messages))
# ---------------------------------------------------------------------------------------------------------------------
async def send_ticks(ticks: List[dict]):
"""
@@ -238,6 +330,14 @@ async def init():
# Start consuming ticks in the background:
cwd = files.get_cwd()
parent_dir = cwd
ssl_context = get_ssl_context(
ca_file = "/etc/ssl/dbu/ca.pem",
cert_file = "/etc/ssl/dbu/fullchain.pem",
key_file = "/etc/ssl/dbu/privkey.pem"
# ca_file = os.path.join(parent_dir, "creds", "kafka", "cert_authority.pem"),
# cert_file = os.path.join(parent_dir, "creds", "kafka", "fullchain.pem"),
# key_file = os.path.join(parent_dir, "creds", "kafka", "privkey.pem")
)
sio.start_background_task(
ticks_from_kafka,
consumer = ConsumerKafka(
@@ -245,19 +345,27 @@ async def init():
# group_id = f"{SERVER_HOSTNAME}_tickers",
bootstrap_servers = "del.ditscentre.in:9092",
security_protocol = "SSL",
ssl_context = get_ssl_context(
ca_file = "/etc/ssl/dbu/ca.pem",
cert_file = "/etc/ssl/dbu/fullchain.pem",
key_file = "/etc/ssl/dbu/privkey.pem"
# ca_file = os.path.join(parent_dir, "creds", "kafka", "cert_authority.pem"),
# cert_file = os.path.join(parent_dir, "creds", "kafka", "fullchain.pem"),
# key_file = os.path.join(parent_dir, "creds", "kafka", "privkey.pem")
),
ssl_context = ssl_context,
auto_offset_reset = "latest"
),
fetch_count = 1_250,
fetch_timeout = 1.0
)
sio.start_background_task(
passthrough_from_kafka,
consumer = ConsumerKafka(
topic = "socket-io-bcast",
# group_id = f"{SERVER_HOSTNAME}_tickers",
bootstrap_servers = "del.ditscentre.in:9092",
security_protocol = "SSL",
ssl_context = ssl_context,
auto_offset_reset = "latest"
),
fetch_count = 100,
fetch_timeout = 1.0
)
printer("Initialized.")
# *****************************************************************************************************************