Compare commits

..

43 Commits

Author SHA1 Message Date
Stanislav Hejny 960850580c feature/#71 - fix test coverage
Unit test coverage / pytest (push) Successful in 1m34s
Unit test coverage / pytest (pull_request) Successful in 1m34s
/ build-and-push (push) Successful in 1m38s
2025-08-29 08:43:36 +01:00
Stanislav Hejny aa4492d443 Create API documentation
Unit test coverage / pytest (push) Failing after 1m54s
/ build-and-push (push) Successful in 1m50s
Unit test coverage / pytest (pull_request) Failing after 1m27s
2025-08-14 09:29:57 +01:00
Stanislav Hejny 07f6f4569c feat/#63 - add iterator instead of RabbitMQ callback
Unit test coverage / pytest (pull_request) Failing after 1m49s
Build and Publish Docker Image / build-and-push (push) Successful in 2m29s
Unit test coverage / pytest (push) Failing after 1m45s
/ build-and-push (push) Successful in 1m52s
CI for pypl publish / publish-lib (push) Successful in 1m44s
2025-07-27 09:50:25 +01:00
Stanislav Hejny 66132db13a feat/#63 - cleverswarm unidirectional command
Unit test coverage / pytest (pull_request) Successful in 1m38s
Unit test coverage / pytest (push) Successful in 1m52s
CI for pypl publish / publish-lib (push) Successful in 2m7s
/ build-and-push (push) Successful in 2m20s
Build and Publish Docker Image / build-and-push (push) Successful in 2m32s
2025-07-26 15:41:47 +01:00
Stanislav Hejny 9984501fee feat/#63 - cleverswarm unidirectional command
Unit test coverage / pytest (push) Failing after 1m46s
/ build-and-push (push) Successful in 1m36s
Unit test coverage / pytest (pull_request) Failing after 1m15s
2025-07-26 15:30:12 +01:00
Stanislav Hejny 41fbe46129 feat/#63 - cleverswarm unidirectional command
Unit test coverage / pytest (push) Has been cancelled
/ build-and-push (push) Has been cancelled
Unit test coverage / pytest (pull_request) Failing after 1m51s
2025-07-26 15:29:07 +01:00
Stanislav Hejny 9491517696 feat/#63 - fix the send_command and add unit tests
Unit test coverage / pytest (pull_request) Successful in 1m15s
Unit test coverage / pytest (push) Failing after 1m50s
CI for pypl publish / publish-lib (push) Successful in 1m57s
/ build-and-push (push) Successful in 1m59s
Build and Publish Docker Image / build-and-push (push) Successful in 2m12s
2025-07-24 10:05:36 +01:00
Stanislav Hejny 4985344e5e test: add package_name parameter to invoke_command calls in test_rpc.py
Co-authored-by: aider (openrouter/openai/o3-mini-high) <aider@aider.chat>
2025-07-24 08:16:42 +01:00
Stanislav Hejny f3be2fbfea test: update tests to use invoke_command directly 2025-07-24 08:16:41 +01:00
Stanislav Hejny ad49cb2836 test: convert demo script to unittest framework in test_rpc.py
Co-authored-by: aider (openrouter/openai/o3-mini-high) <aider@aider.chat>
2025-07-24 08:08:00 +01:00
Stanislav Hejny 2b20c9a0dc test: add tests for RPC command invocation and error handling 2025-07-24 08:07:57 +01:00
Stanislav Hejny 982c72205a Merge branch 'feat/61-multi-user-support' into develop
Unit test coverage / pytest (push) Successful in 2m16s
/ build-and-push (push) Successful in 2m16s
CI for pypl publish / publish-lib (push) Failing after 2m15s
Build and Publish Docker Image / build-and-push (push) Successful in 2m34s
2025-07-23 19:47:31 +01:00
Stanislav Hejny c3346bbe7a Merge branch 'feat-58-backpressure-reactive-streams' into develop
Unit test coverage / pytest (push) Successful in 1m58s
CI for pypl publish / publish-lib (push) Successful in 2m4s
/ build-and-push (push) Successful in 2m22s
Build and Publish Docker Image / build-and-push (push) Successful in 2m58s
2025-07-23 18:41:51 +01:00
Stanislav Hejny b41ca04801 feat/#61 - add one way communication option
Unit test coverage / pytest (push) Successful in 1m23s
/ build-and-push (push) Successful in 1m31s
Unit test coverage / pytest (pull_request) Successful in 1m8s
2025-07-23 18:33:34 +01:00
hurui200320 80a55f9894 ci: fix docker missing issue
Unit test coverage / pytest (push) Successful in 2m0s
/ build-and-push (push) Successful in 2m4s
Build and Publish Docker Image / build-and-push (push) Successful in 3m5s
Unit test coverage / pytest (pull_request) Successful in 1m7s
base: node:lts-bookworm (debian 12)
2025-07-21 18:29:03 +08:00
Stanislav Hejny d8ab0b861d feat/#58 - fix unit test and deployment pipeline
Unit test coverage / pytest (push) Successful in 1m55s
Unit test coverage / pytest (pull_request) Successful in 1m52s
/ build-and-push (push) Successful in 1m58s
Build and Publish Docker Image / build-and-push (push) Failing after 5m12s
2025-07-21 10:52:46 +01:00
Stanislav Hejny 3ee62b0437 feat/#58 - fix unit test and deployment pipeline
Unit test coverage / pytest (push) Successful in 1m20s
/ build-and-push (push) Successful in 1m24s
2025-07-21 10:49:28 +01:00
Stanislav Hejny cf1804d23f feat: implement send_rpc method in DataMessageHandler class
Co-authored-by: aider (openrouter/anthropic/claude-3.7-sonnet) <aider@aider.chat>
2025-07-18 10:29:08 +01:00
Stanislav Hejny 04f1483c06 Merge branch 'feat-58-backpressure-reactive-streams' into feat/61-multi-user-support
Unit test coverage / pytest (push) Successful in 1m22s
/ build-and-push (push) Successful in 1m25s
2025-07-18 09:53:07 +01:00
Stanislav Hejny 050b5ddba4 fix: ensure AsyncMock returns awaitable channel in test_initialize
Unit test coverage / pytest (push) Successful in 1m37s
Unit test coverage / pytest (pull_request) Successful in 1m46s
/ build-and-push (push) Successful in 1m46s
Build and Publish Docker Image / build-and-push (push) Has been cancelled
Co-authored-by: aider (openrouter/openai/o3-mini-high) <aider@aider.chat>
2025-07-18 09:29:54 +01:00
Stanislav Hejny a6ca319e92 fix: use AsyncMock for mock_channel in test setup
Co-authored-by: aider (openrouter/openai/o3-mini-high) <aider@aider.chat>
2025-07-18 09:25:34 +01:00
Stanislav Hejny f2cc138540 feat/#50 - remove obsolete code
Build and Publish Docker Image / build-and-push (push) Waiting to run
Unit test coverage / pytest (push) Failing after 1m24s
Unit test coverage / pytest (pull_request) Failing after 1m56s
/ build-and-push (push) Successful in 2m0s
2025-07-18 07:59:20 +01:00
Stanislav Hejny f02823e18d feat/#61 - add client code for User Managemengt Service
Unit test coverage / pytest (push) Failing after 1m11s
/ build-and-push (push) Successful in 1m28s
2025-07-18 07:54:55 +01:00
Stanislav Hejny 5ab9406430 feat: implement UserManagementServiceClient with RabbitMQ communication
Co-authored-by: aider (openrouter/openai/o3-mini-high) <aider@aider.chat>
2025-07-18 07:47:21 +01:00
Stanislav Hejny a6c918fe43 feat/58 - simplify complex logic
Build and Publish Docker Image / build-and-push (push) Waiting to run
Unit test coverage / pytest (push) Failing after 1m32s
Unit test coverage / pytest (pull_request) Failing after 1m38s
/ build-and-push (push) Successful in 1m46s
2025-07-17 17:51:01 +01:00
Stanislav Hejny 9cae4b168e fix: properly mock nested structure in AMQConfiguration for tests
Co-authored-by: aider (openrouter/openai/o3-mini-high) <aider@aider.chat>
2025-07-17 10:49:47 +01:00
Stanislav Hejny 281004798e test: add comprehensive unit tests for DataMessageHandler
Co-authored-by: aider (openrouter/openai/o3-mini-high) <aider@aider.chat>
2025-07-17 10:45:16 +01:00
Stanislav Hejny ef5a0363cd test: fix async mock in backpressure tests for coroutine compatibility
Co-authored-by: aider (openrouter/openai/o3-mini-high) <aider@aider.chat>
2025-07-17 10:24:43 +01:00
Stanislav Hejny 7f9c02e458 test: simplify and enhance AMQService backpressure tests 2025-07-17 10:24:42 +01:00
Stanislav Hejny cc4fbc68fd test: add unit tests for BackpressureHandler and AMQService classes
Co-authored-by: aider (openrouter/openai/o3-mini-high) <aider@aider.chat>
2025-07-16 18:48:18 +01:00
Stanislav Hejny 9c0cb3a334 refactor: update backpressure logic to handle availability correctly
Co-authored-by: aider (openrouter/openai/o3-mini-high) <aider@aider.chat>
2025-07-16 18:04:09 +01:00
Stanislav Hejny f8fd9f24f8 feature/58 - update unit tests for coverage
Unit test coverage / pytest (push) Successful in 1m39s
Unit test coverage / pytest (pull_request) Successful in 1m46s
/ build-and-push (push) Successful in 1m52s
Build and Publish Docker Image / build-and-push (push) Has been cancelled
2025-07-15 17:12:26 +01:00
Stanislav Hejny c63941e4a1 fix: prevent unnecessary retries on last attempt in ID generation
Co-authored-by: aider (openrouter/openai/o3-mini-high) <aider@aider.chat>
2025-07-15 16:55:07 +01:00
Stanislav Hejny 7cd2960fda feat/58 - improve Backpressure algorithm 2025-07-15 16:40:02 +01:00
Stanislav Hejny 7d4e358ce5 test: add AsyncMock to test backpressure handler conditions
Co-authored-by: aider (openrouter/openai/o3-mini-high) <aider@aider.chat>
2025-07-12 23:02:19 +01:00
Stanislav Hejny 0e294b223d Fix the global unique ID generator recursive constructor call 2025-07-12 22:59:21 +01:00
Stanislav Hejny dd590a11b5 fix: correct consul_initial_retry_delay configuration logic
Co-authored-by: aider (openrouter/openai/o3-mini-high) <aider@aider.chat>
2025-07-12 10:45:46 +01:00
Stanislav Hejny 5d8f07be3c refactor: prioritize env vars over config file in AMQAdapter settings
Co-authored-by: aider (openrouter/openai/o3-mini-high) <aider@aider.chat>
2025-07-12 10:45:10 +01:00
Stanislav Hejny bd4272c30e feat: add Consul configuration to AMQAdapter class 2025-07-12 10:45:09 +01:00
Stanislav Hejny dbfd5ea50d test: add unit tests for backpressure handler methods and conditions
Co-authored-by: aider (openrouter/openai/o3-mini-high) <aider@aider.chat>
2025-07-11 23:58:58 +01:00
Stanislav Hejny 826c859b32 feat: add IDLE event detection to check_overload_condition function
Co-authored-by: aider (openrouter/openai/o3-mini-high) <aider@aider.chat>
2025-07-11 23:54:57 +01:00
Stanislav Hejny 8bfe6a4a49 feat: add update_backpressure_value method to BackpressureHandler class
Co-authored-by: aider (openrouter/openai/o3-mini-high) <aider@aider.chat>
2025-07-11 23:48:31 +01:00
Stanislav Hejny 3150dc9907 feat: add toggle for CPU monitoring in backpressure handler
Co-authored-by: aider (openrouter/openai/o3-mini-high) <aider@aider.chat>
2025-07-11 23:38:01 +01:00
179 changed files with 28276 additions and 1063 deletions
+88
View File
@@ -0,0 +1,88 @@
name: Build and Publish Docker Image
#on:
# push:
# branches: [ main, master ]
# tags: [ 'v*' ]
# pull_request:
# branches: [ main, master ]
on:
push:
branches:
- master # publish release on master
- develop # publish snapshot on develop
- feat-58-backpressure-reactive-streams
workflow_dispatch:
# allow manual trigger
env:
REGISTRY_URL: "git.cleverthis.com"
REPOSITORY: "clevermicro/amq-adapter-python-demo"
DOCKER_HOST: "tcp://dind:2375"
jobs:
build-and-push:
runs-on: general
services:
dind:
image: docker:dind
cmd:
- dockerd
- -H
- tcp://0.0.0.0:2375
- --tls=false
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
ref: ${{ github.ref_name }}
# setup docker
- name: set up docker cli
run: |
apt-get update
apt-get install ca-certificates curl
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
tee /etc/apt/sources.list.d/docker.list > /dev/null
apt-get update
apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to Docker Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY_URL }}
username: ${{ secrets.REGISTRY_USER }}
password: ${{ secrets.REGISTRY_PASSWORD }}
if: github.event_name != 'pull_request'
- name: Extract metadata for Docker
id: meta
uses: docker/metadata-action@v4
with:
images: ${{ env.REGISTRY_URL }}/clevermicro/amq-adapter-python-demo
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha,format=short
- name: Build and push Docker image
uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile
# push: ${{ github.event_name != 'pull_request' }}
push: true
tags: ${{ env.REGISTRY_URL }}/${{ env.REPOSITORY }}:latest
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
+1 -1
View File
@@ -38,4 +38,4 @@ jobs:
file: ./Dockerfile
no-cache: true
push: true
tags: ${{ env.REGISTRY_URL }}/${{ env.REPOSITORY }}:20250715-01
tags: ${{ env.REGISTRY_URL }}/${{ env.REPOSITORY }}:20250709-01
+663
View File
@@ -0,0 +1,663 @@
# AMQ Adapter Developer Guide
## Overview
The AMQ Adapter library enables FastAPI-based Business Services to communicate with the CleverMicro platform via RabbitMQ. This guide demonstrates how to build your own service using the AMQ Adapter, following the pattern established by the OTDemo application.
## Table of Contents
1. [Architecture Overview](#architecture-overview)
2. [Prerequisites](#prerequisites)
3. [Project Structure](#project-structure)
4. [Implementation Steps](#implementation-steps)
5. [Configuration](#configuration)
6. [Creating Your Adapter](#creating-your-adapter)
7. [Frontend Integration](#frontend-integration)
8. [Backend Processing](#backend-processing)
9. [Testing and Deployment](#testing-and-deployment)
10. [Advanced Features](#advanced-features)
## Architecture Overview
The AMQ Adapter follows a layered architecture:
```
┌─────────────────────────────────────────────────────────────┐
│ Business Service │
├─────────────────────────────────────────────────────────────┤
│ FastAPI Endpoints │ Your Custom Adapter │ Backend │
│ │ │ Processing │
└─────────────────────┼───────────────────────┼───────────────┘
│ │
┌─────────────────────┼───────────────────────┼───────────────┐
│ AMQ Adapter Library │ │
├─────────────────────────────────────────────────────────────┤
│ CleverThisServiceAdapter │ AMQService │ Router │
│ (Base Class) │ │ │
└─────────────────────┼───────────────────────┼───────────────┘
│ │
┌─────────────────────┼───────────────────────┼───────────────┐
│ RabbitMQ │ │
│ Exchanges │ Queues │ Routing Keys │ │
└─────────────────────────────────────────────────────────────┘
```
### Key Components
- **Your Custom Adapter**: Extends `CleverThisServiceAdapter` to handle service-specific logic
- **AMQService**: Manages RabbitMQ connections and message routing
- **Router**: Routes incoming AMQP messages to appropriate endpoints
- **Configuration**: Defines service settings, routing, and RabbitMQ connection details
## Prerequisites
Before building your service, ensure you have:
1. **Python 3.8+** installed
2. **RabbitMQ** server running (or access to CleverMicro platform)
3. **FastAPI** knowledge
4. **AMQ Adapter library** installed in your project
### Dependencies
Add the following to your `requirements.txt`:
```txt
fastapi>=0.111.0
uvicorn[standard]>=0.29.0
python-multipart>=0.0.20
aio-pika>=9.0.0
pydantic>=2.0.0
# Add your AMQ Adapter library dependency
```
## Project Structure
Follow this recommended structure for your Business Service:
```
your-business-service/
├── main.py # FastAPI application entry point
├── requirements.txt # Python dependencies
├── config/
│ ├── frontend.properties # Frontend service configuration
│ └── backend.properties # Backend service configuration
├── adapter/
│ └── your_adapter.py # Your custom AMQ adapter
├── backend/
│ └── backend_processor.py # Backend message processing
└── tests/
└── test_your_service.py
```
## Implementation Steps
### Step 1: Create Your Configuration Files
Create configuration files for both frontend and backend services.
**`config/frontend.properties`**:
```properties
# ====================================================================
# CleverMicro AMQ Adapter settings
# ====================================================================
[CleverMicro-AMQ]
cm.amq-adapter.service-name=your-service
cm.amq-adapter.generator-id=1
cm.amq-adapter.route-mapping=your-service:your-exchange:your-queue-1:api.cm.dev.cleverthis.localhost.test.python.frontend.#:5:0
cm.amq-adapter.require-authenticated-user=false
cm.amq-adapter.callbacks-enabled=True
# CleverMicro AMQ Adapter dispatcher settings
cm.dispatch.use-dlq=true
cm.dispatch.amq-host=localhost
cm.dispatch.amq-port=5672
cm.dispatch.amq-port-tls=5671
cm.dispatch.download-dir=/tmp/downloaded_files
# Backpressure settings
cm.backpressure.threshold=1
cm.backpressure.time-window=150
cm.backpressure.cpu-overload-duration=300
cm.backpressure.cpu-idle-duration=300
```
**`config/backend.properties`**:
```properties
# ====================================================================
# CleverMicro AMQ Adapter settings
# ====================================================================
[CleverMicro-AMQ]
cm.amq-adapter.service-name=your-service-backend
cm.amq-adapter.generator-id=1
cm.amq-adapter.route-mapping=your-service-backend:your-exchange:your-queue-2:your-service-backend.#:5:0
cm.amq-adapter.require-authenticated-user=false
cm.amq-adapter.callbacks-enabled=False
# CleverMicro AMQ Adapter dispatcher settings
cm.dispatch.use-dlq=true
cm.dispatch.amq-host=localhost
cm.dispatch.amq-port=5672
cm.dispatch.amq-port-tls=5671
cm.dispatch.download-dir=/tmp/downloaded_files
# Backpressure settings
cm.backpressure.threshold=1
cm.backpressure.time-window=150
cm.backpressure.cpu-overload-duration=300
cm.backpressure.cpu-idle-duration=300
```
### Step 2: Create Your Custom Adapter
Create your custom adapter by extending `CleverThisServiceAdapter`:
```python
"""
Your Business Service AMQP Adapter for handling API requests via AMQP.
This adapter is specific to your business service and handles service-specific logic.
"""
from threading import Thread
from typing import Any, List
from fastapi.routing import APIRoute
from amqp.adapter.cleverthis_service_adapter import CleverThisServiceAdapter
from amqp.config.amq_configuration import AMQConfiguration
from amqp.service.amq_service import AMQService
class YourServiceAmqpAdapter(CleverThisServiceAdapter):
"""
Your Business Service AMQP Adapter. Implements service-specific logic that overrides
common logic defined by the AMQ Adapter library.
Key responsibilities:
1. Handle authentication and user management
2. Process incoming AMQP messages
3. Route messages to appropriate endpoints
4. Manage service-specific business logic
"""
def __init__(self, amq_configuration: AMQConfiguration, routes: List[APIRoute]):
super().__init__(amq_configuration, routes=routes, session=None)
self.amq_service: AMQService = AMQService(amq_configuration, self)
self.thread = Thread(target=self.amq_service.run)
self.thread.start()
async def get_current_user(self, token: str) -> str:
"""
Override the default get_current_user method to handle authentication.
In this example, we simply return the token, but you should implement
proper JWT token validation and user extraction.
:param token: JWT token from the AMQP message
:return: User identifier or user object
"""
# TODO: Implement proper JWT token validation
# Example: return await your_auth_service.validate_token(token)
return token
def get_endpoint(self, endpoint: Any) -> Any:
"""
Override to provide custom endpoint selection logic.
For example, you might want to use JSON wrapper endpoints
or implement custom routing logic.
:param endpoint: The original endpoint callable
:return: The endpoint callable to use (original or modified)
"""
return endpoint
```
### Step 3: Create Your FastAPI Application
Create your main FastAPI application with endpoints:
```python
"""
Your Business Service FastAPI Application
"""
import os
from fastapi import FastAPI, File, Form, UploadFile
from fastapi.routing import APIRoute
from amqp.config.amq_configuration import AMQConfiguration
from adapter.your_adapter import YourServiceAmqpAdapter
# Create FastAPI application
app = FastAPI(
title="Your Business Service",
description="A FastAPI application using AMQ Adapter for CleverMicro communication",
version="1.0.0"
)
# Initialize your AMQ adapter
# This should be done after all routes are defined
your_adapter = None
@app.post("/api/v1/items")
async def create_item(
name: str = Form(...),
description: str = Form(...),
file: UploadFile = File(...)
):
"""
Create a new item with file upload.
This endpoint will be available via both REST and AMQP.
"""
# Your business logic here
result = {
"message": "Item created successfully",
"name": name,
"description": description,
"filename": file.filename
}
# Example: Send a command to backend via AMQP
if your_adapter:
your_adapter.amq_service.command(
"your-service-backend",
"process_item",
item_name=name,
item_description=description
)
return result
@app.get("/api/v1/items")
async def get_items():
"""
Retrieve all items.
This endpoint will be available via both REST and AMQP.
"""
# Your business logic here
items = [
{"id": "1", "name": "Item 1", "description": "Description 1"},
{"id": "2", "name": "Item 2", "description": "Description 2"}
]
return {"items": items}
@app.get("/health")
async def health_check():
"""
Health check endpoint.
"""
return {"status": "healthy", "service": "your-business-service"}
# Initialize the AMQ adapter after all routes are defined
def initialize_amq_adapter():
global your_adapter
config = AMQConfiguration("config/frontend.properties")
your_adapter = YourServiceAmqpAdapter(config, app.routes)
# Initialize adapter when the application starts
@app.on_event("startup")
async def startup_event():
initialize_amq_adapter()
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
```
### Step 4: Create Backend Processing
Create a backend processor for handling AMQP messages:
```python
"""
Backend processor for your business service.
Handles AMQP messages and performs background processing.
"""
import asyncio
from amqp.config.amq_configuration import AMQConfiguration
from amqp.model.model import AMQRoute, DataMessage
from adapter.your_adapter import YourServiceAmqpAdapter
def process_item_static(item_name: str, item_description: str) -> str:
"""
Static function to process an item.
"""
print(f"STATIC Processing item: {item_name} - {item_description}")
return f"STATIC PROCESSED: {item_name}"
class BackendProcessor:
"""
Backend processor class for handling business logic.
"""
def process_item(self, item_name: str, item_description: str) -> str:
"""
Process an item using instance method.
"""
print(f"CLASS Processing item: {item_name} - {item_description}")
return f"CLASS PROCESSED: {item_name}"
async def processing_loop():
"""
Main processing loop for handling AMQP messages.
"""
# Wait for AMQ adapter to initialize
while not otadapter.amq_service.future.done():
await asyncio.sleep(0.1)
# Find the route for backend processing
route: AMQRoute = otadapter.amq_service.router.find_route_by_service("your-service-backend")
generator = otadapter.amq_service.data_message_generator(route)
print(f"Data message generator created: {generator}")
# Start the generator
message = await generator.asend(None)
# Process messages
while True:
print(f"Received message: {message}")
if message is None:
break
data_message: DataMessage = message
# Extract message attributes
print(f"Message attributes: {data_message.method()} {data_message.domain()} {data_message.path()}")
# Process based on message path
if data_message.path() == "process_item_static":
item_name = data_message._base64body.decode("utf-8")
process_item_static(item_name, "Static processing")
elif data_message.path() == "process_item":
item_name = data_message._base64body.decode("utf-8")
processor = BackendProcessor()
processor.process_item(item_name, "Class processing")
# Get next message
message = await generator.asend(True)
if __name__ == "__main__":
# Initialize backend adapter
otadapter = YourServiceAmqpAdapter(AMQConfiguration("config/backend.properties"), [])
# Run the processing loop in the AMQ service event loop
asyncio.run_coroutine_threadsafe(processing_loop(), otadapter.amq_service.loop)
# Keep the program running
otadapter.thread.join()
```
## Configuration
### Configuration Parameters
The configuration file contains several key sections:
#### AMQ Adapter Settings (`cm.amq-adapter.*`)
- **`service-name`**: Unique identifier for your service
- **`generator-id`**: Unique ID for message generation (usually 1)
- **`route-mapping`**: RabbitMQ routing configuration
- **`require-authenticated-user`**: Whether authentication is required
- **`callbacks-enabled`**: Whether to enable callback functionality
#### Dispatch Settings (`cm.dispatch.*`)
- **`amq-host`**: RabbitMQ host address
- **`amq-port`**: RabbitMQ port (5672 for non-TLS, 5671 for TLS)
- **`use-dlq`**: Whether to use Dead Letter Queue
- **`download-dir`**: Directory for downloaded files
#### Backpressure Settings (`cm.backpressure.*`)
- **`threshold`**: Backpressure threshold value
- **`time-window`**: Time window for backpressure calculation
- **`cpu-overload-duration`**: Duration for CPU overload detection
- **`cpu-idle-duration`**: Duration for CPU idle detection
### Route Mapping Format
The route mapping follows this format:
```
service-name:exchange:queue:routing-key:prefetch:durable
```
Example:
```
your-service:your-exchange:your-queue-1:api.cm.dev.cleverthis.localhost.test.python.frontend.#:5:0
```
## Frontend Integration
### Key Integration Points
1. **Adapter Initialization**: Initialize your adapter after defining all FastAPI routes
2. **Message Handling**: The adapter automatically routes AMQP messages to your endpoints
3. **Command Sending**: Use `amq_service.command()` to send commands to backend services
### Example Integration
```python
# In your FastAPI application
@app.post("/api/v1/process")
async def process_data(data: dict):
# Your business logic
result = {"status": "processing", "data": data}
# Send command to backend
your_adapter.amq_service.command(
"your-service-backend",
"process_data",
**data
)
return result
```
## Backend Processing
### Message Processing Pattern
1. **Initialize Adapter**: Create adapter with backend configuration
2. **Wait for Connection**: Wait for RabbitMQ connection to be established
3. **Find Route**: Locate the route for your backend service
4. **Create Generator**: Create message generator for the route
5. **Process Messages**: Continuously process incoming messages
### Example Processing
```python
async def process_messages():
# Wait for connection
while not adapter.amq_service.future.done():
await asyncio.sleep(0.1)
# Get route and generator
route = adapter.amq_service.router.find_route_by_service("your-service-backend")
generator = adapter.amq_service.data_message_generator(route)
# Process messages
message = await generator.asend(None)
while message:
# Process the message
await handle_message(message)
message = await generator.asend(True)
```
## Testing and Deployment
### Local Testing
1. **Start RabbitMQ**: Ensure RabbitMQ is running locally
2. **Run Frontend**: Start your FastAPI application
3. **Run Backend**: Start your backend processor
4. **Test Endpoints**: Use tools like curl or Postman to test REST endpoints
5. **Monitor AMQP**: Check RabbitMQ management interface for message flow
### Docker Deployment
Create a `Dockerfile` for your service:
```dockerfile
FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
```
### Docker Compose
Create a `docker-compose.yml` for local development:
```yaml
version: '3.8'
services:
rabbitmq:
image: rabbitmq:3-management
ports:
- "5672:5672"
- "15672:15672"
environment:
RABBITMQ_DEFAULT_USER: guest
RABBITMQ_DEFAULT_PASS: guest
your-service-frontend:
build: .
ports:
- "8000:8000"
environment:
- RABBITMQ_HOST=rabbitmq
depends_on:
- rabbitmq
your-service-backend:
build: .
command: ["python", "backend/backend_processor.py"]
environment:
- RABBITMQ_HOST=rabbitmq
depends_on:
- rabbitmq
```
## Advanced Features
### Authentication
Implement proper JWT token validation in your adapter:
```python
async def get_current_user(self, token: str) -> User:
"""
Validate JWT token and extract user information.
"""
try:
# Decode and validate JWT token
payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
user_id = payload.get("sub")
# Fetch user from database
user = await get_user_by_id(user_id)
return user
except jwt.InvalidTokenError:
raise HTTPException(status_code=401, detail="Invalid token")
```
### Error Handling
Implement comprehensive error handling:
```python
async def handle_message(self, message: DataMessage):
"""
Handle incoming messages with proper error handling.
"""
try:
# Process message
result = await self.process_message(message)
return result
except ValidationError as e:
logging.error(f"Validation error: {e}")
# Handle validation errors
except ProcessingError as e:
logging.error(f"Processing error: {e}")
# Handle processing errors
except Exception as e:
logging.error(f"Unexpected error: {e}")
# Handle unexpected errors
```
### Monitoring and Logging
Implement proper logging and monitoring:
```python
import logging
from opentelemetry import trace, metrics
# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# Configure tracing
tracer = trace.get_tracer(__name__)
# Configure metrics
meter = metrics.get_meter(__name__)
message_counter = meter.create_counter("messages_processed_total")
async def process_message(self, message: DataMessage):
"""
Process message with tracing and metrics.
"""
with tracer.start_as_current_span("process_message"):
logger.info(f"Processing message: {message.id()}")
# Your processing logic here
message_counter.add(1, {"service": "your-service"})
logger.info(f"Message processed successfully: {message.id()}")
```
## Troubleshooting
### Common Issues
1. **Connection Errors**: Ensure RabbitMQ is running and accessible
2. **Route Not Found**: Check route mapping configuration
3. **Message Not Processed**: Verify endpoint method signatures match expected parameters
4. **Authentication Failures**: Check JWT token validation logic
### Debugging Tips
1. **Enable Debug Logging**: Set logging level to DEBUG
2. **Check RabbitMQ Management**: Use RabbitMQ management interface to monitor queues
3. **Trace Message Flow**: Use OpenTelemetry tracing to follow message flow
4. **Validate Configuration**: Ensure all configuration parameters are correct
## Conclusion
This guide provides a comprehensive overview of building a Business Service using the AMQ Adapter library. By following the patterns established in the OTDemo application, you can create robust, scalable services that integrate seamlessly with the CleverMicro platform.
For more detailed information, refer to the AMQ Adapter library documentation and the OTDemo source code examples.
+182
View File
@@ -0,0 +1,182 @@
# FastAPI Demo - Docker Swarm Deployment
This guide explains how to deploy the FastAPI demo application to an existing Docker Swarm cluster.
## Prerequisites
- Docker Swarm cluster already running
- Docker CLI installed and configured
- Access to the swarm manager node
## Files Created
1. **`Dockerfile.demo`** - Docker image for the FastAPI application
2. **`docker-stack.yml`** - Docker Swarm stack configuration
3. **`prometheus.yml`** - Prometheus configuration for metrics collection
4. **`deploy-stack.sh`** - Automated deployment script
## Quick Deployment
### Option 1: Using the deployment script (Recommended)
```bash
./deploy-stack.sh
```
This script will:
- Check if Docker is running
- Initialize Docker Swarm if needed
- Build the Docker image
- Deploy the stack
- Show service status and access URLs
### Option 2: Manual deployment
1. **Build the Docker image:**
```bash
docker build -f Dockerfile.demo -t fastapi-demo:latest .
```
2. **Deploy the stack:**
```bash
docker stack deploy -c docker-stack.yml fastapi-demo
```
## Services Deployed
The stack deploys the following services:
### 1. FastAPI Demo Application (`fastapi-demo`)
- **Ports:** 8000 (app), 8001 (metrics)
- **Image:** `fastapi-demo:latest`
- **Features:**
- FastAPI application with OpenTelemetry integration
- Prometheus metrics endpoint
- File upload functionality
- Health checks
- Resource limits and reservations
### 2. Jaeger Tracing (Optional)
- **Ports:** 16686 (UI), 4317 (OTLP gRPC)
- **Image:** `jaegertracing/all-in-one:latest`
- **Purpose:** Distributed tracing visualization
### 3. Prometheus Monitoring (Optional)
- **Ports:** 9090 (UI)
- **Image:** `prom/prometheus:latest`
- **Purpose:** Metrics collection and visualization
## Access URLs
After successful deployment:
- **FastAPI Application:** http://localhost:8000
- **FastAPI Documentation:** http://localhost:8000/docs
- **Prometheus Metrics:** http://localhost:8001/metrics
- **Jaeger UI:** http://localhost:16686
- **Prometheus UI:** http://localhost:9090
## Configuration
### Environment Variables
The FastAPI demo service uses these environment variables:
- `OTEL_EXPORTER_OTLP_ENDPOINT`: Jaeger OTLP endpoint (default: http://jaeger:4317)
- `OTEL_DEBUG_CONSOLE_TRACES`: Enable console trace output (default: false)
- `OTEL_EXPORTER_PROMETHEUS_HOST`: Prometheus metrics host (default: 0.0.0.0)
- `OTEL_EXPORTER_PROMETHEUS_PORT`: Prometheus metrics port (default: 8001)
### Properties File
The `otdemo/otdemo.properties` file is automatically included in the Docker image and available at the relative path `./otdemo/otdemo.properties` within the container.
## Management Commands
### View Stack Status
```bash
docker stack services fastapi-demo
```
### View Service Logs
```bash
docker service logs fastapi-demo_fastapi-demo
```
### Scale Services
```bash
docker service scale fastapi-demo_fastapi-demo=2
```
### Update Stack
```bash
docker stack deploy -c docker-stack.yml fastapi-demo
```
### Remove Stack
```bash
docker stack rm fastapi-demo
```
## Monitoring
### Health Checks
The FastAPI service includes health checks that verify the application is responding:
- **Endpoint:** `/docs`
- **Interval:** 30 seconds
- **Timeout:** 10 seconds
- **Retries:** 3
### Resource Limits
- **CPU:** 0.5 cores (limit), 0.25 cores (reservation)
- **Memory:** 512MB (limit), 256MB (reservation)
### Metrics
The application exposes Prometheus metrics at `/metrics` including:
- `documents_uploaded_total`
- `documents_metadata_processed_total`
- `documents_retrieved_total`
- `internal_api_call_duration_seconds`
## Troubleshooting
### Service Not Starting
1. Check service logs: `docker service logs fastapi-demo_fastapi-demo`
2. Verify image was built: `docker images | grep fastapi-demo`
3. Check resource availability on nodes
### Port Conflicts
If ports 8000, 8001, 16686, or 9090 are already in use, modify the `docker-stack.yml` file to use different ports.
### Network Issues
The stack creates an overlay network `demo-network`. If you need to connect to external services, ensure they're on the same network or configure network routing appropriately.
## Customization
### Adding New Services
To add new services to the stack:
1. Add the service definition to `docker-stack.yml`
2. Include it in the `demo-network`
3. Configure appropriate resource limits and health checks
### Modifying Configuration
- **Application config:** Modify `demo.py` and rebuild the image
- **Prometheus config:** Modify `prometheus.yml`
- **Stack config:** Modify `docker-stack.yml`
### Environment-Specific Deployments
Create environment-specific stack files:
- `docker-stack.dev.yml`
- `docker-stack.prod.yml`
- `docker-stack.staging.yml`
## Security Considerations
- The demo runs with minimal security for development purposes
- For production, consider:
- Using secrets for sensitive configuration
- Implementing proper authentication
- Using HTTPS/TLS
- Restricting network access
- Running with non-root user
+3 -5
View File
@@ -82,7 +82,7 @@ python_multipart
```
Go to amq-dapter-python repo source code, and copy the service specific directory, e.g. `<git-root>/cleverswarm`
directory to your service's sources. For the CleverSwarm service, the file is `cleverswarm/clever_swarm.py`,
directory to your service's sources. For the CleverSwarm service, the file is `cleverswarm/clever_swarm.py`,
and contains the AMQ Adapter to CleverSwarm service custom facade, implemented as
```python
class CleverSwarmAmqpAdapter(CleverThisServiceAdapter):
@@ -94,7 +94,7 @@ to instatiate and initialize the AMQ adapter, add following line to the init rou
```
and ensure that the `adapter` stays in the context of the service, so it is not garbage collected.
At version 0.2.21, AMQ Adapter uses local configuration file, relative path to which is passed
At version 0.2.21, AMQ Adapter uses local configuration file, relative path to which is passed
to the AMQConfiguration constructor. This may change in the future, when the central configuration service
will become available in CleverMicro, but for now please ensure correct relative path wrt the current working directory.
@@ -104,8 +104,7 @@ For the config entries, please refer to the wiki page: [AMQ Adapter Config](htt
The AMQ Adapter uses the following environment variables to configure the service:
PARALLEL_WORKERS - number of parallel workers to use for processing incoming requests. This is currently mandatory value,
shall be greater than 0.
MAX_AVAILABILITY - For backpressure management, indicates max capacity for processing incoming requests. If set, shall be greater than 0.
AMQ_VERBOSE_LOGGING - if set to 1, the adapter will indicate in the log next to the message itself also module name, line and function name where the message was generated
@@ -148,4 +147,3 @@ To remove volumes as well:
```bash
docker-compose down -v
```
+194 -104
View File
@@ -3,18 +3,16 @@ import json
import time
from asyncio import AbstractEventLoop
from threading import Thread
from typing import Optional
from aio_pika import Message
from aio_pika.abc import AbstractRobustChannel
from amqp.adapter.logging_utils import logging_info
from amqp.adapter.logging_utils import logging_info, logging_warning
from amqp.config.amq_configuration import AMQConfiguration
from amqp.model.model import ScalingRequestAlert
from amqp.router.utils import await_future, await_result
CPU_IDLE, CPU_ACTIVE, CPU_OVERLOAD = 0, 1, 2
IDLE_THRESHOLD, OVERLOAD_THRESHOLD = 0.15, 0.90
RESOURCE_UNSET, RESOURCE_IDLE, RESOURCE_ACTIVE, RESOURCE_OVERLOAD = -1, 0, 1, 2
class ScaleRequestV1:
@@ -22,12 +20,16 @@ class ScaleRequestV1:
self,
serviceId: str,
taskId: str,
currentAvailability: int,
max_availability: int,
current_availability: int,
requestType: ScalingRequestAlert,
):
self.version = 1 # Version of the request, currently 1
self.serviceId = serviceId
self.taskId = taskId
self.currentAvailability = currentAvailability
self.max_availability = max_availability
self.current_availability = current_availability
self.requestType = requestType
self.thread = None
def to_json(self) -> str:
@@ -37,60 +39,21 @@ class ScaleRequestV1:
"version": self.version,
"serviceId": self.serviceId,
"taskId": self.taskId,
"currentAvailability": self.currentAvailability,
"maxAvailability": self.max_availability,
"currentAvailability": self.current_availability,
"requestType": self.requestType.value, # Using .value for Enum serialization
},
indent=2,
)
class RunningAverage:
"""
A class to maintain a running average of the last N values.
The intended use is to track CPU usage over time window, that is directly related to sample rate and window size.
This is the reason why the constructor takes the number of items to store, calculated as window size / sample rate
Initial_value is for unit test to emulate OVERLOAD or IDLE condition.
"""
def __init__(self, num_items, initial_value=0):
self.buffer = [initial_value] * num_items # Fixed-size array
self.pointer = 0 # Current position in array
self.num_items = num_items # Maximum number of items to store
self.is_filled = False # Track if buffer is fully filled
def add(self, value):
# Store the value at current pointer position
self.buffer[self.pointer] = value
# Move pointer to next position with wrap-around
self.pointer += 1
if self.pointer >= self.num_items:
self.pointer = 0
self.is_filled = True
def get_average(self):
# Determine how many items we should average
count = self.num_items if self.is_filled else self.pointer
if count == 0:
return 0.0 # Avoid division by zero
return sum(self.buffer) / count
def get_current_values(self):
"""Returns the values in chronological order (oldest first)"""
if not self.is_filled:
return self.buffer[: self.pointer]
return self.buffer[self.pointer :] + self.buffer[: self.pointer]
class BackpressureHandler:
# Track the number of messages currently being processed
current_parallel_executions = 0
# report when remain availability goes down
last_usage_report_time = 0
# report when remain availability goes up
last_recover_report_time = 0
current_availability = 0
# helps detect IDLE condition
# helps prevent flooding the system with backpressure events
last_backpressure_event_time = 0
last_backpressure_event = ScalingRequestAlert.UPDATE
# _callback_list is used in unit tests to record the invoked callbacks
_callback_list = None
@@ -107,80 +70,196 @@ class BackpressureHandler:
self.exchange = None
self.swarm_service_id = self.config.amq_adapter.swarm_service_id
self.swarm_task_id = self.config.amq_adapter.swarm_task_id
self.parallel_workers = self.config.backpressure.threshold_threads
self.do_loop = -1
self._resource_usage_changed = 0
self._resource_average_value = 0
self._last_resource_max_value = 100 # Default max value for CPU usage
self.max_availability = -1
self.current_availability = 1
self.max_load = 1
self.current_load = 0
self.idle_state_detected_time = 0
def _do_loop(self) -> bool:
"""
Check if the loop should continue running.
Positive value of do_loop indicates the number of iterations left.
Negative value indicates the loop should run indefinitely.
"""
_val = self.do_loop != 0
if self.do_loop > 0:
self.do_loop -= 1
return _val
async def increase_parallel_executions(self):
"""Increase the number of parallel executions"""
self.current_parallel_executions += 1
def increase_current_load(self):
"""Increase the number of parallel executions, or current_availability load"""
logging_info(
"Backpressure: Increased parallel executions, new value: %s",
self.current_parallel_executions,
"Backpressure: Increase current load (%s) by 1",
self.current_load,
)
# increase parallel -> reduce in remaining availability -> usage
# report usage at least every 1s
# TODO: add config for the interval
if self.last_usage_report_time + 1 < time.time():
await self.send_backpressure_report()
self.last_usage_report_time = time.time()
self.current_load += 1
async def decrease_parallel_executions(self):
"""Decrease the number of parallel executions"""
if self.current_parallel_executions > 0:
self.current_parallel_executions -= 1
def decrease_current_load(self):
"""Decrease the number of parallel executions, or current load"""
logging_info(
"Backpressure: Decreased parallel executions, new value=%s",
self.current_parallel_executions,
"Backpressure: Decrease current load(%s) by 1",
self.current_load,
)
# decrease parallel -> add to remaining availability -> recover
# report recover at every 3s
# TODO: add config for the interval
if self.last_recover_report_time + 3 < time.time():
await self.send_backpressure_report()
self.last_recover_report_time = time.time()
if self.current_load > 0:
self.current_load -= 1
def start_backpressure_monitor(self) -> Thread:
def update_current_availability(self, count: int):
"""Update the number of parallel executions, or current load"""
self.current_availability = count
def update_last_backpressure_event_time(self):
# logging_info("Backpressure: Update last data message time")
"""Update the last data message time"""
self.last_backpressure_event_time = time.time()
async def update_backpressure_value(self, current_availability: int, maximum: int):
"""
Update the current backpressure value and check for overload conditions.
This method is called by the AMQService.backpressure() method to update
the current parallel executions count and check for overload conditions.
Args:
current_availability: Current value of the backpressure metric
maximum: Maximum value of the backpressure metric
"""
logging_info(
"Backpressure: Updating backpressure value, current_availability=%s, maximum=%s",
current_availability,
maximum,
)
if maximum > 0 and maximum > self.max_availability:
self.max_availability = maximum
# Update the current_availability / parallel executions count
self.update_current_availability(current_availability)
# Check for overload conditions
await self.check_overload_condition()
def start_backpressure_monitor(self) -> Optional[Thread]:
# Start the Backpressure monitor loop
self.thread = Thread(target=self.regular_report_loop_wrapper)
self.thread = Thread(target=self.backpressure_monitor_loop)
self.thread.daemon = True # This makes it a daemon thread
self.thread.start()
return self.thread
async def _regular_report_loop(self):
"""Regularly report the availability in a fixed interval"""
async def check_overload_condition(self):
"""
Check if the current_availability availability is too low (OVERLOAD)
or if the service has been idle for too long with high availability (IDLE).
Note: current_availability represents available capacity, not used capacity.
- Low availability (close to 0) means OVERLOAD
- High availability (close to maximum) with no activity means IDLE
"""
current_time = time.time()
last_event_delta: float = current_time - self.last_backpressure_event_time
# logging_info(
# "Backpressure: Check conditions, current_availability=%s, max=%s, last_activity=%s",
# self.current_availability,
# self.max_availability,
# last_event_delta,
# )
# Check for OVERLOAD condition - low availability (less than 20% of maximum)
if self.current_availability <= round(0.1 * self.max_availability):
# Check if the last backpressure event was not an overload
if (
self.last_backpressure_event != ScalingRequestAlert.OVERLOAD
or last_event_delta > self.config.backpressure.idle_duration
):
# Trigger the overload event
await self.handle_backpressure_overload_event()
# update / reset time-window so that the OVERLOAD is not sent too often
self.last_backpressure_event_time = current_time
self.last_backpressure_event = ScalingRequestAlert.OVERLOAD
# Check for IDLE condition - high availability (more than 80% of maximum) with no activity
elif self.current_availability >= round(0.8 * self.max_availability):
idle_duration = self.config.backpressure.idle_duration
# Check if service has been idle for longer than the configured duration
if (
current_time - self.idle_state_detected_time > idle_duration
and self.last_backpressure_event == ScalingRequestAlert.IDLE
):
logging_info(
"Backpressure: Service has been idle for %s seconds (threshold: %s seconds)",
last_event_delta,
idle_duration,
)
# Trigger the idle event
await self._handle_backpressure_idle_event()
# update / reset time-window so that the IDLE is not sent too often
self.last_backpressure_event_time = current_time
self.idle_state_detected_time = current_time
# send IDLE even only once
self.last_backpressure_event = ScalingRequestAlert.UPDATE
else:
# Don't send IDLE right away when the availability increases, but wait for a while, send UPDATE instead
self.last_backpressure_event = ScalingRequestAlert.IDLE
if current_time - self.idle_state_detected_time > idle_duration:
self.idle_state_detected_time = current_time
if last_event_delta > self.config.backpressure.time_window:
_scaling_request: ScaleRequestV1 = ScaleRequestV1(
self.swarm_service_id,
self.swarm_task_id,
self.max_availability,
self.current_availability, # Current availability is passed directly
ScalingRequestAlert.UPDATE,
)
# Address the message to any adapter capable of supporting BACKPRESSURE request
await self.publish_backpressure_request(_scaling_request)
self.last_backpressure_event_time = current_time
# If neither OVERLOAD nor IDLE, and it's time for an update, send UPDATE event
elif last_event_delta > self.config.backpressure.time_window:
_scaling_request: ScaleRequestV1 = ScaleRequestV1(
self.swarm_service_id,
self.swarm_task_id,
self.max_availability,
self.current_availability, # Current availability is passed directly
ScalingRequestAlert.UPDATE,
)
# Address the message to any adapter capable of supporting BACKPRESSURE request
await self.publish_backpressure_request(_scaling_request)
self.last_backpressure_event_time = current_time
self.last_backpressure_event = ScalingRequestAlert.UPDATE
async def _backpressure_monitor(self):
"""Periodically monitor the backpressure conditions and trigger events accordingly"""
_monitor_interval = 0.5 # Monitor every 500ms
while self._do_loop():
await self.send_backpressure_report()
# report recover at every 5s
# TODO: add config for the interval
await asyncio.sleep(5)
await self.check_overload_condition()
await asyncio.sleep(_monitor_interval)
def regular_report_loop_wrapper(self):
def backpressure_monitor_loop(self):
_loop = asyncio.new_event_loop()
_loop.run_until_complete(self._regular_report_loop())
_loop.run_until_complete(self._backpressure_monitor())
async def send_backpressure_report(self):
async def handle_backpressure_overload_event(self):
logging_warning("Backpressure: Capacity close to depleted!")
# Send an Overload event to the Management service
scaling_request: ScaleRequestV1 = ScaleRequestV1(
serviceId=self.swarm_service_id,
taskId=self.swarm_task_id,
currentAvailability=self.parallel_workers - self.current_parallel_executions,
self.swarm_service_id,
self.swarm_task_id,
self.max_availability,
self.current_availability, # Current availability is passed directly
ScalingRequestAlert.OVERLOAD,
)
# Address the message to any management service instance capable of supporting BACKPRESSURE request
await self.publish_backpressure_request(scaling_request)
async def _handle_backpressure_idle_event(self):
logging_warning("Backpressure: Service is idle.")
# Send an Idle event to the Management service
scaling_request: ScaleRequestV1 = ScaleRequestV1(
self.swarm_service_id,
self.swarm_task_id,
self.max_availability,
self.current_availability, # Current availability is passed directly
ScalingRequestAlert.IDLE,
)
# Address the message to any adapter capable of supporting BACKPRESSURE request
await self.publish_backpressure_request(scaling_request)
async def publish_backpressure_request(self, scaling_request: ScaleRequestV1):
# Publish the backpressure request to the management service
logging_info(
f"Publishing backpressure for {scaling_request.serviceId} with availability {scaling_request.currentAvailability}"
f"Publishing backpressure for {scaling_request.serviceId} with request type {scaling_request.requestType}"
)
if not self.exchange:
@@ -222,3 +301,14 @@ class BackpressureHandler:
if BackpressureHandler._callback_list is not None:
BackpressureHandler._callback_list["_wrap_rabbit_mq_api"] = 1
await await_future(asyncio.run_coroutine_threadsafe(_wrap_rabbit_mq_api(), self.loop))
def _do_loop(self) -> bool:
"""
Helper function for unit tests to perform several loops only. Check if the loop should continue running.
Positive value of do_loop indicates the number of iterations left.
Negative value indicates the loop should run indefinitely.
"""
_val = self.do_loop != 0
if self.do_loop > 0:
self.do_loop -= 1
return _val
+2 -2
View File
@@ -83,7 +83,7 @@ async def _convert_file_response(
temporary dedicated queue.
"""
# All calls to RabbitMQ API have to be called threadsafe, because those appear to be attached
# to parent event loop, and need to execute at that event loop, not the current one
# to parent event loop, and need to execute at that event loop, not the current_availability one
# allow coroutine to execute. calling _future.result() will block the entire thread
# and the coroutine will never execute
_channel, _exchange, _routing_key = await await_result(
@@ -241,7 +241,7 @@ class CleverThisServiceAdapter:
async def get_current_user(self, token: str) -> object:
"""
To Be Overriden in subclass for given CleverThis Service, to return the current user based
To Be Overriden in subclass for given CleverThis Service, to return the current_availability user based
on the token, in format appropriate for the service.
:param token: The token to be used for authentication.
+39 -44
View File
@@ -1,51 +1,46 @@
import os
import logging
import os
import random
import socket
import time
from typing import Optional
import consul
from amqp.config.amq_configuration import AMQConfiguration
import consul_kv
from amqp.config.amq_configuration import AMQAdapter
logger = logging.getLogger(__name__)
# Default configuration values for Adapter
DEFAULT_CONSUL_HOST = 'localhost'
DEFAULT_CONSUL_PORT = 8500
DEFAULT_CONSUL_COUNTER_KEY = 'adapter/ids/counter'
DEFAULT_MAX_RETRIES = 5
DEFAULT_RETRY_DELAY_SECONDS = 0.1
def get_config_values():
def get_config_values(config: AMQAdapter) -> tuple:
"""
Get configuration values from AMQConfiguration or environment variables.
Returns:
tuple: (consul_host, consul_port, consul_counter_key, max_retries, retry_delay_seconds)
"""
try:
config = AMQConfiguration("application.properties")
consul_host = os.environ.get('CONSUL_HOST', DEFAULT_CONSUL_HOST)
consul_port = int(os.environ.get('CONSUL_PORT', DEFAULT_CONSUL_PORT))
consul_counter_key = os.environ.get('CONSUL_COUNTER_KEY', DEFAULT_CONSUL_COUNTER_KEY)
max_retries = int(os.environ.get('CONSUL_MAX_RETRIES', DEFAULT_MAX_RETRIES))
retry_delay_seconds = float(os.environ.get('CONSUL_RETRY_DELAY_SECONDS', DEFAULT_RETRY_DELAY_SECONDS))
consul_host = config.consul_host
consul_port = config.consul_port
consul_counter_key = config.consul_counter_key
max_retries = config.consul_max_retries
retry_delay_seconds = config.consul_initial_retry_delay
return consul_host, consul_port, consul_counter_key, max_retries, retry_delay_seconds
except Exception as e:
logger.warning(f"Failed to load configuration: {str(e)}. Using default values.")
return (
os.environ.get('CONSUL_HOST', DEFAULT_CONSUL_HOST),
int(os.environ.get('CONSUL_PORT', DEFAULT_CONSUL_PORT)),
os.environ.get('CONSUL_COUNTER_KEY', DEFAULT_CONSUL_COUNTER_KEY),
int(os.environ.get('CONSUL_MAX_RETRIES', DEFAULT_MAX_RETRIES)),
float(os.environ.get('CONSUL_RETRY_DELAY_SECONDS', DEFAULT_RETRY_DELAY_SECONDS))
os.environ.get("CONSUL_HOST", consul_kv.settings.DEFAULT_ENDPOINT.split(":")[0]),
int(os.environ.get("CONSUL_PORT", consul_kv.settings.DEFAULT_ENDPOINT.split(":")[1])),
os.environ.get("CONSUL_COUNTER_KEY", "service/ids/counter"),
int(os.environ.get("CONSUL_MAX_RETRIES", 5)),
float(os.environ.get("CONSUL_RETRY_DELAY_SECONDS", 0.2)),
)
def generate_fallback_id() -> int:
"""
Generate a fallback ID when Consul is not available.
Uses a combination of timestamp, hostname hash, and random number.
Returns:
int: A reasonably unique integer ID
"""
@@ -57,45 +52,45 @@ def generate_fallback_id() -> int:
logger.warning(f"Using fallback ID generation method: {unique_id}")
return unique_id
def get_unique_instance_id() -> int:
def get_unique_instance_id(config: AMQAdapter) -> int:
"""
Get a globally unique ID from Consul.
Uses Consul's atomic Compare-And-Set operations to safely increment a counter.
Falls back to a local generation method if Consul is unavailable.
Returns:
int: A globally unique integer ID
"""
consul_host, consul_port, consul_counter_key, max_retries, retry_delay_seconds = get_config_values()
consul_host, consul_port, consul_counter_key, max_retries, retry_delay_seconds = (
get_config_values(config)
)
try:
c = consul.Consul(host=consul_host, port=consul_port)
index, data = c.kv.get(consul_counter_key)
c = consul_kv.Connection(endpoint=f"{consul_host}:{consul_port}", timeout=5)
index, data = c.get(consul_counter_key)
if data is None:
logger.info(f"Initializing Consul counter at {consul_counter_key}")
if c.kv.put(consul_counter_key, "1"):
if c.put(consul_counter_key, "1", cas=1):
return 1
else:
logger.error("Failed to initialize Consul counter")
return generate_fallback_id()
current_value = int(data['Value'].decode('utf-8'))
current_value = int(data["Value"].decode("utf-8"))
new_value = current_value + 1
for attempt in range(max_retries):
success = c.kv.put(
consul_counter_key,
str(new_value),
cas=data['ModifyIndex']
)
success = c.put(consul_counter_key, str(new_value), cas=data["ModifyIndex"])
if success:
logger.debug(f"Successfully obtained unique ID: {new_value}")
return new_value
logger.debug(f"CAS update failed on attempt {attempt+1}, retrying...")
time.sleep(retry_delay_seconds)
index, data = c.kv.get(consul_counter_key)
if data is None:
logger.error("Counter disappeared during update")
return generate_fallback_id()
current_value = int(data['Value'].decode('utf-8'))
new_value = current_value + 1
logger.debug(f"CAS update failed on attempt {attempt + 1}, retrying...")
if attempt < max_retries - 1:
time.sleep(retry_delay_seconds * (1 << attempt)) # Exponential backoff
index, data = c.get(consul_counter_key)
if data is None:
logger.error("Counter disappeared during update")
return generate_fallback_id()
current_value = int(data["Value"].decode("utf-8"))
new_value = current_value + 1
logger.error(f"Failed to update counter after {max_retries} attempts")
return generate_fallback_id()
except Exception as e:
+41 -17
View File
@@ -113,6 +113,25 @@ class DataMessageFactory:
payload,
)
def safe_rsplit(self, fq_method_name, default="_"):
"""
Safely split a fully qualified method name into package, class, and method
Args:
fq_method_name (str): Fully qualified method name
default (str, optional): Default value for missing tokens. Defaults to ''.
Returns:
tuple: (package, class_name, method)
"""
if not fq_method_name:
return default, default, default
parts = fq_method_name.rsplit(".", 2)
# Pad with default values if insufficient tokens
while len(parts) < 3:
parts.insert(0, default)
return tuple(parts)
def create_rpc_message(
self,
fq_method_name: str,
@@ -125,9 +144,14 @@ class DataMessageFactory:
:param args: arguments whose serialized form will form the request body
:return: DataMessage object
"""
package, class_name, method = fq_method_name.rsplit(".", 2)
package, class_name, method = self.safe_rsplit(fq_method_name)
headers = {"Content-Type": ["application/octet-stream"], "Return-Address": [swarm_id]}
trace_info = {}
body = python_type_to_json(args).encode(encoding="utf-8") if args else b""
print(
f"Creating RPC message for method: {fq_method_name}, args: {args} body: {body.decode('utf-8') if body else 'None'}"
)
return DataMessage(
DataMessageMagicByte.RPC_REQUEST.value,
self.generate_snowflake_id(),
@@ -136,7 +160,7 @@ class DataMessageFactory:
method,
headers,
trace_info,
python_type_to_json(args) if args else b"",
body,
)
@staticmethod
@@ -195,13 +219,13 @@ class DataMessageFactory:
header_length = 1 + len(id_bytes) + len(prolog)
prolog_len = header_length.to_bytes(2, byteorder="big")
msg_length = 2 + header_length + len(message.base64body())
with BytesIO(bytearray(msg_length)) as baos:
baos.write(prolog_len)
baos.write(DataMessageMagicByte.HTTP_REQUEST.value.encode("utf-8"))
baos.write(id_bytes)
baos.write(prolog)
baos.write(message.base64body())
return baos.getvalue()
baos = BytesIO(bytearray(msg_length))
baos.write(prolog_len)
baos.write(message.magic().encode("utf-8"))
baos.write(id_bytes)
baos.write(prolog)
baos.write(message.base64body())
return baos.getvalue()
@staticmethod
def from_bytes(input_bytes: bytes) -> DataMessage:
@@ -214,7 +238,7 @@ class DataMessageFactory:
metadata = input_bytes[2 : prolog_len + 2].decode()
pattern = re.compile(
f"{DataMessageMagicByte.HTTP_REQUEST.value}"
r"([AR])"
r"([0-9A-Fa-f]+)\|"
r"m=([^|]*)\|"
r"d=([^|]*)\|"
@@ -230,19 +254,19 @@ class DataMessageFactory:
f"Input string [{metadata}] does not match pattern: {pattern.pattern}"
)
id_str = match.group(1)
method = match.group(2)
domain = match.group(3)
path = match.group(4)
headers_str = match.group(5)
trace_info_str = match.group(6)
id_str = match.group(2)
method = match.group(3)
domain = match.group(4)
path = match.group(5)
headers_str = match.group(6)
trace_info_str = match.group(7)
body_b64 = input_bytes[prolog_len + 2 :]
headers = parse_map_list_string(headers_str)
trace_info = parse_map_string(trace_info_str)
return DataMessage(
DataMessageMagicByte.HTTP_REQUEST.value,
match.group(1), # Magic byte (R for RPC, A for HTTP)
SnowflakeId.from_hex(id_str),
method,
domain,
+7 -7
View File
@@ -13,17 +13,17 @@ __verbose__ = os.environ.get("AMQ_VERBOSE_LOGGING", "0") == "1"
def get_context_info():
"""
Retrieves the current module, line number, and function name.
Retrieves the current_availability module, line number, and function name.
Returns:
A tuple containing (module name, line number, function name).
Returns (None, None, None) if it fails to retrieve the information.
"""
try:
# Get the frame object for the current function call
# Get the frame object for the current_availability function call
frame = inspect.currentframe()
if frame is not None:
# Get the frame object for the caller of the current function
# Get the frame object for the caller of the current_availability function
frame = frame.f_back.f_back
if frame:
code_context = frame.f_code
@@ -44,7 +44,7 @@ def get_context_info():
def logging_error(msg: str, *args) -> None:
"""
Log an error message according to current logging for 'ERROR' level.
Log an error message according to current_availability logging for 'ERROR' level.
Add module name, line and function name where the error occurred, on single line.
Args:
msg (str): The error message to log.
@@ -70,7 +70,7 @@ def logging_error(msg: str, *args) -> None:
def logging_warning(msg: str, *args) -> None:
"""
Log a warning message according to current logging for 'WARN' level.
Log a warning message according to current_availability logging for 'WARN' level.
Add module name, line and function name where the print occurred, on single line.
Args:
msg (str): The warning message to log.
@@ -91,7 +91,7 @@ def logging_warning(msg: str, *args) -> None:
def logging_info(msg: str, *args) -> None:
"""
Log an info message according to current logging for 'INFO' level.
Log an info message according to current_availability logging for 'INFO' level.
Add module name, line and function name where the print occurred, on single line.
Args:
msg (str): The info message to log.
@@ -112,7 +112,7 @@ def logging_info(msg: str, *args) -> None:
def logging_debug(msg: str, *args) -> None:
"""
Log a debug message according to current logging for 'DEBUG' level.
Log a debug message according to current_availability logging for 'DEBUG' level.
Add module name, line and function name where the print occurred, on single line.
Args:
msg (str): The debug message to log.
+7 -3
View File
@@ -39,10 +39,14 @@ def map_with_list_as_string(map_: Dict[str, List[str]]) -> str:
def parse_map_string(input_str: str) -> Dict[str, str]:
map_ = {}
if input_str.startswith("{") and input_str.endswith("}"):
for entry in input_str[1:-1].split(","):
for entry in str(input_str[1:-1]).replace("\n", "").split(","):
if len(entry) > 1:
key, value = entry.split("=")
map_[key] = value
if entry.startswith('"'):
key, value = entry.split(":")
map_[key.strip('"')] = value.strip('"')
else:
key, value = entry.split("=")
map_[key] = value
return map_
+82 -6
View File
@@ -24,9 +24,7 @@ class AMQAdapter:
:param config: config parser to read configuration values
"""
self.generator_id = config.getint(
"CleverMicro-AMQ", self.PREFIX + "generator-id", fallback=164
)
self.generator_id = 0
self.service_name = config.get(
"CleverMicro-AMQ",
self.PREFIX + "service-name",
@@ -45,9 +43,72 @@ class AMQAdapter:
self.PREFIX + "default-backpressure-enabled",
fallback=False,
)
self.callbacks_enabled = config.getboolean(
"CleverMicro-AMQ",
self.PREFIX + "callbacks-enabled",
fallback=False,
)
# these 2 shall be provided by Docker swarm, format is a random alphanumeric string
self.swarm_service_id = os.getenv("SWARM_SERVICE_ID", default="clever-amqp-service")
self.swarm_task_id = os.getenv("SWARM_TASK_ID", default="python-adapter")
#
# Consul related configuration
self.consul_port = (
int(
os.getenv(
"CONSUL_PORT",
config.get("CleverMicro-AMQ", self.PREFIX + "consul-port", fallback="8500"),
)
)
if os.getenv("CONSUL_PORT") is not None
else config.getint("CleverMicro-AMQ", self.PREFIX + "consul-port", fallback=8500)
)
self.consul_host = os.getenv(
"CONSUL_HOST",
config.get("CleverMicro-AMQ", self.PREFIX + "consul-host", fallback="consul"),
)
self.consul_max_retries = (
int(
os.getenv(
"CONSUL_MAX_RETRIES",
config.get("CleverMicro-AMQ", self.PREFIX + "consul-max-retries", fallback="5"),
)
)
if os.getenv("CONSUL_MAX_RETRIES") is not None
else config.getint("CleverMicro-AMQ", self.PREFIX + "consul-max-retries", fallback=5)
)
self.consul_initial_retry_delay = (
float(
os.getenv(
"CONSUL_INITIAL_RETRY_DELAY",
config.get(
"CleverMicro-AMQ",
self.PREFIX + "consul-initial-retry-delay",
fallback="0.2",
),
)
)
if os.getenv("CONSUL_INITIAL_RETRY_DELAY") is not None
else config.getfloat(
"CleverMicro-AMQ", self.PREFIX + "consul-initial-retry-delay", fallback=0.2
)
)
self.consul_counter_key = (
os.getenv(
"CONSUL_COUNTER_KEY",
config.get(
"CleverMicro-AMQ",
self.PREFIX + "consul-counter-key",
fallback="service/ids/counter",
),
)
if os.getenv("CONSUL_COUNTER_KEY") is not None
else config.get(
"CleverMicro-AMQ",
self.PREFIX + "consul-counter-key",
fallback="service/ids/counter",
)
)
def adapter_prefix(self) -> str:
return f"{self.service_name}-{self.generator_id}-"
@@ -107,10 +168,10 @@ class Backpressure:
:param config: config parser to read configuration values
"""
self.threshold_threads = config.getint(
self.threshold_load = config.getint(
"CleverMicro-AMQ",
self.PREFIX + "threshold",
fallback=int(os.getenv("PARALLEL_WORKERS", 1)),
fallback=int(os.getenv("MAX_AVAILABILITY", 1)),
)
# time-window in seconds, duration between backpressure reports
self.time_window = config.getint(
@@ -129,6 +190,10 @@ class Backpressure:
self.idle_duration = config.getint(
"CleverMicro-AMQ", self.PREFIX + "idle-duration", fallback=30
)
# Flag to enable/disable CPU monitoring
self.cpu_monitoring_enabled = config.getboolean(
"CleverMicro-AMQ", self.PREFIX + "cpu-monitoring-enabled", fallback=False
)
class AMQConfiguration:
@@ -143,7 +208,7 @@ class AMQConfiguration:
config.read(config_file_name)
else:
# Get the directory of the caller (the module where this function is called)
caller_frame = inspect.stack()[1] # 0 is current frame, 1 is caller
caller_frame = inspect.stack()[1] # 0 is current_availability frame, 1 is caller
caller_module = inspect.getmodule(caller_frame[0])
if caller_module:
caller_dir = os.path.dirname(os.path.abspath(caller_module.__file__))
@@ -168,3 +233,14 @@ class AMQConfiguration:
self.amq_adapter: AMQAdapter = AMQAdapter(config)
self.dispatch: Dispatch = Dispatch(config)
self.backpressure: Backpressure = Backpressure(config)
def get_unique_instance_id(self) -> int:
"""
Get a unique instance ID for this AMQ service.
Returns:
int: A unique instance ID
"""
if self.instance_id == -1:
logging_warning(f"Generated unique instance ID: {self.instance_id}")
return self.instance_id
+9 -2
View File
@@ -14,8 +14,13 @@ cm.amq-adapter.generator-id=1
cm.amq-adapter.route-mapping=
# Indicate if AMQ Adapter should respond with HTTP 401 Unauthorized if the request does not contain valid JWT token
cm.amq-adapter.require-authenticated-user=false
# Indicate if AMQ Adapter should use inbuilt backpressure monitor (True) or rely only on the service backpressure updates (False)
cm.amq-adapter.default-backpressure-enabled=false
# Consul configuration for CleverMicro AMQ Adapter
cm.amq-adapter.consul-host=consul
cm.amq-adapter.consul-port=8500
cm.amq-adapter.consul-max-retries=5
cm.amq-adapter.consul-initial-retry-delay=0.2
cm.amq-adapter.consul-id-generator-key=services/ids/counter
cm.amq-adapter.callbacks-enabled=False
# CleverMicro AMQ Adapter dispatcher, settings related to RabbitMQ connection and optional REST forwarding
cm.dispatch.use-dlq=true
@@ -42,3 +47,5 @@ cm.backpressure.time-window=10
cm.backpressure.cpu-overload-duration=30
# Define the time window length, in seconds, during which, if no request is made to the Service, the system will trigger IDLE alert
cm.backpressure.cpu-idle-duration=30
# AMQ Adapter can monitor CPU usage and trigger backpressure alerts based on CPU usage. Enable this feature explicitly
cm.backpressure.cpu-monitoring-enabled=false
+14
View File
@@ -291,11 +291,21 @@ class ServiceMessage:
return self.message_type is not None
class ScalingRequestAlert(Enum):
OVERLOAD = "OVERLOAD"
IDLE = "IDLE"
UPDATE = "UPDATE"
SCALE_UP = "SCALE_UP"
SCALE_DOWN = "SCALE_DOWN"
@dataclass(frozen=True)
class ScalingRequest:
service_id: str
task_id: str
max_availability: int
current_availability: int
request_type: ScalingRequestAlert
version: int = 1
def to_json(self) -> str:
@@ -305,7 +315,9 @@ class ScalingRequest:
"version": self.version,
"serviceId": self.service_id,
"taskId": self.task_id,
"maxAvailability": self.max_availability,
"currentAvailability": self.current_availability,
"requestType": self.request_type.value, # Using .value for Enum serialization
},
indent=2,
)
@@ -317,7 +329,9 @@ class ScalingRequest:
return cls(
service_id=data["serviceId"],
task_id=data["taskId"],
max_availability=data["maxAvailability"],
current_availability=data["currentAvailability"],
request_type=ScalingRequestAlert(data["requestType"]), # Convert string to Enum
)
+19 -9
View File
@@ -1,4 +1,5 @@
import logging
from typing import Optional
import aio_pika
from aio_pika.abc import AbstractRobustExchange, AbstractRobustQueue
@@ -95,19 +96,25 @@ class RabbitMQClient:
route.queue if route.queue else self.router.get_consume_queue_name()
)
logging_info("RabbitMQClient register route: [%s]", route)
queue: AbstractRobustQueue = await self.channel.declare_queue(
name=queue_name,
durable=True,
exclusive=False,
auto_delete=False,
arguments=queue_args,
)
if self.amq_configuration.amq_adapter.callbacks_enabled:
queue: Optional[AbstractRobustQueue] = await self.channel.declare_queue(
name=queue_name,
durable=True,
exclusive=False,
auto_delete=False,
arguments=queue_args,
)
else:
queue = None
_exchange_name: str = route.exchange if route.exchange else AMQ_RPC_EXCHANGE
exchange: AbstractRobustExchange = await self.channel.declare_exchange(
name=_exchange_name, type=ExchangeType.topic
)
await queue.bind(exchange, route.key)
_c_tag = await queue.consume(callback, no_ack=False)
if self.amq_configuration.amq_adapter.callbacks_enabled:
await queue.bind(exchange, route.key)
_c_tag = await queue.consume(callback, no_ack=False)
else:
_c_tag = None
# Register the route with the router and publish its detail to other adapters
await self.router.register_route(
AMQRoute(
@@ -144,6 +151,9 @@ class RabbitMQClient:
Set up the RabbitMQ connection
:return: nothing, it applies changes to instance variables
"""
logging.info(
f"RabbitMQClient.setupAMQ, connecting to RabbitMQ at {self.amq_configuration.dispatch.amq_host}:{self.amq_configuration.dispatch.amq_port}, loop={loop}"
)
self.connection = await aio_pika.connect_robust(
host=self.amq_configuration.dispatch.amq_host,
port=self.amq_configuration.dispatch.amq_port,
+53
View File
@@ -0,0 +1,53 @@
import logging
from typing import Any, Dict
from amqp.rabbitmq.user_management_service_client import (
UserManagementServiceClient,
UserManagementServiceException,
)
async def get_user_info_from_token(
client: UserManagementServiceClient, token: str
) -> Dict[str, Any]:
"""
Get user information from a JWT token.
Args:
client: User Management Service client
token: JWT token
Returns:
User information
Raises:
UserManagementServiceException: If an error occurs
"""
try:
# Validate the token
token_info = await client.validate_token(token)
# Extract user ID from token info
user_id = None
for item in token_info:
if isinstance(item, dict) and "sub" in item:
user_id = item["sub"]
break
if not user_id:
raise UserManagementServiceException(
"cleverthis.clevermicro.auth.invalid_token",
"Token does not contain user ID (sub claim)",
{},
)
# Query user information
user_info = await client.query_user_by_id(user_id)
return user_info
except UserManagementServiceException as e:
logging.error(f"User Management Service error: {e.exception_type}: {e.message}")
raise
except Exception as e:
logging.error(f"Unexpected error: {e}")
raise
@@ -0,0 +1,260 @@
import asyncio
import json
import logging
import uuid
from typing import Any, Dict, List, Optional
import aio_pika
from aio_pika import Message
from aio_pika.abc import AbstractIncomingMessage, AbstractRobustChannel, AbstractRobustConnection
from amqp.adapter.logging_utils import logging_debug, logging_error, logging_info
from amqp.config.amq_configuration import AMQConfiguration
class UserManagementServiceException(Exception):
"""Exception raised for errors in the User Management Service."""
def __init__(self, exception_type: str, message: str, additional_info: Dict[str, Any] = None):
self.exception_type = exception_type
self.message = message
self.additional_info = additional_info or {}
super().__init__(f"{exception_type}: {message}")
class UserManagementServiceClient:
"""
Client for the User Management Service that communicates over RabbitMQ.
Supports operations for token, user, group, tenant, and permission services.
"""
# Exchange name for User Management Service
EXCHANGE_NAME = "cleverthis.clevermicro.auth.endpoints"
# Service routing keys
TOKEN_SERVICE = "token-service-v1"
USER_SERVICE = "user-service-v1"
GROUP_SERVICE = "group-service-v1"
TENANT_SERVICE = "tenant-service-v1"
PERMISSION_SERVICE = "permission-service-v1"
# Response queue name
RESPONSE_QUEUE_NAME = "user-management-service-cleverswarm"
def __init__(self, configuration: AMQConfiguration, loop: asyncio.AbstractEventLoop = None):
"""
Initialize the User Management Service client.
Args:
configuration: AMQ configuration
loop: Event loop to use (optional)
"""
self.amq_configuration = configuration
self.loop = loop or asyncio.get_event_loop()
self.connection: Optional[AbstractRobustConnection] = None
self.channel: Optional[AbstractRobustChannel] = None
self.exchange: Optional[aio_pika.RobustExchange] = None
self.response_queue: Optional[aio_pika.RobustQueue] = None
self.response_consumer_tag: Optional[str] = None
self.futures: Dict[str, asyncio.Future] = {}
self.initialized = False
async def initialize(self) -> None:
"""Initialize the RabbitMQ connection and set up the exchange and response queue."""
if self.initialized:
return
try:
# Connect to RabbitMQ
self.connection = await aio_pika.connect_robust(
host=self.amq_configuration.dispatch.amq_host,
port=self.amq_configuration.dispatch.amq_port,
login=self.amq_configuration.dispatch.rabbit_mq_user,
password=self.amq_configuration.dispatch.rabbit_mq_password,
loop=self.loop,
)
# Create channel
self.channel = await self.connection.channel()
await self.channel.set_qos(prefetch_count=1)
# Declare exchange
self.exchange = await self.channel.declare_exchange(
name=self.EXCHANGE_NAME,
type=aio_pika.ExchangeType.TOPIC,
durable=True,
)
# Declare response queue
self.response_queue = await self.channel.declare_queue(
name=self.RESPONSE_QUEUE_NAME,
durable=True,
exclusive=False,
auto_delete=False,
)
# Start consuming responses
self.response_consumer_tag = await self.response_queue.consume(
self._on_response_callback,
no_ack=False,
)
self.initialized = True
logging_info("User Management Service client initialized")
except Exception as e:
logging_error(f"Failed to initialize User Management Service client: {e}")
if self.connection and not self.connection.is_closed:
await self.connection.close()
raise
async def _on_response_callback(self, message: AbstractIncomingMessage) -> None:
"""
Handle responses from the User Management Service.
Args:
message: The incoming message
"""
try:
correlation_id = message.correlation_id
if not correlation_id:
logging_error("Received response without correlation ID")
await message.ack()
return
future = self.futures.get(correlation_id)
if not future:
logging_error(f"No pending request found for correlation ID: {correlation_id}")
await message.ack()
return
try:
response_data = json.loads(message.body.decode('utf-8'))
logging_debug(f"Received response: {response_data}")
future.set_result(response_data)
except Exception as e:
future.set_exception(e)
await message.ack()
except Exception as e:
logging_error(f"Error processing response: {e}")
await message.ack()
async def close(self) -> None:
"""Close the RabbitMQ connection."""
if self.connection and not self.connection.is_closed:
await self.connection.close()
self.initialized = False
logging_info("User Management Service client closed")
async def call_service(
self, service: str, method: str, args: Dict[str, Any] = None
) -> Dict[str, Any]:
"""
Call a method on a User Management Service.
Args:
service: Service routing key (e.g., 'token-service-v1')
method: Method name to call
args: Method arguments
Returns:
Response data
Raises:
UserManagementServiceException: If the service returns an error
"""
if not self.initialized:
await self.initialize()
correlation_id = str(uuid.uuid4())
future = self.loop.create_future()
self.futures[correlation_id] = future
request_data = {
"method": method,
"args": args or {},
}
message = Message(
body=json.dumps(request_data).encode('utf-8'),
content_type='application/json',
correlation_id=correlation_id,
reply_to=self.RESPONSE_QUEUE_NAME,
)
try:
await self.exchange.publish(message, routing_key=service)
logging_info(f"Sent request to {service}.{method}: {args}")
# Wait for response
response = await future
# Process response
if response.get("type") == "OK":
return response.get("result", [])
else:
raise UserManagementServiceException(
response.get("exception", "unknown_error"),
response.get("message", "Unknown error"),
response.get("additional_info", {})
)
except asyncio.CancelledError:
raise
except UserManagementServiceException:
raise
except Exception as e:
logging_error(f"Error calling service {service}.{method}: {e}")
raise
finally:
self.futures.pop(correlation_id, None)
async def validate_token(self, token: str) -> Dict[str, Any]:
"""
Validate a JWT token.
Args:
token: JWT token to validate
Returns:
Token information
"""
return await self.call_service(
service=self.TOKEN_SERVICE,
method="validateToken",
args={"token": token}
)
async def query_user_by_id(self, user_id: str) -> Dict[str, Any]:
"""
Query user information by user ID.
Args:
user_id: User ID
Returns:
User information
"""
return await self.call_service(
service=self.USER_SERVICE,
method="queryUserById",
args={"userId": user_id}
)
async def list_users_in_group(self, group_id: str) -> List[Dict[str, Any]]:
"""
List users in a group.
Args:
group_id: Group ID
Returns:
List of users
"""
return await self.call_service(
service=self.GROUP_SERVICE,
method="listUsersInGroup",
args={"groupId": group_id}
)
+6 -1
View File
@@ -50,7 +50,12 @@ class RouterBase:
return self.route_database.find_route(message.domain(), message.path())
def find_route_by_service(self, service_name: str) -> Optional[AMQRoute]:
return self.route_database.find_route_by_service(service_name)
_route: Optional[AMQRoute] = self.route_database.find_route_by_service(service_name)
if _route is None:
for route in self.own_routes:
if route.component_name == service_name:
_route = route
return _route
def add_routes(self, message: str) -> None:
try:
+2 -2
View File
@@ -174,12 +174,12 @@ class RouterConsumer(RouterProducer):
)
if not await self.publish_service_message(service_message, self.cm_response_exchange):
logging_warning(
"RouterConsumer couldn't remove current route: %s, channel not open.",
"RouterConsumer couldn't remove current_availability route: %s, channel not open.",
route,
)
except Exception as ioe:
logging_error("RouterConsumer failed remove current route: %s", ioe)
logging_error("RouterConsumer failed remove current_availability route: %s", ioe)
result: bool = self.remove_route(route)
return result
+1 -1
View File
@@ -81,7 +81,7 @@ class RouterProducer(RouterBase):
name=CM_REQUEST_EXCHANGE, type=ExchangeType.fanout
)
#
# 2. declare ResponseExchange where to publish current RoutingData (response to
# 2. declare ResponseExchange where to publish current_availability RoutingData (response to
# a RoutingData request)
self.cm_response_exchange = await self.channel.declare_exchange(
name=CM_RESPONSE_EXCHANGE, type=ExchangeType.fanout
+266 -12
View File
@@ -1,15 +1,18 @@
import asyncio
import importlib
import inspect
import os
import threading
import time
from asyncio import AbstractEventLoop, Future
from typing import Dict
from typing import Any, Dict
from aio_pika import Message
from aio_pika.abc import AbstractIncomingMessage, AbstractRobustExchange
from opentelemetry import trace
from opentelemetry.trace import Tracer, TraceState
from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator
from pika.exchange_type import ExchangeType
from amqp.adapter.backpressure_handler import BackpressureHandler
from amqp.adapter.cleverthis_service_adapter import AMQMessage, CleverThisServiceAdapter
@@ -17,7 +20,7 @@ from amqp.adapter.data_message_factory import DataMessageFactory
from amqp.adapter.data_response_factory import DataResponseFactory
from amqp.adapter.file_handler import FileHandler, StreamingFileHandler
from amqp.adapter.logging_utils import logging_debug, logging_error, logging_info
from amqp.adapter.serializer import map_as_string
from amqp.adapter.serializer import map_as_string, parse_map_string
from amqp.adapter.service_message_factory import ServiceMessageFactory
from amqp.config.amq_configuration import AMQConfiguration
from amqp.model.model import (
@@ -27,6 +30,7 @@ from amqp.model.model import (
MultipartDataMessage,
)
from amqp.rabbitmq.rabbit_mq_client import RabbitMQClient
from amqp.router.utils import sanitize_as_rabbitmq_name
def collect_trace_info():
@@ -45,6 +49,75 @@ def set_text(carrier, key, value):
carrier[key] = value
async def invoke_command(
package_name: str, class_name: str, function_name: str, msg_id: str = "", kwargs=None
) -> Any:
if kwargs is None:
kwargs = {}
try:
# 1. Dynamically import the package
logging_info(f"Attempting to import package: {package_name}")
package = importlib.import_module(package_name)
logging_info(f"Package '{package_name}' imported successfully.")
target_callable = None
if class_name == "__global__":
# 2. Handle global function invocation
logging_info(f"Attempting to find global function: {function_name} in {package_name}")
target_callable = getattr(package, function_name)
logging_info(f"Global function '{function_name}' found.")
else:
# 3. Handle class method invocation
logging_info(f"Attempting to find class: {class_name} in {package_name}")
target_class = getattr(package, class_name)
logging_info(f"Class '{class_name}' found. Instantiating...")
# Instantiate the class. Assuming a default constructor or one that doesn't
# require arguments from kwargs for initialization.
# If the class __init__ needs specific arguments, this part might need adjustment
# based on how those arguments are provided.
instance = target_class()
logging_info(f"Instance of '{class_name}' created.")
logging_info(f"Attempting to find method: {function_name} in class {class_name}")
target_callable = getattr(instance, function_name)
logging_info(f"Method '{function_name}' found.")
# 4. Invoke the function/method
logging_info(f"Invoking '{function_name}' with arguments: {kwargs}")
if inspect.iscoroutinefunction(target_callable):
result = await target_callable(**kwargs)
logging_info(f"Asynchronous function '{function_name}' invoked. Result: {result}")
else:
result = target_callable(**kwargs)
logging_info(f"Synchronous function '{function_name}' invoked. Result: {result}")
response: DataResponse = DataResponseFactory.of(
id=msg_id,
response_code=200,
content_type="text/plain",
body=result.encode("utf-8"),
trace_info=collect_trace_info(),
error=None,
error_cause=None,
)
response._magic = DataMessageMagicByte.RPC_REQUEST.value
return response
except ModuleNotFoundError as e:
logging_error(f"Error: Package '{package_name}' not found. {e}")
raise
except AttributeError as e:
logging_error(
f"Error: Class '{class_name}' or function/method '{function_name}' not found in '{package_name}'. {e}"
)
raise
except Exception as e:
logging_error(f"An unexpected error occurred during invocation: {e}")
raise
class DataMessageHandler:
def __init__(
self,
@@ -97,6 +170,8 @@ class DataMessageHandler:
self.ensure_trace_info(amq_message)
if amq_message.magic() == DataMessageMagicByte.HTTP_REQUEST.value:
await self.run_http_request_magic(message, amq_message, self.loop)
elif amq_message.magic() == DataMessageMagicByte.RPC_REQUEST.value:
await self.run_rpc_request(message, amq_message, self.loop)
else:
logging_error(
"Unknown MAGIC value: [%s], don't know how to interpret the message",
@@ -123,10 +198,11 @@ class DataMessageHandler:
:param loop: Event loop
:return: DataResponse
"""
# Increment the counter for parallel executions
await self.backpressure_handler.increase_parallel_executions()
# Increment the counter for parallel executions and check resource availability
self.backpressure_handler.increase_current_load()
await self.backpressure_handler.check_overload_condition()
logging_info(
f"PARALLEL: Current Capacity [{self.backpressure_handler.current_parallel_executions}] of [{self.backpressure_handler.parallel_workers}]"
f"PARALLEL: Current Capacity [{self.backpressure_handler.current_availability}] of [{self.backpressure_handler.max_availability}]"
)
if message.reply_to:
self.reply_to = message.reply_to
@@ -153,12 +229,97 @@ class DataMessageHandler:
logging_error(f"Deleting file {filename}: {e}")
except Exception as e:
logging_error(f"Request handler: {e}")
# recover availability
await self.backpressure_handler.decrease_parallel_executions()
self.backpressure_handler.decrease_current_load()
async def run_rpc_request(
self,
message: AbstractIncomingMessage,
amq_message: DataMessage,
loop: AbstractEventLoop,
) -> None:
"""
Synchronous version of on_message method. This is a wrapper around the async on_message method.
It also counts parallel executions and handles backpressure.
:param message: RabbitMQ raw message
:param amq_message: DataMessage
:param loop: Event loop
:return: DataResponse
"""
# Increment the counter for parallel executions and check resource availability
self.backpressure_handler.increase_current_load()
await self.backpressure_handler.check_overload_condition()
logging_info(
f"PARALLEL: Current Capacity [{self.backpressure_handler.current_availability}] of [{self.backpressure_handler.max_availability}]"
)
if message.reply_to:
self.reply_to = message.reply_to
try:
_a_message = AMQMessage(amq_message, self.rabbit_mq_client.connection)
_response: DataResponse = await self.on_rpc(_a_message)
logging_debug(f"Result in thread: {_response}")
try:
await self.send_reply(message.reply_to, _response)
except Exception as e:
logging_error(f"Processing message: {e}")
asyncio.run_coroutine_threadsafe(message.nack(requeue=False), loop=loop)
if isinstance(amq_message, MultipartDataMessage):
# remove the downloaded files from the output_dir
for file_id, filename in amq_message.extra_data.items():
try:
logging_info(
f"[{message.delivery_tag}] Deleting file: {file_id} in {filename}"
)
os.remove(filename)
except OSError as e:
logging_error(f"Deleting file {filename}: {e}")
except Exception as e:
logging_error(f"Request handler: {e}")
self.backpressure_handler.decrease_current_load()
async def on_rpc(self, a_message: AMQMessage) -> DataResponse:
"""
Dynamically invokes a function or a class method from a specified package.
Args:
a_message (AMQMessage): The message containing the package, class, and function details.
Args encoded in the AMQMessage:
package_name (str): The name of the Python package to import.
class_name (str): The name of the class within the package.
Use '__global__' if the function_name refers to a global function
in the package.
function_name (str): The name of the function or method to invoke.
kwargs (Dict[str, Any]): A dictionary of keyword arguments to pass to the function/method (in the body).
Returns:
Any: The return value of the invoked function or method.
Raises:
ModuleNotFoundError: If the specified package cannot be imported.
AttributeError: If the specified class or function/method does not exist.
Exception: For any other errors during invocation.
"""
package_name: str = a_message.method()
class_name: str = a_message.domain()
function_name: str = a_message.path()
kwargs: Dict[str, Any] = parse_map_string(a_message._base64body.decode("utf-8"))
return await invoke_command(
package_name, class_name, function_name, a_message.id().as_string(), kwargs
)
async def reconstitute_data_message(
self, message: AbstractIncomingMessage
) -> DataMessage | None:
"""
DataMessage may be serialized as string in separate queue (addressing == 1) or be a MultiPart message with
files streamed over individual queues, one per file.
This function uses 'addressing' mode from message headers to determine how to deserialize (reconstitute)
the original message.
"""
amq_message: DataMessage | None = None
delivery_tag = message.delivery_tag
addressing: int = message.headers.get("clevermicro.addressing", 0)
@@ -206,12 +367,12 @@ class DataMessageHandler:
# map_as_string(amq_message.trace_info()), context_with_span, context)
def record_duration(self, start, delivery_tag):
global last_data_message_time
last_data_message_time = time.time()
global last_backpressure_event_time
last_backpressure_event_time = time.time()
logging_info(
"######[%s] Done, single ACK: %sms.",
delivery_tag,
last_data_message_time - start,
last_backpressure_event_time - start,
)
async def send_reply(self, reply_to: str, response: DataResponse):
@@ -245,8 +406,8 @@ class DataMessageHandler:
async def reply_received_callback(self, message: AbstractIncomingMessage):
"""
The reply for DataMessage that we sent out earlier - must match the received response with
the original request and respond to the caller.
The handler for reply for DataMessage that we sent out earlier -
the code matches the received response with the original request and passes the response to the caller.
:param message:
:return:
"""
@@ -275,3 +436,96 @@ class DataMessageHandler:
future.set_result(response.body())
await message.ack(multiple=False)
async def send_rpc(self, route, message: DataMessage) -> Future:
"""
Sends an RPC message to the specified route and returns a Future that will be completed
when the response is received.
:param route: AMQRoute object containing exchange and routing information
:param message: DataMessage to be sent
:return: Future that will be completed with the response payload
"""
# Create a Future to be completed when the response is received
future = asyncio.Future()
# Store the future in the outstanding dictionary using the message ID as the key
message_id = message.id().as_string()
self.outstanding[message_id] = future
# Create a Pika message with the correlation ID set to the message ID
pika_message = Message(
body=DataMessageFactory.serialize(message),
correlation_id=message_id,
reply_to=self.rabbit_mq_client.router.get_reply_to_queue_name(),
content_type=(
message.content_type()[0]
if isinstance(message.content_type(), list)
else message.content_type()
),
)
# Get the exchange from the route
rpc_exchange_name = route.exchange
exchange: AbstractRobustExchange = await self.rabbit_mq_client.channel.declare_exchange(
name=rpc_exchange_name, type=ExchangeType.topic
)
# Publish the message to the exchange with the component name as the routing key
await exchange.publish(
message=pika_message, routing_key=sanitize_as_rabbitmq_name(route.component_name)
)
logging_debug(
"###### RPC Request Published to exchg:(%s) routing_key=%s, msgId=%s",
rpc_exchange_name,
route.component_name,
message_id,
)
return future
async def send_command(self, route, message: DataMessage) -> bool:
"""
Sends an RPC message to the specified route and returns a Future that will be completed
when the response is received.
:param route: AMQRoute object containing exchange and routing information
:param message: DataMessage to be sent
:return: Future that will be completed with the response payload
"""
rmq_body = DataMessageFactory.serialize(message)
cid = message.id().as_string()
ctype = (
message.content_type()[0]
if isinstance(message.content_type(), list)
else message.content_type()
)
print(
f"Sending RPC command to route: {route}, message ID: {cid} with body: {rmq_body} correlation ID: {cid}, content type: {ctype}"
)
# Create a Pika message with the correlation ID set to the message ID
pika_message = Message(
body=rmq_body,
correlation_id=cid,
content_type=ctype,
)
print(f"SENDING RPC COMMAND: {pika_message.body} with ID: {message.id().as_string()}")
# Get the exchange from the route
rpc_exchange_name = route.exchange
exchange: AbstractRobustExchange = await self.rabbit_mq_client.channel.declare_exchange(
name=rpc_exchange_name, type=ExchangeType.topic
)
# Publish the message to the exchange with the component name as the routing key
await exchange.publish(
message=pika_message, routing_key=sanitize_as_rabbitmq_name(route.component_name)
)
logging_info(
"###### RPC Request Published to exchg:(%s) routing_key=%s, msgId=%s",
rpc_exchange_name,
route.component_name,
message.id().as_string(),
)
return True
+118 -6
View File
@@ -4,14 +4,15 @@ import logging.config
import os
from asyncio import Future
from threading import Thread
from typing import Optional
from typing import AsyncIterator, Optional
from aio_pika.abc import AbstractRobustExchange
from amqp.adapter.amq_route_factory import AMQRouteFactory
from amqp.adapter.backpressure_handler import BackpressureHandler
from amqp.adapter.consul_global_id_generator import get_unique_instance_id
from amqp.adapter.data_message_factory import DataMessageFactory
from amqp.adapter.logging_utils import logging_info, logging_warning
from amqp.adapter.logging_utils import logging_error, logging_info, logging_warning
from amqp.adapter.service_message_factory import ServiceMessageFactory
from amqp.config.amq_configuration import AMQConfiguration
from amqp.model.model import AMQRoute, DataMessage
@@ -37,14 +38,17 @@ class AMQService:
def __init__(self, amq_configuration: AMQConfiguration, service_adapter=None):
logging.info("***********************************************")
logging.info("********** AMQ Service *******************")
logging.info("************** AMQ Service ***************")
logging.info("***********************************************")
self.loop = asyncio.new_event_loop()
self.amq_configuration = amq_configuration
self.service_adapter = service_adapter
self.unique_id = get_unique_instance_id(amq_configuration.amq_adapter)
amq_configuration.amq_adapter.generator_id = self.unique_id
self.data_message_factory = DataMessageFactory.get_instance(
self.amq_configuration.amq_adapter.generator_id
self.unique_id & DataMessageFactory.MACHINE_ID_MASK
)
self.router = RouterConsumer(self.amq_configuration)
self.rabbit_mq_client = RabbitMQClient(self.amq_configuration, self.router)
@@ -60,10 +64,12 @@ class AMQService:
)
self.backpressure_thread: Optional[Thread] = None
self.backpressure_handler: Optional[BackpressureHandler] = None
self.maximum_availability = -1
self.future: Future = asyncio.Future()
# =======================================================================
# =======================================================================
# ====================== A P I M e t h o d s =========================
# ============== P u b l i c A P I M e t h o d s ===================
# =======================================================================
# =======================================================================
def run(self):
@@ -77,8 +83,38 @@ class AMQService:
logging.info("***********************************************")
logging.info("****** AMQ Service Init Complete *********")
logging.info("***********************************************")
self.future.set_result(True)
self.loop.run_forever()
def backpressure(self, current_availability: int, maximum: int = -1):
"""
Send Backpressure event to the Management Service. The Backpressure logic determines the type of the event
based on the current_availability and maximum values.
- OVERLOAD event is triggered immediately when the current_availability value is below threshold
typically set to 10% of the maximum value, or 0 if no maximum is provided.
- IDLE event is triggered when the current_availability value exeeds 80% of the maximum value or is greater
than 0 if no maximum is provided.
- UPDATE event is sent if neither OVERLOAD nor IDLE conditions are met, indicating that the backpressure is
within acceptable limits.
:param current_availability: Currently available capacity.
:param maximum: Maximum value of the backpressure metric. If undefined or set to lt 0 (e.g. -1),
the maximum is than determined from max value of current_availability seen over the time.
"""
if self.backpressure_handler is not None:
# watch maximum & current value to always have some valid maximum reference
if maximum < 0:
if current_availability > self.maximum_availability:
self.maximum_availability = current_availability
else:
if maximum > self.maximum_availability:
self.maximum_availability = maximum
asyncio.run_coroutine_threadsafe(
self.backpressure_handler.update_backpressure_value(
current_availability, maximum if maximum > 0 else self.maximum_availability
),
loop=self.backpressure_handler.loop,
)
def rpc(self, service_name: str, fq_method_name: str, **kwargs) -> Future:
"""
Send a Remote Procedure Call (RPC) message to the AMQ service.
@@ -94,7 +130,10 @@ class AMQService:
swarm_id=self.amq_configuration.amq_adapter.swarm_task_id,
**kwargs,
)
result: Future = self.amq_data_message_handler.send_rpc(route, message)
result: Future = asyncio.run_coroutine_threadsafe(
self.amq_data_message_handler.send_rpc(route, message),
loop=self.backpressure_handler.loop,
)
self.set_outstanding_future(message, result)
return result
@@ -104,6 +143,79 @@ class AMQService:
)
return result
def command(self, service_name: str, fq_method_name: str, **kwargs) -> bool:
"""
Send a unidirectional Command message to the AMQ service.
:param service_name: The service name to receive the RPC message.
:param fq_method_name: The fully qualified method name to execute the RPC message.
:param kwargs: Additional keyword arguments to be passed to the RPC method.
:return: A Future that resolves when the RPC response is received.
"""
route: Optional[AMQRoute] = self.router.find_route_by_service(service_name)
if route is not None:
m: DataMessage = self.data_message_factory.create_rpc_message(
fq_method_name=fq_method_name,
swarm_id=self.amq_configuration.amq_adapter.swarm_task_id,
args=kwargs,
)
asyncio.run_coroutine_threadsafe(
self.amq_data_message_handler.send_command(route, m),
loop=self.backpressure_handler.loop,
)
return True
return False
async def data_message_generator(self, route: AMQRoute) -> AsyncIterator[DataMessage]:
"""
An async iterator that blocks until messages arrive, processes them,
and continues in a loop.
:param queue_name: The name of the queue to consume messages from
:yield: The processed DataResponse for each message
"""
# Get a channel from the connection
channel = self.rabbit_mq_client.channel
queue_args = (
self.rabbit_mq_client.DLQ_ARGS if self.amq_configuration.dispatch.use_dlq else None
)
queue = await channel.declare_queue(
route.queue,
durable=True,
exclusive=False,
auto_delete=False,
arguments=queue_args,
)
await queue.bind(route.exchange, route.key)
# Start consuming without a callback
async with queue.iterator() as queue_iter:
async for message in queue_iter:
try:
# Process the message using the same logic as in inbound_data_message_callback_no_thread
data_message: DataMessage = (
await self.amq_data_message_handler.reconstitute_data_message(message)
)
success = yield data_message
if not success:
logging_warning(f"Message processing failed for {data_message.id()}.")
# Nack the message without requeuing in case of failure
await message.nack(requeue=False)
else:
await message.ack()
except Exception as e:
logging_error(f"Error processing message: {e}")
# Nack the message without requeuing in case of error
await message.nack(requeue=False)
def get_unique_instance_id(self) -> int:
"""
Provides cluster-wide unique instance ID for this AMQ service instance.
This ID is used to identify the service instance in the cluster and is unique across all instances.
IDs are managed by shared Consul KV store, ensuring that even if multiple instances of the service are running,
they will each have unique ID.
"""
return self.unique_id
# =======================================================================
# ====================== Internal Methods ============================
# =======================================================================
-233
View File
@@ -1,233 +0,0 @@
import consul_kv
import socket
import os
import time
import logging
import threading
# --- Configuration ---
CONSUL_HOST = os.environ.get('CONSUL_HOST', 'localhost')
CONSUL_PORT = int(os.environ.get('CONSUL_PORT', 8500))
CONSUL_COUNTER_KEY = 'service/ids/counter'
MAX_RETRIES = 5 # Max attempts for atomic update
RETRY_DELAY_SECONDS = 0.1 # Delay between retries for atomic update
# --- Logging Setup ---
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(threadName)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
# --- Fallback ID Generation ---
def generate_fallback_id() -> int:
"""
Generates a fallback ID based on hostname and PID if Consul is unavailable.
This provides a unique-ish ID for local testing/development but is not guaranteed
to be globally unique across different machines or after restarts.
"""
hostname = socket.gethostname()
pid = os.getpid()
# A simple way to combine them into a number.
# Hash hostname to an integer and combine with PID.
# Note: This is a simple fallback. For production, consider a more robust
# local ID generation or a different strategy if Consul is critical.
fallback_id = (hash(hostname) % 1000000) * 100000 + pid
logger.warning(
f"Consul is unavailable. Generating fallback ID: {fallback_id} (based on hostname: {hostname}, PID: {pid})")
return fallback_id
# --- Unique Instance ID Generation Function ---
def get_unique_instance_id() -> int:
"""
Reads and atomically increments a counter in Consul KV to get a unique instance ID.
If Consul is unavailable or the atomic update fails after retries,
it falls back to generating an ID based on hostname and PID.
"""
try:
# Initialize Consul client
client = consul_kv.Connection(endpoint=f"{CONSUL_HOST}:{CONSUL_PORT}")
logger.info(f"Attempting to connect to Consul at {CONSUL_HOST}:{CONSUL_PORT}")
for attempt in range(MAX_RETRIES):
try:
# 1. Read the current value and its modifyIndex (for CAS)
# client.get returns (value, modifyIndex)
current_value_str, modify_index = client.get(CONSUL_COUNTER_KEY)
# If key doesn't exist, initialize it to 0
if current_value_str is None:
current_value = 0
modify_index = 0 # For a non-existent key, modify_index is 0 for initial CAS
logger.info(f"Consul key '{CONSUL_COUNTER_KEY}' not found. Initializing to 0.")
else:
current_value = int(current_value_str)
new_value = current_value + 1
# 2. Attempt atomic update using CAS (Check-And-Set)
# client.set returns True on success, False on failure (if modify_index changed)
success = client.put(CONSUL_COUNTER_KEY, str(new_value), cas=modify_index)
if success:
logger.info(f"Successfully obtained unique ID: {new_value} (Attempt {attempt + 1}/{MAX_RETRIES})")
return new_value
else:
logger.warning(
f"CAS failed for '{CONSUL_COUNTER_KEY}' (modify_index changed). Retrying... (Attempt {attempt + 1}/{MAX_RETRIES})")
time.sleep(RETRY_DELAY_SECONDS * (attempt + 1)) # Exponential backoff for retries
except ValueError:
# Handle case where the stored value is not an integer
logger.error(
f"Value stored at '{CONSUL_COUNTER_KEY}' is not a valid integer. Please check Consul KV. Attempting to overwrite.")
# To recover, you might force a set without CAS, but that risks data loss.
# For this demo, we'll just let it retry or fall back.
time.sleep(RETRY_DELAY_SECONDS * (attempt + 1))
except Exception as e:
# Catch specific ConsulKV errors (e.g., connection issues, invalid response)
logger.error(f"ConsulKV error during atomic update (Attempt {attempt + 1}/{MAX_RETRIES}): {e}")
time.sleep(RETRY_DELAY_SECONDS * (attempt + 1)) # Exponential backoff
logger.error(f"Failed to obtain unique ID from Consul after {MAX_RETRIES} attempts.")
return generate_fallback_id() # Fallback if all retries fail
except Exception as e:
# Catch broader connection errors or unexpected issues with Consul client initialization
logger.error(f"Could not connect to Consul or an unexpected error occurred: {e}")
return generate_fallback_id() # Fallback if Consul is completely unreachable
import os
import logging
import random
import socket
import time
from typing import Optional
import consul
from amqp.config.amq_configuration import AMQConfiguration
from amqp.config.amq_configuration import AMQConfiguration
# Configuration from environment variables with defaults
CONSUL_HOST = os.environ.get('CONSUL_HOST', 'localhost')
CONSUL_PORT = int(os.environ.get('CONSUL_PORT', 8500))
CONSUL_COUNTER_KEY = 'service/ids/counter'
MAX_RETRIES = 5 # Max attempts for atomic update
RETRY_DELAY_SECONDS = 0.1 # Delay between retries for atomic update
logger = logging.getLogger(__name__)
def generate_fallback_id() -> int:
"""
Generate a fallback ID when Consul is not available.
Uses a combination of timestamp, hostname hash, and random number.
Returns:
int: A reasonably unique integer ID
"""
# Get current timestamp in milliseconds
timestamp = int(time.time() * 1000)
# Get hostname and hash it to an integer
hostname = socket.gethostname()
hostname_hash = hash(hostname) % 10000 # Limit to 4 digits
# Generate a random number
random_part = random.randint(0, 9999) # 4 digits
# Combine all parts into a single integer
# Format: TTTTTTTTTTT-HHHH-RRRR (T=timestamp, H=hostname hash, R=random)
unique_id = (timestamp * 100000000) + (hostname_hash * 10000) + random_part
logger.warning(f"Using fallback ID generation method: {unique_id}")
return unique_id
def get_unique_instance_id() -> int:
"""
Get a globally unique ID from Consul.
Uses Consul's atomic Compare-And-Set operations to safely increment a counter.
Falls back to a local generation method if Consul is unavailable.
Returns:
int: A globally unique integer ID
"""
consul_host, consul_port, consul_counter_key, max_retries, retry_delay_seconds = get_config_values()
try:
# Connect to Consul
c = consul.Consul(host=consul_host, port=consul_port)
# Try to get the current counter value
index, data = c.kv.get(CONSUL_COUNTER_KEY)
# If the key doesn't exist yet, create it with initial value
if data is None:
logger.info(f"Initializing Consul counter at {CONSUL_COUNTER_KEY}")
if c.kv.put(CONSUL_COUNTER_KEY, "1"):
return 1
else:
logger.error("Failed to initialize Consul counter")
return generate_fallback_id()
# Get the current value
current_value = int(data['Value'].decode('utf-8'))
new_value = current_value + 1
# Try to atomically update the counter
for attempt in range(MAX_RETRIES):
# Use Compare-And-Set to ensure atomicity
success = c.kv.put(
CONSUL_COUNTER_KEY,
str(new_value),
cas=data['ModifyIndex']
)
if success:
logger.debug(f"Successfully obtained unique ID: {new_value}")
return new_value
# If CAS failed, someone else updated the value, retry
logger.debug(f"CAS update failed on attempt {attempt+1}, retrying...")
time.sleep(RETRY_DELAY_SECONDS)
# Get the latest value for the next attempt
index, data = c.kv.get(CONSUL_COUNTER_KEY)
if data is None:
logger.error("Counter disappeared during update")
return generate_fallback_id()
current_value = int(data['Value'].decode('utf-8'))
new_value = current_value + 1
# If we've exhausted all retries, use the fallback
logger.error(f"Failed to update counter after {MAX_RETRIES} attempts")
return generate_fallback_id()
except Exception as e:
logger.error(f"Error accessing Consul: {str(e)}")
return generate_fallback_id()
def get_config_values():
"""
Get configuration values from AMQConfiguration or environment variables.
Returns:
tuple: (consul_host, consul_port, consul_counter_key, max_retries, retry_delay_seconds)
"""
try:
config = AMQConfiguration("application.properties")
consul_host = os.environ.get('CONSUL_HOST', 'localhost')
consul_port = int(os.environ.get('CONSUL_PORT', 8500))
consul_counter_key = os.environ.get('CONSUL_COUNTER_KEY', 'service/ids/counter')
max_retries = int(os.environ.get('CONSUL_MAX_RETRIES', 5))
retry_delay_seconds = float(os.environ.get('CONSUL_RETRY_DELAY_SECONDS', 0.1))
return consul_host, consul_port, consul_counter_key, max_retries, retry_delay_seconds
except Exception as e:
logger.warning(f"Failed to load configuration: {str(e)}. Using default values.")
return (
os.environ.get('CONSUL_HOST', 'localhost'),
int(os.environ.get('CONSUL_PORT', 8500)),
os.environ.get('CONSUL_COUNTER_KEY', 'service/ids/counter'),
int(os.environ.get('CONSUL_MAX_RETRIES', 5)),
float(os.environ.get('CONSUL_RETRY_DELAY_SECONDS', 0.1))
)
+20
View File
@@ -0,0 +1,20 @@
# Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = .
BUILDDIR = _build
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
+51
View File
@@ -0,0 +1,51 @@
# AMQ Adapter Python API Documentation
This directory contains the generated HTML API documentation for the AMQ Adapter Python library.
## Viewing the Documentation
1. **Open the main page**: Open `_build/html/index.html` in your web browser
2. **Browse modules**: Use the navigation menu to explore different modules:
- **Configuration** (`amqp.config`) - Configuration classes and settings
- **Adapter** (`amqp.adapter`) - Core adapter classes and utilities
- **Service** (`amqp.service`) - Service layer and message handling
- **Router** (`amqp.router`) - Routing and service discovery
- **Model** (`amqp.model`) - Data models and message structures
- **RabbitMQ** (`amqp.rabbitmq`) - RabbitMQ client implementations
## Features
- **Search functionality**: Use the search box to find specific classes, methods, or functions
- **Module index**: Browse all modules alphabetically
- **Class inheritance**: View class hierarchies and inheritance relationships
- **Source code**: Click "View page source" to see the actual Python code
- **Cross-references**: Navigate between related classes and methods
## Rebuilding the Documentation
To regenerate the documentation after code changes:
```bash
cd api-doc
make html
```
## Documentation Structure
The documentation is organized by module:
- **amqp.config**: Configuration management and settings
- **amqp.adapter**: Core adapter functionality and service integration
- **amqp.service**: Service layer, message handling, and tracing
- **amqp.router**: Routing, service discovery, and queue management
- **amqp.model**: Data models, message structures, and serialization
- **amqp.rabbitmq**: RabbitMQ client implementations and utilities
## Key Classes
- `CleverThisServiceAdapter`: Base class for service adapters
- `AMQService`: Main service class for AMQP operations
- `AMQConfiguration`: Configuration management
- `DataMessage`: Message structure for AMQP communication
- `RouterConsumer`: Service discovery and routing
- `RabbitMQClient`: RabbitMQ connection management
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+4
View File
@@ -0,0 +1,4 @@
# Sphinx build info version 1
# This file records the configuration used when building these files. When it is not found, a full rebuild will be done.
config: bf29a028b890480b74024cefba26652a
tags: 645f666f9bcd5a90fca523b33c5a78b7
@@ -0,0 +1,193 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" data-content_root="../../../">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>amqp.adapter.amq_route_factory &mdash; AMQ Adapter Python 1.0 documentation</title>
<link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=03e43079" />
<link rel="stylesheet" type="text/css" href="../../../_static/css/theme.css?v=e59714d7" />
<script src="../../../_static/jquery.js?v=5d32c60e"></script>
<script src="../../../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
<script src="../../../_static/documentation_options.js?v=f2a433a1"></script>
<script src="../../../_static/doctools.js?v=9bcbadda"></script>
<script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
<script src="../../../_static/js/theme.js"></script>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="../../../index.html" class="icon icon-home">
AMQ Adapter Python
</a>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" aria-label="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.html">AMQP Package</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.config.html">Configuration Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.adapter.html">Adapter Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.service.html">Service Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.router.html">Router Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.model.html">Model Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.rabbitmq.html">RabbitMQ Module</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="../../../index.html">AMQ Adapter Python</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="../../../index.html" class="icon icon-home" aria-label="Home"></a></li>
<li class="breadcrumb-item"><a href="../../index.html">Module code</a></li>
<li class="breadcrumb-item active">amqp.adapter.amq_route_factory</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<h1>Source code for amqp.adapter.amq_route_factory</h1><div class="highlight"><pre>
<span></span><span class="kn">from</span><span class="w"> </span><span class="nn">amqp.adapter.logging_utils</span><span class="w"> </span><span class="kn">import</span> <span class="n">logging_error</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.model.model</span><span class="w"> </span><span class="kn">import</span> <span class="n">AMQRoute</span>
<span class="c1"># record separator</span>
<span class="n">RS</span> <span class="o">=</span> <span class="s2">&quot;:&quot;</span>
<span class="c1"># null route, in lieu of None value</span>
<span class="n">NULL_ROUTE</span> <span class="o">=</span> <span class="p">{</span>
<span class="s2">&quot;componentName&quot;</span><span class="p">:</span> <span class="s2">&quot;&quot;</span><span class="p">,</span>
<span class="s2">&quot;exchange&quot;</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
<span class="s2">&quot;queue&quot;</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
<span class="s2">&quot;routingKey&quot;</span><span class="p">:</span> <span class="s2">&quot;#&quot;</span><span class="p">,</span>
<span class="s2">&quot;timeout&quot;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
<span class="s2">&quot;validUntil&quot;</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span>
<span class="p">}</span>
<div class="viewcode-block" id="AMQRouteFactory">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.amq_route_factory.AMQRouteFactory">[docs]</a>
<span class="k">class</span><span class="w"> </span><span class="nc">AMQRouteFactory</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Define the methods to create and validate AMQRoute objects.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<div class="viewcode-block" id="AMQRouteFactory.from_string">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.amq_route_factory.AMQRouteFactory.from_string">[docs]</a>
<span class="nd">@staticmethod</span>
<span class="k">def</span><span class="w"> </span><span class="nf">from_string</span><span class="p">(</span><span class="n">data</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Builds the AMQRoute from its string form.</span>
<span class="sd"> :param data: route string</span>
<span class="sd"> :return: AMQRoute object</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">_keys</span> <span class="o">=</span> <span class="n">data</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="n">RS</span><span class="p">)</span>
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">_keys</span><span class="p">)</span> <span class="o">&gt;=</span> <span class="mi">5</span><span class="p">:</span>
<span class="n">_i</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">_component_name</span> <span class="o">=</span> <span class="n">_keys</span><span class="p">[</span><span class="n">_i</span><span class="p">]</span>
<span class="n">_i</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="n">_exchange</span> <span class="o">=</span> <span class="n">_keys</span><span class="p">[</span><span class="n">_i</span><span class="p">]</span>
<span class="n">_i</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="n">_queue</span> <span class="o">=</span> <span class="n">_keys</span><span class="p">[</span><span class="n">_i</span><span class="p">]</span> <span class="k">if</span> <span class="n">_i</span> <span class="o">&lt;</span> <span class="nb">len</span><span class="p">(</span><span class="n">_keys</span><span class="p">)</span> <span class="k">else</span> <span class="s2">&quot;&quot;</span>
<span class="n">_i</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="n">_routing_key</span> <span class="o">=</span> <span class="n">_keys</span><span class="p">[</span><span class="n">_i</span><span class="p">]</span> <span class="k">if</span> <span class="n">_i</span> <span class="o">&lt;</span> <span class="nb">len</span><span class="p">(</span><span class="n">_keys</span><span class="p">)</span> <span class="k">else</span> <span class="s2">&quot;&quot;</span>
<span class="n">_i</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="n">_timeout</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">_keys</span><span class="p">[</span><span class="n">_i</span><span class="p">])</span> <span class="k">if</span> <span class="n">_i</span> <span class="o">&lt;</span> <span class="nb">len</span><span class="p">(</span><span class="n">_keys</span><span class="p">)</span> <span class="k">else</span> <span class="mi">0</span>
<span class="n">_i</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="n">_valid_until</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">_keys</span><span class="p">[</span><span class="n">_i</span><span class="p">])</span> <span class="k">if</span> <span class="n">_i</span> <span class="o">&lt;</span> <span class="nb">len</span><span class="p">(</span><span class="n">_keys</span><span class="p">)</span> <span class="k">else</span> <span class="mi">0</span>
<span class="k">return</span> <span class="n">AMQRoute</span><span class="p">(</span>
<span class="n">component_name</span><span class="o">=</span><span class="n">_component_name</span><span class="p">,</span>
<span class="n">exchange</span><span class="o">=</span><span class="n">_exchange</span><span class="p">,</span>
<span class="n">queue</span><span class="o">=</span><span class="n">_queue</span><span class="p">,</span>
<span class="n">key</span><span class="o">=</span><span class="n">_routing_key</span><span class="p">,</span>
<span class="n">timeout</span><span class="o">=</span><span class="n">_timeout</span><span class="p">,</span>
<span class="n">valid_until</span><span class="o">=</span><span class="n">_valid_until</span><span class="p">,</span>
<span class="p">)</span>
<span class="n">logging_error</span><span class="p">(</span>
<span class="s2">&quot;AMQRoute incorrect format. AMQRoute expects input as: &quot;</span>
<span class="s2">&quot;&#39;Component-Name:AMQExchange-Name:Queue-Name:Routing-Key:Timeout:Valid-Until&#39;, &quot;</span>
<span class="s2">&quot;got: [&#39;</span><span class="si">%s</span><span class="s2">&#39;]&quot;</span><span class="p">,</span>
<span class="n">data</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">err</span><span class="p">:</span>
<span class="n">logging_error</span><span class="p">(</span>
<span class="s2">&quot;</span><span class="si">%s</span><span class="s2">: AMQRoute incorrect format. AMQRoute expects input as: &quot;</span>
<span class="s2">&quot;&#39;Component-Name:AMQExchange-Name:Queue-Name:Routing-Key:Timeout:Valid-Until&#39;, &quot;</span>
<span class="s2">&quot;got: [&#39;</span><span class="si">%s</span><span class="s2">&#39;]&quot;</span><span class="p">,</span>
<span class="n">err</span><span class="p">,</span>
<span class="n">data</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">return</span> <span class="n">NULL_ROUTE</span></div>
<div class="viewcode-block" id="AMQRouteFactory.validate">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.amq_route_factory.AMQRouteFactory.validate">[docs]</a>
<span class="nd">@staticmethod</span>
<span class="k">def</span><span class="w"> </span><span class="nf">validate</span><span class="p">(</span><span class="n">route_str</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Validates the route string.</span>
<span class="sd"> :param route_str: route string</span>
<span class="sd"> :return: boolean validity indicator</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="n">route_str</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">return</span> <span class="n">route_str</span><span class="o">.</span><span class="n">count</span><span class="p">(</span><span class="s2">&quot;:&quot;</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">4</span>
<span class="k">return</span> <span class="kc">False</span></div>
</div>
</pre></div>
</div>
</div>
<footer>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2024, CleverThis.</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>
@@ -0,0 +1,466 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" data-content_root="../../../">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>amqp.adapter.backpressure_handler &mdash; AMQ Adapter Python 1.0 documentation</title>
<link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=03e43079" />
<link rel="stylesheet" type="text/css" href="../../../_static/css/theme.css?v=e59714d7" />
<script src="../../../_static/jquery.js?v=5d32c60e"></script>
<script src="../../../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
<script src="../../../_static/documentation_options.js?v=f2a433a1"></script>
<script src="../../../_static/doctools.js?v=9bcbadda"></script>
<script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
<script src="../../../_static/js/theme.js"></script>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="../../../index.html" class="icon icon-home">
AMQ Adapter Python
</a>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" aria-label="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.html">AMQP Package</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.config.html">Configuration Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.adapter.html">Adapter Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.service.html">Service Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.router.html">Router Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.model.html">Model Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.rabbitmq.html">RabbitMQ Module</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="../../../index.html">AMQ Adapter Python</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="../../../index.html" class="icon icon-home" aria-label="Home"></a></li>
<li class="breadcrumb-item"><a href="../../index.html">Module code</a></li>
<li class="breadcrumb-item active">amqp.adapter.backpressure_handler</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<h1>Source code for amqp.adapter.backpressure_handler</h1><div class="highlight"><pre>
<span></span><span class="kn">import</span><span class="w"> </span><span class="nn">asyncio</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">json</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">time</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">asyncio</span><span class="w"> </span><span class="kn">import</span> <span class="n">AbstractEventLoop</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">threading</span><span class="w"> </span><span class="kn">import</span> <span class="n">Thread</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Optional</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">aio_pika</span><span class="w"> </span><span class="kn">import</span> <span class="n">Message</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">aio_pika.abc</span><span class="w"> </span><span class="kn">import</span> <span class="n">AbstractRobustChannel</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.adapter.logging_utils</span><span class="w"> </span><span class="kn">import</span> <span class="n">logging_info</span><span class="p">,</span> <span class="n">logging_warning</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.config.amq_configuration</span><span class="w"> </span><span class="kn">import</span> <span class="n">AMQConfiguration</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.model.model</span><span class="w"> </span><span class="kn">import</span> <span class="n">ScalingRequestAlert</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.router.utils</span><span class="w"> </span><span class="kn">import</span> <span class="n">await_future</span><span class="p">,</span> <span class="n">await_result</span>
<div class="viewcode-block" id="ScaleRequestV1">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.backpressure_handler.ScaleRequestV1">[docs]</a>
<span class="k">class</span><span class="w"> </span><span class="nc">ScaleRequestV1</span><span class="p">:</span>
<div class="viewcode-block" id="ScaleRequestV1.__init__">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.backpressure_handler.ScaleRequestV1.__init__">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span>
<span class="n">serviceId</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
<span class="n">taskId</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
<span class="n">max_availability</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span>
<span class="n">current_availability</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span>
<span class="n">requestType</span><span class="p">:</span> <span class="n">ScalingRequestAlert</span><span class="p">,</span>
<span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">version</span> <span class="o">=</span> <span class="mi">1</span> <span class="c1"># Version of the request, currently 1</span>
<span class="bp">self</span><span class="o">.</span><span class="n">serviceId</span> <span class="o">=</span> <span class="n">serviceId</span>
<span class="bp">self</span><span class="o">.</span><span class="n">taskId</span> <span class="o">=</span> <span class="n">taskId</span>
<span class="bp">self</span><span class="o">.</span><span class="n">max_availability</span> <span class="o">=</span> <span class="n">max_availability</span>
<span class="bp">self</span><span class="o">.</span><span class="n">current_availability</span> <span class="o">=</span> <span class="n">current_availability</span>
<span class="bp">self</span><span class="o">.</span><span class="n">requestType</span> <span class="o">=</span> <span class="n">requestType</span>
<span class="bp">self</span><span class="o">.</span><span class="n">thread</span> <span class="o">=</span> <span class="kc">None</span></div>
<div class="viewcode-block" id="ScaleRequestV1.to_json">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.backpressure_handler.ScaleRequestV1.to_json">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">to_json</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Converts the object to a JSON string matching the Java structure&quot;&quot;&quot;</span>
<span class="k">return</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span>
<span class="p">{</span>
<span class="s2">&quot;version&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">version</span><span class="p">,</span>
<span class="s2">&quot;serviceId&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">serviceId</span><span class="p">,</span>
<span class="s2">&quot;taskId&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">taskId</span><span class="p">,</span>
<span class="s2">&quot;maxAvailability&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_availability</span><span class="p">,</span>
<span class="s2">&quot;currentAvailability&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">current_availability</span><span class="p">,</span>
<span class="s2">&quot;requestType&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">requestType</span><span class="o">.</span><span class="n">value</span><span class="p">,</span> <span class="c1"># Using .value for Enum serialization</span>
<span class="p">},</span>
<span class="n">indent</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span>
<span class="p">)</span></div>
</div>
<div class="viewcode-block" id="BackpressureHandler">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.backpressure_handler.BackpressureHandler">[docs]</a>
<span class="k">class</span><span class="w"> </span><span class="nc">BackpressureHandler</span><span class="p">:</span>
<span class="c1"># Track the number of messages currently being processed</span>
<span class="n">current_availability</span> <span class="o">=</span> <span class="mi">0</span>
<span class="c1"># helps detect IDLE condition</span>
<span class="c1"># helps prevent flooding the system with backpressure events</span>
<span class="n">last_backpressure_event_time</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">last_backpressure_event</span> <span class="o">=</span> <span class="n">ScalingRequestAlert</span><span class="o">.</span><span class="n">UPDATE</span>
<span class="c1"># _callback_list is used in unit tests to record the invoked callbacks</span>
<span class="n">_callback_list</span> <span class="o">=</span> <span class="kc">None</span>
<div class="viewcode-block" id="BackpressureHandler.__init__">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.backpressure_handler.BackpressureHandler.__init__">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span>
<span class="n">channel</span><span class="p">:</span> <span class="n">AbstractRobustChannel</span><span class="p">,</span>
<span class="n">loop</span><span class="p">:</span> <span class="n">AbstractEventLoop</span><span class="p">,</span>
<span class="n">config</span><span class="p">:</span> <span class="n">AMQConfiguration</span><span class="p">,</span>
<span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">lock</span> <span class="o">=</span> <span class="kc">None</span>
<span class="bp">self</span><span class="o">.</span><span class="n">channel</span> <span class="o">=</span> <span class="n">channel</span>
<span class="bp">self</span><span class="o">.</span><span class="n">loop</span> <span class="o">=</span> <span class="n">loop</span>
<span class="bp">self</span><span class="o">.</span><span class="n">config</span> <span class="o">=</span> <span class="n">config</span>
<span class="bp">self</span><span class="o">.</span><span class="n">exchange</span> <span class="o">=</span> <span class="kc">None</span>
<span class="bp">self</span><span class="o">.</span><span class="n">swarm_service_id</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">amq_adapter</span><span class="o">.</span><span class="n">swarm_service_id</span>
<span class="bp">self</span><span class="o">.</span><span class="n">swarm_task_id</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">amq_adapter</span><span class="o">.</span><span class="n">swarm_task_id</span>
<span class="bp">self</span><span class="o">.</span><span class="n">do_loop</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_resource_usage_changed</span> <span class="o">=</span> <span class="mi">0</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_resource_average_value</span> <span class="o">=</span> <span class="mi">0</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_last_resource_max_value</span> <span class="o">=</span> <span class="mi">100</span> <span class="c1"># Default max value for CPU usage</span>
<span class="bp">self</span><span class="o">.</span><span class="n">max_availability</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span>
<span class="bp">self</span><span class="o">.</span><span class="n">current_availability</span> <span class="o">=</span> <span class="mi">1</span>
<span class="bp">self</span><span class="o">.</span><span class="n">max_load</span> <span class="o">=</span> <span class="mi">1</span>
<span class="bp">self</span><span class="o">.</span><span class="n">current_load</span> <span class="o">=</span> <span class="mi">0</span>
<span class="bp">self</span><span class="o">.</span><span class="n">idle_state_detected_time</span> <span class="o">=</span> <span class="mi">0</span></div>
<div class="viewcode-block" id="BackpressureHandler.increase_current_load">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.backpressure_handler.BackpressureHandler.increase_current_load">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">increase_current_load</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Increase the number of parallel executions, or current_availability load&quot;&quot;&quot;</span>
<span class="n">logging_info</span><span class="p">(</span>
<span class="s2">&quot;Backpressure: Increase current load (</span><span class="si">%s</span><span class="s2">) by 1&quot;</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">current_load</span><span class="p">,</span>
<span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">current_load</span> <span class="o">+=</span> <span class="mi">1</span></div>
<div class="viewcode-block" id="BackpressureHandler.decrease_current_load">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.backpressure_handler.BackpressureHandler.decrease_current_load">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">decrease_current_load</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Decrease the number of parallel executions, or current load&quot;&quot;&quot;</span>
<span class="n">logging_info</span><span class="p">(</span>
<span class="s2">&quot;Backpressure: Decrease current load(</span><span class="si">%s</span><span class="s2">) by 1&quot;</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">current_load</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">current_load</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">current_load</span> <span class="o">-=</span> <span class="mi">1</span></div>
<div class="viewcode-block" id="BackpressureHandler.update_current_availability">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.backpressure_handler.BackpressureHandler.update_current_availability">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">update_current_availability</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">count</span><span class="p">:</span> <span class="nb">int</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Update the number of parallel executions, or current load&quot;&quot;&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">current_availability</span> <span class="o">=</span> <span class="n">count</span></div>
<div class="viewcode-block" id="BackpressureHandler.update_last_backpressure_event_time">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.backpressure_handler.BackpressureHandler.update_last_backpressure_event_time">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">update_last_backpressure_event_time</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="c1"># logging_info(&quot;Backpressure: Update last data message time&quot;)</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Update the last data message time&quot;&quot;&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">last_backpressure_event_time</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span></div>
<div class="viewcode-block" id="BackpressureHandler.update_backpressure_value">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.backpressure_handler.BackpressureHandler.update_backpressure_value">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">update_backpressure_value</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">current_availability</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">maximum</span><span class="p">:</span> <span class="nb">int</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Update the current backpressure value and check for overload conditions.</span>
<span class="sd"> This method is called by the AMQService.backpressure() method to update</span>
<span class="sd"> the current parallel executions count and check for overload conditions.</span>
<span class="sd"> Args:</span>
<span class="sd"> current_availability: Current value of the backpressure metric</span>
<span class="sd"> maximum: Maximum value of the backpressure metric</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">logging_info</span><span class="p">(</span>
<span class="s2">&quot;Backpressure: Updating backpressure value, current_availability=</span><span class="si">%s</span><span class="s2">, maximum=</span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span>
<span class="n">current_availability</span><span class="p">,</span>
<span class="n">maximum</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">if</span> <span class="n">maximum</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="ow">and</span> <span class="n">maximum</span> <span class="o">&gt;</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_availability</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">max_availability</span> <span class="o">=</span> <span class="n">maximum</span>
<span class="c1"># Update the current_availability / parallel executions count</span>
<span class="bp">self</span><span class="o">.</span><span class="n">update_current_availability</span><span class="p">(</span><span class="n">current_availability</span><span class="p">)</span>
<span class="c1"># Check for overload conditions</span>
<span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">check_overload_condition</span><span class="p">()</span></div>
<div class="viewcode-block" id="BackpressureHandler.start_backpressure_monitor">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.backpressure_handler.BackpressureHandler.start_backpressure_monitor">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">start_backpressure_monitor</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Optional</span><span class="p">[</span><span class="n">Thread</span><span class="p">]:</span>
<span class="c1"># Start the Backpressure monitor loop</span>
<span class="bp">self</span><span class="o">.</span><span class="n">thread</span> <span class="o">=</span> <span class="n">Thread</span><span class="p">(</span><span class="n">target</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">backpressure_monitor_loop</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">thread</span><span class="o">.</span><span class="n">daemon</span> <span class="o">=</span> <span class="kc">True</span> <span class="c1"># This makes it a daemon thread</span>
<span class="bp">self</span><span class="o">.</span><span class="n">thread</span><span class="o">.</span><span class="n">start</span><span class="p">()</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">thread</span></div>
<div class="viewcode-block" id="BackpressureHandler.check_overload_condition">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.backpressure_handler.BackpressureHandler.check_overload_condition">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">check_overload_condition</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Check if the current_availability availability is too low (OVERLOAD)</span>
<span class="sd"> or if the service has been idle for too long with high availability (IDLE).</span>
<span class="sd"> Note: current_availability represents available capacity, not used capacity.</span>
<span class="sd"> - Low availability (close to 0) means OVERLOAD</span>
<span class="sd"> - High availability (close to maximum) with no activity means IDLE</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">current_time</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span>
<span class="n">last_event_delta</span><span class="p">:</span> <span class="nb">float</span> <span class="o">=</span> <span class="n">current_time</span> <span class="o">-</span> <span class="bp">self</span><span class="o">.</span><span class="n">last_backpressure_event_time</span>
<span class="c1"># logging_info(</span>
<span class="c1"># &quot;Backpressure: Check conditions, current_availability=%s, max=%s, last_activity=%s&quot;,</span>
<span class="c1"># self.current_availability,</span>
<span class="c1"># self.max_availability,</span>
<span class="c1"># last_event_delta,</span>
<span class="c1"># )</span>
<span class="c1"># Check for OVERLOAD condition - low availability (less than 20% of maximum)</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">current_availability</span> <span class="o">&lt;=</span> <span class="nb">round</span><span class="p">(</span><span class="mf">0.1</span> <span class="o">*</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_availability</span><span class="p">):</span>
<span class="c1"># Check if the last backpressure event was not an overload</span>
<span class="k">if</span> <span class="p">(</span>
<span class="bp">self</span><span class="o">.</span><span class="n">last_backpressure_event</span> <span class="o">!=</span> <span class="n">ScalingRequestAlert</span><span class="o">.</span><span class="n">OVERLOAD</span>
<span class="ow">or</span> <span class="n">last_event_delta</span> <span class="o">&gt;</span> <span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">backpressure</span><span class="o">.</span><span class="n">idle_duration</span>
<span class="p">):</span>
<span class="c1"># Trigger the overload event</span>
<span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">handle_backpressure_overload_event</span><span class="p">()</span>
<span class="c1"># update / reset time-window so that the OVERLOAD is not sent too often</span>
<span class="bp">self</span><span class="o">.</span><span class="n">last_backpressure_event_time</span> <span class="o">=</span> <span class="n">current_time</span>
<span class="bp">self</span><span class="o">.</span><span class="n">last_backpressure_event</span> <span class="o">=</span> <span class="n">ScalingRequestAlert</span><span class="o">.</span><span class="n">OVERLOAD</span>
<span class="c1"># Check for IDLE condition - high availability (more than 80% of maximum) with no activity</span>
<span class="k">elif</span> <span class="bp">self</span><span class="o">.</span><span class="n">current_availability</span> <span class="o">&gt;=</span> <span class="nb">round</span><span class="p">(</span><span class="mf">0.8</span> <span class="o">*</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_availability</span><span class="p">):</span>
<span class="n">idle_duration</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">backpressure</span><span class="o">.</span><span class="n">idle_duration</span>
<span class="c1"># Check if service has been idle for longer than the configured duration</span>
<span class="k">if</span> <span class="p">(</span>
<span class="n">current_time</span> <span class="o">-</span> <span class="bp">self</span><span class="o">.</span><span class="n">idle_state_detected_time</span> <span class="o">&gt;</span> <span class="n">idle_duration</span>
<span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">last_backpressure_event</span> <span class="o">==</span> <span class="n">ScalingRequestAlert</span><span class="o">.</span><span class="n">IDLE</span>
<span class="p">):</span>
<span class="n">logging_info</span><span class="p">(</span>
<span class="s2">&quot;Backpressure: Service has been idle for </span><span class="si">%s</span><span class="s2"> seconds (threshold: </span><span class="si">%s</span><span class="s2"> seconds)&quot;</span><span class="p">,</span>
<span class="n">last_event_delta</span><span class="p">,</span>
<span class="n">idle_duration</span><span class="p">,</span>
<span class="p">)</span>
<span class="c1"># Trigger the idle event</span>
<span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">_handle_backpressure_idle_event</span><span class="p">()</span>
<span class="c1"># update / reset time-window so that the IDLE is not sent too often</span>
<span class="bp">self</span><span class="o">.</span><span class="n">last_backpressure_event_time</span> <span class="o">=</span> <span class="n">current_time</span>
<span class="bp">self</span><span class="o">.</span><span class="n">idle_state_detected_time</span> <span class="o">=</span> <span class="n">current_time</span>
<span class="c1"># send IDLE even only once</span>
<span class="bp">self</span><span class="o">.</span><span class="n">last_backpressure_event</span> <span class="o">=</span> <span class="n">ScalingRequestAlert</span><span class="o">.</span><span class="n">UPDATE</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># Don&#39;t send IDLE right away when the availability increases, but wait for a while, send UPDATE instead</span>
<span class="bp">self</span><span class="o">.</span><span class="n">last_backpressure_event</span> <span class="o">=</span> <span class="n">ScalingRequestAlert</span><span class="o">.</span><span class="n">IDLE</span>
<span class="k">if</span> <span class="n">current_time</span> <span class="o">-</span> <span class="bp">self</span><span class="o">.</span><span class="n">idle_state_detected_time</span> <span class="o">&gt;</span> <span class="n">idle_duration</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">idle_state_detected_time</span> <span class="o">=</span> <span class="n">current_time</span>
<span class="k">if</span> <span class="n">last_event_delta</span> <span class="o">&gt;</span> <span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">backpressure</span><span class="o">.</span><span class="n">time_window</span><span class="p">:</span>
<span class="n">_scaling_request</span><span class="p">:</span> <span class="n">ScaleRequestV1</span> <span class="o">=</span> <span class="n">ScaleRequestV1</span><span class="p">(</span>
<span class="bp">self</span><span class="o">.</span><span class="n">swarm_service_id</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">swarm_task_id</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">max_availability</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">current_availability</span><span class="p">,</span> <span class="c1"># Current availability is passed directly</span>
<span class="n">ScalingRequestAlert</span><span class="o">.</span><span class="n">UPDATE</span><span class="p">,</span>
<span class="p">)</span>
<span class="c1"># Address the message to any adapter capable of supporting BACKPRESSURE request</span>
<span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">publish_backpressure_request</span><span class="p">(</span><span class="n">_scaling_request</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">last_backpressure_event_time</span> <span class="o">=</span> <span class="n">current_time</span>
<span class="c1"># If neither OVERLOAD nor IDLE, and it&#39;s time for an update, send UPDATE event</span>
<span class="k">elif</span> <span class="n">last_event_delta</span> <span class="o">&gt;</span> <span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">backpressure</span><span class="o">.</span><span class="n">time_window</span><span class="p">:</span>
<span class="n">_scaling_request</span><span class="p">:</span> <span class="n">ScaleRequestV1</span> <span class="o">=</span> <span class="n">ScaleRequestV1</span><span class="p">(</span>
<span class="bp">self</span><span class="o">.</span><span class="n">swarm_service_id</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">swarm_task_id</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">max_availability</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">current_availability</span><span class="p">,</span> <span class="c1"># Current availability is passed directly</span>
<span class="n">ScalingRequestAlert</span><span class="o">.</span><span class="n">UPDATE</span><span class="p">,</span>
<span class="p">)</span>
<span class="c1"># Address the message to any adapter capable of supporting BACKPRESSURE request</span>
<span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">publish_backpressure_request</span><span class="p">(</span><span class="n">_scaling_request</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">last_backpressure_event_time</span> <span class="o">=</span> <span class="n">current_time</span>
<span class="bp">self</span><span class="o">.</span><span class="n">last_backpressure_event</span> <span class="o">=</span> <span class="n">ScalingRequestAlert</span><span class="o">.</span><span class="n">UPDATE</span></div>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_backpressure_monitor</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Periodically monitor the backpressure conditions and trigger events accordingly&quot;&quot;&quot;</span>
<span class="n">_monitor_interval</span> <span class="o">=</span> <span class="mf">0.5</span> <span class="c1"># Monitor every 500ms</span>
<span class="k">while</span> <span class="bp">self</span><span class="o">.</span><span class="n">_do_loop</span><span class="p">():</span>
<span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">check_overload_condition</span><span class="p">()</span>
<span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="n">_monitor_interval</span><span class="p">)</span>
<div class="viewcode-block" id="BackpressureHandler.backpressure_monitor_loop">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.backpressure_handler.BackpressureHandler.backpressure_monitor_loop">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">backpressure_monitor_loop</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">_loop</span> <span class="o">=</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">new_event_loop</span><span class="p">()</span>
<span class="n">_loop</span><span class="o">.</span><span class="n">run_until_complete</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_backpressure_monitor</span><span class="p">())</span></div>
<div class="viewcode-block" id="BackpressureHandler.handle_backpressure_overload_event">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.backpressure_handler.BackpressureHandler.handle_backpressure_overload_event">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">handle_backpressure_overload_event</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">logging_warning</span><span class="p">(</span><span class="s2">&quot;Backpressure: Capacity close to depleted!&quot;</span><span class="p">)</span>
<span class="c1"># Send an Overload event to the Management service</span>
<span class="n">scaling_request</span><span class="p">:</span> <span class="n">ScaleRequestV1</span> <span class="o">=</span> <span class="n">ScaleRequestV1</span><span class="p">(</span>
<span class="bp">self</span><span class="o">.</span><span class="n">swarm_service_id</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">swarm_task_id</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">max_availability</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">current_availability</span><span class="p">,</span> <span class="c1"># Current availability is passed directly</span>
<span class="n">ScalingRequestAlert</span><span class="o">.</span><span class="n">OVERLOAD</span><span class="p">,</span>
<span class="p">)</span>
<span class="c1"># Address the message to any management service instance capable of supporting BACKPRESSURE request</span>
<span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">publish_backpressure_request</span><span class="p">(</span><span class="n">scaling_request</span><span class="p">)</span></div>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_handle_backpressure_idle_event</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">logging_warning</span><span class="p">(</span><span class="s2">&quot;Backpressure: Service is idle.&quot;</span><span class="p">)</span>
<span class="c1"># Send an Idle event to the Management service</span>
<span class="n">scaling_request</span><span class="p">:</span> <span class="n">ScaleRequestV1</span> <span class="o">=</span> <span class="n">ScaleRequestV1</span><span class="p">(</span>
<span class="bp">self</span><span class="o">.</span><span class="n">swarm_service_id</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">swarm_task_id</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">max_availability</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">current_availability</span><span class="p">,</span> <span class="c1"># Current availability is passed directly</span>
<span class="n">ScalingRequestAlert</span><span class="o">.</span><span class="n">IDLE</span><span class="p">,</span>
<span class="p">)</span>
<span class="c1"># Address the message to any adapter capable of supporting BACKPRESSURE request</span>
<span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">publish_backpressure_request</span><span class="p">(</span><span class="n">scaling_request</span><span class="p">)</span>
<div class="viewcode-block" id="BackpressureHandler.publish_backpressure_request">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.backpressure_handler.BackpressureHandler.publish_backpressure_request">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">publish_backpressure_request</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">scaling_request</span><span class="p">:</span> <span class="n">ScaleRequestV1</span><span class="p">):</span>
<span class="c1"># Publish the backpressure request to the management service</span>
<span class="n">logging_info</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;Publishing backpressure for </span><span class="si">{</span><span class="n">scaling_request</span><span class="o">.</span><span class="n">serviceId</span><span class="si">}</span><span class="s2"> with request type </span><span class="si">{</span><span class="n">scaling_request</span><span class="o">.</span><span class="n">requestType</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">exchange</span><span class="p">:</span>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_wrap_rabbit_mq_api_init</span><span class="p">(</span><span class="n">channel</span><span class="p">):</span>
<span class="n">_exchange</span> <span class="o">=</span> <span class="k">await</span> <span class="n">channel</span><span class="o">.</span><span class="n">get_exchange</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&quot;cleverthis.clevermicro.management&quot;</span><span class="p">)</span>
<span class="k">return</span> <span class="n">_exchange</span>
<span class="k">if</span> <span class="n">BackpressureHandler</span><span class="o">.</span><span class="n">_callback_list</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">BackpressureHandler</span><span class="o">.</span><span class="n">_callback_list</span><span class="p">[</span><span class="s2">&quot;_wrap_rabbit_mq_api_init&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span>
<span class="bp">self</span><span class="o">.</span><span class="n">exchange</span> <span class="o">=</span> <span class="k">await</span> <span class="n">await_result</span><span class="p">(</span>
<span class="n">asyncio</span><span class="o">.</span><span class="n">run_coroutine_threadsafe</span><span class="p">(</span><span class="n">_wrap_rabbit_mq_api_init</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">channel</span><span class="p">),</span> <span class="bp">self</span><span class="o">.</span><span class="n">loop</span><span class="p">)</span>
<span class="p">)</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">exchange</span><span class="p">:</span>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_wrap_rabbit_mq_api</span><span class="p">():</span>
<span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">channel</span><span class="o">.</span><span class="n">is_closed</span><span class="p">:</span>
<span class="n">binary_content</span><span class="p">:</span> <span class="nb">bytes</span> <span class="o">=</span> <span class="n">scaling_request</span><span class="o">.</span><span class="n">to_json</span><span class="p">()</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s2">&quot;utf-8&quot;</span><span class="p">)</span>
<span class="n">pika_message</span><span class="p">:</span> <span class="n">Message</span> <span class="o">=</span> <span class="n">Message</span><span class="p">(</span>
<span class="n">body</span><span class="o">=</span><span class="n">binary_content</span><span class="p">,</span>
<span class="n">content_encoding</span><span class="o">=</span><span class="s2">&quot;utf-8&quot;</span><span class="p">,</span>
<span class="n">delivery_mode</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span>
<span class="n">content_type</span><span class="o">=</span><span class="s2">&quot;application/octet-stream&quot;</span><span class="p">,</span>
<span class="n">headers</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
<span class="n">priority</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span>
<span class="n">correlation_id</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">exchange</span><span class="o">.</span><span class="n">publish</span><span class="p">(</span>
<span class="n">message</span><span class="o">=</span><span class="n">pika_message</span><span class="p">,</span> <span class="n">routing_key</span><span class="o">=</span><span class="s2">&quot;backpressure-scaling-v1&quot;</span>
<span class="p">)</span>
<span class="n">logging_info</span><span class="p">(</span>
<span class="s2">&quot;Service Message Published to </span><span class="si">%s</span><span class="s2">, msg: </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">exchange</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
<span class="nb">str</span><span class="p">(</span><span class="n">binary_content</span><span class="p">),</span>
<span class="p">)</span>
<span class="k">return</span> <span class="kc">True</span>
<span class="k">return</span> <span class="kc">False</span>
<span class="k">if</span> <span class="n">BackpressureHandler</span><span class="o">.</span><span class="n">_callback_list</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">BackpressureHandler</span><span class="o">.</span><span class="n">_callback_list</span><span class="p">[</span><span class="s2">&quot;_wrap_rabbit_mq_api&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span>
<span class="k">await</span> <span class="n">await_future</span><span class="p">(</span><span class="n">asyncio</span><span class="o">.</span><span class="n">run_coroutine_threadsafe</span><span class="p">(</span><span class="n">_wrap_rabbit_mq_api</span><span class="p">(),</span> <span class="bp">self</span><span class="o">.</span><span class="n">loop</span><span class="p">))</span></div>
<span class="k">def</span><span class="w"> </span><span class="nf">_do_loop</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Helper function for unit tests to perform several loops only. Check if the loop should continue running.</span>
<span class="sd"> Positive value of do_loop indicates the number of iterations left.</span>
<span class="sd"> Negative value indicates the loop should run indefinitely.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">_val</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">do_loop</span> <span class="o">!=</span> <span class="mi">0</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">do_loop</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">do_loop</span> <span class="o">-=</span> <span class="mi">1</span>
<span class="k">return</span> <span class="n">_val</span></div>
</pre></div>
</div>
</div>
<footer>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2024, CleverThis.</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>
@@ -0,0 +1,948 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" data-content_root="../../../">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>amqp.adapter.cleverthis_service_adapter &mdash; AMQ Adapter Python 1.0 documentation</title>
<link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=03e43079" />
<link rel="stylesheet" type="text/css" href="../../../_static/css/theme.css?v=e59714d7" />
<script src="../../../_static/jquery.js?v=5d32c60e"></script>
<script src="../../../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
<script src="../../../_static/documentation_options.js?v=f2a433a1"></script>
<script src="../../../_static/doctools.js?v=9bcbadda"></script>
<script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
<script src="../../../_static/js/theme.js"></script>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="../../../index.html" class="icon icon-home">
AMQ Adapter Python
</a>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" aria-label="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.html">AMQP Package</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.config.html">Configuration Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.adapter.html">Adapter Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.service.html">Service Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.router.html">Router Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.model.html">Model Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.rabbitmq.html">RabbitMQ Module</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="../../../index.html">AMQ Adapter Python</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="../../../index.html" class="icon icon-home" aria-label="Home"></a></li>
<li class="breadcrumb-item"><a href="../../index.html">Module code</a></li>
<li class="breadcrumb-item active">amqp.adapter.cleverthis_service_adapter</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<h1>Source code for amqp.adapter.cleverthis_service_adapter</h1><div class="highlight"><pre>
<span></span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">The layer that interfaces with the CleverThis service that this Adapter is integrating with.</span>
<span class="sd">Methods here will invoke the actual CleverThis Service code, which are passed as Callable object.</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">asyncio</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">enum</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">inspect</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">json</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">pathlib</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">re</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">asyncio</span><span class="w"> </span><span class="kn">import</span> <span class="n">AbstractEventLoop</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">collections</span><span class="w"> </span><span class="kn">import</span> <span class="n">defaultdict</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Any</span><span class="p">,</span> <span class="n">Callable</span><span class="p">,</span> <span class="n">Coroutine</span><span class="p">,</span> <span class="n">Dict</span><span class="p">,</span> <span class="n">List</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">aio_pika.abc</span><span class="w"> </span><span class="kn">import</span> <span class="p">(</span>
<span class="n">AbstractExchange</span><span class="p">,</span>
<span class="n">AbstractRobustChannel</span><span class="p">,</span>
<span class="n">AbstractRobustConnection</span><span class="p">,</span>
<span class="p">)</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">aiohttp</span><span class="w"> </span><span class="kn">import</span> <span class="n">ClientResponse</span><span class="p">,</span> <span class="n">ClientSession</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">fastapi</span><span class="w"> </span><span class="kn">import</span> <span class="n">HTTPException</span><span class="p">,</span> <span class="n">UploadFile</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">fastapi.params</span><span class="w"> </span><span class="kn">import</span> <span class="n">File</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">fastapi.routing</span><span class="w"> </span><span class="kn">import</span> <span class="n">APIRoute</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">fastapi.security</span><span class="w"> </span><span class="kn">import</span> <span class="n">OAuth2PasswordRequestForm</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">pydantic</span><span class="w"> </span><span class="kn">import</span> <span class="n">BaseModel</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">starlette.datastructures</span><span class="w"> </span><span class="kn">import</span> <span class="n">Headers</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">starlette.responses</span><span class="w"> </span><span class="kn">import</span> <span class="n">FileResponse</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.adapter</span><span class="w"> </span><span class="kn">import</span> <span class="n">serializer</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.adapter.data_parser</span><span class="w"> </span><span class="kn">import</span> <span class="n">AMQDataParser</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.adapter.data_response_factory</span><span class="w"> </span><span class="kn">import</span> <span class="n">DataResponseFactory</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.adapter.file_handler</span><span class="w"> </span><span class="kn">import</span> <span class="n">FileHandler</span><span class="p">,</span> <span class="n">StreamingFileHandler</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.adapter.logging_utils</span><span class="w"> </span><span class="kn">import</span> <span class="p">(</span>
<span class="n">logging_debug</span><span class="p">,</span>
<span class="n">logging_error</span><span class="p">,</span>
<span class="n">logging_info</span><span class="p">,</span>
<span class="n">logging_warning</span><span class="p">,</span>
<span class="p">)</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.adapter.pydantic_serializer</span><span class="w"> </span><span class="kn">import</span> <span class="n">python_type_to_json</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.adapter.type_descriptor</span><span class="w"> </span><span class="kn">import</span> <span class="n">TypeDescriptor</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.config.amq_configuration</span><span class="w"> </span><span class="kn">import</span> <span class="n">AMQConfiguration</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.model.model</span><span class="w"> </span><span class="kn">import</span> <span class="n">AMQErrorMessage</span><span class="p">,</span> <span class="n">AMQMessage</span><span class="p">,</span> <span class="n">DataMessage</span><span class="p">,</span> <span class="n">DataResponse</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.router.router_base</span><span class="w"> </span><span class="kn">import</span> <span class="n">AMQ_REPLY_TO_EXCHANGE</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.router.utils</span><span class="w"> </span><span class="kn">import</span> <span class="n">await_result</span>
<span class="n">g_extra_init_data</span><span class="p">:</span> <span class="nb">dict</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">()</span>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_create_reply_exchange_and_queue</span><span class="p">(</span>
<span class="n">connection</span><span class="p">:</span> <span class="n">AbstractRobustConnection</span><span class="p">,</span>
<span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">tuple</span><span class="p">[</span><span class="n">AbstractRobustChannel</span><span class="p">,</span> <span class="n">AbstractExchange</span><span class="p">,</span> <span class="nb">str</span><span class="p">]:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Create objects for reply.</span>
<span class="sd"> Return (channel for reply queue, exchange for reply, reply queue name)</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="c1"># Wrap calls to RabbitMQ API to make it Awaitable, so it can be run thread-safe with</span>
<span class="c1"># correct event loop. This is needed because the RabbitMQ API is not thread-safe and needs</span>
<span class="c1"># to be called in the context of event loop the first RabbitMQ connection was created with.</span>
<span class="n">_channel</span> <span class="o">=</span> <span class="k">await</span> <span class="n">connection</span><span class="o">.</span><span class="n">channel</span><span class="p">()</span>
<span class="n">_exchange_name</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="n">AMQ_REPLY_TO_EXCHANGE</span>
<span class="n">_exchange</span> <span class="o">=</span> <span class="k">await</span> <span class="n">_channel</span><span class="o">.</span><span class="n">get_exchange</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="n">_exchange_name</span><span class="p">,</span> <span class="n">ensure</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">_queue</span> <span class="o">=</span> <span class="k">await</span> <span class="n">_channel</span><span class="o">.</span><span class="n">declare_queue</span><span class="p">(</span><span class="n">exclusive</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span> <span class="c1"># Declare a unique, non-exclusive queue</span>
<span class="n">_queue_name</span> <span class="o">=</span> <span class="n">_queue</span><span class="o">.</span><span class="n">name</span>
<span class="k">await</span> <span class="n">_queue</span><span class="o">.</span><span class="n">bind</span><span class="p">(</span>
<span class="n">exchange</span><span class="o">=</span><span class="n">_exchange_name</span><span class="p">,</span>
<span class="n">routing_key</span><span class="o">=</span><span class="n">_queue_name</span><span class="p">,</span> <span class="c1"># Use queue name as routing key</span>
<span class="p">)</span>
<span class="n">logging_debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Publishing to exchange: </span><span class="si">{</span><span class="n">_exchange_name</span><span class="si">}</span><span class="s2">, q: </span><span class="si">{</span><span class="n">_queue_name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">return</span> <span class="n">_channel</span><span class="p">,</span> <span class="n">_exchange</span><span class="p">,</span> <span class="n">_queue_name</span>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_convert_file_response</span><span class="p">(</span>
<span class="n">obj</span><span class="p">:</span> <span class="n">FileResponse</span><span class="p">,</span>
<span class="n">connection</span><span class="p">:</span> <span class="n">AbstractRobustConnection</span><span class="p">,</span>
<span class="n">file_handler</span><span class="p">:</span> <span class="n">FileHandler</span><span class="p">,</span>
<span class="n">loop</span><span class="p">:</span> <span class="n">AbstractEventLoop</span> <span class="o">|</span> <span class="kc">None</span><span class="p">,</span>
<span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Converts a FileResponse object to a JSON string containing the filename and stream name.</span>
<span class="sd"> The file content itself is transmitted through the named stream (which is implemented as</span>
<span class="sd"> temporary dedicated queue.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="c1"># All calls to RabbitMQ API have to be called threadsafe, because those appear to be attached</span>
<span class="c1"># to parent event loop, and need to execute at that event loop, not the current_availability one</span>
<span class="c1"># allow coroutine to execute. calling _future.result() will block the entire thread</span>
<span class="c1"># and the coroutine will never execute</span>
<span class="n">_channel</span><span class="p">,</span> <span class="n">_exchange</span><span class="p">,</span> <span class="n">_routing_key</span> <span class="o">=</span> <span class="k">await</span> <span class="n">await_result</span><span class="p">(</span>
<span class="n">asyncio</span><span class="o">.</span><span class="n">run_coroutine_threadsafe</span><span class="p">(</span><span class="n">_create_reply_exchange_and_queue</span><span class="p">(</span><span class="n">connection</span><span class="p">),</span> <span class="n">loop</span><span class="p">)</span>
<span class="p">)</span>
<span class="c1"># publish_file also needs RabbitMQ API, ensure the loop is passed as argument</span>
<span class="p">(</span><span class="n">_stream_name</span><span class="p">,</span> <span class="n">_file_size</span><span class="p">)</span> <span class="o">=</span> <span class="k">await</span> <span class="n">file_handler</span><span class="o">.</span><span class="n">publish_file</span><span class="p">(</span>
<span class="n">_exchange</span><span class="p">,</span> <span class="n">obj</span><span class="o">.</span><span class="n">path</span><span class="p">,</span> <span class="n">_routing_key</span><span class="p">,</span> <span class="n">loop</span>
<span class="p">)</span>
<span class="c1"># as above, but luckily this time we don&#39;t need to wait for the result</span>
<span class="n">asyncio</span><span class="o">.</span><span class="n">run_coroutine_threadsafe</span><span class="p">(</span><span class="n">_channel</span><span class="o">.</span><span class="n">close</span><span class="p">(),</span> <span class="n">loop</span><span class="p">)</span>
<span class="k">return</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span>
<span class="p">{</span>
<span class="s2">&quot;files&quot;</span><span class="p">:</span> <span class="p">[</span>
<span class="p">{</span>
<span class="s2">&quot;filename&quot;</span><span class="p">:</span> <span class="n">obj</span><span class="o">.</span><span class="n">filename</span><span class="p">,</span>
<span class="s2">&quot;mediaType&quot;</span><span class="p">:</span> <span class="s2">&quot;application/octet-stream&quot;</span><span class="p">,</span>
<span class="s2">&quot;streamName&quot;</span><span class="p">:</span> <span class="n">_stream_name</span><span class="p">,</span>
<span class="s2">&quot;fileSize&quot;</span><span class="p">:</span> <span class="n">_file_size</span><span class="p">,</span>
<span class="p">}</span>
<span class="p">]</span>
<span class="p">}</span>
<span class="p">)</span>
<div class="viewcode-block" id="is_likely_json">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.cleverthis_service_adapter.is_likely_json">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">is_likely_json</span><span class="p">(</span><span class="n">text</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Quick test to see if should convert the response string to JSON format.&quot;&quot;&quot;</span>
<span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">text</span><span class="p">,</span> <span class="nb">str</span><span class="p">):</span>
<span class="k">return</span> <span class="kc">False</span>
<span class="n">_text</span> <span class="o">=</span> <span class="n">text</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
<span class="k">return</span> <span class="p">(</span><span class="n">_text</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&quot;{&quot;</span><span class="p">)</span> <span class="ow">and</span> <span class="n">_text</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="s2">&quot;}&quot;</span><span class="p">))</span> <span class="ow">or</span> <span class="p">(</span>
<span class="n">_text</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&quot;[&quot;</span><span class="p">)</span> <span class="ow">and</span> <span class="n">_text</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="s2">&quot;]&quot;</span><span class="p">)</span>
<span class="p">)</span></div>
<span class="c1"># ============= CleverThisServiceAdapter =============</span>
<div class="viewcode-block" id="CleverThisServiceAdapter">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.cleverthis_service_adapter.CleverThisServiceAdapter">[docs]</a>
<span class="k">class</span><span class="w"> </span><span class="nc">CleverThisServiceAdapter</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> A base class for CleverThis service adapter that handles the incoming AMQP messages and routes</span>
<span class="sd"> them to the appropriate CleverThisService API endpoint.</span>
<span class="sd"> IMPORTANT: This class is not intended to be used directly. It should be subclassed for</span>
<span class="sd"> each CleverThis service and override the methods to handle the specific API calls.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<div class="viewcode-block" id="CleverThisServiceAdapter.__init__">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.cleverthis_service_adapter.CleverThisServiceAdapter.__init__">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span>
<span class="n">amq_configuration</span><span class="p">:</span> <span class="n">AMQConfiguration</span><span class="p">,</span>
<span class="n">routes</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="n">APIRoute</span><span class="p">],</span>
<span class="n">session</span><span class="p">:</span> <span class="n">ClientSession</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
<span class="n">authenticated_user_arg_name</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">&quot;authenticated_user&quot;</span><span class="p">,</span>
<span class="n">extra_init_data</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
<span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Initializes the CleverThisServiceAdapter with the given AMQ configuration and optional HTTP</span>
<span class="sd"> session. The HTTP session is for the case when the adapter uses loose coupling with</span>
<span class="sd"> the CleverThis service via HTTP REST API.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="n">extra_init_data</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">extra_init_data</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">authenticated_user_arg_name</span> <span class="o">=</span> <span class="n">authenticated_user_arg_name</span>
<span class="bp">self</span><span class="o">.</span><span class="n">amq_configuration</span> <span class="o">=</span> <span class="n">amq_configuration</span>
<span class="bp">self</span><span class="o">.</span><span class="n">session</span> <span class="o">=</span> <span class="n">session</span>
<span class="bp">self</span><span class="o">.</span><span class="n">service_host</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">amq_configuration</span><span class="o">.</span><span class="n">dispatch</span><span class="o">.</span><span class="n">service_host</span>
<span class="bp">self</span><span class="o">.</span><span class="n">service_port</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">amq_configuration</span><span class="o">.</span><span class="n">dispatch</span><span class="o">.</span><span class="n">service_port</span>
<span class="bp">self</span><span class="o">.</span><span class="n">loop</span><span class="p">:</span> <span class="n">AbstractEventLoop</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span>
<span class="bp">self</span><span class="o">.</span><span class="n">require_authenticated_user</span> <span class="o">=</span> <span class="p">(</span>
<span class="bp">self</span><span class="o">.</span><span class="n">amq_configuration</span><span class="o">.</span><span class="n">amq_adapter</span><span class="o">.</span><span class="n">require_authenticated_user</span>
<span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">routes</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">group_routes_by_method</span><span class="p">(</span><span class="n">api_routes</span><span class="o">=</span><span class="n">routes</span><span class="p">)</span>
<span class="k">global</span> <span class="n">g_extra_init_data</span>
<span class="n">g_extra_init_data</span> <span class="o">=</span> <span class="n">extra_init_data</span> <span class="ow">or</span> <span class="p">{}</span></div>
<div class="viewcode-block" id="CleverThisServiceAdapter.get_endpoint">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.cleverthis_service_adapter.CleverThisServiceAdapter.get_endpoint">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">get_endpoint</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">endpoint</span><span class="p">:</span> <span class="n">Any</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Any</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Optionally, Service can override this method to alter the endpoint mapping.</span>
<span class="sd"> This is useful for example when the CleverThis service has a JSON wrapper</span>
<span class="sd"> around the endpoint, like CleverSwarm, which might be the preferred endpoint to call.</span>
<span class="sd"> :param endpoint: The original endpoint to be called.</span>
<span class="sd"> :return: The actual endpoint to be called.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="n">endpoint</span></div>
<div class="viewcode-block" id="CleverThisServiceAdapter.clone_and_adapt_route">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.cleverthis_service_adapter.CleverThisServiceAdapter.clone_and_adapt_route">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">clone_and_adapt_route</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">original_route</span><span class="p">:</span> <span class="n">APIRoute</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">APIRoute</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Creates a clone of APIRoute. Checks if there&#39;s preferred endpoint with json serialization.</span>
<span class="sd"> It also adjusts the path regex to ensure it matches the path in different API versions.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="c1"># Need to adapt also the path regex to ensure it matches the path in different API versions</span>
<span class="c1"># Ensures the leading &#39;^&#39; is followed by any match and there&#39;s no &#39;/&#39; before final &#39;$&#39;</span>
<span class="n">_new_regex_string</span> <span class="o">=</span> <span class="s2">&quot;^.*&quot;</span> <span class="o">+</span> <span class="n">original_route</span><span class="o">.</span><span class="n">path_regex</span><span class="o">.</span><span class="n">pattern</span><span class="o">.</span><span class="n">lstrip</span><span class="p">(</span><span class="s2">&quot;^&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">rstrip</span><span class="p">(</span><span class="s2">&quot;/$&quot;</span><span class="p">)</span> <span class="o">+</span> <span class="s2">&quot;$&quot;</span>
<span class="n">_new_route</span><span class="p">:</span> <span class="n">APIRoute</span> <span class="o">=</span> <span class="n">APIRoute</span><span class="p">(</span>
<span class="n">path</span><span class="o">=</span><span class="n">original_route</span><span class="o">.</span><span class="n">path</span><span class="p">,</span>
<span class="n">endpoint</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">get_endpoint</span><span class="p">(</span>
<span class="n">original_route</span><span class="o">.</span><span class="n">endpoint</span>
<span class="p">),</span> <span class="c1"># Service can alter the endpoint mapping here</span>
<span class="n">response_model</span><span class="o">=</span><span class="n">original_route</span><span class="o">.</span><span class="n">response_model</span><span class="p">,</span>
<span class="n">status_code</span><span class="o">=</span><span class="n">original_route</span><span class="o">.</span><span class="n">status_code</span><span class="p">,</span>
<span class="n">tags</span><span class="o">=</span><span class="n">original_route</span><span class="o">.</span><span class="n">tags</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span> <span class="k">if</span> <span class="n">original_route</span><span class="o">.</span><span class="n">tags</span> <span class="k">else</span> <span class="kc">None</span><span class="p">,</span>
<span class="n">dependencies</span><span class="o">=</span><span class="p">(</span>
<span class="n">original_route</span><span class="o">.</span><span class="n">dependencies</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span> <span class="k">if</span> <span class="n">original_route</span><span class="o">.</span><span class="n">dependencies</span> <span class="k">else</span> <span class="kc">None</span>
<span class="p">),</span>
<span class="n">summary</span><span class="o">=</span><span class="n">original_route</span><span class="o">.</span><span class="n">summary</span><span class="p">,</span>
<span class="n">description</span><span class="o">=</span><span class="n">original_route</span><span class="o">.</span><span class="n">description</span><span class="p">,</span>
<span class="n">response_description</span><span class="o">=</span><span class="n">original_route</span><span class="o">.</span><span class="n">response_description</span><span class="p">,</span>
<span class="n">responses</span><span class="o">=</span><span class="p">(</span><span class="n">original_route</span><span class="o">.</span><span class="n">responses</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span> <span class="k">if</span> <span class="n">original_route</span><span class="o">.</span><span class="n">responses</span> <span class="k">else</span> <span class="kc">None</span><span class="p">),</span>
<span class="n">deprecated</span><span class="o">=</span><span class="n">original_route</span><span class="o">.</span><span class="n">deprecated</span><span class="p">,</span>
<span class="n">name</span><span class="o">=</span><span class="n">original_route</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
<span class="n">methods</span><span class="o">=</span><span class="n">original_route</span><span class="o">.</span><span class="n">methods</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span> <span class="k">if</span> <span class="n">original_route</span><span class="o">.</span><span class="n">methods</span> <span class="k">else</span> <span class="kc">None</span><span class="p">,</span>
<span class="n">operation_id</span><span class="o">=</span><span class="n">original_route</span><span class="o">.</span><span class="n">operation_id</span><span class="p">,</span>
<span class="n">response_model_include</span><span class="o">=</span><span class="n">original_route</span><span class="o">.</span><span class="n">response_model_include</span><span class="p">,</span>
<span class="n">response_model_exclude</span><span class="o">=</span><span class="n">original_route</span><span class="o">.</span><span class="n">response_model_exclude</span><span class="p">,</span>
<span class="n">response_model_by_alias</span><span class="o">=</span><span class="n">original_route</span><span class="o">.</span><span class="n">response_model_by_alias</span><span class="p">,</span>
<span class="n">response_model_exclude_unset</span><span class="o">=</span><span class="n">original_route</span><span class="o">.</span><span class="n">response_model_exclude_unset</span><span class="p">,</span>
<span class="n">response_model_exclude_defaults</span><span class="o">=</span><span class="n">original_route</span><span class="o">.</span><span class="n">response_model_exclude_defaults</span><span class="p">,</span>
<span class="n">response_model_exclude_none</span><span class="o">=</span><span class="n">original_route</span><span class="o">.</span><span class="n">response_model_exclude_none</span><span class="p">,</span>
<span class="n">include_in_schema</span><span class="o">=</span><span class="n">original_route</span><span class="o">.</span><span class="n">include_in_schema</span><span class="p">,</span>
<span class="n">response_class</span><span class="o">=</span><span class="n">original_route</span><span class="o">.</span><span class="n">response_class</span><span class="p">,</span>
<span class="n">dependency_overrides_provider</span><span class="o">=</span><span class="n">original_route</span><span class="o">.</span><span class="n">dependency_overrides_provider</span><span class="p">,</span>
<span class="n">callbacks</span><span class="o">=</span><span class="p">(</span><span class="n">original_route</span><span class="o">.</span><span class="n">callbacks</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span> <span class="k">if</span> <span class="n">original_route</span><span class="o">.</span><span class="n">callbacks</span> <span class="k">else</span> <span class="kc">None</span><span class="p">),</span>
<span class="n">openapi_extra</span><span class="o">=</span><span class="p">(</span>
<span class="n">original_route</span><span class="o">.</span><span class="n">openapi_extra</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span> <span class="k">if</span> <span class="n">original_route</span><span class="o">.</span><span class="n">openapi_extra</span> <span class="k">else</span> <span class="kc">None</span>
<span class="p">),</span>
<span class="n">generate_unique_id_function</span><span class="o">=</span><span class="n">original_route</span><span class="o">.</span><span class="n">generate_unique_id_function</span><span class="p">,</span>
<span class="p">)</span>
<span class="n">_new_route</span><span class="o">.</span><span class="n">path_regex</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="n">_new_regex_string</span><span class="p">)</span>
<span class="k">return</span> <span class="n">_new_route</span></div>
<div class="viewcode-block" id="CleverThisServiceAdapter.group_routes_by_method">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.cleverthis_service_adapter.CleverThisServiceAdapter.group_routes_by_method">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">group_routes_by_method</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">api_routes</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="n">APIRoute</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">List</span><span class="p">[</span><span class="n">APIRoute</span><span class="p">]]:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Groups API routes by their HTTP method. This is important to ensure that URLPath is matched</span>
<span class="sd"> correctly, as different methods may share the same URLPath (e.g. GET, POST PUT, DELETE).</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">_method_to_routes</span> <span class="o">=</span> <span class="n">defaultdict</span><span class="p">(</span><span class="nb">list</span><span class="p">)</span> <span class="c1"># Automatically initializes new lists for new keys</span>
<span class="k">for</span> <span class="n">_route</span> <span class="ow">in</span> <span class="n">api_routes</span><span class="p">:</span>
<span class="k">if</span> <span class="p">(</span>
<span class="nb">isinstance</span><span class="p">(</span><span class="n">_route</span><span class="p">,</span> <span class="n">APIRoute</span><span class="p">)</span> <span class="ow">and</span> <span class="n">_route</span><span class="o">.</span><span class="n">methods</span>
<span class="p">):</span> <span class="c1"># Ensure methods exist (should always be true for valid routes)</span>
<span class="k">for</span> <span class="n">method</span> <span class="ow">in</span> <span class="n">_route</span><span class="o">.</span><span class="n">methods</span><span class="p">:</span>
<span class="n">_method_to_routes</span><span class="p">[</span><span class="n">method</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">clone_and_adapt_route</span><span class="p">(</span><span class="n">_route</span><span class="p">))</span>
<span class="k">return</span> <span class="nb">dict</span><span class="p">(</span><span class="n">_method_to_routes</span><span class="p">)</span></div>
<div class="viewcode-block" id="CleverThisServiceAdapter.get_content_type">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.cleverthis_service_adapter.CleverThisServiceAdapter.get_content_type">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">get_content_type</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message_headers</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]])</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Pull the value of the Content-Type header from the message headers.</span>
<span class="sd"> :param message_headers: The headers of the message.</span>
<span class="sd"> return: The content type of the message.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">for</span> <span class="n">header</span><span class="p">,</span> <span class="n">values</span> <span class="ow">in</span> <span class="n">message_headers</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
<span class="k">if</span> <span class="n">header</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="o">==</span> <span class="s2">&quot;content-type&quot;</span><span class="p">:</span>
<span class="k">return</span> <span class="n">values</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;;&quot;</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
<span class="k">return</span> <span class="s2">&quot;application/json&quot;</span></div>
<div class="viewcode-block" id="CleverThisServiceAdapter.get_current_user">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.cleverthis_service_adapter.CleverThisServiceAdapter.get_current_user">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">get_current_user</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">token</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">object</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> To Be Overriden in subclass for given CleverThis Service, to return the current_availability user based</span>
<span class="sd"> on the token, in format appropriate for the service.</span>
<span class="sd"> :param token: The token to be used for authentication.</span>
<span class="sd"> :return: A user object or None if the user is not authenticated.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="kc">None</span></div>
<div class="viewcode-block" id="CleverThisServiceAdapter.on_message">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.cleverthis_service_adapter.CleverThisServiceAdapter.on_message">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">on_message</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">AMQMessage</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">DataResponse</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Called when a message is received from the AMQP.</span>
<span class="sd"> :param message:</span>
<span class="sd"> :return: AMQP response class with operation status code and optional error details.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">_auth_user</span><span class="p">:</span> <span class="n">Any</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">_amq_response</span><span class="p">:</span> <span class="n">Any</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">logging_debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;on_message: require_authenticated_user=</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">require_authenticated_user</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">require_authenticated_user</span><span class="p">:</span>
<span class="n">_auth</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="n">message</span><span class="o">.</span><span class="n">headers</span><span class="p">()</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;Authorization&quot;</span><span class="p">,</span> <span class="s2">&quot;&quot;</span><span class="p">)</span>
<span class="n">logging_debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Auth: </span><span class="si">{</span><span class="n">_auth</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">_auth</span><span class="p">,</span> <span class="n">List</span><span class="p">):</span>
<span class="n">_auth</span> <span class="o">=</span> <span class="n">_auth</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="k">if</span> <span class="s2">&quot;Bearer&quot;</span> <span class="ow">in</span> <span class="n">_auth</span><span class="p">:</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">token</span> <span class="o">=</span> <span class="n">_auth</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot; &quot;</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span>
<span class="n">logging_info</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Token: </span><span class="si">{</span><span class="n">token</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="n">_auth_user</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_current_user</span><span class="p">(</span><span class="n">token</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">error</span><span class="p">:</span>
<span class="n">logging_error</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;on_message: Error getting user: </span><span class="si">{</span><span class="n">error</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="n">_auth_user</span> <span class="ow">or</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">require_authenticated_user</span> <span class="ow">or</span> <span class="n">message</span><span class="o">.</span><span class="n">path</span><span class="p">()</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="s2">&quot;/login&quot;</span><span class="p">):</span>
<span class="n">method</span> <span class="o">=</span> <span class="n">message</span><span class="o">.</span><span class="n">method</span><span class="p">()</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span>
<span class="k">if</span> <span class="n">method</span> <span class="o">==</span> <span class="s2">&quot;get&quot;</span><span class="p">:</span>
<span class="n">_amq_response</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">_auth_user</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">method</span> <span class="o">==</span> <span class="s2">&quot;put&quot;</span><span class="p">:</span>
<span class="n">_amq_response</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">_auth_user</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">method</span> <span class="o">==</span> <span class="s2">&quot;post&quot;</span><span class="p">:</span>
<span class="n">_amq_response</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">_auth_user</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">method</span> <span class="o">==</span> <span class="s2">&quot;head&quot;</span><span class="p">:</span>
<span class="n">_amq_response</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">head</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">_auth_user</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">method</span> <span class="o">==</span> <span class="s2">&quot;delete&quot;</span><span class="p">:</span>
<span class="n">_amq_response</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">delete</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">_auth_user</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Unexpected HTTP method: </span><span class="si">{</span><span class="n">message</span><span class="o">.</span><span class="n">method</span><span class="p">()</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">_amq_response</span> <span class="o">=</span> <span class="n">DataResponseFactory</span><span class="o">.</span><span class="n">of_error_message</span><span class="p">(</span>
<span class="n">message</span><span class="o">.</span><span class="n">id</span><span class="p">(),</span>
<span class="n">AMQErrorMessage</span><span class="p">(</span><span class="mi">401</span><span class="p">,</span> <span class="s2">&quot;Unauthorized&quot;</span><span class="p">,</span> <span class="s2">&quot;Unauthorized&quot;</span><span class="p">),</span>
<span class="n">message</span><span class="o">.</span><span class="n">trace_info</span><span class="p">(),</span>
<span class="p">)</span>
<span class="n">logging_info</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;ALL DONE in on_message id:</span><span class="si">{</span><span class="n">message</span><span class="o">.</span><span class="n">id</span><span class="p">()</span><span class="si">}</span><span class="s2">, resp code:</span><span class="si">{</span><span class="n">_amq_response</span><span class="o">.</span><span class="n">response_code</span><span class="p">()</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="p">)</span>
<span class="k">return</span> <span class="n">_amq_response</span></div>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_authorize_forward_request</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">DataMessage</span><span class="p">,</span> <span class="n">request_coroutine</span><span class="p">,</span> <span class="n">auth_user</span><span class="p">:</span> <span class="n">Any</span>
<span class="p">)</span> <span class="o">-&gt;</span> <span class="n">DataResponse</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> This method is used to authorize the request and forward it to the CleverThis Service API.</span>
<span class="sd"> Used only for loose / 3rd party mode of coupling with the Service</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="c1"># AMQDataParser.parse_request_body(message)</span>
<span class="c1"># TODO: implement authorization logic here - ensure the security related headers are set</span>
<span class="c1"># This depends on what kind of security is required by the CleverThis service.</span>
<span class="c1"># However at this time there is no loosely coupled Service.</span>
<span class="k">return</span> <span class="k">await</span> <span class="n">request_coroutine</span>
<span class="c1"># ==============================================================================================</span>
<span class="c1"># ===================== C l e v e r T h i s A P I m e t h o d s ========================</span>
<span class="c1"># ==============================================================================================</span>
<div class="viewcode-block" id="CleverThisServiceAdapter.get">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.cleverthis_service_adapter.CleverThisServiceAdapter.get">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">get</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">AMQMessage</span><span class="p">,</span> <span class="n">auth_user</span><span class="p">:</span> <span class="n">Any</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">DataResponse</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Handles the GET requests for the CleverThis API. In tight coupling (self.session is None),</span>
<span class="sd"> use path, path params and query string to determine the endpoint method to invoke.</span>
<span class="sd"> In loose coupling (self.session is not None), forward the request as REST request using</span>
<span class="sd"> the session, i.e. attempt to call the REST endpoint directly using HTTP protocol.</span>
<span class="sd"> :param message: message from the AMQP that contains the GET request</span>
<span class="sd"> :param auth_user: user authenticated by the API Gateway, as UserSchem</span>
<span class="sd"> :return: DataResponse to be sent back to the API Gateway via AMQP</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">session</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">return</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">handle_no_body_payload</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">auth_user</span><span class="p">,</span> <span class="s2">&quot;GET&quot;</span><span class="p">)</span>
<span class="c1"># Forwards as REST - try to invoke the service directly on this path</span>
<span class="n">url</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;http://</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">service_host</span><span class="si">}</span><span class="s2">:</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">service_port</span><span class="si">}{</span><span class="n">message</span><span class="o">.</span><span class="n">path</span><span class="p">()</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="n">headers</span> <span class="o">=</span> <span class="p">{</span><span class="o">**</span><span class="n">message</span><span class="o">.</span><span class="n">headers</span><span class="p">(),</span> <span class="o">**</span><span class="n">message</span><span class="o">.</span><span class="n">trace_info</span><span class="p">()}</span>
<span class="n">logging_info</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;SEND HEADERS out: </span><span class="si">{</span><span class="s1">&#39;, &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="sa">f</span><span class="s1">&#39;</span><span class="si">{</span><span class="n">k</span><span class="si">}</span><span class="s1">=</span><span class="si">{</span><span class="n">v</span><span class="si">}</span><span class="s1">&#39;</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">k</span><span class="p">,</span><span class="w"> </span><span class="n">v</span><span class="w"> </span><span class="ow">in</span><span class="w"> </span><span class="n">headers</span><span class="o">.</span><span class="n">items</span><span class="p">())</span><span class="si">}</span><span class="s2">, REQ=</span><span class="si">{</span><span class="n">url</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="p">)</span>
<span class="n">_http_resp</span><span class="p">:</span> <span class="n">ClientResponse</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">session</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="n">headers</span><span class="o">=</span><span class="n">headers</span><span class="p">)</span>
<span class="k">return</span> <span class="n">DataResponseFactory</span><span class="o">.</span><span class="n">of</span><span class="p">(</span>
<span class="n">message</span><span class="o">.</span><span class="n">id</span><span class="p">(),</span>
<span class="n">_http_resp</span><span class="o">.</span><span class="n">status</span><span class="p">,</span>
<span class="n">_http_resp</span><span class="o">.</span><span class="n">content_type</span><span class="p">,</span>
<span class="k">await</span> <span class="n">_http_resp</span><span class="o">.</span><span class="n">read</span><span class="p">(),</span>
<span class="n">message</span><span class="o">.</span><span class="n">trace_info</span><span class="p">(),</span>
<span class="p">)</span></div>
<div class="viewcode-block" id="CleverThisServiceAdapter.put">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.cleverthis_service_adapter.CleverThisServiceAdapter.put">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">put</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">AMQMessage</span><span class="p">,</span> <span class="n">auth_user</span><span class="p">:</span> <span class="n">Any</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">DataResponse</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Handles the PUT requests for the CleverThis API. Uses path, path params, query string and</span>
<span class="sd"> body payload to determine the endpoint method to invoke and its input arguments</span>
<span class="sd"> In loose coupling (self.session is not None), attempt to call the REST endpoint directly</span>
<span class="sd"> using HTTP protocol.</span>
<span class="sd"> :param message: message from the AMQP that contains the PUT request</span>
<span class="sd"> :param auth_user: user authenticated by the API Gateway, as UserSchem</span>
<span class="sd"> :return: DataResponse to be sent back to the API Gateway via AMQP</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">session</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">return</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">handle_body_payload</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">auth_user</span><span class="p">,</span> <span class="s2">&quot;PUT&quot;</span><span class="p">)</span>
<span class="c1"># Forwards as REST - try to invoke the service directly on this path</span>
<span class="k">return</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">_authorize_forward_request</span><span class="p">(</span>
<span class="n">message</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">session</span><span class="o">.</span><span class="n">put</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;http://</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">service_host</span><span class="si">}</span><span class="s2">:</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">service_port</span><span class="si">}{</span><span class="n">message</span><span class="o">.</span><span class="n">path</span><span class="p">()</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">,</span>
<span class="n">data</span><span class="o">=</span><span class="n">message</span><span class="o">.</span><span class="n">body</span><span class="p">(),</span>
<span class="n">headers</span><span class="o">=</span><span class="p">{</span><span class="o">**</span><span class="n">message</span><span class="o">.</span><span class="n">headers</span><span class="p">(),</span> <span class="o">**</span><span class="n">message</span><span class="o">.</span><span class="n">trace_info</span><span class="p">()},</span>
<span class="p">),</span>
<span class="n">auth_user</span><span class="p">,</span>
<span class="p">)</span></div>
<div class="viewcode-block" id="CleverThisServiceAdapter.post">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.cleverthis_service_adapter.CleverThisServiceAdapter.post">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">post</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">AMQMessage</span><span class="p">,</span> <span class="n">auth_user</span><span class="p">:</span> <span class="n">Any</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">DataResponse</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Handles the POST requests for the CleverThis API. Uses path, path params, query string and</span>
<span class="sd"> body payload to determine the endpoint method to invoke and its input arguments</span>
<span class="sd"> In loose coupling (self.session is not None), attempt to call the REST endpoint directly</span>
<span class="sd"> using HTTP protocol.</span>
<span class="sd"> :param message: message from AMQP that contains the POST request, including body and headers</span>
<span class="sd"> :param auth_user: user authenticated by the API Gateway, as UserSchem</span>
<span class="sd"> :return: DataResponse to be sent back to the API Gateway via AMQP</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">session</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">return</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">handle_body_payload</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">auth_user</span><span class="p">,</span> <span class="s2">&quot;POST&quot;</span><span class="p">)</span>
<span class="k">return</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">_authorize_forward_request</span><span class="p">(</span>
<span class="n">message</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">session</span><span class="o">.</span><span class="n">post</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;http://</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">service_host</span><span class="si">}</span><span class="s2">:</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">service_port</span><span class="si">}{</span><span class="n">message</span><span class="o">.</span><span class="n">path</span><span class="p">()</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">,</span>
<span class="n">data</span><span class="o">=</span><span class="n">message</span><span class="o">.</span><span class="n">body</span><span class="p">(),</span>
<span class="n">headers</span><span class="o">=</span><span class="p">{</span><span class="o">**</span><span class="n">message</span><span class="o">.</span><span class="n">headers</span><span class="p">(),</span> <span class="o">**</span><span class="n">message</span><span class="o">.</span><span class="n">trace_info</span><span class="p">()},</span>
<span class="p">),</span>
<span class="n">auth_user</span><span class="p">,</span>
<span class="p">)</span></div>
<div class="viewcode-block" id="CleverThisServiceAdapter.head">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.cleverthis_service_adapter.CleverThisServiceAdapter.head">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">head</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">AMQMessage</span><span class="p">,</span> <span class="n">auth_user</span><span class="p">:</span> <span class="n">Any</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">DataResponse</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Handles the HEAD requests for the CleverThis API. In tight coupling (self.session is None),</span>
<span class="sd"> use path, path params and query string to determine the endpoint method to invoke.</span>
<span class="sd"> In loose coupling (self.session is not None), HEAD call is not supported.</span>
<span class="sd"> :param message: message from AMQP containing the HEAD request, including body and headers</span>
<span class="sd"> :param auth_user: user authenticated by the API Gateway, as UserSchema</span>
<span class="sd"> :return: DataResponse to be sent back to the API Gateway via AMQP</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">session</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">return</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">handle_no_body_payload</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">auth_user</span><span class="p">,</span> <span class="s2">&quot;HEAD&quot;</span><span class="p">)</span>
<span class="k">raise</span> <span class="ne">NotImplementedError</span></div>
<div class="viewcode-block" id="CleverThisServiceAdapter.delete">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.cleverthis_service_adapter.CleverThisServiceAdapter.delete">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">delete</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">AMQMessage</span><span class="p">,</span> <span class="n">auth_user</span><span class="p">:</span> <span class="n">Any</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">DataResponse</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Handles the DELETE requests for the CleverThis API.</span>
<span class="sd"> :param message: message from AMQP that contains the DELETE request, including body &amp; headers</span>
<span class="sd"> :param auth_user: user authenticated by the API Gateway, as UserSchema</span>
<span class="sd"> :return: DataResponse to be sent back to the API Gateway via AMQP</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">session</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">return</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">handle_no_body_payload</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">auth_user</span><span class="p">,</span> <span class="s2">&quot;DELETE&quot;</span><span class="p">)</span>
<span class="k">return</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">_authorize_forward_request</span><span class="p">(</span>
<span class="n">message</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">session</span><span class="o">.</span><span class="n">post</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;http://</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">service_host</span><span class="si">}</span><span class="s2">:</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">service_port</span><span class="si">}{</span><span class="n">message</span><span class="o">.</span><span class="n">path</span><span class="p">()</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">,</span>
<span class="n">data</span><span class="o">=</span><span class="n">message</span><span class="o">.</span><span class="n">body</span><span class="p">(),</span>
<span class="n">headers</span><span class="o">=</span><span class="p">{</span><span class="o">**</span><span class="n">message</span><span class="o">.</span><span class="n">headers</span><span class="p">(),</span> <span class="o">**</span><span class="n">message</span><span class="o">.</span><span class="n">trace_info</span><span class="p">()},</span>
<span class="p">),</span>
<span class="n">auth_user</span><span class="p">,</span>
<span class="p">)</span></div>
<div class="viewcode-block" id="CleverThisServiceAdapter.options">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.cleverthis_service_adapter.CleverThisServiceAdapter.options">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">options</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">AMQMessage</span><span class="p">,</span> <span class="n">auth_user</span><span class="p">:</span> <span class="n">Any</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">DataResponse</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Handles the OPTIONS requests. In tight coupling (self.session is None),</span>
<span class="sd"> use path, path params and query string to determine the endpoint method to invoke.</span>
<span class="sd"> In loose coupling (self.session is not None), forward the request as REST request using</span>
<span class="sd"> the session, i.e. attempt to call the REST endpoint directly using HTTP protocol.</span>
<span class="sd"> :param message: message from AMQP that contains the OPTIONS request, including headers</span>
<span class="sd"> :param auth_user: user authenticated by the API Gateway, as UserSchema</span>
<span class="sd"> :return: DataResponse to be sent back to the API Gateway via AMQP</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">session</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">return</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">handle_no_body_payload</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">auth_user</span><span class="p">,</span> <span class="s2">&quot;OPTIONS&quot;</span><span class="p">)</span>
<span class="k">raise</span> <span class="ne">NotImplementedError</span></div>
<div class="viewcode-block" id="CleverThisServiceAdapter.patch">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.cleverthis_service_adapter.CleverThisServiceAdapter.patch">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">patch</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">AMQMessage</span><span class="p">,</span> <span class="n">auth_user</span><span class="p">:</span> <span class="n">Any</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">DataResponse</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Handles the PATCH requests for the CleverBRAG API.</span>
<span class="sd"> :param message: message from AMQP that contains the PATCH request, including body &amp; headers</span>
<span class="sd"> :param auth_user: user authenticated by the API Gateway, as UserSchema</span>
<span class="sd"> :return: DataResponse to be sent back to the API Gateway via AMQP</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">session</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">return</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">handle_no_body_payload</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">auth_user</span><span class="p">,</span> <span class="s2">&quot;PATCH&quot;</span><span class="p">)</span>
<span class="k">return</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">_authorize_forward_request</span><span class="p">(</span>
<span class="n">message</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">session</span><span class="o">.</span><span class="n">post</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;http://</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">service_host</span><span class="si">}</span><span class="s2">:</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">service_port</span><span class="si">}{</span><span class="n">message</span><span class="o">.</span><span class="n">path</span><span class="p">()</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">,</span>
<span class="n">data</span><span class="o">=</span><span class="n">message</span><span class="o">.</span><span class="n">body</span><span class="p">(),</span>
<span class="n">headers</span><span class="o">=</span><span class="p">{</span><span class="o">**</span><span class="n">message</span><span class="o">.</span><span class="n">headers</span><span class="p">(),</span> <span class="o">**</span><span class="n">message</span><span class="o">.</span><span class="n">trace_info</span><span class="p">()},</span>
<span class="p">),</span>
<span class="n">auth_user</span><span class="p">,</span>
<span class="p">)</span></div>
<span class="c1"># ==============================================================================================</span>
<span class="c1"># ================= C l e v e r S w a r m p a y l o a d h a n d l e r s ==================</span>
<span class="c1"># ==============================================================================================</span>
<div class="viewcode-block" id="CleverThisServiceAdapter.handle_no_body_payload">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.cleverthis_service_adapter.CleverThisServiceAdapter.handle_no_body_payload">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">handle_no_body_payload</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">AMQMessage</span><span class="p">,</span> <span class="n">auth_user</span><span class="p">:</span> <span class="n">Any</span><span class="p">,</span> <span class="n">method</span><span class="p">:</span> <span class="nb">str</span>
<span class="p">)</span> <span class="o">-&gt;</span> <span class="n">DataResponse</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Handles the requests that do not have a body payload.</span>
<span class="sd"> :param message: message from the AMQP that contains the request</span>
<span class="sd"> :param auth_user: user authenticated by the API Gateway, as UserSchem</span>
<span class="sd"> :return: DataResponse to be sent back to the API Gateway via AMQP</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">_routes</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">routes</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">method</span><span class="p">,</span> <span class="p">[])</span>
<span class="n">_path</span><span class="p">,</span> <span class="n">_args</span> <span class="o">=</span> <span class="n">AMQDataParser</span><span class="o">.</span><span class="n">parse_get_url</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">path</span><span class="p">())</span>
<span class="k">for</span> <span class="n">_route</span> <span class="ow">in</span> <span class="n">_routes</span><span class="p">:</span>
<span class="c1"># TODO: here the regex will match with path prefix,</span>
<span class="c1"># but it might not be a stable feature that we could rely on.</span>
<span class="c1"># Need to figure out something stable for the prefix path.</span>
<span class="n">_match</span> <span class="o">=</span> <span class="n">_route</span><span class="o">.</span><span class="n">path_regex</span><span class="o">.</span><span class="n">match</span><span class="p">(</span><span class="n">_path</span><span class="p">)</span>
<span class="k">if</span> <span class="n">_match</span><span class="p">:</span>
<span class="n">_args</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">_match</span><span class="o">.</span><span class="n">groupdict</span><span class="p">())</span>
<span class="n">_signature_args</span> <span class="o">=</span> <span class="n">inspect</span><span class="o">.</span><span class="n">signature</span><span class="p">(</span><span class="n">_route</span><span class="o">.</span><span class="n">endpoint</span><span class="p">)</span><span class="o">.</span><span class="n">parameters</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">authenticated_user_arg_name</span> <span class="ow">in</span> <span class="n">_signature_args</span><span class="o">.</span><span class="n">keys</span><span class="p">():</span>
<span class="n">_args</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">authenticated_user_arg_name</span><span class="p">]</span> <span class="o">=</span> <span class="n">auth_user</span>
<span class="c1"># If the path matches, call the corresponding function</span>
<span class="k">return</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">call_cleverthis_api</span><span class="p">(</span>
<span class="n">message</span><span class="p">,</span>
<span class="n">_args</span><span class="p">,</span>
<span class="n">api_method</span><span class="o">=</span><span class="n">_route</span><span class="o">.</span><span class="n">endpoint</span><span class="p">,</span>
<span class="n">success_code</span><span class="o">=</span><span class="n">_route</span><span class="o">.</span><span class="n">status_code</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">return</span> <span class="n">DataResponseFactory</span><span class="o">.</span><span class="n">of</span><span class="p">(</span>
<span class="n">message</span><span class="o">.</span><span class="n">id</span><span class="p">(),</span>
<span class="mi">404</span><span class="p">,</span>
<span class="s2">&quot;text/plain&quot;</span><span class="p">,</span>
<span class="nb">str</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Destination location [</span><span class="si">{</span><span class="n">message</span><span class="o">.</span><span class="n">path</span><span class="p">()</span><span class="si">}</span><span class="s2">] does not exists&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s2">&quot;utf-8&quot;</span><span class="p">),</span>
<span class="n">message</span><span class="o">.</span><span class="n">trace_info</span><span class="p">(),</span>
<span class="p">)</span></div>
<div class="viewcode-block" id="CleverThisServiceAdapter.handle_body_payload">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.cleverthis_service_adapter.CleverThisServiceAdapter.handle_body_payload">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">handle_body_payload</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">AMQMessage</span><span class="p">,</span> <span class="n">auth_user</span><span class="p">:</span> <span class="n">Any</span><span class="p">,</span> <span class="n">method</span><span class="p">:</span> <span class="nb">str</span>
<span class="p">)</span> <span class="o">-&gt;</span> <span class="n">DataResponse</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Handles the requests that have a body payload, including Multipart data.</span>
<span class="sd"> :param message: message from the AMQP that contains the request</span>
<span class="sd"> :param auth_user: user authenticated by the API Gateway, as UserSchem</span>
<span class="sd"> :param method: HTTP method (POST, PUT, etc.)</span>
<span class="sd"> :return: DataResponse to be sent back to the API Gateway via AMQP</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">_form_data</span> <span class="o">=</span> <span class="n">AMQDataParser</span><span class="o">.</span><span class="n">parse_request_body</span><span class="p">(</span><span class="n">message</span><span class="p">)</span>
<span class="n">_routes</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">routes</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">method</span><span class="p">,</span> <span class="p">[])</span>
<span class="n">_path</span><span class="p">,</span> <span class="n">_query_args</span> <span class="o">=</span> <span class="n">AMQDataParser</span><span class="o">.</span><span class="n">parse_get_url</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">path</span><span class="p">())</span>
<span class="k">for</span> <span class="n">_route</span> <span class="ow">in</span> <span class="n">_routes</span><span class="p">:</span>
<span class="n">_match</span> <span class="o">=</span> <span class="n">_route</span><span class="o">.</span><span class="n">path_regex</span><span class="o">.</span><span class="n">match</span><span class="p">(</span><span class="n">_path</span><span class="p">)</span>
<span class="k">if</span> <span class="n">_match</span><span class="p">:</span>
<span class="c1"># If the path matches, call the corresponding function</span>
<span class="n">_form_data</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">_match</span><span class="o">.</span><span class="n">groupdict</span><span class="p">())</span>
<span class="n">_form_data</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">_query_args</span><span class="p">)</span>
<span class="k">for</span> <span class="n">_body_param</span> <span class="ow">in</span> <span class="n">_route</span><span class="o">.</span><span class="n">dependant</span><span class="o">.</span><span class="n">body_params</span><span class="p">:</span>
<span class="k">if</span> <span class="n">_body_param</span><span class="o">.</span><span class="n">name</span> <span class="ow">in</span> <span class="n">_form_data</span><span class="p">:</span>
<span class="n">_file_data</span> <span class="o">=</span> <span class="n">_form_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">_body_param</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
<span class="n">actual_filepath</span> <span class="o">=</span> <span class="n">message</span><span class="o">.</span><span class="n">extra_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">_body_param</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
<span class="n">_form_data</span><span class="p">[</span><span class="n">_body_param</span><span class="o">.</span><span class="n">name</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span>
<span class="p">(</span>
<span class="n">_body_param</span><span class="o">.</span><span class="n">type_</span><span class="o">.</span><span class="vm">__name__</span> <span class="o">==</span> <span class="s2">&quot;UploadFile&quot;</span>
<span class="ow">or</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">_body_param</span><span class="o">.</span><span class="n">field_info</span><span class="p">,</span> <span class="n">File</span><span class="p">)</span>
<span class="p">)</span>
<span class="ow">and</span> <span class="n">_file_data</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span>
<span class="ow">and</span> <span class="n">actual_filepath</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span>
<span class="ow">and</span> <span class="n">UploadFile</span><span class="p">(</span>
<span class="n">file</span><span class="o">=</span><span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="n">actual_filepath</span><span class="p">)</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="s2">&quot;rb&quot;</span><span class="p">),</span>
<span class="n">size</span><span class="o">=</span><span class="n">_file_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;size&quot;</span><span class="p">),</span>
<span class="n">filename</span><span class="o">=</span><span class="n">_file_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;filename&quot;</span><span class="p">),</span>
<span class="n">headers</span><span class="o">=</span><span class="n">Headers</span><span class="p">({</span><span class="s2">&quot;Content-Type&quot;</span><span class="p">:</span> <span class="n">_file_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;mediaType&quot;</span><span class="p">)}),</span>
<span class="p">)</span>
<span class="ow">or</span> <span class="n">_form_data</span><span class="p">[</span><span class="n">_body_param</span><span class="o">.</span><span class="n">name</span><span class="p">]</span>
<span class="p">)</span>
<span class="n">_verified_args</span> <span class="o">=</span> <span class="p">{}</span>
<span class="n">_required_args</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">_route</span><span class="o">.</span><span class="n">endpoint</span><span class="p">,</span> <span class="s2">&quot;__annotations__&quot;</span><span class="p">,</span> <span class="p">{})</span>
<span class="n">_signature_args</span> <span class="o">=</span> <span class="n">inspect</span><span class="o">.</span><span class="n">signature</span><span class="p">(</span><span class="n">_route</span><span class="o">.</span><span class="n">endpoint</span><span class="p">)</span><span class="o">.</span><span class="n">parameters</span>
<span class="k">for</span> <span class="n">arg</span> <span class="ow">in</span> <span class="n">_required_args</span><span class="p">:</span>
<span class="k">if</span> <span class="n">arg</span> <span class="ow">in</span> <span class="n">_form_data</span><span class="p">:</span>
<span class="n">_verified_args</span><span class="p">[</span><span class="n">arg</span><span class="p">]</span> <span class="o">=</span> <span class="n">_form_data</span><span class="p">[</span><span class="n">arg</span><span class="p">]</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># needed for CleverSwarm /login input</span>
<span class="k">if</span> <span class="n">_required_args</span><span class="p">[</span><span class="n">arg</span><span class="p">]</span><span class="o">.</span><span class="vm">__name__</span> <span class="o">==</span> <span class="s2">&quot;OAuth2PasswordRequestForm&quot;</span><span class="p">:</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">_verified_args</span><span class="p">[</span><span class="n">arg</span><span class="p">]</span> <span class="o">=</span> <span class="n">OAuth2PasswordRequestForm</span><span class="p">(</span><span class="o">**</span><span class="n">_form_data</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Error: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">authenticated_user_arg_name</span> <span class="ow">in</span> <span class="n">_signature_args</span><span class="o">.</span><span class="n">keys</span><span class="p">():</span>
<span class="n">_verified_args</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">authenticated_user_arg_name</span><span class="p">]</span> <span class="o">=</span> <span class="n">auth_user</span>
<span class="k">return</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">call_cleverthis_api</span><span class="p">(</span>
<span class="n">message</span><span class="p">,</span>
<span class="n">_verified_args</span><span class="p">,</span>
<span class="n">api_method</span><span class="o">=</span><span class="n">_route</span><span class="o">.</span><span class="n">endpoint</span><span class="p">,</span>
<span class="n">success_code</span><span class="o">=</span><span class="n">_route</span><span class="o">.</span><span class="n">status_code</span> <span class="k">if</span> <span class="n">_route</span><span class="o">.</span><span class="n">status_code</span> <span class="k">else</span> <span class="mi">200</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">return</span> <span class="n">DataResponseFactory</span><span class="o">.</span><span class="n">of</span><span class="p">(</span>
<span class="n">message</span><span class="o">.</span><span class="n">id</span><span class="p">(),</span>
<span class="mi">404</span><span class="p">,</span>
<span class="s2">&quot;text/plain&quot;</span><span class="p">,</span>
<span class="nb">str</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Destination location [</span><span class="si">{</span><span class="n">message</span><span class="o">.</span><span class="n">path</span><span class="p">()</span><span class="si">}</span><span class="s2">] does not exists&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s2">&quot;utf-8&quot;</span><span class="p">),</span>
<span class="n">message</span><span class="o">.</span><span class="n">trace_info</span><span class="p">(),</span>
<span class="p">)</span></div>
<span class="k">def</span><span class="w"> </span><span class="nf">_verify_and_instantiate_arguments</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span>
<span class="n">args</span><span class="p">:</span> <span class="n">Any</span><span class="p">,</span>
<span class="n">api_method</span><span class="p">:</span> <span class="n">Callable</span><span class="p">[[</span><span class="n">Any</span><span class="p">,</span> <span class="n">Any</span><span class="p">],</span> <span class="n">Coroutine</span><span class="p">],</span>
<span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">dict</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Check the provided arguments against the API method signature and convert the incoming string value</span>
<span class="sd"> into correct expected input object.</span>
<span class="sd"> The logic used FastAPI annotation and would use the value from &#39;default_factory&#39; invocation (where defined)</span>
<span class="sd"> or &#39;default&#39; value, as defined in the FastAPI annotation, to create default value in case the object is not in</span>
<span class="sd"> the input values provided by the caller.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">_verified_args</span> <span class="o">=</span> <span class="p">{}</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">_sig</span> <span class="o">=</span> <span class="n">inspect</span><span class="o">.</span><span class="n">signature</span><span class="p">(</span><span class="n">api_method</span><span class="p">)</span>
<span class="n">_required_args</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">_sig</span><span class="o">.</span><span class="n">parameters</span><span class="o">.</span><span class="n">values</span><span class="p">())</span>
<span class="c1"># _required_args = getattr(api_method, &#39;__annotations__&#39;, {})</span>
<span class="k">for</span> <span class="n">arg</span> <span class="ow">in</span> <span class="n">_required_args</span><span class="p">:</span>
<span class="k">if</span> <span class="n">arg</span><span class="o">.</span><span class="n">name</span> <span class="ow">in</span> <span class="n">args</span><span class="p">:</span>
<span class="n">_annotation</span> <span class="o">=</span> <span class="n">arg</span><span class="o">.</span><span class="n">annotation</span>
<span class="n">_str_annotation</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">_annotation</span><span class="p">)</span>
<span class="c1"># convert to another type if arg is not a str</span>
<span class="k">if</span> <span class="n">arg</span><span class="o">.</span><span class="n">name</span> <span class="o">==</span> <span class="bp">self</span><span class="o">.</span><span class="n">authenticated_user_arg_name</span><span class="p">:</span>
<span class="n">_verified_args</span><span class="p">[</span><span class="n">arg</span><span class="o">.</span><span class="n">name</span><span class="p">]</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">arg</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">_annotation</span> <span class="o">==</span> <span class="nb">int</span><span class="p">:</span>
<span class="n">_verified_args</span><span class="p">[</span><span class="n">arg</span><span class="o">.</span><span class="n">name</span><span class="p">]</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">arg</span><span class="o">.</span><span class="n">name</span><span class="p">))</span>
<span class="k">elif</span> <span class="n">_annotation</span> <span class="o">==</span> <span class="nb">float</span><span class="p">:</span>
<span class="n">_verified_args</span><span class="p">[</span><span class="n">arg</span><span class="o">.</span><span class="n">name</span><span class="p">]</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">arg</span><span class="o">.</span><span class="n">name</span><span class="p">))</span>
<span class="k">elif</span> <span class="n">_annotation</span> <span class="o">==</span> <span class="nb">bool</span><span class="p">:</span>
<span class="n">_verified_args</span><span class="p">[</span><span class="n">arg</span><span class="o">.</span><span class="n">name</span><span class="p">]</span> <span class="o">=</span> <span class="n">serializer</span><span class="o">.</span><span class="n">str_to_bool</span><span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">arg</span><span class="o">.</span><span class="n">name</span><span class="p">))</span>
<span class="k">elif</span> <span class="p">(</span>
<span class="s2">&quot;Optional&quot;</span> <span class="ow">in</span> <span class="n">_str_annotation</span>
<span class="ow">or</span> <span class="n">_str_annotation</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&quot;list&quot;</span><span class="p">)</span>
<span class="ow">or</span> <span class="n">_str_annotation</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&quot;typing.List&quot;</span><span class="p">)</span>
<span class="ow">or</span> <span class="s2">&quot;class&quot;</span> <span class="ow">in</span> <span class="n">_str_annotation</span>
<span class="p">):</span>
<span class="n">_type_descr</span> <span class="o">=</span> <span class="n">TypeDescriptor</span><span class="p">(</span>
<span class="n">_str_annotation</span><span class="p">,</span> <span class="n">extra_init_data</span><span class="o">=</span><span class="n">g_extra_init_data</span>
<span class="p">)</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">_payload</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">arg</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="s2">&quot;&quot;</span><span class="p">)</span>
<span class="n">_verified_args</span><span class="p">[</span><span class="n">arg</span><span class="o">.</span><span class="n">name</span><span class="p">]</span> <span class="o">=</span> <span class="n">_type_descr</span><span class="o">.</span><span class="n">instantiate</span><span class="p">(</span>
<span class="n">_payload</span><span class="p">,</span> <span class="n">is_json</span><span class="o">=</span><span class="n">is_likely_json</span><span class="p">(</span><span class="n">_payload</span><span class="p">)</span>
<span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">err</span><span class="p">:</span>
<span class="n">logging_error</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;Could not instantiate argument </span><span class="si">{</span><span class="n">arg</span><span class="si">}</span><span class="s2">, defaulting to its string value&quot;</span><span class="p">,</span>
<span class="n">err</span><span class="p">,</span>
<span class="p">)</span>
<span class="n">_verified_args</span><span class="p">[</span><span class="n">arg</span><span class="o">.</span><span class="n">name</span><span class="p">]</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">arg</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">_temp</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">arg</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">arg</span><span class="o">.</span><span class="n">annotation</span><span class="p">,</span> <span class="n">enum</span><span class="o">.</span><span class="n">EnumType</span><span class="p">)</span> <span class="ow">or</span> <span class="nb">isinstance</span><span class="p">(</span>
<span class="n">arg</span><span class="o">.</span><span class="n">annotation</span><span class="p">,</span> <span class="n">enum</span><span class="o">.</span><span class="n">Enum</span>
<span class="p">):</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">_temp</span> <span class="o">=</span> <span class="n">arg</span><span class="o">.</span><span class="n">annotation</span><span class="p">[</span><span class="n">_temp</span><span class="p">]</span>
<span class="k">except</span> <span class="ne">KeyError</span> <span class="k">as</span> <span class="n">ke</span><span class="p">:</span>
<span class="c1"># some enums have string value different to key spelling, try different thing</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">_temp</span> <span class="o">=</span> <span class="n">arg</span><span class="o">.</span><span class="n">annotation</span><span class="p">(</span><span class="n">_temp</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">ValueError</span> <span class="k">as</span> <span class="n">ve</span><span class="p">:</span>
<span class="n">logging_warning</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;cannot convert &#39;</span><span class="si">{</span><span class="n">_temp</span><span class="si">}</span><span class="s2">&#39; to Enum type </span><span class="si">{</span><span class="n">arg</span><span class="o">.</span><span class="n">annotation</span><span class="si">}</span><span class="s2">, </span><span class="si">{</span><span class="n">ke</span><span class="si">}</span><span class="s2">, </span><span class="si">{</span><span class="n">ve</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;ENUM -&gt; </span><span class="si">{</span><span class="n">_temp</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="n">_verified_args</span><span class="p">[</span><span class="n">arg</span><span class="o">.</span><span class="n">name</span><span class="p">]</span> <span class="o">=</span> <span class="n">_temp</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">arg</span><span class="p">,</span> <span class="s2">&quot;default&quot;</span><span class="p">):</span>
<span class="n">_temp</span> <span class="o">=</span> <span class="n">arg</span><span class="o">.</span><span class="n">default</span>
<span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">_temp</span><span class="p">,</span> <span class="s2">&quot;default_factory&quot;</span><span class="p">)</span> <span class="ow">and</span> <span class="n">_temp</span><span class="o">.</span><span class="n">default_factory</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">_temp</span> <span class="o">=</span> <span class="n">_temp</span><span class="o">.</span><span class="n">default_factory</span><span class="p">()</span>
<span class="k">elif</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">_temp</span><span class="p">,</span> <span class="s2">&quot;default&quot;</span><span class="p">):</span>
<span class="n">_temp</span> <span class="o">=</span> <span class="n">_temp</span><span class="o">.</span><span class="n">default</span>
<span class="k">if</span> <span class="ow">not</span> <span class="nb">str</span><span class="p">(</span><span class="n">_temp</span><span class="p">)</span> <span class="o">==</span> <span class="s2">&quot;&lt;class &#39;inspect._empty&#39;&gt;&quot;</span><span class="p">:</span>
<span class="n">_verified_args</span><span class="p">[</span><span class="n">arg</span><span class="o">.</span><span class="n">name</span><span class="p">]</span> <span class="o">=</span> <span class="n">_temp</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">logging_warning</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">api_method</span><span class="o">.</span><span class="vm">__name__</span><span class="si">}</span><span class="s2">: Missing required argument: </span><span class="si">{</span><span class="n">arg</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="n">logging_error</span><span class="p">(</span><span class="s2">&quot;Failed to validate and instantiate input args&quot;</span><span class="p">,</span> <span class="n">e</span><span class="p">)</span>
<span class="k">return</span> <span class="n">_verified_args</span>
<div class="viewcode-block" id="CleverThisServiceAdapter.call_cleverthis_api">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.cleverthis_service_adapter.CleverThisServiceAdapter.call_cleverthis_api">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">call_cleverthis_api</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span>
<span class="n">message</span><span class="p">:</span> <span class="n">AMQMessage</span><span class="p">,</span>
<span class="n">args</span><span class="p">:</span> <span class="n">Any</span><span class="p">,</span>
<span class="n">api_method</span><span class="p">:</span> <span class="n">Callable</span><span class="p">[[</span><span class="n">Any</span><span class="p">,</span> <span class="n">Any</span><span class="p">],</span> <span class="n">Coroutine</span><span class="p">],</span>
<span class="n">success_code</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span>
<span class="p">)</span> <span class="o">-&gt;</span> <span class="n">DataResponse</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Handles POST and PUT requests, which typically contain possibly complex payload data,</span>
<span class="sd"> passed as a dictionary. Invokes the provided API method with the given arguments and</span>
<span class="sd"> authenticated user, and returns the response as DataResponse.</span>
<span class="sd"> :param message: DataMessage containing the details of the call and the payload</span>
<span class="sd"> :param args: map of the arguments to pass to the API method</span>
<span class="sd"> :param api_method: Callable - the method to invoke. Last parameter is the authenticated user</span>
<span class="sd"> :param success_code: HTTP code to be returned when operation suceeds</span>
<span class="sd"> :return: DataResponse class</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">_verified_args</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_verify_and_instantiate_arguments</span><span class="p">(</span>
<span class="n">args</span><span class="o">=</span><span class="n">args</span><span class="p">,</span> <span class="n">api_method</span><span class="o">=</span><span class="n">api_method</span>
<span class="p">)</span>
<span class="n">logging_info</span><span class="p">(</span>
<span class="s2">&quot;INVOKE ENDPOINT: [</span><span class="si">%s</span><span class="s2">], ARGS: {</span><span class="si">%s</span><span class="s2">}&quot;</span><span class="p">,</span>
<span class="n">api_method</span><span class="o">.</span><span class="vm">__name__</span><span class="p">,</span>
<span class="s2">&quot;, &quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">k</span><span class="si">}</span><span class="s2">=</span><span class="si">{</span><span class="n">v</span><span class="si">}</span><span class="s2">&quot;</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">_verified_args</span><span class="o">.</span><span class="n">items</span><span class="p">()),</span>
<span class="p">)</span>
<span class="n">_result</span><span class="p">:</span> <span class="n">Any</span> <span class="o">=</span> <span class="k">await</span> <span class="n">api_method</span><span class="p">(</span><span class="o">**</span><span class="n">_verified_args</span><span class="p">)</span>
<span class="n">logging_info</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;ENDPOINT RESULT: [</span><span class="si">{</span><span class="n">api_method</span><span class="o">.</span><span class="vm">__name__</span><span class="si">}</span><span class="s2">], RESULT: </span><span class="si">{</span><span class="nb">str</span><span class="p">(</span><span class="n">_result</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">_result</span><span class="p">,</span> <span class="n">FileResponse</span><span class="p">):</span>
<span class="n">_json_result</span><span class="p">,</span> <span class="n">_content_type</span> <span class="o">=</span> <span class="p">(</span>
<span class="k">await</span> <span class="n">_convert_file_response</span><span class="p">(</span>
<span class="n">_result</span><span class="p">,</span>
<span class="n">message</span><span class="o">.</span><span class="n">connection</span><span class="p">,</span>
<span class="n">file_handler</span><span class="o">=</span><span class="n">StreamingFileHandler</span><span class="p">(),</span>
<span class="n">loop</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">loop</span><span class="p">,</span>
<span class="p">),</span>
<span class="s2">&quot;application/octet-stream&quot;</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">_result</span><span class="p">,</span> <span class="n">BaseModel</span><span class="p">):</span>
<span class="n">_json_result</span> <span class="o">=</span> <span class="n">_result</span><span class="o">.</span><span class="n">json</span><span class="p">()</span>
<span class="n">_content_type</span> <span class="o">=</span> <span class="s2">&quot;application/json&quot;</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">_result</span><span class="p">,</span> <span class="nb">str</span><span class="p">):</span>
<span class="n">_json_result</span> <span class="o">=</span> <span class="n">_result</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">_json_result</span> <span class="o">=</span> <span class="n">python_type_to_json</span><span class="p">(</span><span class="n">_result</span><span class="p">)</span>
<span class="n">_content_type</span> <span class="o">=</span> <span class="s2">&quot;application/json&quot;</span>
<span class="n">_binary_result</span> <span class="o">=</span> <span class="p">(</span>
<span class="n">_json_result</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s2">&quot;utf-8&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">_json_result</span><span class="p">,</span> <span class="s2">&quot;encode&quot;</span><span class="p">)</span>
<span class="k">else</span> <span class="p">(</span>
<span class="n">_json_result</span><span class="o">.</span><span class="n">body</span>
<span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">_json_result</span><span class="p">,</span> <span class="s2">&quot;body&quot;</span><span class="p">)</span>
<span class="k">else</span> <span class="p">(</span><span class="n">_json_result</span><span class="o">.</span><span class="n">read</span><span class="p">()</span> <span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">_json_result</span><span class="p">,</span> <span class="s2">&quot;read&quot;</span><span class="p">)</span> <span class="k">else</span> <span class="n">_json_result</span><span class="p">)</span>
<span class="p">)</span>
<span class="p">)</span>
<span class="n">logging_info</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;ALL DONE in call_cleverthis_api id:</span><span class="si">{</span><span class="n">message</span><span class="o">.</span><span class="n">id</span><span class="p">()</span><span class="si">}</span><span class="s2">, resp code:</span><span class="si">{</span><span class="n">success_code</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="p">)</span>
<span class="k">return</span> <span class="n">DataResponseFactory</span><span class="o">.</span><span class="n">of</span><span class="p">(</span>
<span class="n">message</span><span class="o">.</span><span class="n">id</span><span class="p">(),</span>
<span class="n">success_code</span><span class="p">,</span>
<span class="n">_content_type</span><span class="p">,</span>
<span class="n">_binary_result</span><span class="p">,</span>
<span class="n">message</span><span class="o">.</span><span class="n">trace_info</span><span class="p">(),</span>
<span class="p">)</span>
<span class="k">except</span> <span class="n">HTTPException</span> <span class="k">as</span> <span class="n">http_error</span><span class="p">:</span>
<span class="n">logging_error</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Service REST endpoint invocation failed: </span><span class="si">{</span><span class="n">http_error</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="n">_content</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">http_error</span><span class="o">.</span><span class="n">detail</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">is_likely_json</span><span class="p">(</span><span class="n">_content</span><span class="p">):</span>
<span class="k">return</span> <span class="n">DataResponseFactory</span><span class="o">.</span><span class="n">of_error_message</span><span class="p">(</span>
<span class="n">message</span><span class="o">.</span><span class="n">id</span><span class="p">(),</span>
<span class="n">AMQErrorMessage</span><span class="p">(</span>
<span class="n">http_error</span><span class="o">.</span><span class="n">status_code</span><span class="p">,</span>
<span class="s2">&quot;Service Invocation Failed&quot;</span><span class="p">,</span>
<span class="n">_content</span><span class="p">,</span>
<span class="p">),</span>
<span class="n">message</span><span class="o">.</span><span class="n">trace_info</span><span class="p">(),</span>
<span class="p">)</span>
<span class="k">return</span> <span class="n">DataResponseFactory</span><span class="o">.</span><span class="n">of</span><span class="p">(</span>
<span class="n">message</span><span class="o">.</span><span class="n">id</span><span class="p">(),</span>
<span class="n">http_error</span><span class="o">.</span><span class="n">status_code</span><span class="p">,</span>
<span class="s2">&quot;application/json&quot;</span><span class="p">,</span>
<span class="n">_content</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s2">&quot;utf-8&quot;</span><span class="p">),</span>
<span class="n">message</span><span class="o">.</span><span class="n">trace_info</span><span class="p">(),</span>
<span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">error</span><span class="p">:</span>
<span class="n">logging_error</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Service endpoint invocation failed: </span><span class="si">{</span><span class="n">error</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="n">_content</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">error</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">is_likely_json</span><span class="p">(</span><span class="n">_content</span><span class="p">):</span>
<span class="k">return</span> <span class="n">DataResponseFactory</span><span class="o">.</span><span class="n">of_error_message</span><span class="p">(</span>
<span class="n">message</span><span class="o">.</span><span class="n">id</span><span class="p">(),</span>
<span class="n">AMQErrorMessage</span><span class="p">(</span>
<span class="mi">500</span><span class="p">,</span>
<span class="s2">&quot;Service Invocation Failed&quot;</span><span class="p">,</span>
<span class="n">_content</span><span class="p">,</span>
<span class="p">),</span>
<span class="n">message</span><span class="o">.</span><span class="n">trace_info</span><span class="p">(),</span>
<span class="p">)</span>
<span class="k">return</span> <span class="n">DataResponseFactory</span><span class="o">.</span><span class="n">of</span><span class="p">(</span>
<span class="n">message</span><span class="o">.</span><span class="n">id</span><span class="p">(),</span>
<span class="mi">500</span><span class="p">,</span>
<span class="s2">&quot;application/json&quot;</span><span class="p">,</span>
<span class="n">_content</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s2">&quot;utf-8&quot;</span><span class="p">),</span>
<span class="n">message</span><span class="o">.</span><span class="n">trace_info</span><span class="p">(),</span>
<span class="p">)</span></div>
</div>
</pre></div>
</div>
</div>
<footer>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2024, CleverThis.</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>
@@ -0,0 +1,214 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" data-content_root="../../../">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>amqp.adapter.consul_global_id_generator &mdash; AMQ Adapter Python 1.0 documentation</title>
<link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=03e43079" />
<link rel="stylesheet" type="text/css" href="../../../_static/css/theme.css?v=e59714d7" />
<script src="../../../_static/jquery.js?v=5d32c60e"></script>
<script src="../../../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
<script src="../../../_static/documentation_options.js?v=f2a433a1"></script>
<script src="../../../_static/doctools.js?v=9bcbadda"></script>
<script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
<script src="../../../_static/js/theme.js"></script>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="../../../index.html" class="icon icon-home">
AMQ Adapter Python
</a>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" aria-label="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.html">AMQP Package</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.config.html">Configuration Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.adapter.html">Adapter Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.service.html">Service Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.router.html">Router Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.model.html">Model Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.rabbitmq.html">RabbitMQ Module</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="../../../index.html">AMQ Adapter Python</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="../../../index.html" class="icon icon-home" aria-label="Home"></a></li>
<li class="breadcrumb-item"><a href="../../index.html">Module code</a></li>
<li class="breadcrumb-item active">amqp.adapter.consul_global_id_generator</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<h1>Source code for amqp.adapter.consul_global_id_generator</h1><div class="highlight"><pre>
<span></span><span class="kn">import</span><span class="w"> </span><span class="nn">logging</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">os</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">random</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">socket</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">time</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">consul_kv</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.config.amq_configuration</span><span class="w"> </span><span class="kn">import</span> <span class="n">AMQAdapter</span>
<span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="vm">__name__</span><span class="p">)</span>
<div class="viewcode-block" id="get_config_values">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.consul_global_id_generator.get_config_values">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">get_config_values</span><span class="p">(</span><span class="n">config</span><span class="p">:</span> <span class="n">AMQAdapter</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">tuple</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Get configuration values from AMQConfiguration or environment variables.</span>
<span class="sd"> Returns:</span>
<span class="sd"> tuple: (consul_host, consul_port, consul_counter_key, max_retries, retry_delay_seconds)</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">consul_host</span> <span class="o">=</span> <span class="n">config</span><span class="o">.</span><span class="n">consul_host</span>
<span class="n">consul_port</span> <span class="o">=</span> <span class="n">config</span><span class="o">.</span><span class="n">consul_port</span>
<span class="n">consul_counter_key</span> <span class="o">=</span> <span class="n">config</span><span class="o">.</span><span class="n">consul_counter_key</span>
<span class="n">max_retries</span> <span class="o">=</span> <span class="n">config</span><span class="o">.</span><span class="n">consul_max_retries</span>
<span class="n">retry_delay_seconds</span> <span class="o">=</span> <span class="n">config</span><span class="o">.</span><span class="n">consul_initial_retry_delay</span>
<span class="k">return</span> <span class="n">consul_host</span><span class="p">,</span> <span class="n">consul_port</span><span class="p">,</span> <span class="n">consul_counter_key</span><span class="p">,</span> <span class="n">max_retries</span><span class="p">,</span> <span class="n">retry_delay_seconds</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="n">logger</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Failed to load configuration: </span><span class="si">{</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="si">}</span><span class="s2">. Using default values.&quot;</span><span class="p">)</span>
<span class="k">return</span> <span class="p">(</span>
<span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;CONSUL_HOST&quot;</span><span class="p">,</span> <span class="n">consul_kv</span><span class="o">.</span><span class="n">settings</span><span class="o">.</span><span class="n">DEFAULT_ENDPOINT</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;:&quot;</span><span class="p">)[</span><span class="mi">0</span><span class="p">]),</span>
<span class="nb">int</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;CONSUL_PORT&quot;</span><span class="p">,</span> <span class="n">consul_kv</span><span class="o">.</span><span class="n">settings</span><span class="o">.</span><span class="n">DEFAULT_ENDPOINT</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;:&quot;</span><span class="p">)[</span><span class="mi">1</span><span class="p">])),</span>
<span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;CONSUL_COUNTER_KEY&quot;</span><span class="p">,</span> <span class="s2">&quot;service/ids/counter&quot;</span><span class="p">),</span>
<span class="nb">int</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;CONSUL_MAX_RETRIES&quot;</span><span class="p">,</span> <span class="mi">5</span><span class="p">)),</span>
<span class="nb">float</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;CONSUL_RETRY_DELAY_SECONDS&quot;</span><span class="p">,</span> <span class="mf">0.2</span><span class="p">)),</span>
<span class="p">)</span></div>
<div class="viewcode-block" id="generate_fallback_id">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.consul_global_id_generator.generate_fallback_id">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">generate_fallback_id</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Generate a fallback ID when Consul is not available.</span>
<span class="sd"> Uses a combination of timestamp, hostname hash, and random number.</span>
<span class="sd"> Returns:</span>
<span class="sd"> int: A reasonably unique integer ID</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">timestamp</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span> <span class="o">*</span> <span class="mi">1000</span><span class="p">)</span>
<span class="n">hostname</span> <span class="o">=</span> <span class="n">socket</span><span class="o">.</span><span class="n">gethostname</span><span class="p">()</span>
<span class="n">hostname_hash</span> <span class="o">=</span> <span class="nb">hash</span><span class="p">(</span><span class="n">hostname</span><span class="p">)</span> <span class="o">%</span> <span class="mi">10000</span>
<span class="n">random_part</span> <span class="o">=</span> <span class="n">random</span><span class="o">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">9999</span><span class="p">)</span>
<span class="n">unique_id</span> <span class="o">=</span> <span class="p">(</span><span class="n">timestamp</span> <span class="o">*</span> <span class="mi">100000000</span><span class="p">)</span> <span class="o">+</span> <span class="p">(</span><span class="n">hostname_hash</span> <span class="o">*</span> <span class="mi">10000</span><span class="p">)</span> <span class="o">+</span> <span class="n">random_part</span>
<span class="n">logger</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Using fallback ID generation method: </span><span class="si">{</span><span class="n">unique_id</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">return</span> <span class="n">unique_id</span></div>
<div class="viewcode-block" id="get_unique_instance_id">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.consul_global_id_generator.get_unique_instance_id">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">get_unique_instance_id</span><span class="p">(</span><span class="n">config</span><span class="p">:</span> <span class="n">AMQAdapter</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Get a globally unique ID from Consul.</span>
<span class="sd"> Uses Consul&#39;s atomic Compare-And-Set operations to safely increment a counter.</span>
<span class="sd"> Falls back to a local generation method if Consul is unavailable.</span>
<span class="sd"> Returns:</span>
<span class="sd"> int: A globally unique integer ID</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">consul_host</span><span class="p">,</span> <span class="n">consul_port</span><span class="p">,</span> <span class="n">consul_counter_key</span><span class="p">,</span> <span class="n">max_retries</span><span class="p">,</span> <span class="n">retry_delay_seconds</span> <span class="o">=</span> <span class="p">(</span>
<span class="n">get_config_values</span><span class="p">(</span><span class="n">config</span><span class="p">)</span>
<span class="p">)</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">c</span> <span class="o">=</span> <span class="n">consul_kv</span><span class="o">.</span><span class="n">Connection</span><span class="p">(</span><span class="n">endpoint</span><span class="o">=</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">consul_host</span><span class="si">}</span><span class="s2">:</span><span class="si">{</span><span class="n">consul_port</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">timeout</span><span class="o">=</span><span class="mi">5</span><span class="p">)</span>
<span class="n">index</span><span class="p">,</span> <span class="n">data</span> <span class="o">=</span> <span class="n">c</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">consul_counter_key</span><span class="p">)</span>
<span class="k">if</span> <span class="n">data</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Initializing Consul counter at </span><span class="si">{</span><span class="n">consul_counter_key</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="n">c</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="n">consul_counter_key</span><span class="p">,</span> <span class="s2">&quot;1&quot;</span><span class="p">,</span> <span class="n">cas</span><span class="o">=</span><span class="mi">1</span><span class="p">):</span>
<span class="k">return</span> <span class="mi">1</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="s2">&quot;Failed to initialize Consul counter&quot;</span><span class="p">)</span>
<span class="k">return</span> <span class="n">generate_fallback_id</span><span class="p">()</span>
<span class="n">current_value</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">data</span><span class="p">[</span><span class="s2">&quot;Value&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s2">&quot;utf-8&quot;</span><span class="p">))</span>
<span class="n">new_value</span> <span class="o">=</span> <span class="n">current_value</span> <span class="o">+</span> <span class="mi">1</span>
<span class="k">for</span> <span class="n">attempt</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">max_retries</span><span class="p">):</span>
<span class="n">success</span> <span class="o">=</span> <span class="n">c</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="n">consul_counter_key</span><span class="p">,</span> <span class="nb">str</span><span class="p">(</span><span class="n">new_value</span><span class="p">),</span> <span class="n">cas</span><span class="o">=</span><span class="n">data</span><span class="p">[</span><span class="s2">&quot;ModifyIndex&quot;</span><span class="p">])</span>
<span class="k">if</span> <span class="n">success</span><span class="p">:</span>
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Successfully obtained unique ID: </span><span class="si">{</span><span class="n">new_value</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">return</span> <span class="n">new_value</span>
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;CAS update failed on attempt </span><span class="si">{</span><span class="n">attempt</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="si">}</span><span class="s2">, retrying...&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="n">attempt</span> <span class="o">&lt;</span> <span class="n">max_retries</span> <span class="o">-</span> <span class="mi">1</span><span class="p">:</span>
<span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="n">retry_delay_seconds</span> <span class="o">*</span> <span class="p">(</span><span class="mi">1</span> <span class="o">&lt;&lt;</span> <span class="n">attempt</span><span class="p">))</span> <span class="c1"># Exponential backoff</span>
<span class="n">index</span><span class="p">,</span> <span class="n">data</span> <span class="o">=</span> <span class="n">c</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">consul_counter_key</span><span class="p">)</span>
<span class="k">if</span> <span class="n">data</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="s2">&quot;Counter disappeared during update&quot;</span><span class="p">)</span>
<span class="k">return</span> <span class="n">generate_fallback_id</span><span class="p">()</span>
<span class="n">current_value</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">data</span><span class="p">[</span><span class="s2">&quot;Value&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s2">&quot;utf-8&quot;</span><span class="p">))</span>
<span class="n">new_value</span> <span class="o">=</span> <span class="n">current_value</span> <span class="o">+</span> <span class="mi">1</span>
<span class="n">logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Failed to update counter after </span><span class="si">{</span><span class="n">max_retries</span><span class="si">}</span><span class="s2"> attempts&quot;</span><span class="p">)</span>
<span class="k">return</span> <span class="n">generate_fallback_id</span><span class="p">()</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="n">logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Error accessing Consul: </span><span class="si">{</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">return</span> <span class="n">generate_fallback_id</span><span class="p">()</span></div>
</pre></div>
</div>
</div>
<footer>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2024, CleverThis.</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>
@@ -0,0 +1,449 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" data-content_root="../../../">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>amqp.adapter.data_message_factory &mdash; AMQ Adapter Python 1.0 documentation</title>
<link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=03e43079" />
<link rel="stylesheet" type="text/css" href="../../../_static/css/theme.css?v=e59714d7" />
<script src="../../../_static/jquery.js?v=5d32c60e"></script>
<script src="../../../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
<script src="../../../_static/documentation_options.js?v=f2a433a1"></script>
<script src="../../../_static/doctools.js?v=9bcbadda"></script>
<script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
<script src="../../../_static/js/theme.js"></script>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="../../../index.html" class="icon icon-home">
AMQ Adapter Python
</a>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" aria-label="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.html">AMQP Package</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.config.html">Configuration Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.adapter.html">Adapter Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.service.html">Service Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.router.html">Router Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.model.html">Model Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.rabbitmq.html">RabbitMQ Module</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="../../../index.html">AMQ Adapter Python</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="../../../index.html" class="icon icon-home" aria-label="Home"></a></li>
<li class="breadcrumb-item"><a href="../../index.html">Module code</a></li>
<li class="breadcrumb-item active">amqp.adapter.data_message_factory</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<h1>Source code for amqp.adapter.data_message_factory</h1><div class="highlight"><pre>
<span></span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">methods to create, serialize and deserialize DataMessage objects.</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">base64</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">json</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">re</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">datetime</span><span class="w"> </span><span class="kn">import</span> <span class="n">datetime</span><span class="p">,</span> <span class="n">timezone</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">io</span><span class="w"> </span><span class="kn">import</span> <span class="n">BytesIO</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Any</span><span class="p">,</span> <span class="n">Dict</span><span class="p">,</span> <span class="n">List</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">amqp.adapter.file_handler</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.adapter.file_handler</span><span class="w"> </span><span class="kn">import</span> <span class="n">FileHandler</span><span class="p">,</span> <span class="n">StreamingFileHandler</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.adapter.pydantic_serializer</span><span class="w"> </span><span class="kn">import</span> <span class="n">python_type_to_json</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.adapter.serializer</span><span class="w"> </span><span class="kn">import</span> <span class="p">(</span>
<span class="n">map_as_string</span><span class="p">,</span>
<span class="n">map_with_list_as_string</span><span class="p">,</span>
<span class="n">parse_map_list_string</span><span class="p">,</span>
<span class="n">parse_map_string</span><span class="p">,</span>
<span class="p">)</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.model.model</span><span class="w"> </span><span class="kn">import</span> <span class="n">DataMessage</span><span class="p">,</span> <span class="n">DataMessageMagicByte</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.model.snowflake_id</span><span class="w"> </span><span class="kn">import</span> <span class="n">SnowflakeId</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.router.utils</span><span class="w"> </span><span class="kn">import</span> <span class="n">sanitize_as_rabbitmq_name</span>
<div class="viewcode-block" id="DataMessageFactory">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.data_message_factory.DataMessageFactory">[docs]</a>
<span class="k">class</span><span class="w"> </span><span class="nc">DataMessageFactory</span><span class="p">:</span>
<span class="n">SNOWFLAKE_ID_BITS</span> <span class="o">=</span> <span class="mi">80</span>
<span class="n">SEQUENCE_BITS</span> <span class="o">=</span> <span class="mi">12</span>
<span class="n">MACHINE_ID_BITS</span> <span class="o">=</span> <span class="mi">24</span>
<span class="n">TIMESTAMP_BITS</span> <span class="o">=</span> <span class="n">SNOWFLAKE_ID_BITS</span> <span class="o">-</span> <span class="n">SEQUENCE_BITS</span> <span class="o">-</span> <span class="n">MACHINE_ID_BITS</span>
<span class="n">MACHINE_ID_MASK</span> <span class="o">=</span> <span class="p">(</span><span class="mi">1</span> <span class="o">&lt;&lt;</span> <span class="n">MACHINE_ID_BITS</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span>
<span class="n">SEQUENCE_MASK</span> <span class="o">=</span> <span class="p">(</span><span class="mi">1</span> <span class="o">&lt;&lt;</span> <span class="n">SEQUENCE_BITS</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span>
<span class="n">_instance</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">snowflake_epoch</span> <span class="o">=</span> <span class="n">datetime</span><span class="p">(</span><span class="mi">2024</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">tzinfo</span><span class="o">=</span><span class="n">timezone</span><span class="o">.</span><span class="n">utc</span><span class="p">)</span><span class="o">.</span><span class="n">timestamp</span><span class="p">()</span>
<div class="viewcode-block" id="DataMessageFactory.__init__">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.data_message_factory.DataMessageFactory.__init__">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">machine_id</span><span class="p">:</span> <span class="nb">int</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">machine_id</span> <span class="o">=</span> <span class="p">(</span><span class="n">machine_id</span> <span class="o">&amp;</span> <span class="bp">self</span><span class="o">.</span><span class="n">MACHINE_ID_MASK</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="bp">self</span><span class="o">.</span><span class="n">SEQUENCE_BITS</span>
<span class="bp">self</span><span class="o">.</span><span class="n">snowflake_sequence</span> <span class="o">=</span> <span class="mi">0</span>
<span class="bp">self</span><span class="o">.</span><span class="n">snowflake_last_timestamp</span> <span class="o">=</span> <span class="mi">0</span></div>
<div class="viewcode-block" id="DataMessageFactory.get_instance">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.data_message_factory.DataMessageFactory.get_instance">[docs]</a>
<span class="nd">@classmethod</span>
<span class="k">def</span><span class="w"> </span><span class="nf">get_instance</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">machine_id</span><span class="p">:</span> <span class="nb">int</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> return reusable factory instance</span>
<span class="sd"> :param machine_id: a generator ID, should be unique for each component to prevent duplicate IDs</span>
<span class="sd"> :return: factory instance</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_instance</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="bp">cls</span><span class="o">.</span><span class="n">_instance</span> <span class="o">=</span> <span class="n">DataMessageFactory</span><span class="p">(</span><span class="n">machine_id</span><span class="p">)</span>
<span class="k">return</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_instance</span></div>
<div class="viewcode-block" id="DataMessageFactory.generate_snowflake_id">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.data_message_factory.DataMessageFactory.generate_snowflake_id">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">generate_snowflake_id</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">SnowflakeId</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Generate an unique ID following the SnowflakeID structure, see https://en.wikipedia.org/wiki/Snowflake_ID</span>
<span class="sd"> :return: 80-bit wide ID</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">timestamp</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">(</span><span class="n">timezone</span><span class="o">.</span><span class="n">utc</span><span class="p">)</span><span class="o">.</span><span class="n">timestamp</span><span class="p">()</span> <span class="o">*</span> <span class="mi">1000</span><span class="p">)</span>
<span class="k">if</span> <span class="n">timestamp</span> <span class="o">&lt;</span> <span class="bp">self</span><span class="o">.</span><span class="n">snowflake_last_timestamp</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span><span class="s2">&quot;Clock moved backwards. Refusing to generate id&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="n">timestamp</span> <span class="o">==</span> <span class="bp">self</span><span class="o">.</span><span class="n">snowflake_last_timestamp</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">snowflake_sequence</span> <span class="o">=</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">snowflake_sequence</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">&amp;</span> <span class="bp">self</span><span class="o">.</span><span class="n">SEQUENCE_MASK</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">snowflake_sequence</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
<span class="k">while</span> <span class="n">timestamp</span> <span class="o">==</span> <span class="bp">self</span><span class="o">.</span><span class="n">snowflake_last_timestamp</span><span class="p">:</span>
<span class="n">timestamp</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">(</span><span class="n">timezone</span><span class="o">.</span><span class="n">utc</span><span class="p">)</span><span class="o">.</span><span class="n">timestamp</span><span class="p">()</span> <span class="o">*</span> <span class="mi">1000</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">snowflake_last_timestamp</span> <span class="o">=</span> <span class="n">timestamp</span>
<span class="k">else</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">snowflake_sequence</span> <span class="o">=</span> <span class="mi">0</span>
<span class="bp">self</span><span class="o">.</span><span class="n">snowflake_last_timestamp</span> <span class="o">=</span> <span class="n">timestamp</span>
<span class="n">time</span> <span class="o">=</span> <span class="n">timestamp</span> <span class="o">-</span> <span class="mi">1000</span> <span class="o">*</span> <span class="nb">int</span><span class="p">(</span><span class="n">DataMessageFactory</span><span class="o">.</span><span class="n">snowflake_epoch</span><span class="p">)</span>
<span class="k">return</span> <span class="n">SnowflakeId</span><span class="p">(</span>
<span class="n">time</span> <span class="o">&gt;&gt;</span> <span class="p">(</span><span class="mi">64</span> <span class="o">-</span> <span class="bp">self</span><span class="o">.</span><span class="n">SEQUENCE_BITS</span> <span class="o">-</span> <span class="bp">self</span><span class="o">.</span><span class="n">MACHINE_ID_BITS</span><span class="p">),</span>
<span class="p">(</span>
<span class="p">(</span><span class="n">time</span> <span class="o">&lt;&lt;</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">SEQUENCE_BITS</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">MACHINE_ID_BITS</span><span class="p">))</span>
<span class="o">|</span> <span class="bp">self</span><span class="o">.</span><span class="n">machine_id</span>
<span class="o">|</span> <span class="bp">self</span><span class="o">.</span><span class="n">snowflake_sequence</span>
<span class="p">)</span>
<span class="o">&amp;</span> <span class="mh">0xFFFFFFFFFFFFFFFF</span><span class="p">,</span>
<span class="p">)</span></div>
<div class="viewcode-block" id="DataMessageFactory.create_request_message">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.data_message_factory.DataMessageFactory.create_request_message">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">create_request_message</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span>
<span class="n">method</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
<span class="n">domain</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
<span class="n">path</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
<span class="n">headers</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]],</span>
<span class="n">message</span><span class="p">,</span>
<span class="p">)</span> <span class="o">-&gt;</span> <span class="n">DataMessage</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Encapsulate / hide the system level inputs, create the AMQ message from business relevant input</span>
<span class="sd"> :param method: a method requested (e.g. HTTP method like GET, POST in case of REST request)</span>
<span class="sd"> :param domain: service host name</span>
<span class="sd"> :param path: path at the service</span>
<span class="sd"> :param headers: HTTP headers</span>
<span class="sd"> :param message: payload</span>
<span class="sd"> :return: DataMessage object</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">serializable_headers</span> <span class="o">=</span> <span class="n">headers</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span> <span class="k">if</span> <span class="n">headers</span> <span class="k">else</span> <span class="p">{}</span>
<span class="n">payload</span> <span class="o">=</span> <span class="n">base64</span><span class="o">.</span><span class="n">b64encode</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s2">&quot;utf-8&quot;</span><span class="p">)</span> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="nb">str</span><span class="p">)</span> <span class="k">else</span> <span class="n">message</span><span class="p">)</span>
<span class="n">trace_info</span> <span class="o">=</span> <span class="p">{}</span>
<span class="k">return</span> <span class="n">DataMessage</span><span class="p">(</span>
<span class="n">DataMessageMagicByte</span><span class="o">.</span><span class="n">HTTP_REQUEST</span><span class="o">.</span><span class="n">value</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">generate_snowflake_id</span><span class="p">(),</span>
<span class="n">method</span><span class="p">,</span>
<span class="n">domain</span><span class="p">,</span>
<span class="n">path</span><span class="p">,</span>
<span class="n">serializable_headers</span><span class="p">,</span>
<span class="n">trace_info</span><span class="p">,</span>
<span class="n">payload</span><span class="p">,</span>
<span class="p">)</span></div>
<div class="viewcode-block" id="DataMessageFactory.safe_rsplit">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.data_message_factory.DataMessageFactory.safe_rsplit">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">safe_rsplit</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">fq_method_name</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="s2">&quot;_&quot;</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Safely split a fully qualified method name into package, class, and method</span>
<span class="sd"> Args:</span>
<span class="sd"> fq_method_name (str): Fully qualified method name</span>
<span class="sd"> default (str, optional): Default value for missing tokens. Defaults to &#39;&#39;.</span>
<span class="sd"> Returns:</span>
<span class="sd"> tuple: (package, class_name, method)</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">fq_method_name</span><span class="p">:</span>
<span class="k">return</span> <span class="n">default</span><span class="p">,</span> <span class="n">default</span><span class="p">,</span> <span class="n">default</span>
<span class="n">parts</span> <span class="o">=</span> <span class="n">fq_method_name</span><span class="o">.</span><span class="n">rsplit</span><span class="p">(</span><span class="s2">&quot;.&quot;</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
<span class="c1"># Pad with default values if insufficient tokens</span>
<span class="k">while</span> <span class="nb">len</span><span class="p">(</span><span class="n">parts</span><span class="p">)</span> <span class="o">&lt;</span> <span class="mi">3</span><span class="p">:</span>
<span class="n">parts</span><span class="o">.</span><span class="n">insert</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">default</span><span class="p">)</span>
<span class="k">return</span> <span class="nb">tuple</span><span class="p">(</span><span class="n">parts</span><span class="p">)</span></div>
<div class="viewcode-block" id="DataMessageFactory.create_rpc_message">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.data_message_factory.DataMessageFactory.create_rpc_message">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">create_rpc_message</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span>
<span class="n">fq_method_name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
<span class="n">swarm_id</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
<span class="n">args</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
<span class="p">)</span> <span class="o">-&gt;</span> <span class="n">DataMessage</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Create a RPC message with the given parameters.</span>
<span class="sd"> :param fq_method_name: fully qualified method name (e.g. &#39;com.example.ServiceClass.method_name&#39;)</span>
<span class="sd"> :param args: arguments whose serialized form will form the request body</span>
<span class="sd"> :return: DataMessage object</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">package</span><span class="p">,</span> <span class="n">class_name</span><span class="p">,</span> <span class="n">method</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">safe_rsplit</span><span class="p">(</span><span class="n">fq_method_name</span><span class="p">)</span>
<span class="n">headers</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&quot;Content-Type&quot;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&quot;application/octet-stream&quot;</span><span class="p">],</span> <span class="s2">&quot;Return-Address&quot;</span><span class="p">:</span> <span class="p">[</span><span class="n">swarm_id</span><span class="p">]}</span>
<span class="n">trace_info</span> <span class="o">=</span> <span class="p">{}</span>
<span class="n">body</span> <span class="o">=</span> <span class="n">python_type_to_json</span><span class="p">(</span><span class="n">args</span><span class="p">)</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="n">encoding</span><span class="o">=</span><span class="s2">&quot;utf-8&quot;</span><span class="p">)</span> <span class="k">if</span> <span class="n">args</span> <span class="k">else</span> <span class="sa">b</span><span class="s2">&quot;&quot;</span>
<span class="nb">print</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;Creating RPC message for method: </span><span class="si">{</span><span class="n">fq_method_name</span><span class="si">}</span><span class="s2">, args: </span><span class="si">{</span><span class="n">args</span><span class="si">}</span><span class="s2"> body: </span><span class="si">{</span><span class="n">body</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s1">&#39;utf-8&#39;</span><span class="p">)</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="n">body</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="s1">&#39;None&#39;</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="p">)</span>
<span class="k">return</span> <span class="n">DataMessage</span><span class="p">(</span>
<span class="n">DataMessageMagicByte</span><span class="o">.</span><span class="n">RPC_REQUEST</span><span class="o">.</span><span class="n">value</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">generate_snowflake_id</span><span class="p">(),</span>
<span class="n">package</span><span class="p">,</span>
<span class="n">class_name</span><span class="p">,</span>
<span class="n">method</span><span class="p">,</span>
<span class="n">headers</span><span class="p">,</span>
<span class="n">trace_info</span><span class="p">,</span>
<span class="n">body</span><span class="p">,</span>
<span class="p">)</span></div>
<div class="viewcode-block" id="DataMessageFactory.amq_message_routing_key">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.data_message_factory.DataMessageFactory.amq_message_routing_key">[docs]</a>
<span class="nd">@staticmethod</span>
<span class="k">def</span><span class="w"> </span><span class="nf">amq_message_routing_key</span><span class="p">(</span><span class="n">message</span><span class="p">:</span> <span class="n">DataMessage</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Constructs the message specific routing key.</span>
<span class="sd"> :param message: DataMessage input</span>
<span class="sd"> :return: routing key (as string) compliant to RabbitMQ allowed character set.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="n">sanitize_as_rabbitmq_name</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">message</span><span class="o">.</span><span class="n">domain</span><span class="p">()</span><span class="si">}</span><span class="s2">.</span><span class="si">{</span><span class="n">message</span><span class="o">.</span><span class="n">path</span><span class="p">()</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span></div>
<div class="viewcode-block" id="DataMessageFactory.get_timestamp_from_id">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.data_message_factory.DataMessageFactory.get_timestamp_from_id">[docs]</a>
<span class="nd">@staticmethod</span>
<span class="k">def</span><span class="w"> </span><span class="nf">get_timestamp_from_id</span><span class="p">(</span><span class="n">_id</span><span class="p">:</span> <span class="n">SnowflakeId</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Helper method - retrieve the timestamp from the ID</span>
<span class="sd"> :param _id: SnowflakeID (includes encoded timestamp)</span>
<span class="sd"> :return: the message timestamp</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">bits</span> <span class="o">=</span> <span class="n">_id</span><span class="o">.</span><span class="n">get_bits</span><span class="p">()</span>
<span class="n">low</span> <span class="o">=</span> <span class="n">bits</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">&gt;&gt;</span> <span class="p">(</span><span class="n">DataMessageFactory</span><span class="o">.</span><span class="n">SEQUENCE_BITS</span> <span class="o">+</span> <span class="n">DataMessageFactory</span><span class="o">.</span><span class="n">MACHINE_ID_BITS</span><span class="p">)</span>
<span class="n">high</span> <span class="o">=</span> <span class="n">bits</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">&lt;&lt;</span> <span class="p">(</span>
<span class="mi">64</span> <span class="o">-</span> <span class="n">DataMessageFactory</span><span class="o">.</span><span class="n">SEQUENCE_BITS</span> <span class="o">-</span> <span class="n">DataMessageFactory</span><span class="o">.</span><span class="n">MACHINE_ID_BITS</span>
<span class="p">)</span>
<span class="k">return</span> <span class="p">(</span><span class="n">high</span> <span class="o">|</span> <span class="n">low</span><span class="p">)</span> <span class="o">+</span> <span class="n">DataMessageFactory</span><span class="o">.</span><span class="n">snowflake_epoch</span> <span class="o">*</span> <span class="mi">1000</span></div>
<div class="viewcode-block" id="DataMessageFactory.to_string">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.data_message_factory.DataMessageFactory.to_string">[docs]</a>
<span class="nd">@staticmethod</span>
<span class="k">def</span><span class="w"> </span><span class="nf">to_string</span><span class="p">(</span><span class="n">message</span><span class="p">:</span> <span class="n">DataMessage</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Human-readable representation.</span>
<span class="sd"> :param message: DataMessage input</span>
<span class="sd"> :return: as string</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;DataMessage</span><span class="se">{{</span><span class="s2">&quot;</span>
<span class="sa">f</span><span class="s2">&quot;id=</span><span class="si">{</span><span class="n">message</span><span class="o">.</span><span class="n">id</span><span class="p">()</span><span class="si">}</span><span class="s2">, &quot;</span>
<span class="sa">f</span><span class="s2">&quot;method=&#39;</span><span class="si">{</span><span class="n">message</span><span class="o">.</span><span class="n">method</span><span class="p">()</span><span class="si">}</span><span class="s2">&#39;, &quot;</span>
<span class="sa">f</span><span class="s2">&quot;domain=&#39;</span><span class="si">{</span><span class="n">message</span><span class="o">.</span><span class="n">domain</span><span class="p">()</span><span class="si">}</span><span class="s2">&#39;, &quot;</span>
<span class="sa">f</span><span class="s2">&quot;path=&#39;</span><span class="si">{</span><span class="n">message</span><span class="o">.</span><span class="n">path</span><span class="p">()</span><span class="si">}</span><span class="s2">&#39;, &quot;</span>
<span class="sa">f</span><span class="s2">&quot;headers=</span><span class="se">{{</span><span class="si">{</span><span class="n">map_with_list_as_string</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">headers</span><span class="p">())</span><span class="si">}</span><span class="se">}}</span><span class="s2">, &quot;</span>
<span class="sa">f</span><span class="s2">&quot;traceInfo=</span><span class="se">{{</span><span class="si">{</span><span class="n">map_as_string</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">trace_info</span><span class="p">())</span><span class="si">}</span><span class="se">}}</span><span class="s2">, &quot;</span>
<span class="sa">f</span><span class="s2">&quot;base64body=</span><span class="si">{</span><span class="n">message</span><span class="o">.</span><span class="n">base64body</span><span class="p">()</span><span class="o">.</span><span class="n">decode</span><span class="p">()</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="sa">f</span><span class="s2">&quot;</span><span class="se">}}</span><span class="s2">&quot;</span>
<span class="p">)</span></div>
<div class="viewcode-block" id="DataMessageFactory.serialize">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.data_message_factory.DataMessageFactory.serialize">[docs]</a>
<span class="nd">@staticmethod</span>
<span class="k">def</span><span class="w"> </span><span class="nf">serialize</span><span class="p">(</span><span class="n">message</span><span class="p">:</span> <span class="n">DataMessage</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bytes</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Converts DataMessage to byte array</span>
<span class="sd"> :param message: message to serialize</span>
<span class="sd"> :return: messages as bytes</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">id_bytes</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">id</span><span class="p">())</span><span class="o">.</span><span class="n">encode</span><span class="p">()</span>
<span class="n">prolog</span> <span class="o">=</span> <span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;|m=</span><span class="si">{</span><span class="n">message</span><span class="o">.</span><span class="n">method</span><span class="p">()</span><span class="si">}</span><span class="s2">|d=</span><span class="si">{</span><span class="n">message</span><span class="o">.</span><span class="n">domain</span><span class="p">()</span><span class="si">}</span><span class="s2">|p=</span><span class="si">{</span><span class="n">message</span><span class="o">.</span><span class="n">path</span><span class="p">()</span><span class="si">}</span><span class="s2">|h=</span><span class="se">{{</span><span class="si">{</span><span class="n">map_with_list_as_string</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">headers</span><span class="p">())</span><span class="si">}</span><span class="se">}}</span><span class="s2">|t=</span><span class="se">{{</span><span class="si">{</span><span class="n">map_as_string</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">trace_info</span><span class="p">())</span><span class="si">}</span><span class="se">}}</span><span class="s2">|b=&quot;</span>
<span class="p">)</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s2">&quot;utf-8&quot;</span><span class="p">)</span>
<span class="n">header_length</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">+</span> <span class="nb">len</span><span class="p">(</span><span class="n">id_bytes</span><span class="p">)</span> <span class="o">+</span> <span class="nb">len</span><span class="p">(</span><span class="n">prolog</span><span class="p">)</span>
<span class="n">prolog_len</span> <span class="o">=</span> <span class="n">header_length</span><span class="o">.</span><span class="n">to_bytes</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="n">byteorder</span><span class="o">=</span><span class="s2">&quot;big&quot;</span><span class="p">)</span>
<span class="n">msg_length</span> <span class="o">=</span> <span class="mi">2</span> <span class="o">+</span> <span class="n">header_length</span> <span class="o">+</span> <span class="nb">len</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">base64body</span><span class="p">())</span>
<span class="n">baos</span> <span class="o">=</span> <span class="n">BytesIO</span><span class="p">(</span><span class="nb">bytearray</span><span class="p">(</span><span class="n">msg_length</span><span class="p">))</span>
<span class="n">baos</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">prolog_len</span><span class="p">)</span>
<span class="n">baos</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">magic</span><span class="p">()</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s2">&quot;utf-8&quot;</span><span class="p">))</span>
<span class="n">baos</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">id_bytes</span><span class="p">)</span>
<span class="n">baos</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">prolog</span><span class="p">)</span>
<span class="n">baos</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">base64body</span><span class="p">())</span>
<span class="k">return</span> <span class="n">baos</span><span class="o">.</span><span class="n">getvalue</span><span class="p">()</span></div>
<div class="viewcode-block" id="DataMessageFactory.from_bytes">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.data_message_factory.DataMessageFactory.from_bytes">[docs]</a>
<span class="nd">@staticmethod</span>
<span class="k">def</span><span class="w"> </span><span class="nf">from_bytes</span><span class="p">(</span><span class="n">input_bytes</span><span class="p">:</span> <span class="nb">bytes</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">DataMessage</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Builds the DataMessage from its serialized (byte array) form.</span>
<span class="sd"> :param input_bytes: serialized message</span>
<span class="sd"> :return: DataMessage instance</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">prolog_len</span> <span class="o">=</span> <span class="p">(</span><span class="n">input_bytes</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">&lt;&lt;</span> <span class="mi">8</span><span class="p">)</span> <span class="o">+</span> <span class="n">input_bytes</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="n">metadata</span> <span class="o">=</span> <span class="n">input_bytes</span><span class="p">[</span><span class="mi">2</span> <span class="p">:</span> <span class="n">prolog_len</span> <span class="o">+</span> <span class="mi">2</span><span class="p">]</span><span class="o">.</span><span class="n">decode</span><span class="p">()</span>
<span class="n">pattern</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span>
<span class="sa">r</span><span class="s2">&quot;([AR])&quot;</span>
<span class="sa">r</span><span class="s2">&quot;([0-9A-Fa-f]+)\|&quot;</span>
<span class="sa">r</span><span class="s2">&quot;m=([^|]*)\|&quot;</span>
<span class="sa">r</span><span class="s2">&quot;d=([^|]*)\|&quot;</span>
<span class="sa">r</span><span class="s2">&quot;p=([^|]*)\|&quot;</span>
<span class="sa">r</span><span class="s2">&quot;h=(\{[^}]*\})\|&quot;</span>
<span class="sa">r</span><span class="s2">&quot;t=(\{[^}]*\})\|&quot;</span>
<span class="sa">r</span><span class="s2">&quot;b=&quot;</span>
<span class="p">)</span>
<span class="n">match</span> <span class="o">=</span> <span class="n">pattern</span><span class="o">.</span><span class="n">match</span><span class="p">(</span><span class="n">metadata</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">match</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;DataMessage format does not match expected format. &quot;</span>
<span class="sa">f</span><span class="s2">&quot;Input string [</span><span class="si">{</span><span class="n">metadata</span><span class="si">}</span><span class="s2">] does not match pattern: </span><span class="si">{</span><span class="n">pattern</span><span class="o">.</span><span class="n">pattern</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="p">)</span>
<span class="n">id_str</span> <span class="o">=</span> <span class="n">match</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="n">method</span> <span class="o">=</span> <span class="n">match</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>
<span class="n">domain</span> <span class="o">=</span> <span class="n">match</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span>
<span class="n">path</span> <span class="o">=</span> <span class="n">match</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span>
<span class="n">headers_str</span> <span class="o">=</span> <span class="n">match</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">6</span><span class="p">)</span>
<span class="n">trace_info_str</span> <span class="o">=</span> <span class="n">match</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">7</span><span class="p">)</span>
<span class="n">body_b64</span> <span class="o">=</span> <span class="n">input_bytes</span><span class="p">[</span><span class="n">prolog_len</span> <span class="o">+</span> <span class="mi">2</span> <span class="p">:]</span>
<span class="n">headers</span> <span class="o">=</span> <span class="n">parse_map_list_string</span><span class="p">(</span><span class="n">headers_str</span><span class="p">)</span>
<span class="n">trace_info</span> <span class="o">=</span> <span class="n">parse_map_string</span><span class="p">(</span><span class="n">trace_info_str</span><span class="p">)</span>
<span class="k">return</span> <span class="n">DataMessage</span><span class="p">(</span>
<span class="k">match</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">1</span><span class="p">),</span> <span class="c1"># Magic byte (R for RPC, A for HTTP)</span>
<span class="n">SnowflakeId</span><span class="o">.</span><span class="n">from_hex</span><span class="p">(</span><span class="n">id_str</span><span class="p">),</span>
<span class="n">method</span><span class="p">,</span>
<span class="n">domain</span><span class="p">,</span>
<span class="n">path</span><span class="p">,</span>
<span class="n">headers</span><span class="p">,</span>
<span class="n">trace_info</span><span class="p">,</span>
<span class="n">body_b64</span><span class="p">,</span>
<span class="p">)</span></div>
<div class="viewcode-block" id="DataMessageFactory.from_stream">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.data_message_factory.DataMessageFactory.from_stream">[docs]</a>
<span class="nd">@staticmethod</span>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">from_stream</span><span class="p">(</span>
<span class="n">stream</span><span class="p">:</span> <span class="nb">bytes</span><span class="p">,</span>
<span class="n">rabbitmq_url</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
<span class="n">loop</span><span class="p">,</span>
<span class="n">file_handler</span><span class="p">:</span> <span class="n">FileHandler</span> <span class="o">=</span> <span class="n">StreamingFileHandler</span><span class="p">(),</span>
<span class="p">)</span> <span class="o">-&gt;</span> <span class="n">DataMessage</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Builds the DataMessage from its serialized (byte array) form.</span>
<span class="sd"> :param stream: serialized message</span>
<span class="sd"> :param rabbitmq_url: RabbitMQ connection URL</span>
<span class="sd"> :param loop: event loop</span>
<span class="sd"> :param file_handler: file handler for downloading the message</span>
<span class="sd"> :return: DataMessage instance</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="c1"># async implementation</span>
<span class="n">_message_data</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">stream</span><span class="o">.</span><span class="n">decode</span><span class="p">())</span>
<span class="n">_req_info</span> <span class="o">=</span> <span class="n">_message_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;req-info&quot;</span><span class="p">,</span> <span class="s2">&quot;&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="n">_req_info</span><span class="p">:</span>
<span class="p">(</span><span class="n">body</span><span class="p">,</span> <span class="n">eof</span><span class="p">)</span> <span class="o">=</span> <span class="k">await</span> <span class="n">file_handler</span><span class="o">.</span><span class="n">download_buffer</span><span class="p">(</span>
<span class="n">loop</span><span class="o">=</span><span class="n">loop</span><span class="p">,</span> <span class="n">rabbitmq_url</span><span class="o">=</span><span class="n">rabbitmq_url</span><span class="p">,</span> <span class="n">queue_name</span><span class="o">=</span><span class="n">_req_info</span>
<span class="p">)</span>
<span class="k">if</span> <span class="n">eof</span> <span class="o">==</span> <span class="n">amqp</span><span class="o">.</span><span class="n">adapter</span><span class="o">.</span><span class="n">file_handler</span><span class="o">.</span><span class="n">END_OF_FILE</span><span class="p">:</span>
<span class="k">return</span> <span class="n">DataMessageFactory</span><span class="o">.</span><span class="n">from_bytes</span><span class="p">(</span><span class="n">body</span><span class="p">)</span>
<span class="k">return</span> <span class="kc">None</span></div>
</div>
</pre></div>
</div>
</div>
<footer>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2024, CleverThis.</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>
@@ -0,0 +1,325 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" data-content_root="../../../">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>amqp.adapter.data_parser &mdash; AMQ Adapter Python 1.0 documentation</title>
<link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=03e43079" />
<link rel="stylesheet" type="text/css" href="../../../_static/css/theme.css?v=e59714d7" />
<script src="../../../_static/jquery.js?v=5d32c60e"></script>
<script src="../../../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
<script src="../../../_static/documentation_options.js?v=f2a433a1"></script>
<script src="../../../_static/doctools.js?v=9bcbadda"></script>
<script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
<script src="../../../_static/js/theme.js"></script>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="../../../index.html" class="icon icon-home">
AMQ Adapter Python
</a>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" aria-label="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.html">AMQP Package</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.config.html">Configuration Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.adapter.html">Adapter Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.service.html">Service Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.router.html">Router Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.model.html">Model Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.rabbitmq.html">RabbitMQ Module</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="../../../index.html">AMQ Adapter Python</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="../../../index.html" class="icon icon-home" aria-label="Home"></a></li>
<li class="breadcrumb-item"><a href="../../index.html">Module code</a></li>
<li class="breadcrumb-item active">amqp.adapter.data_parser</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<h1>Source code for amqp.adapter.data_parser</h1><div class="highlight"><pre>
<span></span><span class="kn">import</span><span class="w"> </span><span class="nn">io</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">json</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Dict</span><span class="p">,</span> <span class="n">Tuple</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">urllib.parse</span><span class="w"> </span><span class="kn">import</span> <span class="n">parse_qs</span><span class="p">,</span> <span class="n">urlparse</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">xml.etree</span><span class="w"> </span><span class="kn">import</span> <span class="n">ElementTree</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">python_multipart</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">fastapi</span><span class="w"> </span><span class="kn">import</span> <span class="n">UploadFile</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">python_multipart.multipart</span><span class="w"> </span><span class="kn">import</span> <span class="n">Field</span><span class="p">,</span> <span class="n">File</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.adapter.logging_utils</span><span class="w"> </span><span class="kn">import</span> <span class="n">logging_debug</span><span class="p">,</span> <span class="n">logging_error</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.model.model</span><span class="w"> </span><span class="kn">import</span> <span class="n">AMQMessage</span>
<div class="viewcode-block" id="MultipartFormDataParser">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.data_parser.MultipartFormDataParser">[docs]</a>
<span class="k">class</span><span class="w"> </span><span class="nc">MultipartFormDataParser</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Parses multipart/form-data content and extracts form fields (key/value pairs) and files.</span>
<span class="sd"> Note: multipart message that contains file(s) to upload are converted to CleverMicro JSON-based streaming format,</span>
<span class="sd"> where files are transmitted separately via stream using dedicated queue, so the message content is no longer</span>
<span class="sd"> the HTTP multipart format, but the Content-Type is being preserved for compatibility with the original message.</span>
<span class="sd"> This class supports both formats (multipart and JSON) depending on the message content, because if no file is</span>
<span class="sd"> included, the message is transmitted in the unchanged multipart/form-data format.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<div class="viewcode-block" id="MultipartFormDataParser.__init__">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.data_parser.MultipartFormDataParser.__init__">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">AMQMessage</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">form_data</span><span class="p">:</span> <span class="nb">dict</span> <span class="o">=</span> <span class="p">{}</span>
<span class="bp">self</span><span class="o">.</span><span class="n">is_multipart</span> <span class="o">=</span> <span class="kc">False</span>
<span class="bp">self</span><span class="o">.</span><span class="n">is_json</span> <span class="o">=</span> <span class="kc">False</span>
<span class="bp">self</span><span class="o">.</span><span class="n">is_valid</span> <span class="o">=</span> <span class="kc">True</span>
<span class="c1"># Convert each list of strings to a single string joined by newline, then to bytes</span>
<span class="n">_headers</span> <span class="o">=</span> <span class="p">{</span>
<span class="n">key</span><span class="p">:</span> <span class="s2">&quot;</span><span class="se">\n</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">value</span><span class="p">)</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s2">&quot;utf-8&quot;</span><span class="p">)</span> <span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">message</span><span class="o">.</span><span class="n">headers</span><span class="p">()</span><span class="o">.</span><span class="n">items</span><span class="p">()</span>
<span class="p">}</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">if</span> <span class="p">(</span>
<span class="nb">hasattr</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="s2">&quot;extra_data&quot;</span><span class="p">)</span>
<span class="ow">and</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">extra_data</span><span class="p">,</span> <span class="nb">dict</span><span class="p">)</span>
<span class="ow">and</span> <span class="nb">len</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">extra_data</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span>
<span class="p">):</span>
<span class="k">try</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">form_data</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">body</span><span class="p">())</span>
<span class="bp">self</span><span class="o">.</span><span class="n">is_json</span> <span class="o">=</span> <span class="kc">True</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">form_data</span><span class="p">[</span><span class="s2">&quot;files&quot;</span><span class="p">]</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">form_data</span><span class="p">[</span><span class="s2">&quot;form&quot;</span><span class="p">]</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">form_data</span> <span class="o">=</span> <span class="n">AMQDataParser</span><span class="o">.</span><span class="n">process_form_data</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">form_data</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">jsonerror</span><span class="p">:</span>
<span class="n">logging_error</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Parsing JSON: </span><span class="si">{</span><span class="n">jsonerror</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">is_valid</span> <span class="o">=</span> <span class="kc">False</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">python_multipart</span><span class="o">.</span><span class="n">parse_form</span><span class="p">(</span>
<span class="n">_headers</span><span class="p">,</span> <span class="n">io</span><span class="o">.</span><span class="n">BytesIO</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">body</span><span class="p">()),</span> <span class="bp">self</span><span class="o">.</span><span class="n">on_field</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">on_file</span>
<span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">is_multipart</span> <span class="o">=</span> <span class="kc">True</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="n">__error</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;Error parsing multipart/form-data: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">. Trying parsing as JSON.&quot;</span>
<span class="k">try</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">form_data</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">body</span><span class="p">())</span>
<span class="bp">self</span><span class="o">.</span><span class="n">is_json</span> <span class="o">=</span> <span class="kc">True</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">form_data</span><span class="p">[</span><span class="s2">&quot;files&quot;</span><span class="p">]</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">form_data</span><span class="p">[</span><span class="s2">&quot;form&quot;</span><span class="p">]</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">form_data</span> <span class="o">=</span> <span class="n">AMQDataParser</span><span class="o">.</span><span class="n">process_form_data</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">form_data</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">jsonerror</span><span class="p">:</span>
<span class="n">logging_error</span><span class="p">(</span><span class="n">__error</span><span class="p">)</span>
<span class="n">logging_error</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Parsing JSON: </span><span class="si">{</span><span class="n">jsonerror</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">is_valid</span> <span class="o">=</span> <span class="kc">False</span></div>
<div class="viewcode-block" id="MultipartFormDataParser.on_field">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.data_parser.MultipartFormDataParser.on_field">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">on_field</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">field</span><span class="p">:</span> <span class="n">Field</span><span class="p">):</span>
<span class="n">logging_debug</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">field</span><span class="p">))</span>
<span class="bp">self</span><span class="o">.</span><span class="n">form_data</span><span class="p">[</span><span class="n">field</span><span class="o">.</span><span class="n">field_name</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s2">&quot;utf-8&quot;</span><span class="p">)]</span> <span class="o">=</span> <span class="n">field</span><span class="o">.</span><span class="n">value</span></div>
<div class="viewcode-block" id="MultipartFormDataParser.on_file">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.data_parser.MultipartFormDataParser.on_file">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">on_file</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">file</span><span class="p">:</span> <span class="n">File</span><span class="p">):</span>
<span class="n">logging_debug</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">file</span><span class="p">))</span>
<span class="n">file</span><span class="o">.</span><span class="n">file_object</span><span class="o">.</span><span class="n">seek</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">form_data</span><span class="p">[</span><span class="n">file</span><span class="o">.</span><span class="n">field_name</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s2">&quot;utf-8&quot;</span><span class="p">)]</span> <span class="o">=</span> <span class="n">UploadFile</span><span class="p">(</span>
<span class="n">file</span><span class="o">.</span><span class="n">file_object</span><span class="p">,</span> <span class="n">size</span><span class="o">=</span><span class="n">file</span><span class="o">.</span><span class="n">size</span><span class="p">,</span> <span class="n">filename</span><span class="o">=</span><span class="n">file</span><span class="o">.</span><span class="n">file_name</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s2">&quot;utf-8&quot;</span><span class="p">)</span>
<span class="p">)</span></div>
</div>
<div class="viewcode-block" id="AMQDataParser">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.data_parser.AMQDataParser">[docs]</a>
<span class="k">class</span><span class="w"> </span><span class="nc">AMQDataParser</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> A class for parsing AMQ data messages. It provides methods to parse form data,</span>
<span class="sd"> &quot;&quot;&quot;</span>
<div class="viewcode-block" id="AMQDataParser.process_form_data">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.data_parser.AMQDataParser.process_form_data">[docs]</a>
<span class="nd">@staticmethod</span>
<span class="k">def</span><span class="w"> </span><span class="nf">process_form_data</span><span class="p">(</span><span class="n">json_input</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">dict</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Processes the input JSON to extract form data. The JSON has two top entries: &#39;files&#39; and &#39;form&#39;.</span>
<span class="sd"> This is part of the file stream implementation in AMQ adapter to stream large files in chunks.</span>
<span class="sd"> &#39;files&#39; contains information about the AMQ queue from which read the file, while &#39;form&#39; contains</span>
<span class="sd"> additional non-file form values.</span>
<span class="sd"> This function combines the file and values at the top level in the returned dictionary.</span>
<span class="sd"> Args:</span>
<span class="sd"> json_input: JSON string or dict containing the form and files data</span>
<span class="sd"> Returns:</span>
<span class="sd"> dict: Processed form data with files data overriding non-empty values</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="c1"># Load JSON if input is string</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">json_input</span><span class="p">,</span> <span class="nb">str</span><span class="p">):</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">json_input</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">json_input</span>
<span class="n">result</span> <span class="o">=</span> <span class="p">{}</span>
<span class="c1"># Process form data - take first element of each list</span>
<span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">data</span><span class="p">[</span><span class="s2">&quot;form&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
<span class="k">if</span> <span class="n">value</span><span class="p">:</span> <span class="c1"># Only process if list is not empty</span>
<span class="n">result</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="c1"># Override with files data where available</span>
<span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">data</span><span class="p">[</span><span class="s2">&quot;files&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
<span class="k">if</span> <span class="n">value</span><span class="p">:</span> <span class="c1"># Only override if files data is non-empty</span>
<span class="n">result</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="k">return</span> <span class="n">result</span></div>
<div class="viewcode-block" id="AMQDataParser.parse_get_url">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.data_parser.AMQDataParser.parse_get_url">[docs]</a>
<span class="nd">@staticmethod</span>
<span class="k">def</span><span class="w"> </span><span class="nf">parse_get_url</span><span class="p">(</span><span class="n">url</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Tuple</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">str</span><span class="p">]]:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Parses an HTTP GET URL and returns (context_path, query_params_dict)</span>
<span class="sd"> Args:</span>
<span class="sd"> url: The URL string to parse (e.g., &quot;http://example.com/path?foo=1&amp;bar=2&amp;foo=3&quot;)</span>
<span class="sd"> Returns:</span>
<span class="sd"> tuple: (context_path, query_params_dict)</span>
<span class="sd"> - context_path: The path part of the URL (e.g., &quot;/path&quot;)</span>
<span class="sd"> - query_params_dict: Query parameters where values are str for single value or list of str for multivalue</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">_parsed</span> <span class="o">=</span> <span class="n">urlparse</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
<span class="n">_query_params</span> <span class="o">=</span> <span class="n">parse_qs</span><span class="p">(</span><span class="n">_parsed</span><span class="o">.</span><span class="n">query</span><span class="p">)</span>
<span class="c1"># Convert values from lists to single values when there&#39;s only one value</span>
<span class="n">_simplified_params</span> <span class="o">=</span> <span class="p">{</span><span class="n">k</span><span class="p">:</span> <span class="n">v</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">v</span><span class="p">)</span> <span class="o">==</span> <span class="mi">1</span> <span class="k">else</span> <span class="n">v</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">_query_params</span><span class="o">.</span><span class="n">items</span><span class="p">()}</span>
<span class="k">return</span> <span class="n">_parsed</span><span class="o">.</span><span class="n">path</span><span class="p">,</span> <span class="n">_simplified_params</span></div>
<div class="viewcode-block" id="AMQDataParser.parse_request_body">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.data_parser.AMQDataParser.parse_request_body">[docs]</a>
<span class="nd">@staticmethod</span>
<span class="k">def</span><span class="w"> </span><span class="nf">parse_request_body</span><span class="p">(</span><span class="n">message</span><span class="p">:</span> <span class="n">AMQMessage</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Parses the HTTP POST request body based on the MIME type.</span>
<span class="sd"> This is typically called fom the concrete CleverThis Service to extract parameters from the message body.</span>
<span class="sd"> Args:</span>
<span class="sd"> message (DataMessage): Contains raw request and MIME headers.</span>
<span class="sd"> Returns:</span>
<span class="sd"> dict: Parsed data as a dictionary.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">_content_type</span> <span class="o">=</span> <span class="n">message</span><span class="o">.</span><span class="n">headers</span><span class="p">()</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;Content-Type&quot;</span><span class="p">,</span> <span class="s2">&quot;&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">_content_type</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">&quot;Content-Type header is required&quot;</span><span class="p">)</span>
<span class="n">content_type</span> <span class="o">=</span> <span class="n">_content_type</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="c1"># Parse JSON</span>
<span class="k">if</span> <span class="n">content_type</span> <span class="o">==</span> <span class="s2">&quot;application/json&quot;</span><span class="p">:</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">return</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">body</span><span class="p">()</span> <span class="ow">or</span> <span class="s2">&quot;</span><span class="si">{}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">except</span> <span class="n">json</span><span class="o">.</span><span class="n">JSONDecodeError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="n">logging_error</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Invalid JSON: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Invalid JSON: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="c1"># Parse URL-encoded form data</span>
<span class="k">elif</span> <span class="n">content_type</span> <span class="o">==</span> <span class="s2">&quot;application/x-www-form-urlencoded&quot;</span><span class="p">:</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">_form_data</span><span class="p">:</span> <span class="nb">dict</span> <span class="o">=</span> <span class="p">{</span>
<span class="n">k</span><span class="p">:</span> <span class="n">v</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">v</span><span class="p">)</span> <span class="o">==</span> <span class="mi">1</span> <span class="k">else</span> <span class="n">v</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">parse_qs</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">body</span><span class="p">())</span><span class="o">.</span><span class="n">items</span><span class="p">()</span>
<span class="p">}</span>
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">_form_data</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span> <span class="ow">and</span> <span class="nb">len</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">body</span><span class="p">())</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
<span class="n">_form_data</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">body</span><span class="p">())</span>
<span class="k">if</span> <span class="n">_form_data</span><span class="p">[</span><span class="s2">&quot;files&quot;</span><span class="p">]</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="ow">and</span> <span class="n">_form_data</span><span class="p">[</span><span class="s2">&quot;form&quot;</span><span class="p">]</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">_form_data</span> <span class="o">=</span> <span class="n">AMQDataParser</span><span class="o">.</span><span class="n">process_form_data</span><span class="p">(</span><span class="n">_form_data</span><span class="p">)</span>
<span class="k">return</span> <span class="n">_form_data</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="n">logging_error</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Invalid URL-encoded form data: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Invalid URL-encoded form data: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="c1"># Parse multipart/form-data</span>
<span class="k">elif</span> <span class="n">content_type</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&quot;multipart/form-data&quot;</span><span class="p">):</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">parser</span><span class="p">:</span> <span class="n">MultipartFormDataParser</span> <span class="o">=</span> <span class="n">MultipartFormDataParser</span><span class="p">(</span><span class="n">message</span><span class="p">)</span>
<span class="k">return</span> <span class="n">parser</span><span class="o">.</span><span class="n">form_data</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="n">logging_error</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Invalid multipart/form-data: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Invalid multipart/form-data: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="c1"># Parse plain text</span>
<span class="k">elif</span> <span class="n">content_type</span> <span class="o">==</span> <span class="s2">&quot;text/plain&quot;</span><span class="p">:</span>
<span class="k">return</span> <span class="p">{</span><span class="s2">&quot;text&quot;</span><span class="p">:</span> <span class="n">message</span><span class="o">.</span><span class="n">body</span><span class="p">()}</span>
<span class="c1"># Parse XML</span>
<span class="k">elif</span> <span class="n">content_type</span> <span class="o">==</span> <span class="s2">&quot;application/xml&quot;</span><span class="p">:</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">_root</span> <span class="o">=</span> <span class="n">ElementTree</span><span class="o">.</span><span class="n">fromstring</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">body</span><span class="p">())</span>
<span class="k">return</span> <span class="p">{</span><span class="n">elem</span><span class="o">.</span><span class="n">tag</span><span class="p">:</span> <span class="n">elem</span><span class="o">.</span><span class="n">text</span> <span class="k">for</span> <span class="n">elem</span> <span class="ow">in</span> <span class="n">_root</span><span class="p">}</span>
<span class="k">except</span> <span class="n">ElementTree</span><span class="o">.</span><span class="n">ParseError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Invalid XML: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Unsupported Content-Type: </span><span class="si">{</span><span class="n">content_type</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span></div>
</div>
</pre></div>
</div>
</div>
<footer>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2024, CleverThis.</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>
@@ -0,0 +1,276 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" data-content_root="../../../">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>amqp.adapter.data_response_factory &mdash; AMQ Adapter Python 1.0 documentation</title>
<link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=03e43079" />
<link rel="stylesheet" type="text/css" href="../../../_static/css/theme.css?v=e59714d7" />
<script src="../../../_static/jquery.js?v=5d32c60e"></script>
<script src="../../../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
<script src="../../../_static/documentation_options.js?v=f2a433a1"></script>
<script src="../../../_static/doctools.js?v=9bcbadda"></script>
<script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
<script src="../../../_static/js/theme.js"></script>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="../../../index.html" class="icon icon-home">
AMQ Adapter Python
</a>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" aria-label="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.html">AMQP Package</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.config.html">Configuration Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.adapter.html">Adapter Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.service.html">Service Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.router.html">Router Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.model.html">Model Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.rabbitmq.html">RabbitMQ Module</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="../../../index.html">AMQ Adapter Python</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="../../../index.html" class="icon icon-home" aria-label="Home"></a></li>
<li class="breadcrumb-item"><a href="../../index.html">Module code</a></li>
<li class="breadcrumb-item active">amqp.adapter.data_response_factory</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<h1>Source code for amqp.adapter.data_response_factory</h1><div class="highlight"><pre>
<span></span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">method to create, serialize and deserialize DataResponse message</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">base64</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">re</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">io</span><span class="w"> </span><span class="kn">import</span> <span class="n">BytesIO</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.adapter.serializer</span><span class="w"> </span><span class="kn">import</span> <span class="n">map_as_string</span><span class="p">,</span> <span class="n">parse_map_string</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.model.model</span><span class="w"> </span><span class="kn">import</span> <span class="n">AMQErrorMessage</span><span class="p">,</span> <span class="n">DataMessageMagicByte</span><span class="p">,</span> <span class="n">DataResponse</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.model.snowflake_id</span><span class="w"> </span><span class="kn">import</span> <span class="n">SnowflakeId</span>
<div class="viewcode-block" id="DataResponseFactory">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.data_response_factory.DataResponseFactory">[docs]</a>
<span class="k">class</span><span class="w"> </span><span class="nc">DataResponseFactory</span><span class="p">:</span>
<div class="viewcode-block" id="DataResponseFactory.create_async_response_message">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.data_response_factory.DataResponseFactory.create_async_response_message">[docs]</a>
<span class="nd">@staticmethod</span>
<span class="k">def</span><span class="w"> </span><span class="nf">create_async_response_message</span><span class="p">(</span><span class="n">_id</span><span class="p">:</span> <span class="n">SnowflakeId</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">DataResponse</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Helper method to create standard OK response.</span>
<span class="sd"> :param _id: ID</span>
<span class="sd"> :return: Response message</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="n">DataResponseFactory</span><span class="o">.</span><span class="n">of</span><span class="p">(</span>
<span class="nb">id</span><span class="o">=</span><span class="n">_id</span><span class="p">,</span>
<span class="n">response_code</span><span class="o">=</span><span class="mi">200</span><span class="p">,</span>
<span class="n">content_type</span><span class="o">=</span><span class="s2">&quot;application/text&quot;</span><span class="p">,</span>
<span class="n">body</span><span class="o">=</span><span class="s2">&quot;OK&quot;</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s2">&quot;utf-8&quot;</span><span class="p">),</span>
<span class="n">trace_info</span><span class="o">=</span><span class="p">{},</span>
<span class="n">error</span><span class="o">=</span><span class="s2">&quot;&quot;</span><span class="p">,</span>
<span class="n">error_cause</span><span class="o">=</span><span class="s2">&quot;&quot;</span><span class="p">,</span>
<span class="p">)</span></div>
<div class="viewcode-block" id="DataResponseFactory.of">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.data_response_factory.DataResponseFactory.of">[docs]</a>
<span class="nd">@staticmethod</span>
<span class="k">def</span><span class="w"> </span><span class="nf">of</span><span class="p">(</span>
<span class="nb">id</span><span class="p">:</span> <span class="n">SnowflakeId</span><span class="p">,</span>
<span class="n">response_code</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span>
<span class="n">content_type</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
<span class="n">body</span><span class="p">:</span> <span class="nb">bytes</span><span class="p">,</span>
<span class="n">trace_info</span><span class="p">:</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">str</span><span class="p">],</span>
<span class="n">error</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
<span class="n">error_cause</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
<span class="p">)</span> <span class="o">-&gt;</span> <span class="n">DataResponse</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Create the DataResponse message supplying all key values</span>
<span class="sd"> :param id: SnowflakeID</span>
<span class="sd"> :param response_code: HTTP response code</span>
<span class="sd"> :param content_type: MIME content type</span>
<span class="sd"> :param body: payload</span>
<span class="sd"> :param trace_info: Jaeger trace info (id)</span>
<span class="sd"> :return: DataResponseMessage object</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="n">DataResponse</span><span class="p">(</span>
<span class="n">magic</span><span class="o">=</span><span class="n">DataMessageMagicByte</span><span class="o">.</span><span class="n">HTTP_REQUEST</span><span class="o">.</span><span class="n">value</span><span class="p">,</span>
<span class="nb">id</span><span class="o">=</span><span class="nb">id</span><span class="p">,</span>
<span class="n">response_code</span><span class="o">=</span><span class="nb">str</span><span class="p">(</span><span class="n">response_code</span><span class="p">),</span>
<span class="n">content_type</span><span class="o">=</span><span class="n">content_type</span><span class="p">,</span>
<span class="n">error</span><span class="o">=</span><span class="n">error</span><span class="p">,</span>
<span class="n">error_cause</span><span class="o">=</span><span class="n">error_cause</span><span class="p">,</span>
<span class="n">headers</span><span class="o">=</span><span class="p">{},</span>
<span class="n">trace_info</span><span class="o">=</span><span class="n">trace_info</span><span class="p">,</span>
<span class="n">base64body</span><span class="o">=</span><span class="n">base64</span><span class="o">.</span><span class="n">b64encode</span><span class="p">(</span><span class="n">body</span><span class="p">),</span>
<span class="p">)</span></div>
<div class="viewcode-block" id="DataResponseFactory.of_error_message">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.data_response_factory.DataResponseFactory.of_error_message">[docs]</a>
<span class="nd">@staticmethod</span>
<span class="k">def</span><span class="w"> </span><span class="nf">of_error_message</span><span class="p">(</span>
<span class="nb">id</span><span class="p">:</span> <span class="n">SnowflakeId</span><span class="p">,</span>
<span class="n">error_message</span><span class="p">:</span> <span class="n">AMQErrorMessage</span><span class="p">,</span>
<span class="n">trace_info</span><span class="p">:</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">str</span><span class="p">],</span>
<span class="p">)</span> <span class="o">-&gt;</span> <span class="n">DataResponse</span><span class="p">:</span>
<span class="k">return</span> <span class="n">DataResponseFactory</span><span class="o">.</span><span class="n">of</span><span class="p">(</span>
<span class="nb">id</span><span class="o">=</span><span class="nb">id</span><span class="p">,</span>
<span class="n">response_code</span><span class="o">=</span><span class="n">error_message</span><span class="o">.</span><span class="n">response_code</span><span class="p">,</span>
<span class="n">content_type</span><span class="o">=</span><span class="n">error_message</span><span class="o">.</span><span class="n">content_type</span><span class="p">,</span>
<span class="n">body</span><span class="o">=</span><span class="n">error_message</span><span class="o">.</span><span class="n">serialize</span><span class="p">(),</span>
<span class="n">trace_info</span><span class="o">=</span><span class="n">trace_info</span><span class="p">,</span>
<span class="n">error</span><span class="o">=</span><span class="n">error_message</span><span class="o">.</span><span class="n">error</span><span class="p">,</span>
<span class="n">error_cause</span><span class="o">=</span><span class="n">error_message</span><span class="o">.</span><span class="n">detail</span><span class="p">,</span>
<span class="p">)</span></div>
<div class="viewcode-block" id="DataResponseFactory.serialize">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.data_response_factory.DataResponseFactory.serialize">[docs]</a>
<span class="nd">@staticmethod</span>
<span class="k">def</span><span class="w"> </span><span class="nf">serialize</span><span class="p">(</span><span class="n">response</span><span class="p">:</span> <span class="n">DataResponse</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bytes</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Serialize the message to byte array (to be sent over RabbitMQ)</span>
<span class="sd"> :param response: Object to serialize</span>
<span class="sd"> :return: byte array as serialized message</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">id_bytes</span> <span class="o">=</span> <span class="n">response</span><span class="o">.</span><span class="n">id</span><span class="p">()</span><span class="o">.</span><span class="n">as_string</span><span class="p">()</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s2">&quot;utf-8&quot;</span><span class="p">)</span>
<span class="n">prolog</span> <span class="o">=</span> <span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;|r=</span><span class="si">{</span><span class="n">response</span><span class="o">.</span><span class="n">response_code</span><span class="p">()</span><span class="si">}</span><span class="s2">|c=</span><span class="si">{</span><span class="n">response</span><span class="o">.</span><span class="n">content_type</span><span class="p">()</span><span class="si">}</span><span class="s2">|e=</span><span class="si">{</span><span class="n">response</span><span class="o">.</span><span class="n">error</span><span class="p">()</span><span class="si">}</span><span class="s2">|f=</span><span class="si">{</span><span class="n">response</span><span class="o">.</span><span class="n">error_cause</span><span class="p">()</span><span class="si">}</span><span class="s2">|t=</span><span class="se">{{</span><span class="si">{</span><span class="n">map_as_string</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">trace_info</span><span class="p">())</span><span class="si">}</span><span class="se">}}</span><span class="s2">|b=&quot;</span>
<span class="p">)</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s2">&quot;utf-8&quot;</span><span class="p">)</span>
<span class="n">header_length</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">+</span> <span class="nb">len</span><span class="p">(</span><span class="n">id_bytes</span><span class="p">)</span> <span class="o">+</span> <span class="nb">len</span><span class="p">(</span><span class="n">prolog</span><span class="p">)</span>
<span class="n">prolog_len</span> <span class="o">=</span> <span class="n">header_length</span><span class="o">.</span><span class="n">to_bytes</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="n">byteorder</span><span class="o">=</span><span class="s2">&quot;big&quot;</span><span class="p">)</span>
<span class="n">msg_length</span> <span class="o">=</span> <span class="mi">2</span> <span class="o">+</span> <span class="n">header_length</span> <span class="o">+</span> <span class="nb">len</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">base64body</span><span class="p">())</span>
<span class="k">with</span> <span class="n">BytesIO</span><span class="p">(</span><span class="nb">bytearray</span><span class="p">(</span><span class="n">msg_length</span><span class="p">))</span> <span class="k">as</span> <span class="n">baos</span><span class="p">:</span>
<span class="n">baos</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">prolog_len</span><span class="p">)</span>
<span class="n">baos</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">DataMessageMagicByte</span><span class="o">.</span><span class="n">HTTP_REQUEST</span><span class="o">.</span><span class="n">value</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s2">&quot;utf-8&quot;</span><span class="p">))</span>
<span class="n">baos</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">id_bytes</span><span class="p">)</span>
<span class="n">baos</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">prolog</span><span class="p">)</span>
<span class="n">baos</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">base64body</span><span class="p">())</span>
<span class="k">return</span> <span class="n">baos</span><span class="o">.</span><span class="n">getvalue</span><span class="p">()</span></div>
<div class="viewcode-block" id="DataResponseFactory.from_bytes">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.data_response_factory.DataResponseFactory.from_bytes">[docs]</a>
<span class="nd">@staticmethod</span>
<span class="k">def</span><span class="w"> </span><span class="nf">from_bytes</span><span class="p">(</span><span class="n">input_bytes</span><span class="p">:</span> <span class="nb">bytes</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">DataResponse</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Buil;ds the DataResponse object from its serialized form</span>
<span class="sd"> :param input_bytes: byte array - serialized response</span>
<span class="sd"> :return: DataResponse object</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">prolog_len</span> <span class="o">=</span> <span class="p">(</span><span class="n">input_bytes</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">&lt;&lt;</span> <span class="mi">8</span><span class="p">)</span> <span class="o">+</span> <span class="n">input_bytes</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="n">metadata</span> <span class="o">=</span> <span class="n">input_bytes</span><span class="p">[</span><span class="mi">2</span> <span class="p">:</span> <span class="n">prolog_len</span> <span class="o">+</span> <span class="mi">2</span><span class="p">]</span><span class="o">.</span><span class="n">decode</span><span class="p">()</span>
<span class="n">pattern</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">DataMessageMagicByte</span><span class="o">.</span><span class="n">HTTP_REQUEST</span><span class="o">.</span><span class="n">value</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="sa">r</span><span class="s2">&quot;([0-9A-Fa-f]+)\|&quot;</span>
<span class="sa">r</span><span class="s2">&quot;r=([^|]*)\|&quot;</span>
<span class="sa">r</span><span class="s2">&quot;c=([^|]*)\|&quot;</span>
<span class="sa">r</span><span class="s2">&quot;e=([^|]*)\|&quot;</span>
<span class="sa">r</span><span class="s2">&quot;f=([^|]*)\|&quot;</span>
<span class="sa">r</span><span class="s2">&quot;t=(\{[^}]*\})\|&quot;</span>
<span class="sa">r</span><span class="s2">&quot;b=&quot;</span>
<span class="p">)</span>
<span class="n">match</span> <span class="o">=</span> <span class="n">pattern</span><span class="o">.</span><span class="n">match</span><span class="p">(</span><span class="n">metadata</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">match</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;DataResponse format does not match expected format. &quot;</span>
<span class="sa">f</span><span class="s2">&quot;Input string [</span><span class="si">{</span><span class="n">metadata</span><span class="si">}</span><span class="s2">] does not match pattern: </span><span class="si">{</span><span class="n">pattern</span><span class="o">.</span><span class="n">pattern</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="p">)</span>
<span class="n">id_str</span> <span class="o">=</span> <span class="n">match</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="n">response_code</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">match</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">2</span><span class="p">))</span>
<span class="n">content_type</span> <span class="o">=</span> <span class="n">match</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>
<span class="n">error</span> <span class="o">=</span> <span class="n">match</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span>
<span class="n">error_cause</span> <span class="o">=</span> <span class="n">match</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span>
<span class="n">trace_info_str</span> <span class="o">=</span> <span class="n">match</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">6</span><span class="p">)</span>
<span class="n">body_b64</span> <span class="o">=</span> <span class="n">input_bytes</span><span class="p">[</span><span class="n">prolog_len</span> <span class="o">+</span> <span class="mi">2</span> <span class="p">:]</span>
<span class="n">trace_info</span> <span class="o">=</span> <span class="n">parse_map_string</span><span class="p">(</span><span class="n">trace_info_str</span><span class="p">)</span>
<span class="k">return</span> <span class="n">DataResponseFactory</span><span class="o">.</span><span class="n">of</span><span class="p">(</span>
<span class="n">id_str</span><span class="p">,</span>
<span class="n">response_code</span><span class="p">,</span>
<span class="n">content_type</span><span class="p">,</span>
<span class="n">base64</span><span class="o">.</span><span class="n">b64decode</span><span class="p">(</span><span class="n">body_b64</span><span class="p">),</span>
<span class="n">trace_info</span><span class="p">,</span>
<span class="n">error</span><span class="p">,</span>
<span class="n">error_cause</span><span class="p">,</span>
<span class="p">)</span></div>
</div>
<span class="c1"># Ensure backward compatibility</span>
<span class="n">AMQResponseFactory</span> <span class="o">=</span> <span class="n">DataResponseFactory</span>
</pre></div>
</div>
</div>
<footer>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2024, CleverThis.</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>
@@ -0,0 +1,561 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" data-content_root="../../../">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>amqp.adapter.file_handler &mdash; AMQ Adapter Python 1.0 documentation</title>
<link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=03e43079" />
<link rel="stylesheet" type="text/css" href="../../../_static/css/theme.css?v=e59714d7" />
<script src="../../../_static/jquery.js?v=5d32c60e"></script>
<script src="../../../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
<script src="../../../_static/documentation_options.js?v=f2a433a1"></script>
<script src="../../../_static/doctools.js?v=9bcbadda"></script>
<script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
<script src="../../../_static/js/theme.js"></script>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="../../../index.html" class="icon icon-home">
AMQ Adapter Python
</a>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" aria-label="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.html">AMQP Package</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.config.html">Configuration Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.adapter.html">Adapter Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.service.html">Service Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.router.html">Router Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.model.html">Model Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.rabbitmq.html">RabbitMQ Module</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="../../../index.html">AMQ Adapter Python</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="../../../index.html" class="icon icon-home" aria-label="Home"></a></li>
<li class="breadcrumb-item"><a href="../../index.html">Module code</a></li>
<li class="breadcrumb-item active">amqp.adapter.file_handler</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<h1>Source code for amqp.adapter.file_handler</h1><div class="highlight"><pre>
<span></span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">implements the file downloader for the amqp adapter, where file is sent in chunks over RabbitMQ</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">asyncio</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">json</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">logging</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">os</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">asyncio</span><span class="w"> </span><span class="kn">import</span> <span class="n">AbstractEventLoop</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">collections</span><span class="w"> </span><span class="kn">import</span> <span class="n">defaultdict</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">pathlib</span><span class="w"> </span><span class="kn">import</span> <span class="n">Path</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">aio_pika</span><span class="w"> </span><span class="kn">import</span> <span class="n">Message</span><span class="p">,</span> <span class="n">connect_robust</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">aio_pika.abc</span><span class="w"> </span><span class="kn">import</span> <span class="p">(</span>
<span class="n">AbstractExchange</span><span class="p">,</span>
<span class="n">AbstractIncomingMessage</span><span class="p">,</span>
<span class="n">AbstractQueue</span><span class="p">,</span>
<span class="n">AbstractRobustChannel</span><span class="p">,</span>
<span class="n">DeliveryMode</span><span class="p">,</span>
<span class="p">)</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.adapter.logging_utils</span><span class="w"> </span><span class="kn">import</span> <span class="n">logging_debug</span><span class="p">,</span> <span class="n">logging_error</span><span class="p">,</span> <span class="n">logging_info</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.router.utils</span><span class="w"> </span><span class="kn">import</span> <span class="n">await_result</span>
<span class="c1"># Global dictionary to track completed downloads</span>
<span class="n">download_locations</span> <span class="o">=</span> <span class="n">defaultdict</span><span class="p">(</span><span class="nb">str</span><span class="p">)</span>
<span class="n">IN_PROGRESS</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">END_OF_FILE</span> <span class="o">=</span> <span class="mi">1</span>
<span class="n">CANCELLED</span> <span class="o">=</span> <span class="mi">2</span>
<div class="viewcode-block" id="FileHandler">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.file_handler.FileHandler">[docs]</a>
<span class="k">class</span><span class="w"> </span><span class="nc">FileHandler</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> The abstract base class for file handling. This is mainly to make the code testable, as there are only 2</span>
<span class="sd"> options for pushing (uploading) a file(s) to a service: as HTTP multipart message delivered via RabbitMQ</span>
<span class="sd"> or via stream in RabbitMQ. Downloading a file is always done via RabbitMQ stream. Thus the method signiture</span>
<span class="sd"> is tighly coupled to the RabbitMQ API in v1. Only alternative implementation is a mock object in unittests.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<div class="viewcode-block" id="FileHandler.__init__">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.file_handler.FileHandler.__init__">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">pass</span></div>
<div class="viewcode-block" id="FileHandler.ensure_directory_exists">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.file_handler.FileHandler.ensure_directory_exists">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">ensure_directory_exists</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">filepath</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Ensures that the directory for the given filepath exists, and handles file versioning.</span>
<span class="sd"> Args:</span>
<span class="sd"> filepath: The path to the file.</span>
<span class="sd"> Returns:</span>
<span class="sd"> The original filepath if the file does not exist, or a modified filepath</span>
<span class="sd"> pointing to the next available version of the file if it does.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="c1"># 1. Ensure directory exists</span>
<span class="n">directory</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">dirname</span><span class="p">(</span><span class="n">filepath</span><span class="p">)</span>
<span class="k">if</span> <span class="n">directory</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">directory</span><span class="p">):</span>
<span class="n">os</span><span class="o">.</span><span class="n">makedirs</span><span class="p">(</span><span class="n">directory</span><span class="p">)</span>
<span class="c1"># 2. Handle file versioning</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">filepath</span><span class="p">):</span>
<span class="k">return</span> <span class="n">filepath</span> <span class="c1"># File doesn&#39;t exist, return original path</span>
<span class="c1"># File exists, find next available version</span>
<span class="n">base</span><span class="p">,</span> <span class="n">ext</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">splitext</span><span class="p">(</span><span class="n">filepath</span><span class="p">)</span>
<span class="n">version</span> <span class="o">=</span> <span class="mi">1</span>
<span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
<span class="n">new_filepath</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">base</span><span class="si">}</span><span class="s2">.</span><span class="si">{</span><span class="n">version</span><span class="si">}{</span><span class="n">ext</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">new_filepath</span><span class="p">):</span>
<span class="k">return</span> <span class="n">new_filepath</span> <span class="c1"># Found a free version, return this path</span>
<span class="n">version</span> <span class="o">+=</span> <span class="mi">1</span></div>
<div class="viewcode-block" id="FileHandler.download_buffer">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.file_handler.FileHandler.download_buffer">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">download_buffer</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">loop</span><span class="p">,</span> <span class="n">rabbitmq_url</span><span class="p">,</span> <span class="n">queue_name</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="p">(</span><span class="nb">bytearray</span><span class="p">,</span> <span class="nb">int</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Asynchronously downloads a bytearray from RabbitMQ based on the provided file information.</span>
<span class="sd"> It assumes entire array is in the first (and only) chunk</span>
<span class="sd"> Args:</span>
<span class="sd"> loop: The asyncio event loop.</span>
<span class="sd"> rabbitmq_url: The RabbitMQ connection URL.</span>
<span class="sd"> queue_name (str): The directory where the file should be saved.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">raise</span> <span class="ne">NotImplementedError</span><span class="p">(</span><span class="s2">&quot;Subclasses must implement this method.&quot;</span><span class="p">)</span></div>
<div class="viewcode-block" id="FileHandler.download_file">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.file_handler.FileHandler.download_file">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">download_file</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span> <span class="n">loop</span><span class="p">,</span> <span class="n">rabbitmq_url</span><span class="p">,</span> <span class="n">file_info</span><span class="p">,</span> <span class="n">message_data</span><span class="p">,</span> <span class="n">output_dir</span>
<span class="p">)</span> <span class="o">-&gt;</span> <span class="p">(</span><span class="nb">int</span><span class="p">,</span> <span class="nb">int</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Asynchronously downloads a file from RabbitMQ based on the provided file information.</span>
<span class="sd"> takes the file_info and message_data and output_dir, creates queue consumer and waits for the file</span>
<span class="sd"> to be downloaded. File may consist of multiple chunks, so the function will wait until all chunks are received.</span>
<span class="sd"> Args:</span>
<span class="sd"> loop: The asyncio event loop.</span>
<span class="sd"> rabbitmq_url: The RabbitMQ connection URL.</span>
<span class="sd"> file_info (dict): A dictionary containing file metadata</span>
<span class="sd"> message_data (dict): The entire message</span>
<span class="sd"> output_dir (str): The directory where the file should be saved.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">raise</span> <span class="ne">NotImplementedError</span><span class="p">(</span><span class="s2">&quot;Subclasses must implement this method.&quot;</span><span class="p">)</span></div>
<div class="viewcode-block" id="FileHandler.on_message">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.file_handler.FileHandler.on_message">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">on_message</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span>
<span class="n">message</span><span class="p">:</span> <span class="n">AbstractIncomingMessage</span><span class="p">,</span>
<span class="n">json_data</span><span class="p">:</span> <span class="nb">bytes</span><span class="p">,</span>
<span class="n">rabbitmq_url</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
<span class="n">loop</span><span class="p">,</span>
<span class="n">output_dir</span><span class="o">=</span><span class="s2">&quot;downloaded_files&quot;</span><span class="p">,</span>
<span class="p">)</span> <span class="o">-&gt;</span> <span class="n">defaultdict</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Asynchronous callback function for handling messages from the &#39;amq-cleverswarm&#39; queue.</span>
<span class="sd"> Args:</span>
<span class="sd"> message: The incoming RabbitMQ message.</span>
<span class="sd"> rabbitmq_url: The RabbitMQ connection URL.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">raise</span> <span class="ne">NotImplementedError</span><span class="p">(</span><span class="s2">&quot;Subclasses must implement this method.&quot;</span><span class="p">)</span></div>
<div class="viewcode-block" id="FileHandler.publish_file">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.file_handler.FileHandler.publish_file">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">publish_file</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span>
<span class="n">exchange</span><span class="p">:</span> <span class="n">AbstractExchange</span><span class="p">,</span>
<span class="n">file_path</span><span class="p">:</span> <span class="n">Path</span><span class="p">,</span>
<span class="n">routing_key</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
<span class="n">loop</span><span class="p">:</span> <span class="n">AbstractEventLoop</span><span class="p">,</span>
<span class="n">max_chunk_size</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">2</span><span class="o">**</span><span class="mi">20</span><span class="p">,</span> <span class="c1"># 1MB default chunk size</span>
<span class="n">content_type</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">&quot;application/octet-stream&quot;</span><span class="p">,</span> <span class="c1"># Default content type</span>
<span class="n">delivery_mode</span><span class="p">:</span> <span class="n">DeliveryMode</span> <span class="o">=</span> <span class="n">DeliveryMode</span><span class="o">.</span><span class="n">PERSISTENT</span><span class="p">,</span>
<span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">tuple</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">int</span><span class="p">]:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Reads a file from the file system and publishes its content to a RabbitMQ exchange</span>
<span class="sd"> in chunks. It declares a queue with a random name, binds it to the specified</span>
<span class="sd"> exchange, and uses the queue name as the routing key.</span>
<span class="sd"> Args:</span>
<span class="sd"> exchange: The aio_pika RobustChannel to use for communication with RabbitMQ.</span>
<span class="sd"> file_path: The path to the file to publish.</span>
<span class="sd"> max_chunk_size: The maximum size of each chunk (in bytes).</span>
<span class="sd"> routing_key: The name of the RabbitMQ exchange routing key to publish to correct queue.</span>
<span class="sd"> loop: correct event loop</span>
<span class="sd"> max_chunk_size: chunk size to send</span>
<span class="sd"> content_type: The content type of the file data.</span>
<span class="sd"> delivery_mode: The delivery mode (e.g., PERSISTENT or TRANSIENT).</span>
<span class="sd"> Returns:</span>
<span class="sd"> The name of the randomly generated queue where the file content was published.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">raise</span> <span class="ne">NotImplementedError</span><span class="p">(</span><span class="s2">&quot;Subclasses must implement this method.&quot;</span><span class="p">)</span></div>
</div>
<span class="c1"># The StreamingFileHandler class is a subclass of FileHandler that implements the download_file method</span>
<div class="viewcode-block" id="StreamingFileHandler">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.file_handler.StreamingFileHandler">[docs]</a>
<span class="k">class</span><span class="w"> </span><span class="nc">StreamingFileHandler</span><span class="p">(</span><span class="n">FileHandler</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Handles file downloads from RabbitMQ streams.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<div class="viewcode-block" id="StreamingFileHandler.__init__">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.file_handler.StreamingFileHandler.__init__">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">()</span></div>
<span class="c1"># This method MUST NOT be static.</span>
<span class="c1"># For testing purpose, we will mock this method and inject a mock connection.</span>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_get_connection</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">rabbitmq_url</span><span class="p">,</span> <span class="n">loop</span><span class="p">):</span>
<span class="k">return</span> <span class="k">await</span> <span class="n">connect_robust</span><span class="p">(</span><span class="n">rabbitmq_url</span><span class="p">,</span> <span class="n">loop</span><span class="o">=</span><span class="n">loop</span><span class="p">)</span>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_download_from_queue_to_file</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span> <span class="n">rabbitmq_url</span><span class="p">,</span> <span class="n">queue_name</span><span class="p">,</span> <span class="n">filepath</span><span class="p">,</span> <span class="n">loop</span>
<span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">tuple</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="nb">int</span><span class="p">]</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Internal method for downloading a file from a queue to disk.</span>
<span class="sd"> Return (file size, eof status).</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="c1"># Here the normal mock doesn&#39;t work since this method</span>
<span class="c1"># is async and will be run in another loop,</span>
<span class="c1"># out of the scope of method mock.</span>
<span class="n">connection</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_connection</span><span class="p">(</span><span class="n">rabbitmq_url</span><span class="p">,</span> <span class="n">loop</span><span class="o">=</span><span class="n">loop</span><span class="p">)</span>
<span class="n">_file_size</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">_eof</span> <span class="o">=</span> <span class="n">IN_PROGRESS</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">channel</span><span class="p">:</span> <span class="n">AbstractRobustChannel</span> <span class="o">=</span> <span class="k">await</span> <span class="n">connection</span><span class="o">.</span><span class="n">channel</span><span class="p">()</span>
<span class="n">queue</span><span class="p">:</span> <span class="n">AbstractQueue</span> <span class="o">=</span> <span class="k">await</span> <span class="n">channel</span><span class="o">.</span><span class="n">get_queue</span><span class="p">(</span><span class="n">queue_name</span><span class="p">,</span> <span class="n">ensure</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">logging_debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Awaiting all file chunks being downloaded for </span><span class="si">{</span><span class="n">filepath</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">async</span> <span class="k">with</span> <span class="n">queue</span><span class="o">.</span><span class="n">iterator</span><span class="p">()</span> <span class="k">as</span> <span class="n">queue_iter</span><span class="p">:</span>
<span class="k">async</span> <span class="k">for</span> <span class="n">message</span> <span class="ow">in</span> <span class="n">queue_iter</span><span class="p">:</span>
<span class="k">async</span> <span class="k">with</span> <span class="n">message</span><span class="o">.</span><span class="n">process</span><span class="p">():</span>
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">filepath</span><span class="p">,</span> <span class="s2">&quot;ab&quot;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
<span class="n">f</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">body</span><span class="p">)</span>
<span class="n">_file_size</span> <span class="o">=</span> <span class="n">_file_size</span> <span class="o">+</span> <span class="n">message</span><span class="o">.</span><span class="n">body_size</span>
<span class="n">_eof</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">headers</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;eof&quot;</span><span class="p">,</span> <span class="n">END_OF_FILE</span><span class="p">))</span>
<span class="k">if</span> <span class="n">_eof</span> <span class="o">!=</span> <span class="n">IN_PROGRESS</span><span class="p">:</span>
<span class="k">break</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="n">logging_error</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;File download failed: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">finally</span><span class="p">:</span>
<span class="k">await</span> <span class="n">connection</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
<span class="k">return</span> <span class="n">_file_size</span><span class="p">,</span> <span class="n">_eof</span>
<div class="viewcode-block" id="StreamingFileHandler.download_file">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.file_handler.StreamingFileHandler.download_file">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">download_file</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span> <span class="n">loop</span><span class="p">,</span> <span class="n">rabbitmq_url</span><span class="p">,</span> <span class="n">file_info</span><span class="p">,</span> <span class="n">message_data</span><span class="p">,</span> <span class="n">output_dir</span>
<span class="p">)</span> <span class="o">-&gt;</span> <span class="p">(</span><span class="nb">int</span><span class="p">,</span> <span class="nb">int</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Asynchronously downloads a file from RabbitMQ based on the provided file information.</span>
<span class="sd"> takes the file_info and message_data and output_dir, creates queue consumer and waits for the file to be downloaded</span>
<span class="sd"> Args:</span>
<span class="sd"> loop: The asyncio event loop.</span>
<span class="sd"> rabbitmq_url: The RabbitMQ connection URL.</span>
<span class="sd"> file_info (dict): A dictionary containing file metadata</span>
<span class="sd"> message_data (dict): The entire message</span>
<span class="sd"> output_dir (str): The directory where the file should be saved.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">filename</span> <span class="o">=</span> <span class="n">file_info</span><span class="p">[</span><span class="s2">&quot;filename&quot;</span><span class="p">]</span>
<span class="n">size</span> <span class="o">=</span> <span class="n">file_info</span><span class="p">[</span><span class="s2">&quot;size&quot;</span><span class="p">]</span>
<span class="n">stream_name</span> <span class="o">=</span> <span class="n">file_info</span><span class="p">[</span><span class="s2">&quot;streamName&quot;</span><span class="p">]</span>
<span class="n">queue_name</span> <span class="o">=</span> <span class="n">file_info</span><span class="p">[</span><span class="s2">&quot;queue_name&quot;</span><span class="p">]</span>
<span class="n">filepath</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">output_dir</span><span class="p">,</span> <span class="n">filename</span><span class="p">)</span>
<span class="n">filepath</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">ensure_directory_exists</span><span class="p">(</span>
<span class="n">filepath</span>
<span class="p">)</span> <span class="c1"># if filename exists, create a new (next) version</span>
<span class="n">download_locations</span><span class="p">[</span><span class="n">file_info</span><span class="p">[</span><span class="s2">&quot;key&quot;</span><span class="p">]]</span> <span class="o">=</span> <span class="n">filepath</span>
<span class="n">filename</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">basename</span><span class="p">(</span>
<span class="n">filepath</span>
<span class="p">)</span> <span class="c1"># if a new version was created, ensure to use that new version</span>
<span class="n">file_info</span><span class="p">[</span><span class="s2">&quot;filename&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">filename</span>
<span class="n">logging_debug</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;Downloading file: </span><span class="si">{</span><span class="n">filename</span><span class="si">}</span><span class="s2"> (size: </span><span class="si">{</span><span class="n">size</span><span class="si">}</span><span class="s2"> bytes) from stream: </span><span class="si">{</span><span class="n">stream_name</span><span class="si">}</span><span class="s2">:</span><span class="si">{</span><span class="n">queue_name</span><span class="si">}</span><span class="s2"> to </span><span class="si">{</span><span class="n">filepath</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="p">)</span>
<span class="k">if</span> <span class="n">queue_name</span><span class="p">:</span>
<span class="n">_local_file_size</span><span class="p">,</span> <span class="n">_local_eof</span> <span class="o">=</span> <span class="k">await</span> <span class="n">await_result</span><span class="p">(</span>
<span class="n">asyncio</span><span class="o">.</span><span class="n">run_coroutine_threadsafe</span><span class="p">(</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_download_from_queue_to_file</span><span class="p">(</span><span class="n">rabbitmq_url</span><span class="p">,</span> <span class="n">queue_name</span><span class="p">,</span> <span class="n">filepath</span><span class="p">,</span> <span class="n">loop</span><span class="p">),</span>
<span class="n">loop</span><span class="o">=</span><span class="n">loop</span><span class="p">,</span>
<span class="p">)</span>
<span class="p">)</span>
<span class="k">return</span> <span class="n">_local_file_size</span><span class="p">,</span> <span class="n">_local_eof</span>
<span class="k">return</span> <span class="mi">0</span><span class="p">,</span> <span class="n">CANCELLED</span></div>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_download_from_queue_to_buffer</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span> <span class="n">rabbitmq_url</span><span class="p">,</span> <span class="n">queue_name</span><span class="p">,</span> <span class="n">loop</span>
<span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">tuple</span><span class="p">[</span><span class="nb">bytearray</span><span class="p">,</span> <span class="nb">int</span><span class="p">]:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Internal method for downloading a file from a queue to RAM.</span>
<span class="sd"> Return (bytearray, eof status).</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">_connection</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_connection</span><span class="p">(</span><span class="n">rabbitmq_url</span><span class="p">,</span> <span class="n">loop</span><span class="o">=</span><span class="n">loop</span><span class="p">)</span>
<span class="n">_eof</span> <span class="o">=</span> <span class="n">IN_PROGRESS</span>
<span class="n">_res</span> <span class="o">=</span> <span class="nb">bytearray</span><span class="p">()</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">channel</span><span class="p">:</span> <span class="n">AbstractRobustChannel</span> <span class="o">=</span> <span class="k">await</span> <span class="n">_connection</span><span class="o">.</span><span class="n">channel</span><span class="p">()</span>
<span class="n">queue</span><span class="p">:</span> <span class="n">AbstractQueue</span> <span class="o">=</span> <span class="k">await</span> <span class="n">channel</span><span class="o">.</span><span class="n">get_queue</span><span class="p">(</span><span class="n">queue_name</span><span class="p">,</span> <span class="n">ensure</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">logging_debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Awaiting all buffer chunks being downloaded for </span><span class="si">{</span><span class="n">queue_name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">async</span> <span class="k">with</span> <span class="n">queue</span><span class="o">.</span><span class="n">iterator</span><span class="p">()</span> <span class="k">as</span> <span class="n">queue_iter</span><span class="p">:</span>
<span class="k">async</span> <span class="k">for</span> <span class="n">message</span> <span class="ow">in</span> <span class="n">queue_iter</span><span class="p">:</span>
<span class="k">async</span> <span class="k">with</span> <span class="n">message</span><span class="o">.</span><span class="n">process</span><span class="p">():</span>
<span class="n">_res</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">body</span><span class="p">)</span>
<span class="n">_eof</span> <span class="o">=</span> <span class="n">message</span><span class="o">.</span><span class="n">headers</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;eof&quot;</span><span class="p">,</span> <span class="n">END_OF_FILE</span><span class="p">)</span>
<span class="k">if</span> <span class="n">_eof</span> <span class="o">!=</span> <span class="n">IN_PROGRESS</span><span class="p">:</span>
<span class="k">break</span>
<span class="n">logging_info</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Finished downloading buffer </span><span class="si">{</span><span class="n">queue_name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="n">logging_error</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Downloading buffer: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">await</span> <span class="n">_connection</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
<span class="k">return</span> <span class="n">_res</span><span class="p">,</span> <span class="n">_eof</span>
<div class="viewcode-block" id="StreamingFileHandler.download_buffer">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.file_handler.StreamingFileHandler.download_buffer">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">download_buffer</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">loop</span><span class="p">,</span> <span class="n">rabbitmq_url</span><span class="p">,</span> <span class="n">queue_name</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="p">(</span><span class="nb">bytearray</span><span class="p">,</span> <span class="nb">int</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Asynchronously downloads a bytearay from RabbitMQ based on the provided file information.</span>
<span class="sd"> It assumes entire array is in the first (and only) chunk</span>
<span class="sd"> Args:</span>
<span class="sd"> loop: The asyncio event loop.</span>
<span class="sd"> rabbitmq_url: The RabbitMQ connection URL.</span>
<span class="sd"> queue_name (str): The directory where the file should be saved.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">logging_debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Downloading buffer from stream: </span><span class="si">{</span><span class="n">queue_name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="n">queue_name</span><span class="p">:</span>
<span class="n">_local_res</span><span class="p">,</span> <span class="n">_local_eof</span> <span class="o">=</span> <span class="k">await</span> <span class="n">await_result</span><span class="p">(</span>
<span class="n">asyncio</span><span class="o">.</span><span class="n">run_coroutine_threadsafe</span><span class="p">(</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_download_from_queue_to_buffer</span><span class="p">(</span><span class="n">rabbitmq_url</span><span class="p">,</span> <span class="n">queue_name</span><span class="p">,</span> <span class="n">loop</span><span class="p">),</span> <span class="n">loop</span><span class="o">=</span><span class="n">loop</span>
<span class="p">)</span>
<span class="p">)</span>
<span class="k">return</span> <span class="n">_local_res</span><span class="p">,</span> <span class="n">_local_eof</span>
<span class="k">return</span> <span class="mi">0</span><span class="p">,</span> <span class="n">CANCELLED</span></div>
<div class="viewcode-block" id="StreamingFileHandler.on_message">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.file_handler.StreamingFileHandler.on_message">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">on_message</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span>
<span class="n">message</span><span class="p">:</span> <span class="n">AbstractIncomingMessage</span><span class="p">,</span>
<span class="n">json_data</span><span class="p">:</span> <span class="nb">bytes</span><span class="p">,</span>
<span class="n">rabbitmq_url</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
<span class="n">loop</span><span class="p">,</span>
<span class="n">output_dir</span><span class="o">=</span><span class="s2">&quot;downloaded_files&quot;</span><span class="p">,</span>
<span class="p">)</span> <span class="o">-&gt;</span> <span class="n">defaultdict</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Asynchronous callback function for handling messages from the &#39;amq-cleverswarm&#39; queue.</span>
<span class="sd"> Args:</span>
<span class="sd"> message: The incoming RabbitMQ message.</span>
<span class="sd"> json_data: The JSON data from the message.</span>
<span class="sd"> rabbitmq_url: The RabbitMQ connection URL.</span>
<span class="sd"> loop: The asyncio event loop of the RabbitMQ API</span>
<span class="sd"> output_dir</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">_message_data</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">body</span><span class="o">.</span><span class="n">decode</span><span class="p">())</span>
<span class="n">_amq_message_data</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">json_data</span><span class="o">.</span><span class="n">decode</span><span class="p">())</span>
<span class="n">files_to_download</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">_key</span><span class="p">,</span> <span class="n">_file_type</span> <span class="ow">in</span> <span class="n">_amq_message_data</span><span class="p">[</span><span class="s2">&quot;files&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">_file_type</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
<span class="n">files_info</span> <span class="o">=</span> <span class="n">_file_type</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">stream_name</span> <span class="o">=</span> <span class="n">files_info</span><span class="p">[</span><span class="s2">&quot;streamName&quot;</span><span class="p">]</span>
<span class="n">files_info</span><span class="p">[</span><span class="s2">&quot;queue_name&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span>
<span class="n">_message_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">stream_name</span><span class="p">,</span> <span class="s2">&quot;&quot;</span><span class="p">)</span> <span class="k">if</span> <span class="n">stream_name</span> <span class="k">else</span> <span class="s2">&quot;&quot;</span>
<span class="p">)</span>
<span class="n">files_info</span><span class="p">[</span><span class="s2">&quot;key&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">_key</span>
<span class="n">files_to_download</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">files_info</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">files_to_download</span><span class="p">:</span>
<span class="n">logging_info</span><span class="p">(</span><span class="s2">&quot; [</span><span class="si">%s</span><span class="s2">] No files to download in this message.&quot;</span><span class="p">,</span> <span class="n">message</span><span class="o">.</span><span class="n">delivery_tag</span><span class="p">)</span>
<span class="c1"># await message.ack()</span>
<span class="k">return</span> <span class="n">defaultdict</span><span class="p">()</span>
<span class="c1"># Create a task for each file download</span>
<span class="n">_tasks</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">file_info</span> <span class="ow">in</span> <span class="n">files_to_download</span><span class="p">:</span>
<span class="n">logging_info</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot; [</span><span class="si">{</span><span class="n">message</span><span class="o">.</span><span class="n">delivery_tag</span><span class="si">}</span><span class="s2">] about to create task for </span><span class="si">{</span><span class="n">file_info</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="n">_task</span> <span class="o">=</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">create_task</span><span class="p">(</span>
<span class="bp">self</span><span class="o">.</span><span class="n">download_file</span><span class="p">(</span><span class="n">loop</span><span class="p">,</span> <span class="n">rabbitmq_url</span><span class="p">,</span> <span class="n">file_info</span><span class="p">,</span> <span class="n">_message_data</span><span class="p">,</span> <span class="n">output_dir</span><span class="p">)</span>
<span class="p">)</span>
<span class="n">_tasks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">_task</span><span class="p">)</span>
<span class="n">logging_info</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot; [</span><span class="si">{</span><span class="n">message</span><span class="o">.</span><span class="n">delivery_tag</span><span class="si">}</span><span class="s2">] Waiting for all files to download...gather(*tasks)&quot;</span>
<span class="p">)</span>
<span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">gather</span><span class="p">(</span><span class="o">*</span><span class="n">_tasks</span><span class="p">)</span> <span class="c1"># Wait for all downloads to complete</span>
<span class="n">logging_info</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;All files downloaded. d-tag: </span><span class="si">{</span><span class="n">message</span><span class="o">.</span><span class="n">delivery_tag</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="n">logging_error</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Building DataMessage: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="n">asyncio</span><span class="o">.</span><span class="n">run_coroutine_threadsafe</span><span class="p">(</span>
<span class="n">message</span><span class="o">.</span><span class="n">ack</span><span class="p">(),</span> <span class="n">loop</span><span class="o">=</span><span class="n">loop</span>
<span class="p">)</span> <span class="c1"># ACK -&gt; ignore the message (do not redeliver)</span>
<span class="k">return</span> <span class="n">download_locations</span></div>
<div class="viewcode-block" id="StreamingFileHandler.publish_file">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.file_handler.StreamingFileHandler.publish_file">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">publish_file</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span>
<span class="n">exchange</span><span class="p">:</span> <span class="n">AbstractExchange</span><span class="p">,</span>
<span class="n">file_path</span><span class="p">:</span> <span class="n">Path</span><span class="p">,</span>
<span class="n">routing_key</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
<span class="n">loop</span><span class="p">:</span> <span class="n">AbstractEventLoop</span><span class="p">,</span>
<span class="n">max_chunk_size</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">2</span><span class="o">**</span><span class="mi">20</span><span class="p">,</span> <span class="c1"># 1MB default chunk size</span>
<span class="n">content_type</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">&quot;application/octet-stream&quot;</span><span class="p">,</span> <span class="c1"># Default content type</span>
<span class="n">delivery_mode</span><span class="p">:</span> <span class="n">DeliveryMode</span> <span class="o">=</span> <span class="n">DeliveryMode</span><span class="o">.</span><span class="n">PERSISTENT</span><span class="p">,</span>
<span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">tuple</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">int</span><span class="p">]:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Reads a file from the file system and publishes its content to a RabbitMQ exchange</span>
<span class="sd"> in chunks. It declares a queue with a random name, binds it to the specified</span>
<span class="sd"> exchange, and uses the queue name as the routing key.</span>
<span class="sd"> Args:</span>
<span class="sd"> exchange: The aio_pika RobustChannel to use for communication with RabbitMQ.</span>
<span class="sd"> file_path: The path to the file to publish.</span>
<span class="sd"> max_chunk_size: The maximum size of each chunk (in bytes).</span>
<span class="sd"> routing_key: The name of the RabbitMQ exchange routing key to publish to correct queue.</span>
<span class="sd"> loop: correct event loop</span>
<span class="sd"> max_chunk_size: chunk size to send</span>
<span class="sd"> content_type: The content type of the file data.</span>
<span class="sd"> delivery_mode: The delivery mode (e.g., PERSISTENT or TRANSIENT).</span>
<span class="sd"> Returns:</span>
<span class="sd"> The name of the randomly generated queue where the file content was published.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">file_path</span><span class="o">.</span><span class="n">is_file</span><span class="p">():</span>
<span class="k">raise</span> <span class="ne">FileNotFoundError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;File not found: </span><span class="si">{</span><span class="n">file_path</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="n">_file_size</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">getsize</span><span class="p">(</span><span class="n">file_path</span><span class="p">)</span>
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">file_path</span><span class="p">,</span> <span class="s2">&quot;rb&quot;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
<span class="n">_offset</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
<span class="n">_chunk</span> <span class="o">=</span> <span class="n">f</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="n">max_chunk_size</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">_chunk</span><span class="p">:</span>
<span class="k">break</span> <span class="c1"># End of file</span>
<span class="n">message</span> <span class="o">=</span> <span class="n">Message</span><span class="p">(</span>
<span class="n">body</span><span class="o">=</span><span class="n">_chunk</span><span class="p">,</span>
<span class="n">content_type</span><span class="o">=</span><span class="n">content_type</span><span class="p">,</span>
<span class="n">delivery_mode</span><span class="o">=</span><span class="n">delivery_mode</span><span class="p">,</span>
<span class="n">headers</span><span class="o">=</span><span class="p">{</span>
<span class="s2">&quot;file_name&quot;</span><span class="p">:</span> <span class="n">file_path</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
<span class="s2">&quot;pos&quot;</span><span class="p">:</span> <span class="n">_offset</span><span class="p">,</span>
<span class="s2">&quot;total_size&quot;</span><span class="p">:</span> <span class="n">_file_size</span><span class="p">,</span>
<span class="s2">&quot;chunk_size&quot;</span><span class="p">:</span> <span class="nb">len</span><span class="p">(</span><span class="n">_chunk</span><span class="p">),</span>
<span class="s2">&quot;eof&quot;</span><span class="p">:</span> <span class="p">(</span>
<span class="n">END_OF_FILE</span> <span class="k">if</span> <span class="n">max_chunk_size</span> <span class="o">+</span> <span class="n">_offset</span> <span class="o">&gt;=</span> <span class="n">_file_size</span> <span class="k">else</span> <span class="n">IN_PROGRESS</span>
<span class="p">),</span>
<span class="p">},</span>
<span class="p">)</span>
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;Going to Publish chunk </span><span class="si">{</span><span class="n">_offset</span><span class="si">}</span><span class="s2">/</span><span class="si">{</span><span class="n">_file_size</span><span class="si">}</span><span class="s2"> to </span><span class="si">{</span><span class="n">exchange</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">:</span><span class="si">{</span><span class="n">routing_key</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="p">)</span>
<span class="n">_future</span> <span class="o">=</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">run_coroutine_threadsafe</span><span class="p">(</span>
<span class="n">exchange</span><span class="o">.</span><span class="n">publish</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">routing_key</span><span class="o">=</span><span class="n">routing_key</span><span class="p">),</span> <span class="n">loop</span>
<span class="p">)</span>
<span class="k">while</span> <span class="ow">not</span> <span class="n">_future</span><span class="o">.</span><span class="n">done</span><span class="p">():</span>
<span class="c1"># sleep allows coroutine to execute. must wait for completion to ensure all chunks written in right order</span>
<span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.02</span><span class="p">)</span>
<span class="n">logging_debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Waiting for chunk </span><span class="si">{</span><span class="n">_offset</span><span class="si">}</span><span class="s2">/</span><span class="si">{</span><span class="n">_file_size</span><span class="si">}</span><span class="s2"> future= </span><span class="si">{</span><span class="n">_future</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="n">_offset</span> <span class="o">+=</span> <span class="nb">len</span><span class="p">(</span><span class="n">_chunk</span><span class="p">)</span>
<span class="n">logging_debug</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;Published chunk </span><span class="si">{</span><span class="n">_offset</span><span class="si">}</span><span class="s2">/</span><span class="si">{</span><span class="n">_file_size</span><span class="si">}</span><span class="s2"> to </span><span class="si">{</span><span class="n">exchange</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">:</span><span class="si">{</span><span class="n">routing_key</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="p">)</span>
<span class="n">logging_debug</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;File </span><span class="si">{</span><span class="n">file_path</span><span class="si">}</span><span class="s2"> published to RabbitMQ exchange </span><span class="si">{</span><span class="n">exchange</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">, queue </span><span class="si">{</span><span class="n">routing_key</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="p">)</span>
<span class="k">return</span> <span class="n">routing_key</span><span class="p">,</span> <span class="n">_file_size</span></div>
</div>
</pre></div>
</div>
</div>
<footer>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2024, CleverThis.</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>
@@ -0,0 +1,250 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" data-content_root="../../../">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>amqp.adapter.logging_utils &mdash; AMQ Adapter Python 1.0 documentation</title>
<link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=03e43079" />
<link rel="stylesheet" type="text/css" href="../../../_static/css/theme.css?v=e59714d7" />
<script src="../../../_static/jquery.js?v=5d32c60e"></script>
<script src="../../../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
<script src="../../../_static/documentation_options.js?v=f2a433a1"></script>
<script src="../../../_static/doctools.js?v=9bcbadda"></script>
<script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
<script src="../../../_static/js/theme.js"></script>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="../../../index.html" class="icon icon-home">
AMQ Adapter Python
</a>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" aria-label="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.html">AMQP Package</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.config.html">Configuration Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.adapter.html">Adapter Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.service.html">Service Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.router.html">Router Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.model.html">Model Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.rabbitmq.html">RabbitMQ Module</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="../../../index.html">AMQ Adapter Python</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="../../../index.html" class="icon icon-home" aria-label="Home"></a></li>
<li class="breadcrumb-item"><a href="../../index.html">Module code</a></li>
<li class="breadcrumb-item active">amqp.adapter.logging_utils</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<h1>Source code for amqp.adapter.logging_utils</h1><div class="highlight"><pre>
<span></span><span class="kn">import</span><span class="w"> </span><span class="nn">inspect</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">logging</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">os</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">sys</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">threading</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">traceback</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">importlib.metadata</span><span class="w"> </span><span class="kn">import</span> <span class="n">version</span>
<span class="c1"># Get version from installed package metadata</span>
<span class="n">__version__</span> <span class="o">=</span> <span class="n">version</span><span class="p">(</span><span class="s2">&quot;amq_adapter&quot;</span><span class="p">)</span> <span class="c1"># Name must match pyproject.toml [project] name</span>
<span class="n">__verbose__</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;AMQ_VERBOSE_LOGGING&quot;</span><span class="p">,</span> <span class="s2">&quot;0&quot;</span><span class="p">)</span> <span class="o">==</span> <span class="s2">&quot;1&quot;</span>
<div class="viewcode-block" id="get_context_info">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.logging_utils.get_context_info">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">get_context_info</span><span class="p">():</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Retrieves the current_availability module, line number, and function name.</span>
<span class="sd"> Returns:</span>
<span class="sd"> A tuple containing (module name, line number, function name).</span>
<span class="sd"> Returns (None, None, None) if it fails to retrieve the information.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">try</span><span class="p">:</span>
<span class="c1"># Get the frame object for the current_availability function call</span>
<span class="n">frame</span> <span class="o">=</span> <span class="n">inspect</span><span class="o">.</span><span class="n">currentframe</span><span class="p">()</span>
<span class="k">if</span> <span class="n">frame</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="c1"># Get the frame object for the caller of the current_availability function</span>
<span class="n">frame</span> <span class="o">=</span> <span class="n">frame</span><span class="o">.</span><span class="n">f_back</span><span class="o">.</span><span class="n">f_back</span>
<span class="k">if</span> <span class="n">frame</span><span class="p">:</span>
<span class="n">code_context</span> <span class="o">=</span> <span class="n">frame</span><span class="o">.</span><span class="n">f_code</span>
<span class="n">module_name</span> <span class="o">=</span> <span class="n">code_context</span><span class="o">.</span><span class="n">co_filename</span>
<span class="n">module_name</span> <span class="o">=</span> <span class="p">(</span>
<span class="s2">&quot;amqp&quot;</span> <span class="o">+</span> <span class="n">module_name</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;/amqp&quot;</span><span class="p">,</span> <span class="mi">1</span><span class="p">)[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
<span class="k">if</span> <span class="s2">&quot;/amqp&quot;</span> <span class="ow">in</span> <span class="n">module_name</span>
<span class="k">else</span> <span class="n">module_name</span>
<span class="p">)</span>
<span class="n">line_number</span> <span class="o">=</span> <span class="n">frame</span><span class="o">.</span><span class="n">f_lineno</span>
<span class="n">function_name</span> <span class="o">=</span> <span class="n">code_context</span><span class="o">.</span><span class="n">co_name</span>
<span class="k">return</span> <span class="n">module_name</span><span class="p">,</span> <span class="n">line_number</span><span class="p">,</span> <span class="n">function_name</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">None</span><span class="p">,</span> <span class="kc">None</span><span class="p">,</span> <span class="kc">None</span>
<span class="k">except</span> <span class="ne">Exception</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">None</span><span class="p">,</span> <span class="kc">None</span><span class="p">,</span> <span class="kc">None</span></div>
<div class="viewcode-block" id="logging_error">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.logging_utils.logging_error">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">logging_error</span><span class="p">(</span><span class="n">msg</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Log an error message according to current_availability logging for &#39;ERROR&#39; level.</span>
<span class="sd"> Add module name, line and function name where the error occurred, on single line.</span>
<span class="sd"> Args:</span>
<span class="sd"> msg (str): The error message to log.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">_exec_info</span> <span class="o">=</span> <span class="n">sys</span><span class="o">.</span><span class="n">exc_info</span><span class="p">()[</span><span class="mi">2</span><span class="p">]</span>
<span class="n">_thread_id</span> <span class="o">=</span> <span class="n">threading</span><span class="o">.</span><span class="n">get_ident</span><span class="p">()</span>
<span class="k">if</span> <span class="n">_exec_info</span><span class="p">:</span>
<span class="n">_tb</span> <span class="o">=</span> <span class="n">traceback</span><span class="o">.</span><span class="n">extract_tb</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">exc_info</span><span class="p">()[</span><span class="mi">2</span><span class="p">])[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
<span class="n">logging</span><span class="o">.</span><span class="n">error</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">_thread_id</span><span class="si">}</span><span class="s2">:</span><span class="si">{</span><span class="n">__version__</span><span class="si">}</span><span class="s2"> [E] &#39;</span><span class="si">{</span><span class="n">msg</span><span class="si">}</span><span class="s2">&#39; ---&gt; &#39;</span><span class="si">{</span><span class="n">_tb</span><span class="o">.</span><span class="n">filename</span><span class="si">}</span><span class="s2">&#39;:</span><span class="si">{</span><span class="n">_tb</span><span class="o">.</span><span class="n">lineno</span><span class="si">}</span><span class="s2">, &#39;</span><span class="si">{</span><span class="n">_tb</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">()&#39;&quot;</span><span class="p">,</span>
<span class="o">*</span><span class="n">args</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">module</span><span class="p">,</span> <span class="n">line_number</span><span class="p">,</span> <span class="n">function_name</span> <span class="o">=</span> <span class="n">get_context_info</span><span class="p">()</span>
<span class="k">if</span> <span class="n">module</span> <span class="ow">and</span> <span class="n">line_number</span> <span class="ow">and</span> <span class="n">function_name</span><span class="p">:</span>
<span class="n">logging</span><span class="o">.</span><span class="n">error</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">_thread_id</span><span class="si">}</span><span class="s2">:</span><span class="si">{</span><span class="n">__version__</span><span class="si">}</span><span class="s2"> [E] &#39;</span><span class="si">{</span><span class="n">msg</span><span class="si">}</span><span class="s2">&#39; ---&gt; &#39;</span><span class="si">{</span><span class="n">module</span><span class="si">}</span><span class="s2">&#39;:</span><span class="si">{</span><span class="n">line_number</span><span class="si">}</span><span class="s2">, &#39;</span><span class="si">{</span><span class="n">function_name</span><span class="si">}</span><span class="s2">()&#39;&quot;</span><span class="p">,</span>
<span class="o">*</span><span class="n">args</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">logging</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">_thread_id</span><span class="si">}</span><span class="s2">:</span><span class="si">{</span><span class="n">__version__</span><span class="si">}</span><span class="s2"> [E] </span><span class="si">{</span><span class="n">msg</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">)</span></div>
<div class="viewcode-block" id="logging_warning">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.logging_utils.logging_warning">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">logging_warning</span><span class="p">(</span><span class="n">msg</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Log a warning message according to current_availability logging for &#39;WARN&#39; level.</span>
<span class="sd"> Add module name, line and function name where the print occurred, on single line.</span>
<span class="sd"> Args:</span>
<span class="sd"> msg (str): The warning message to log.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">_thread_id</span> <span class="o">=</span> <span class="n">threading</span><span class="o">.</span><span class="n">get_ident</span><span class="p">()</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">__verbose__</span><span class="p">:</span>
<span class="n">logging</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">_thread_id</span><span class="si">}</span><span class="s2">:</span><span class="si">{</span><span class="n">__version__</span><span class="si">}</span><span class="s2"> [W] </span><span class="si">{</span><span class="n">msg</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">)</span>
<span class="k">return</span>
<span class="n">module</span><span class="p">,</span> <span class="n">line_number</span><span class="p">,</span> <span class="n">function_name</span> <span class="o">=</span> <span class="n">get_context_info</span><span class="p">()</span>
<span class="k">if</span> <span class="n">module</span> <span class="ow">and</span> <span class="n">line_number</span> <span class="ow">and</span> <span class="n">function_name</span><span class="p">:</span>
<span class="n">logging</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">_thread_id</span><span class="si">}</span><span class="s2">:</span><span class="si">{</span><span class="n">__version__</span><span class="si">}</span><span class="s2"> [W] &#39;</span><span class="si">{</span><span class="n">msg</span><span class="si">}</span><span class="s2">&#39; ---&gt; &#39;</span><span class="si">{</span><span class="n">module</span><span class="si">}</span><span class="s2">&#39;:</span><span class="si">{</span><span class="n">line_number</span><span class="si">}</span><span class="s2">, &#39;</span><span class="si">{</span><span class="n">function_name</span><span class="si">}</span><span class="s2">()&#39;&quot;</span><span class="p">,</span>
<span class="o">*</span><span class="n">args</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">logging</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">_thread_id</span><span class="si">}</span><span class="s2">:</span><span class="si">{</span><span class="n">__version__</span><span class="si">}</span><span class="s2"> [W] </span><span class="si">{</span><span class="n">msg</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">)</span></div>
<div class="viewcode-block" id="logging_info">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.logging_utils.logging_info">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">logging_info</span><span class="p">(</span><span class="n">msg</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Log an info message according to current_availability logging for &#39;INFO&#39; level.</span>
<span class="sd"> Add module name, line and function name where the print occurred, on single line.</span>
<span class="sd"> Args:</span>
<span class="sd"> msg (str): The info message to log.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">_thread_id</span> <span class="o">=</span> <span class="n">threading</span><span class="o">.</span><span class="n">get_ident</span><span class="p">()</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">__verbose__</span><span class="p">:</span>
<span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">_thread_id</span><span class="si">}</span><span class="s2">:</span><span class="si">{</span><span class="n">__version__</span><span class="si">}</span><span class="s2"> [*] </span><span class="si">{</span><span class="n">msg</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">)</span>
<span class="k">return</span>
<span class="n">module</span><span class="p">,</span> <span class="n">line_number</span><span class="p">,</span> <span class="n">function_name</span> <span class="o">=</span> <span class="n">get_context_info</span><span class="p">()</span>
<span class="k">if</span> <span class="n">module</span> <span class="ow">and</span> <span class="n">line_number</span> <span class="ow">and</span> <span class="n">function_name</span><span class="p">:</span>
<span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">_thread_id</span><span class="si">}</span><span class="s2">:</span><span class="si">{</span><span class="n">__version__</span><span class="si">}</span><span class="s2"> [*] &#39;</span><span class="si">{</span><span class="n">msg</span><span class="si">}</span><span class="s2">&#39; ---&gt; &#39;</span><span class="si">{</span><span class="n">module</span><span class="si">}</span><span class="s2">&#39;:</span><span class="si">{</span><span class="n">line_number</span><span class="si">}</span><span class="s2">, &#39;</span><span class="si">{</span><span class="n">function_name</span><span class="si">}</span><span class="s2">()&#39;&quot;</span><span class="p">,</span>
<span class="o">*</span><span class="n">args</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">_thread_id</span><span class="si">}</span><span class="s2">:</span><span class="si">{</span><span class="n">__version__</span><span class="si">}</span><span class="s2"> [*] </span><span class="si">{</span><span class="n">msg</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">)</span></div>
<div class="viewcode-block" id="logging_debug">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.logging_utils.logging_debug">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">logging_debug</span><span class="p">(</span><span class="n">msg</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Log a debug message according to current_availability logging for &#39;DEBUG&#39; level.</span>
<span class="sd"> Add module name, line and function name where the print occurred, on single line.</span>
<span class="sd"> Args:</span>
<span class="sd"> msg (str): The debug message to log.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">_thread_id</span> <span class="o">=</span> <span class="n">threading</span><span class="o">.</span><span class="n">get_ident</span><span class="p">()</span>
<span class="n">module</span><span class="p">,</span> <span class="n">line_number</span><span class="p">,</span> <span class="n">function_name</span> <span class="o">=</span> <span class="n">get_context_info</span><span class="p">()</span>
<span class="k">if</span> <span class="n">module</span> <span class="ow">and</span> <span class="n">line_number</span> <span class="ow">and</span> <span class="n">function_name</span><span class="p">:</span>
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">_thread_id</span><span class="si">}</span><span class="s2">:</span><span class="si">{</span><span class="n">__version__</span><span class="si">}</span><span class="s2"> [DBG] &#39;</span><span class="si">{</span><span class="n">msg</span><span class="si">}</span><span class="s2">&#39; ---&gt; &#39;</span><span class="si">{</span><span class="n">module</span><span class="si">}</span><span class="s2">&#39;:</span><span class="si">{</span><span class="n">line_number</span><span class="si">}</span><span class="s2">, &#39;</span><span class="si">{</span><span class="n">function_name</span><span class="si">}</span><span class="s2">()&#39;&quot;</span><span class="p">,</span>
<span class="o">*</span><span class="n">args</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">_thread_id</span><span class="si">}</span><span class="s2">:</span><span class="si">{</span><span class="n">__version__</span><span class="si">}</span><span class="s2"> [DBG] </span><span class="si">{</span><span class="n">msg</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">)</span></div>
</pre></div>
</div>
</div>
<footer>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2024, CleverThis.</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>
@@ -0,0 +1,304 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" data-content_root="../../../">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>amqp.adapter.pydantic_serializer &mdash; AMQ Adapter Python 1.0 documentation</title>
<link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=03e43079" />
<link rel="stylesheet" type="text/css" href="../../../_static/css/theme.css?v=e59714d7" />
<script src="../../../_static/jquery.js?v=5d32c60e"></script>
<script src="../../../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
<script src="../../../_static/documentation_options.js?v=f2a433a1"></script>
<script src="../../../_static/doctools.js?v=9bcbadda"></script>
<script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
<script src="../../../_static/js/theme.js"></script>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="../../../index.html" class="icon icon-home">
AMQ Adapter Python
</a>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" aria-label="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.html">AMQP Package</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.config.html">Configuration Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.adapter.html">Adapter Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.service.html">Service Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.router.html">Router Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.model.html">Model Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.rabbitmq.html">RabbitMQ Module</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="../../../index.html">AMQ Adapter Python</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="../../../index.html" class="icon icon-home" aria-label="Home"></a></li>
<li class="breadcrumb-item"><a href="../../index.html">Module code</a></li>
<li class="breadcrumb-item active">amqp.adapter.pydantic_serializer</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<h1>Source code for amqp.adapter.pydantic_serializer</h1><div class="highlight"><pre>
<span></span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">This module provides serialization and deserialization functions for Pydantic models that extend BaseModel</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">importlib</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">json</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">uuid</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">datetime</span><span class="w"> </span><span class="kn">import</span> <span class="n">date</span><span class="p">,</span> <span class="n">datetime</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">types</span><span class="w"> </span><span class="kn">import</span> <span class="n">UnionType</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Any</span><span class="p">,</span> <span class="n">Dict</span><span class="p">,</span> <span class="n">Union</span><span class="p">,</span> <span class="n">get_args</span><span class="p">,</span> <span class="n">get_origin</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">urllib.parse</span><span class="w"> </span><span class="kn">import</span> <span class="n">parse_qs</span><span class="p">,</span> <span class="n">urlparse</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">pydantic</span><span class="w"> </span><span class="kn">import</span> <span class="n">BaseModel</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.adapter.logging_utils</span><span class="w"> </span><span class="kn">import</span> <span class="n">logging_debug</span>
<div class="viewcode-block" id="serialize_object">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.pydantic_serializer.serialize_object">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">serialize_object</span><span class="p">(</span><span class="n">obj</span><span class="p">:</span> <span class="n">BaseModel</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Serializes an R2RSerializable object to a string in the format</span>
<span class="sd"> &quot;&lt;ClassName&gt;:{key1:value1, key2:value2,...}&quot;. Handles UUIDs and datetimes,</span>
<span class="sd"> and nested Pydantic models.</span>
<span class="sd"> Args:</span>
<span class="sd"> obj: The BaseModel object to serialize.</span>
<span class="sd"> Returns:</span>
<span class="sd"> A string representation of the object.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">class_name</span> <span class="o">=</span> <span class="n">obj</span><span class="o">.</span><span class="vm">__class__</span><span class="o">.</span><span class="vm">__name__</span>
<span class="n">module_name</span> <span class="o">=</span> <span class="n">obj</span><span class="o">.</span><span class="vm">__class__</span><span class="o">.</span><span class="vm">__module__</span>
<span class="n">obj_dict</span> <span class="o">=</span> <span class="p">{}</span>
<span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">_</span> <span class="ow">in</span> <span class="n">obj</span><span class="o">.</span><span class="n">model_dump</span><span class="p">()</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
<span class="c1"># here we use the original value</span>
<span class="c1"># the one returned by model_dump will convert everything into dict recursively</span>
<span class="n">value</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">key</span><span class="p">)</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="n">uuid</span><span class="o">.</span><span class="n">UUID</span><span class="p">):</span>
<span class="n">obj_dict</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
<span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="n">datetime</span><span class="p">):</span>
<span class="n">obj_dict</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span><span class="o">.</span><span class="n">isoformat</span><span class="p">()</span>
<span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">dict</span><span class="p">):</span> <span class="c1"># Ensure dictionaries are handled</span>
<span class="n">obj_dict</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span>
<span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="n">BaseModel</span><span class="p">):</span>
<span class="n">obj_dict</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">serialize_object</span><span class="p">(</span><span class="n">value</span><span class="p">)</span> <span class="c1"># Recursively serialize</span>
<span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">list</span><span class="p">):</span>
<span class="n">serialized_list</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">value</span><span class="p">:</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="n">BaseModel</span><span class="p">):</span>
<span class="n">serialized_list</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">serialize_object</span><span class="p">(</span><span class="n">item</span><span class="p">))</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">serialized_list</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">item</span><span class="p">)</span>
<span class="n">obj_dict</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">serialized_list</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">obj_dict</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span>
<span class="n">dict_string</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">obj_dict</span><span class="p">)</span>
<span class="k">return</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">module_name</span><span class="si">}</span><span class="s2">.</span><span class="si">{</span><span class="n">class_name</span><span class="si">}</span><span class="s2">:</span><span class="si">{</span><span class="n">dict_string</span><span class="si">}</span><span class="s2">&quot;</span></div>
<div class="viewcode-block" id="python_type_to_json">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.pydantic_serializer.python_type_to_json">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">python_type_to_json</span><span class="p">(</span><span class="n">data</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Convert Python objects (dict, list, tuple, set, datetime, etc.) to a JSON string.</span>
<span class="sd"> Handles common non-JSON-serializable types like datetime, date, and sets.</span>
<span class="sd"> Args:</span>
<span class="sd"> data: Python object to be converted (dict, list, tuple, set, etc.)</span>
<span class="sd"> Returns:</span>
<span class="sd"> str: JSON string representation of the input data</span>
<span class="sd"> Raises:</span>
<span class="sd"> TypeError: If the object contains non-serializable types (e.g., custom classes)</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">def</span><span class="w"> </span><span class="nf">default_serializer</span><span class="p">(</span><span class="n">obj</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Custom serializer for non-JSON-serializable objects.&quot;&quot;&quot;</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="p">(</span><span class="n">datetime</span><span class="p">,</span> <span class="n">date</span><span class="p">)):</span>
<span class="k">return</span> <span class="n">obj</span><span class="o">.</span><span class="n">isoformat</span><span class="p">()</span> <span class="c1"># Convert datetime/date to ISO string</span>
<span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="nb">set</span><span class="p">):</span>
<span class="k">return</span> <span class="nb">list</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span> <span class="c1"># Convert sets to lists</span>
<span class="k">elif</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="s2">&quot;__dict__&quot;</span><span class="p">):</span>
<span class="k">return</span> <span class="n">obj</span><span class="o">.</span><span class="vm">__dict__</span> <span class="c1"># Attempt to serialize custom objects</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Object of type </span><span class="si">{</span><span class="nb">type</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span><span class="si">}</span><span class="s2"> is not JSON serializable&quot;</span><span class="p">)</span>
<span class="k">return</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="n">default_serializer</span><span class="p">,</span> <span class="n">indent</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">ensure_ascii</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span></div>
<div class="viewcode-block" id="try_deserialize_object">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.pydantic_serializer.try_deserialize_object">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">try_deserialize_object</span><span class="p">(</span><span class="n">data</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">BaseModel</span> <span class="o">|</span> <span class="nb">str</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Try deserialize object, if failed, return the input string as-is.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="nb">str</span><span class="p">):</span>
<span class="k">return</span> <span class="n">data</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">return</span> <span class="n">deserialize_object</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="n">logging_debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Failed to deserialize object: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">return</span> <span class="n">data</span></div>
<div class="viewcode-block" id="deserialize_object">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.pydantic_serializer.deserialize_object">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">deserialize_object</span><span class="p">(</span><span class="n">data</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">BaseModel</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Deserializes a string in the format &quot;&lt;ClassName&gt;:{key1:value1, key2:value2,...}&quot;</span>
<span class="sd"> back into an BaseModel object. Handles UUIDs, datetimes, and</span>
<span class="sd"> nested Pydantic models.</span>
<span class="sd"> Args:</span>
<span class="sd"> data: The string to deserialize.</span>
<span class="sd"> Returns:</span>
<span class="sd"> An R2RSerializable object.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">class_path</span><span class="p">,</span> <span class="n">dict_str</span> <span class="o">=</span> <span class="n">data</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;:&quot;</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">module_path</span><span class="p">,</span> <span class="n">class_name</span> <span class="o">=</span> <span class="n">class_path</span><span class="o">.</span><span class="n">rsplit</span><span class="p">(</span><span class="s2">&quot;.&quot;</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">obj_dict</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">dict_str</span><span class="p">)</span>
<span class="n">logging_debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Deserialized object: </span><span class="si">{</span><span class="n">class_path</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="s2">&quot;[&quot;</span> <span class="ow">in</span> <span class="n">class_name</span><span class="p">:</span>
<span class="n">class_name</span> <span class="o">=</span> <span class="n">class_name</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;[&quot;</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">logging_debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;trying object: </span><span class="si">{</span><span class="n">class_name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="n">module</span> <span class="o">=</span> <span class="n">importlib</span><span class="o">.</span><span class="n">import_module</span><span class="p">(</span><span class="n">module_path</span><span class="p">)</span>
<span class="bp">cls</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">module</span><span class="p">,</span> <span class="n">class_name</span><span class="p">)</span>
<span class="k">if</span> <span class="bp">cls</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Unknown class: </span><span class="si">{</span><span class="n">class_name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="c1"># process nested model, dict and list</span>
<span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">obj_dict</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
<span class="n">key_type</span><span class="p">:</span> <span class="nb">type</span><span class="p">[</span><span class="n">Any</span><span class="p">]</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">model_fields</span><span class="p">[</span><span class="n">key</span><span class="p">]</span><span class="o">.</span><span class="n">annotation</span>
<span class="c1"># handle union with none, this will give the true type</span>
<span class="c1"># for example, return `A` if the type is `A | None`</span>
<span class="k">if</span> <span class="n">get_origin</span><span class="p">(</span><span class="n">key_type</span><span class="p">)</span> <span class="ow">is</span> <span class="n">UnionType</span> <span class="ow">or</span> <span class="n">get_origin</span><span class="p">(</span><span class="n">key_type</span><span class="p">)</span> <span class="ow">is</span> <span class="n">Union</span><span class="p">:</span>
<span class="n">union_types</span> <span class="o">=</span> <span class="n">get_args</span><span class="p">(</span><span class="n">key_type</span><span class="p">)</span>
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">union_types</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">2</span><span class="p">:</span>
<span class="c1"># if there are multiple unions, like `A | B | None`</span>
<span class="c1"># then we have no way to figure out which one to use</span>
<span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Unsupported Union type: </span><span class="si">{</span><span class="n">key_type</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="c1"># return the none-None one as the type for processing</span>
<span class="k">if</span> <span class="n">union_types</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="ow">is</span> <span class="nb">type</span><span class="p">(</span><span class="kc">None</span><span class="p">):</span>
<span class="n">key_type</span> <span class="o">=</span> <span class="n">union_types</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">key_type</span> <span class="o">=</span> <span class="n">union_types</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="c1"># skip if the value is None</span>
<span class="k">if</span> <span class="n">value</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">continue</span>
<span class="k">if</span> <span class="n">key_type</span> <span class="o">==</span> <span class="n">uuid</span><span class="o">.</span><span class="n">UUID</span><span class="p">:</span>
<span class="n">obj_dict</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">uuid</span><span class="o">.</span><span class="n">UUID</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">key_type</span> <span class="o">==</span> <span class="n">datetime</span><span class="p">:</span>
<span class="n">obj_dict</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">fromisoformat</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">key_type</span> <span class="o">==</span> <span class="nb">dict</span><span class="p">:</span>
<span class="n">obj_dict</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span>
<span class="k">elif</span> <span class="nb">issubclass</span><span class="p">(</span><span class="n">key_type</span><span class="p">,</span> <span class="n">BaseModel</span><span class="p">):</span>
<span class="n">obj_dict</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">deserialize_object</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">key_type</span> <span class="o">==</span> <span class="nb">list</span><span class="p">:</span>
<span class="n">obj_dict</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="nb">map</span><span class="p">(</span><span class="n">try_deserialize_object</span><span class="p">,</span> <span class="n">value</span><span class="p">))</span>
<span class="k">return</span> <span class="bp">cls</span><span class="p">(</span><span class="o">**</span><span class="n">obj_dict</span><span class="p">)</span></div>
<div class="viewcode-block" id="parse_url_query">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.pydantic_serializer.parse_url_query">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">parse_url_query</span><span class="p">(</span><span class="n">url</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Parses a HTTP GET URL and returns (context_path, query_params_dict)</span>
<span class="sd"> Args:</span>
<span class="sd"> url: The URL string to parse (e.g., &quot;http://example.com/path?foo=1&amp;bar=2&amp;foo=3&quot;)</span>
<span class="sd"> Returns:</span>
<span class="sd"> tuple: (context_path, query_params_dict)</span>
<span class="sd"> - context_path: The path part of the URL (e.g., &quot;/path&quot;)</span>
<span class="sd"> - query_params_dict: Dictionary of query parameters where values are always lists</span>
<span class="sd"> (e.g., {&quot;foo&quot;: [&quot;1&quot;, &quot;3&quot;], &quot;bar&quot;: [&quot;2&quot;]})</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">parsed</span> <span class="o">=</span> <span class="n">urlparse</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
<span class="n">query_params</span> <span class="o">=</span> <span class="n">parse_qs</span><span class="p">(</span><span class="n">parsed</span><span class="o">.</span><span class="n">query</span><span class="p">)</span>
<span class="c1"># Convert values from lists to single values when there&#39;s only one value</span>
<span class="c1"># If you prefer to always keep values as lists, remove this comprehension</span>
<span class="n">simplified_params</span> <span class="o">=</span> <span class="p">{</span><span class="n">k</span><span class="p">:</span> <span class="n">v</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">v</span><span class="p">)</span> <span class="o">==</span> <span class="mi">1</span> <span class="k">else</span> <span class="n">v</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">query_params</span><span class="o">.</span><span class="n">items</span><span class="p">()}</span>
<span class="k">return</span> <span class="p">(</span><span class="n">parsed</span><span class="o">.</span><span class="n">path</span><span class="p">,</span> <span class="n">simplified_params</span><span class="p">)</span></div>
</pre></div>
</div>
</div>
<footer>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2024, CleverThis.</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>
@@ -0,0 +1,216 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" data-content_root="../../../">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>amqp.adapter.serializer &mdash; AMQ Adapter Python 1.0 documentation</title>
<link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=03e43079" />
<link rel="stylesheet" type="text/css" href="../../../_static/css/theme.css?v=e59714d7" />
<script src="../../../_static/jquery.js?v=5d32c60e"></script>
<script src="../../../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
<script src="../../../_static/documentation_options.js?v=f2a433a1"></script>
<script src="../../../_static/doctools.js?v=9bcbadda"></script>
<script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
<script src="../../../_static/js/theme.js"></script>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="../../../index.html" class="icon icon-home">
AMQ Adapter Python
</a>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" aria-label="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.html">AMQP Package</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.config.html">Configuration Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.adapter.html">Adapter Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.service.html">Service Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.router.html">Router Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.model.html">Model Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.rabbitmq.html">RabbitMQ Module</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="../../../index.html">AMQ Adapter Python</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="../../../index.html" class="icon icon-home" aria-label="Home"></a></li>
<li class="breadcrumb-item"><a href="../../index.html">Module code</a></li>
<li class="breadcrumb-item active">amqp.adapter.serializer</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<h1>Source code for amqp.adapter.serializer</h1><div class="highlight"><pre>
<span></span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">Helper functions used to aid with (de)serialization of messages sent over AMQP.</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">struct</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">io</span><span class="w"> </span><span class="kn">import</span> <span class="n">BytesIO</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Dict</span><span class="p">,</span> <span class="n">List</span><span class="p">,</span> <span class="n">Union</span>
<div class="viewcode-block" id="long_to_bytes">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.serializer.long_to_bytes">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">long_to_bytes</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bytes</span><span class="p">:</span>
<span class="k">return</span> <span class="n">struct</span><span class="o">.</span><span class="n">pack</span><span class="p">(</span><span class="s2">&quot;q&quot;</span><span class="p">,</span> <span class="n">x</span><span class="p">)</span></div>
<div class="viewcode-block" id="bytes_to_long">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.serializer.bytes_to_long">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">bytes_to_long</span><span class="p">(</span><span class="n">b</span><span class="p">:</span> <span class="nb">bytes</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
<span class="k">return</span> <span class="n">struct</span><span class="o">.</span><span class="n">unpack</span><span class="p">(</span><span class="s2">&quot;q&quot;</span><span class="p">,</span> <span class="n">b</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span></div>
<div class="viewcode-block" id="read_long">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.serializer.read_long">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">read_long</span><span class="p">(</span><span class="n">bis</span><span class="p">:</span> <span class="n">BytesIO</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">return</span> <span class="n">struct</span><span class="o">.</span><span class="n">unpack</span><span class="p">(</span><span class="s2">&quot;q&quot;</span><span class="p">,</span> <span class="n">bis</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="mi">8</span><span class="p">))[</span><span class="mi">0</span><span class="p">]</span>
<span class="k">except</span> <span class="n">struct</span><span class="o">.</span><span class="n">error</span><span class="p">:</span>
<span class="k">return</span> <span class="mi">0</span></div>
<div class="viewcode-block" id="object_or_list_as_string">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.serializer.object_or_list_as_string">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">object_or_list_as_string</span><span class="p">(</span><span class="n">value</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]])</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">list</span><span class="p">):</span>
<span class="k">return</span> <span class="sa">f</span><span class="s2">&quot;[</span><span class="si">{</span><span class="s1">&#39;,&#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">value</span><span class="p">)</span><span class="si">}</span><span class="s2">]&quot;</span>
<span class="k">return</span> <span class="nb">str</span><span class="p">(</span><span class="n">value</span><span class="p">)</span></div>
<div class="viewcode-block" id="map_as_string">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.serializer.map_as_string">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">map_as_string</span><span class="p">(</span><span class="n">map_</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">str</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="k">return</span> <span class="s2">&quot;,&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">k</span><span class="si">}</span><span class="s2">=</span><span class="si">{</span><span class="n">object_or_list_as_string</span><span class="p">(</span><span class="n">v</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">map_</span><span class="o">.</span><span class="n">items</span><span class="p">())</span></div>
<div class="viewcode-block" id="map_with_list_as_string">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.serializer.map_with_list_as_string">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">map_with_list_as_string</span><span class="p">(</span><span class="n">map_</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]])</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="k">return</span> <span class="s2">&quot;,&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">k</span><span class="si">}</span><span class="s2">=</span><span class="si">{</span><span class="n">object_or_list_as_string</span><span class="p">(</span><span class="n">v</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">map_</span><span class="o">.</span><span class="n">items</span><span class="p">())</span></div>
<div class="viewcode-block" id="parse_map_string">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.serializer.parse_map_string">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">parse_map_string</span><span class="p">(</span><span class="n">input_str</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">str</span><span class="p">]:</span>
<span class="n">map_</span> <span class="o">=</span> <span class="p">{}</span>
<span class="k">if</span> <span class="n">input_str</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&quot;{&quot;</span><span class="p">)</span> <span class="ow">and</span> <span class="n">input_str</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="s2">&quot;}&quot;</span><span class="p">):</span>
<span class="k">for</span> <span class="n">entry</span> <span class="ow">in</span> <span class="nb">str</span><span class="p">(</span><span class="n">input_str</span><span class="p">[</span><span class="mi">1</span><span class="p">:</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2">&quot;</span><span class="p">,</span> <span class="s2">&quot;&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;,&quot;</span><span class="p">):</span>
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">entry</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">:</span>
<span class="k">if</span> <span class="n">entry</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s1">&#39;&quot;&#39;</span><span class="p">):</span>
<span class="n">key</span><span class="p">,</span> <span class="n">value</span> <span class="o">=</span> <span class="n">entry</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;:&quot;</span><span class="p">)</span>
<span class="n">map_</span><span class="p">[</span><span class="n">key</span><span class="o">.</span><span class="n">strip</span><span class="p">(</span><span class="s1">&#39;&quot;&#39;</span><span class="p">)]</span> <span class="o">=</span> <span class="n">value</span><span class="o">.</span><span class="n">strip</span><span class="p">(</span><span class="s1">&#39;&quot;&#39;</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">key</span><span class="p">,</span> <span class="n">value</span> <span class="o">=</span> <span class="n">entry</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;=&quot;</span><span class="p">)</span>
<span class="n">map_</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span>
<span class="k">return</span> <span class="n">map_</span></div>
<div class="viewcode-block" id="csv_as_list">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.serializer.csv_as_list">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">csv_as_list</span><span class="p">(</span><span class="n">input_str</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]:</span>
<span class="k">return</span> <span class="p">[</span><span class="n">item</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span> <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">input_str</span><span class="o">.</span><span class="n">strip</span><span class="p">(</span><span class="s2">&quot;[]&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;,&quot;</span><span class="p">)]</span></div>
<div class="viewcode-block" id="add_to_map">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.serializer.add_to_map">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">add_to_map</span><span class="p">(</span><span class="n">map_</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]],</span> <span class="n">token</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">eq_idx</span> <span class="o">=</span> <span class="n">token</span><span class="o">.</span><span class="n">index</span><span class="p">(</span><span class="s2">&quot;=&quot;</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">ValueError</span><span class="p">:</span>
<span class="n">eq_idx</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span> <span class="c1"># set to -1 when not found</span>
<span class="k">if</span> <span class="n">eq_idx</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
<span class="n">key</span> <span class="o">=</span> <span class="n">token</span><span class="p">[:</span><span class="n">eq_idx</span><span class="p">]</span>
<span class="n">map_</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">csv_as_list</span><span class="p">(</span><span class="n">token</span><span class="p">[</span><span class="n">eq_idx</span> <span class="o">+</span> <span class="mi">1</span> <span class="p">:])</span></div>
<div class="viewcode-block" id="parse_map_list_string">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.serializer.parse_map_list_string">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">parse_map_list_string</span><span class="p">(</span><span class="n">input_str</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]]:</span>
<span class="n">map_</span> <span class="o">=</span> <span class="p">{}</span>
<span class="k">if</span> <span class="n">input_str</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&quot;{&quot;</span><span class="p">)</span> <span class="ow">and</span> <span class="n">input_str</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="s2">&quot;}&quot;</span><span class="p">):</span>
<span class="k">for</span> <span class="n">token</span> <span class="ow">in</span> <span class="n">input_str</span><span class="p">[</span><span class="mi">1</span><span class="p">:</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;],&quot;</span><span class="p">):</span>
<span class="n">add_to_map</span><span class="p">(</span><span class="n">map_</span><span class="p">,</span> <span class="n">token</span><span class="p">)</span>
<span class="k">return</span> <span class="n">map_</span></div>
<div class="viewcode-block" id="str_to_bool">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.serializer.str_to_bool">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">str_to_bool</span><span class="p">(</span><span class="n">value</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
<span class="k">return</span> <span class="n">value</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="ow">in</span> <span class="p">(</span><span class="s2">&quot;true&quot;</span><span class="p">,</span> <span class="s2">&quot;yes&quot;</span><span class="p">,</span> <span class="s2">&quot;1&quot;</span><span class="p">,</span> <span class="s2">&quot;t&quot;</span><span class="p">,</span> <span class="s2">&quot;y&quot;</span><span class="p">,</span> <span class="s2">&quot;on&quot;</span><span class="p">)</span></div>
</pre></div>
</div>
</div>
<footer>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2024, CleverThis.</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>
@@ -0,0 +1,278 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" data-content_root="../../../">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>amqp.adapter.service_message_factory &mdash; AMQ Adapter Python 1.0 documentation</title>
<link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=03e43079" />
<link rel="stylesheet" type="text/css" href="../../../_static/css/theme.css?v=e59714d7" />
<script src="../../../_static/jquery.js?v=5d32c60e"></script>
<script src="../../../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
<script src="../../../_static/documentation_options.js?v=f2a433a1"></script>
<script src="../../../_static/doctools.js?v=9bcbadda"></script>
<script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
<script src="../../../_static/js/theme.js"></script>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="../../../index.html" class="icon icon-home">
AMQ Adapter Python
</a>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" aria-label="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.html">AMQP Package</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.config.html">Configuration Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.adapter.html">Adapter Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.service.html">Service Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.router.html">Router Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.model.html">Model Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.rabbitmq.html">RabbitMQ Module</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="../../../index.html">AMQ Adapter Python</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="../../../index.html" class="icon icon-home" aria-label="Home"></a></li>
<li class="breadcrumb-item"><a href="../../index.html">Module code</a></li>
<li class="breadcrumb-item active">amqp.adapter.service_message_factory</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<h1>Source code for amqp.adapter.service_message_factory</h1><div class="highlight"><pre>
<span></span><span class="kn">import</span><span class="w"> </span><span class="nn">base64</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.adapter.data_message_factory</span><span class="w"> </span><span class="kn">import</span> <span class="n">DataMessageFactory</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.adapter.logging_utils</span><span class="w"> </span><span class="kn">import</span> <span class="n">logging_error</span><span class="p">,</span> <span class="n">logging_info</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.adapter.serializer</span><span class="w"> </span><span class="kn">import</span> <span class="n">map_as_string</span><span class="p">,</span> <span class="n">parse_map_string</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.adapter.trace_info_adapter</span><span class="w"> </span><span class="kn">import</span> <span class="n">TraceInfoAdapter</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.model.model</span><span class="w"> </span><span class="kn">import</span> <span class="n">ServiceMessage</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.model.service_message_type</span><span class="w"> </span><span class="kn">import</span> <span class="n">ServiceMessageType</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.model.snowflake_id</span><span class="w"> </span><span class="kn">import</span> <span class="n">SnowflakeId</span>
<span class="n">RS</span> <span class="o">=</span> <span class="s2">&quot;|&quot;</span>
<span class="n">SPLIT_RS</span> <span class="o">=</span> <span class="sa">r</span><span class="s2">&quot;\|&quot;</span>
<span class="n">INVALID_MESSAGE</span> <span class="o">=</span> <span class="n">ServiceMessage</span><span class="p">()</span> <span class="c1"># default values mean invalid message</span>
<div class="viewcode-block" id="ServiceMessageFactory">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.service_message_factory.ServiceMessageFactory">[docs]</a>
<span class="k">class</span><span class="w"> </span><span class="nc">ServiceMessageFactory</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> build/serialize/deserialize CleverMicro Service Message class</span>
<span class="sd"> &quot;&quot;&quot;</span>
<div class="viewcode-block" id="ServiceMessageFactory.__init__">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.service_message_factory.ServiceMessageFactory.__init__">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">:</span> <span class="nb">str</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">process_name</span> <span class="o">=</span> <span class="n">name</span></div>
<div class="viewcode-block" id="ServiceMessageFactory.to_string">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.service_message_factory.ServiceMessageFactory.to_string">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">to_string</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">ServiceMessage</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Convert ServiceMessage to human-readable format</span>
<span class="sd"> :param message: ServiceMessage object</span>
<span class="sd"> :return: as string</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="n">message</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">return</span> <span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;ServiceMessage</span><span class="se">{{</span><span class="s2">id=</span><span class="si">{</span><span class="n">message</span><span class="o">.</span><span class="n">id</span><span class="o">.</span><span class="n">as_string</span><span class="p">()</span><span class="si">}</span><span class="s2">|type=</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">format_message_type</span><span class="p">(</span><span class="n">message</span><span class="p">)</span><span class="si">}</span><span class="s2">|&quot;</span>
<span class="sa">f</span><span class="s2">&quot;recipient=</span><span class="si">{</span><span class="n">message</span><span class="o">.</span><span class="n">recipient_name</span><span class="si">}</span><span class="s2">|replyTo=</span><span class="si">{</span><span class="n">message</span><span class="o">.</span><span class="n">reply_to</span><span class="si">}</span><span class="s2">|&quot;</span>
<span class="sa">f</span><span class="s2">&quot;traceInfo=</span><span class="si">{</span><span class="n">message</span><span class="o">.</span><span class="n">trace_info</span><span class="si">}</span><span class="s2">|body=</span><span class="si">{</span><span class="n">base64</span><span class="o">.</span><span class="n">b64encode</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">message</span><span class="o">.</span><span class="n">encode</span><span class="p">())</span><span class="o">.</span><span class="n">decode</span><span class="p">()</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="n">message</span><span class="o">.</span><span class="n">payload_type</span><span class="w"> </span><span class="o">&amp;</span><span class="w"> </span><span class="mh">0x80</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="n">message</span><span class="o">.</span><span class="n">message</span><span class="si">}</span><span class="se">}}</span><span class="s2">&quot;</span>
<span class="p">)</span>
<span class="k">return</span> <span class="s2">&quot;null&quot;</span></div>
<div class="viewcode-block" id="ServiceMessageFactory.of">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.service_message_factory.ServiceMessageFactory.of">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">of</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span> <span class="n">message_type</span><span class="p">:</span> <span class="n">ServiceMessageType</span><span class="p">,</span> <span class="n">payload</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">recipient_name</span><span class="p">:</span> <span class="nb">str</span>
<span class="p">)</span> <span class="o">-&gt;</span> <span class="n">ServiceMessage</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Builds ServiceMessage object from relevant values.</span>
<span class="sd"> :param message_type: enum Message type</span>
<span class="sd"> :param payload: Message content, stored as-is</span>
<span class="sd"> :param recipient_name: Recipient name (from the routing expression)</span>
<span class="sd"> :return: ServiceMessage object</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">_id</span> <span class="o">=</span> <span class="n">DataMessageFactory</span><span class="o">.</span><span class="n">get_instance</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">generate_snowflake_id</span><span class="p">()</span>
<span class="k">return</span> <span class="n">ServiceMessage</span><span class="p">(</span>
<span class="nb">id</span><span class="o">=</span><span class="n">_id</span><span class="p">,</span>
<span class="n">payload_type</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span>
<span class="n">message_type</span><span class="o">=</span><span class="n">message_type</span><span class="p">,</span>
<span class="n">recipient_name</span><span class="o">=</span><span class="n">recipient_name</span><span class="p">,</span>
<span class="n">reply_to</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">process_name</span><span class="p">,</span>
<span class="n">trace_info</span><span class="o">=</span><span class="n">TraceInfoAdapter</span><span class="o">.</span><span class="n">create_produce_span</span><span class="p">(</span><span class="n">_id</span><span class="p">),</span>
<span class="n">message</span><span class="o">=</span><span class="n">payload</span><span class="p">,</span>
<span class="p">)</span></div>
<div class="viewcode-block" id="ServiceMessageFactory.as_base64">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.service_message_factory.ServiceMessageFactory.as_base64">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">as_base64</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span> <span class="n">message_type</span><span class="p">:</span> <span class="n">ServiceMessageType</span><span class="p">,</span> <span class="n">payload</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">recipient_name</span><span class="p">:</span> <span class="nb">str</span>
<span class="p">)</span> <span class="o">-&gt;</span> <span class="n">ServiceMessage</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Builds ServiceMessage object from relevant values, stores content Base64 encoded.</span>
<span class="sd"> :param message_type: enum Message type</span>
<span class="sd"> :param payload: Message content, stored as Base64 string</span>
<span class="sd"> :param recipient_name: Recipient name (from the routing expression)</span>
<span class="sd"> :return: ServiceMessage object</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">_id</span> <span class="o">=</span> <span class="n">DataMessageFactory</span><span class="o">.</span><span class="n">get_instance</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">generate_snowflake_id</span><span class="p">()</span>
<span class="k">return</span> <span class="n">ServiceMessage</span><span class="p">(</span>
<span class="nb">id</span><span class="o">=</span><span class="n">_id</span><span class="p">,</span>
<span class="n">payload_type</span><span class="o">=</span><span class="mh">0x80</span><span class="p">,</span>
<span class="n">message_type</span><span class="o">=</span><span class="n">message_type</span><span class="p">,</span>
<span class="n">recipient_name</span><span class="o">=</span><span class="n">recipient_name</span><span class="p">,</span>
<span class="n">reply_to</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">process_name</span><span class="p">,</span>
<span class="n">trace_info</span><span class="o">=</span><span class="n">TraceInfoAdapter</span><span class="o">.</span><span class="n">create_produce_span</span><span class="p">(</span><span class="n">_id</span><span class="o">.</span><span class="n">as_string</span><span class="p">()),</span>
<span class="n">message</span><span class="o">=</span><span class="n">payload</span><span class="p">,</span>
<span class="p">)</span></div>
<div class="viewcode-block" id="ServiceMessageFactory.from_bytes">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.service_message_factory.ServiceMessageFactory.from_bytes">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">from_bytes</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">input_bytes</span><span class="p">:</span> <span class="nb">bytes</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">ServiceMessage</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Deserialize ServiceMessage from byte array serialized form.</span>
<span class="sd"> :param input_bytes: serialized ServiceMessage</span>
<span class="sd"> :return: ServiceMessage object represented by the input.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">logging_info</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;ServiceMessage &gt;&gt;&gt; [</span><span class="si">{</span><span class="n">input_bytes</span><span class="o">.</span><span class="n">decode</span><span class="p">()</span><span class="si">}</span><span class="s2">]&quot;</span><span class="p">)</span>
<span class="n">input_str_array</span> <span class="o">=</span> <span class="n">input_bytes</span><span class="o">.</span><span class="n">decode</span><span class="p">()</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="n">RS</span><span class="p">)</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">i</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">_id</span> <span class="o">=</span> <span class="n">input_str_array</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>
<span class="n">i</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="n">payload_type</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">input_str_array</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="mi">16</span><span class="p">)</span>
<span class="n">i</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="n">message_type</span> <span class="o">=</span> <span class="n">ServiceMessageType</span><span class="p">(</span><span class="n">payload_type</span> <span class="o">+</span> <span class="mi">1</span> <span class="o">&amp;</span> <span class="mh">0x7F</span><span class="p">)</span>
<span class="n">recipient_name</span> <span class="o">=</span> <span class="n">input_str_array</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="k">if</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="nb">len</span><span class="p">(</span><span class="n">input_str_array</span><span class="p">)</span> <span class="k">else</span> <span class="s2">&quot;&quot;</span>
<span class="n">i</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="n">reply_to</span> <span class="o">=</span> <span class="n">input_str_array</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="k">if</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="nb">len</span><span class="p">(</span><span class="n">input_str_array</span><span class="p">)</span> <span class="k">else</span> <span class="s2">&quot;&quot;</span>
<span class="n">i</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="n">trace_info</span> <span class="o">=</span> <span class="n">parse_map_string</span><span class="p">(</span><span class="n">input_str_array</span><span class="p">[</span><span class="n">i</span><span class="p">])</span> <span class="k">if</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="nb">len</span><span class="p">(</span><span class="n">input_str_array</span><span class="p">)</span> <span class="k">else</span> <span class="p">{}</span>
<span class="n">i</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="n">message</span> <span class="o">=</span> <span class="n">input_str_array</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="k">if</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="nb">len</span><span class="p">(</span><span class="n">input_str_array</span><span class="p">)</span> <span class="k">else</span> <span class="s2">&quot;&quot;</span>
<span class="k">return</span> <span class="n">ServiceMessage</span><span class="p">(</span>
<span class="nb">id</span><span class="o">=</span><span class="n">SnowflakeId</span><span class="o">.</span><span class="n">from_hex</span><span class="p">(</span><span class="n">_id</span><span class="p">),</span>
<span class="n">payload_type</span><span class="o">=</span><span class="n">payload_type</span><span class="p">,</span>
<span class="n">message_type</span><span class="o">=</span><span class="n">message_type</span><span class="p">,</span>
<span class="n">recipient_name</span><span class="o">=</span><span class="n">recipient_name</span><span class="p">,</span>
<span class="n">reply_to</span><span class="o">=</span><span class="n">reply_to</span><span class="p">,</span>
<span class="n">trace_info</span><span class="o">=</span><span class="n">trace_info</span><span class="p">,</span>
<span class="n">message</span><span class="o">=</span><span class="p">(</span><span class="n">base64</span><span class="o">.</span><span class="n">b64decode</span><span class="p">(</span><span class="n">message</span><span class="p">)</span><span class="o">.</span><span class="n">decode</span><span class="p">()</span> <span class="k">if</span> <span class="n">payload_type</span> <span class="o">&amp;</span> <span class="mh">0x80</span> <span class="k">else</span> <span class="n">message</span><span class="p">),</span>
<span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="n">logging_error</span><span class="p">(</span>
<span class="s2">&quot;Unexpected ServiceMessage format. Expected 6 tokens separated by &#39;|&#39; in format: &quot;</span>
<span class="s2">&quot;[ID(64bit number)|MessageType(8bit number)|RecipientName(String)|&quot;</span>
<span class="s2">&quot;ReplyTo(String)|TraceInfo|Payload(String or Base64)], got: &quot;</span>
<span class="s2">&quot;[</span><span class="si">%s</span><span class="s2">], reported problem: </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span>
<span class="n">input_bytes</span><span class="o">.</span><span class="n">decode</span><span class="p">(),</span>
<span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">),</span>
<span class="p">)</span>
<span class="k">return</span> <span class="n">INVALID_MESSAGE</span></div>
<div class="viewcode-block" id="ServiceMessageFactory.serialize">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.service_message_factory.ServiceMessageFactory.serialize">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">serialize</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">ServiceMessage</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bytes</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Serialize ServiceMessage to byte array.</span>
<span class="sd"> :param message: ServiceMessage to serialize.</span>
<span class="sd"> :return: serialized object.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">message</span><span class="o">.</span><span class="n">id</span><span class="o">.</span><span class="n">as_string</span><span class="p">()</span><span class="si">}{</span><span class="n">RS</span><span class="si">}{</span><span class="bp">self</span><span class="o">.</span><span class="n">format_message_type</span><span class="p">(</span><span class="n">message</span><span class="p">)</span><span class="si">}{</span><span class="n">RS</span><span class="si">}{</span><span class="n">message</span><span class="o">.</span><span class="n">recipient_name</span><span class="si">}{</span><span class="n">RS</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">message</span><span class="o">.</span><span class="n">reply_to</span><span class="si">}{</span><span class="n">RS</span><span class="si">}{</span><span class="n">map_as_string</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">trace_info</span><span class="p">)</span><span class="si">}{</span><span class="n">RS</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">base64</span><span class="o">.</span><span class="n">b64encode</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">message</span><span class="o">.</span><span class="n">encode</span><span class="p">())</span><span class="o">.</span><span class="n">decode</span><span class="p">()</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="n">message</span><span class="o">.</span><span class="n">payload_type</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="n">message</span><span class="o">.</span><span class="n">message</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="p">)</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s2">&quot;utf-8&quot;</span><span class="p">)</span></div>
<div class="viewcode-block" id="ServiceMessageFactory.format_message_type">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.service_message_factory.ServiceMessageFactory.format_message_type">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">format_message_type</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">ServiceMessage</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Formats the Enum message type and decorates it with base64 flag at highest bit.</span>
<span class="sd"> For compatibility with 0-based enum ordinals in Java subtract 1 from ordinal value.</span>
<span class="sd"> :param message: Service message to send</span>
<span class="sd"> :return: formatted message type</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">num_type</span> <span class="o">=</span> <span class="p">(</span>
<span class="n">message</span><span class="o">.</span><span class="n">message_type</span><span class="o">.</span><span class="n">value</span> <span class="k">if</span> <span class="n">message</span><span class="o">.</span><span class="n">message_type</span> <span class="k">else</span> <span class="n">ServiceMessageType</span><span class="o">.</span><span class="n">UNKNOWN</span><span class="o">.</span><span class="n">value</span>
<span class="p">)</span> <span class="o">-</span> <span class="mi">1</span>
<span class="n">fmt</span> <span class="o">=</span> <span class="p">(</span><span class="n">num_type</span> <span class="o">&amp;</span> <span class="mh">0x7F</span><span class="p">)</span> <span class="o">|</span> <span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">payload_type</span> <span class="o">&amp;</span> <span class="mh">0x80</span><span class="p">)</span>
<span class="k">return</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">fmt</span><span class="si">:</span><span class="s2">02X</span><span class="si">}</span><span class="s2">&quot;</span></div>
</div>
</pre></div>
</div>
</div>
<footer>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2024, CleverThis.</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>
@@ -0,0 +1,126 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" data-content_root="../../../">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>amqp.adapter.trace_info_adapter &mdash; AMQ Adapter Python 1.0 documentation</title>
<link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=03e43079" />
<link rel="stylesheet" type="text/css" href="../../../_static/css/theme.css?v=e59714d7" />
<script src="../../../_static/jquery.js?v=5d32c60e"></script>
<script src="../../../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
<script src="../../../_static/documentation_options.js?v=f2a433a1"></script>
<script src="../../../_static/doctools.js?v=9bcbadda"></script>
<script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
<script src="../../../_static/js/theme.js"></script>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="../../../index.html" class="icon icon-home">
AMQ Adapter Python
</a>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" aria-label="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.html">AMQP Package</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.config.html">Configuration Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.adapter.html">Adapter Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.service.html">Service Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.router.html">Router Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.model.html">Model Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.rabbitmq.html">RabbitMQ Module</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="../../../index.html">AMQ Adapter Python</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="../../../index.html" class="icon icon-home" aria-label="Home"></a></li>
<li class="breadcrumb-item"><a href="../../index.html">Module code</a></li>
<li class="breadcrumb-item active">amqp.adapter.trace_info_adapter</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<h1>Source code for amqp.adapter.trace_info_adapter</h1><div class="highlight"><pre>
<span></span><span class="kn">from</span><span class="w"> </span><span class="nn">dataclasses</span><span class="w"> </span><span class="kn">import</span> <span class="n">dataclass</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Dict</span>
<div class="viewcode-block" id="TraceInfoAdapter">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.trace_info_adapter.TraceInfoAdapter">[docs]</a>
<span class="nd">@dataclass</span>
<span class="k">class</span><span class="w"> </span><span class="nc">TraceInfoAdapter</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> TODO This class should set up the Open Telemetry tracing stack. To be done later.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<div class="viewcode-block" id="TraceInfoAdapter.create_produce_span">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.trace_info_adapter.TraceInfoAdapter.create_produce_span">[docs]</a>
<span class="nd">@staticmethod</span>
<span class="k">def</span><span class="w"> </span><span class="nf">create_produce_span</span><span class="p">(</span><span class="n">message_id</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">str</span><span class="p">]:</span>
<span class="k">return</span> <span class="p">{</span><span class="s2">&quot;trace-id&quot;</span><span class="p">:</span> <span class="n">message_id</span><span class="p">}</span></div>
</div>
</pre></div>
</div>
</div>
<footer>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2024, CleverThis.</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>
@@ -0,0 +1,324 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" data-content_root="../../../">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>amqp.adapter.type_descriptor &mdash; AMQ Adapter Python 1.0 documentation</title>
<link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=03e43079" />
<link rel="stylesheet" type="text/css" href="../../../_static/css/theme.css?v=e59714d7" />
<script src="../../../_static/jquery.js?v=5d32c60e"></script>
<script src="../../../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
<script src="../../../_static/documentation_options.js?v=f2a433a1"></script>
<script src="../../../_static/doctools.js?v=9bcbadda"></script>
<script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
<script src="../../../_static/js/theme.js"></script>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="../../../index.html" class="icon icon-home">
AMQ Adapter Python
</a>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" aria-label="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.html">AMQP Package</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.config.html">Configuration Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.adapter.html">Adapter Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.service.html">Service Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.router.html">Router Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.model.html">Model Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.rabbitmq.html">RabbitMQ Module</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="../../../index.html">AMQ Adapter Python</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="../../../index.html" class="icon icon-home" aria-label="Home"></a></li>
<li class="breadcrumb-item"><a href="../../index.html">Module code</a></li>
<li class="breadcrumb-item active">amqp.adapter.type_descriptor</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<h1>Source code for amqp.adapter.type_descriptor</h1><div class="highlight"><pre>
<span></span><span class="sd">&quot;&quot;&quot; &quot;&quot;&quot;</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">importlib</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">json</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Any</span>
<div class="viewcode-block" id="TypeDescriptor">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.type_descriptor.TypeDescriptor">[docs]</a>
<span class="k">class</span><span class="w"> </span><span class="nc">TypeDescriptor</span><span class="p">:</span>
<div class="viewcode-block" id="TypeDescriptor.__init__">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.type_descriptor.TypeDescriptor.__init__">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">type_string</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">extra_init_data</span><span class="p">:</span> <span class="nb">dict</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">type_string</span> <span class="o">=</span> <span class="n">type_string</span>
<span class="bp">self</span><span class="o">.</span><span class="n">extra_init_data</span> <span class="o">=</span> <span class="n">extra_init_data</span> <span class="ow">or</span> <span class="p">{}</span>
<span class="bp">self</span><span class="o">.</span><span class="n">is_json</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span>
<span class="bp">self</span><span class="o">.</span><span class="n">type</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_extract_type</span><span class="p">()</span></div>
<span class="k">def</span><span class="w"> </span><span class="nf">_extract_type</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">type_string</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&quot;&lt;class &#39;&quot;</span><span class="p">):</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">type_string</span><span class="p">[</span><span class="mi">8</span><span class="p">:</span><span class="o">-</span><span class="mi">2</span><span class="p">]</span>
<span class="c1"># Handle Annotated case of FastAPI annotation</span>
<span class="k">if</span> <span class="s2">&quot;typing.Optional&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">type_string</span><span class="p">:</span>
<span class="n">annotated</span> <span class="o">=</span> <span class="n">_extract_type_of</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">type_string</span><span class="p">)</span>
<span class="k">if</span> <span class="s2">&quot;typing.Annotated&quot;</span> <span class="ow">in</span> <span class="n">annotated</span><span class="p">:</span>
<span class="c1"># Extract content between the first square brackets after Annotated</span>
<span class="n">match</span> <span class="o">=</span> <span class="n">_extract_type_of</span><span class="p">(</span><span class="n">annotated</span><span class="p">)</span>
<span class="k">if</span> <span class="n">match</span><span class="p">:</span>
<span class="c1"># Split by comma and get first part, then strip whitespace</span>
<span class="n">parts</span> <span class="o">=</span> <span class="p">[</span><span class="n">p</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">match</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;,&quot;</span><span class="p">)]</span>
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">parts</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">is_json</span> <span class="o">=</span> <span class="n">parts</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="o">==</span> <span class="s2">&quot;json&quot;</span>
<span class="k">return</span> <span class="n">parts</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">if</span> <span class="n">parts</span> <span class="k">else</span> <span class="s2">&quot;&quot;</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># Handle simple Optional case</span>
<span class="k">return</span> <span class="n">annotated</span>
<span class="k">return</span> <span class="n">_extract_type_of</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">type_string</span><span class="p">)</span>
<div class="viewcode-block" id="TypeDescriptor.instantiate">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.type_descriptor.TypeDescriptor.instantiate">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">instantiate</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">payload</span><span class="p">:</span> <span class="n">Any</span><span class="p">,</span> <span class="n">is_json</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Any</span><span class="p">:</span>
<span class="k">return</span> <span class="n">_instantiate</span><span class="p">(</span>
<span class="p">(</span>
<span class="bp">self</span><span class="o">.</span><span class="n">type</span>
<span class="k">if</span> <span class="s2">&quot;typing.Optional&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">type_string</span> <span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">type_string</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&quot;&lt;class &quot;</span><span class="p">)</span>
<span class="k">else</span> <span class="bp">self</span><span class="o">.</span><span class="n">type_string</span>
<span class="p">),</span>
<span class="n">payload</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">is_json</span> <span class="ow">or</span> <span class="n">is_json</span><span class="p">,</span>
<span class="n">extra_init_data</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">extra_init_data</span><span class="p">,</span>
<span class="p">)</span></div>
<span class="k">def</span><span class="w"> </span><span class="fm">__repr__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="k">return</span> <span class="sa">f</span><span class="s2">&quot;TypeDescriptor(type=&#39;</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">type</span><span class="si">}</span><span class="s2">&#39;, is_json=</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">is_json</span><span class="si">}</span><span class="s2">)&quot;</span></div>
<span class="k">def</span><span class="w"> </span><span class="nf">_extract_type_of</span><span class="p">(</span><span class="n">input_string</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="n">stack</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">start_index</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span>
<span class="n">end_index</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span>
<span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">char</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">input_string</span><span class="p">):</span>
<span class="k">if</span> <span class="n">i</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span> <span class="c1"># this assumes paramerized type, that must be at lest 1 char long</span>
<span class="k">if</span> <span class="n">char</span> <span class="o">==</span> <span class="s2">&quot;[&quot;</span><span class="p">:</span>
<span class="k">if</span> <span class="n">start_index</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">:</span>
<span class="n">start_index</span> <span class="o">=</span> <span class="n">i</span>
<span class="n">stack</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">char</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">char</span> <span class="o">==</span> <span class="s2">&quot;]&quot;</span><span class="p">:</span>
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">stack</span><span class="p">)</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
<span class="n">end_index</span> <span class="o">=</span> <span class="n">i</span>
<span class="k">break</span>
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">stack</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
<span class="n">stack</span><span class="o">.</span><span class="n">pop</span><span class="p">()</span>
<span class="k">if</span> <span class="n">start_index</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span> <span class="ow">and</span> <span class="n">end_index</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">:</span>
<span class="k">return</span> <span class="n">input_string</span><span class="p">[</span><span class="n">start_index</span> <span class="o">+</span> <span class="mi">1</span> <span class="p">:</span> <span class="n">end_index</span><span class="p">]</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">return</span> <span class="n">input_string</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span> <span class="k">if</span> <span class="n">start_index</span> <span class="o">==</span> <span class="mi">1</span> <span class="ow">and</span> <span class="n">end_index</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span> <span class="k">else</span> <span class="s2">&quot;&quot;</span>
<div class="viewcode-block" id="merge_extra_init_data">
<a class="viewcode-back" href="../../../modules/amqp.adapter.html#amqp.adapter.type_descriptor.merge_extra_init_data">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">merge_extra_init_data</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">json_payload</span><span class="p">,</span> <span class="n">extra_init_data</span><span class="p">:</span> <span class="nb">dict</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Merges extra_init_data into json_payload only when:</span>
<span class="sd"> 1. cls has an attribute named like the key</span>
<span class="sd"> 2. json_payload doesn&#39;t already have the key</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="p">{</span>
<span class="o">**</span><span class="n">json_payload</span><span class="p">,</span>
<span class="o">**</span><span class="p">{</span>
<span class="n">k</span><span class="p">:</span> <span class="n">v</span>
<span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">extra_init_data</span><span class="o">.</span><span class="n">items</span><span class="p">()</span>
<span class="k">if</span> <span class="p">(</span><span class="nb">hasattr</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">k</span><span class="p">)</span> <span class="ow">or</span> <span class="p">(</span><span class="nb">hasattr</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="s2">&quot;model_fields&quot;</span><span class="p">)</span> <span class="ow">and</span> <span class="n">k</span> <span class="ow">in</span> <span class="bp">cls</span><span class="o">.</span><span class="n">model_fields</span><span class="p">))</span>
<span class="ow">and</span> <span class="n">k</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">json_payload</span>
<span class="p">},</span>
<span class="p">}</span></div>
<span class="k">def</span><span class="w"> </span><span class="nf">_instantiate</span><span class="p">(</span>
<span class="n">type_string</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">payload</span><span class="p">:</span> <span class="n">Any</span><span class="p">,</span> <span class="n">is_json</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span><span class="p">,</span> <span class="n">extra_init_data</span><span class="p">:</span> <span class="nb">dict</span> <span class="o">=</span> <span class="kc">None</span>
<span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Any</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Dynamically imports and instantiates a class from a TypeDescriptor&#39;s type_string attribute.</span>
<span class="sd"> Args:</span>
<span class="sd"> type_string: TypeDescriptor instance with the class path</span>
<span class="sd"> payload: Argument to pass to the constructor</span>
<span class="sd"> Returns:</span>
<span class="sd"> Instance of the target class initialized with payload</span>
<span class="sd"> Raises:</span>
<span class="sd"> ImportError: If the module/class cannot be imported</span>
<span class="sd"> TypeError: If instantiation fails</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="c1"># Handle JSON payload first</span>
<span class="n">json_payload</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">payload</span><span class="p">)</span> <span class="k">if</span> <span class="n">is_json</span> <span class="ow">and</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">payload</span><span class="p">,</span> <span class="nb">str</span><span class="p">)</span> <span class="k">else</span> <span class="kc">None</span>
<span class="c1"># Handle basic types</span>
<span class="k">if</span> <span class="n">type_string</span> <span class="o">==</span> <span class="s2">&quot;str&quot;</span><span class="p">:</span>
<span class="k">return</span> <span class="nb">str</span><span class="p">(</span><span class="n">payload</span><span class="p">)</span>
<span class="k">if</span> <span class="n">type_string</span> <span class="o">==</span> <span class="s2">&quot;int&quot;</span><span class="p">:</span>
<span class="k">return</span> <span class="nb">int</span><span class="p">(</span><span class="n">payload</span><span class="p">)</span>
<span class="k">if</span> <span class="n">type_string</span> <span class="o">==</span> <span class="s2">&quot;float&quot;</span><span class="p">:</span>
<span class="k">return</span> <span class="nb">float</span><span class="p">(</span><span class="n">payload</span><span class="p">)</span>
<span class="k">if</span> <span class="n">type_string</span> <span class="o">==</span> <span class="s2">&quot;bool&quot;</span><span class="p">:</span>
<span class="k">return</span> <span class="nb">bool</span><span class="p">(</span><span class="n">payload</span><span class="p">)</span>
<span class="c1"># Handle typing module types</span>
<span class="k">if</span> <span class="n">type_string</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&quot;typing.&quot;</span><span class="p">)</span> <span class="ow">or</span> <span class="n">type_string</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&quot;list&quot;</span><span class="p">):</span>
<span class="k">if</span> <span class="p">(</span>
<span class="n">type_string</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&quot;typing.List&quot;</span><span class="p">)</span>
<span class="ow">or</span> <span class="n">type_string</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&quot;typing.Sequence&quot;</span><span class="p">)</span>
<span class="ow">or</span> <span class="n">type_string</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&quot;list&quot;</span><span class="p">)</span>
<span class="p">):</span>
<span class="k">if</span> <span class="n">json_payload</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">return</span> <span class="n">json_payload</span>
<span class="n">inner_type</span> <span class="o">=</span> <span class="n">_extract_type_of</span><span class="p">(</span><span class="n">type_string</span><span class="p">)</span>
<span class="k">if</span> <span class="n">inner_type</span><span class="p">:</span>
<span class="k">return</span> <span class="p">[</span>
<span class="n">_instantiate</span><span class="p">(</span><span class="n">inner_type</span><span class="p">,</span> <span class="n">p</span><span class="p">,</span> <span class="n">extra_init_data</span><span class="o">=</span><span class="n">extra_init_data</span><span class="p">)</span>
<span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="p">(</span><span class="n">payload</span> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">payload</span><span class="p">,</span> <span class="nb">list</span><span class="p">)</span> <span class="k">else</span> <span class="n">payload</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;,&quot;</span><span class="p">))</span>
<span class="p">]</span>
<span class="k">return</span> <span class="n">payload</span> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">payload</span><span class="p">,</span> <span class="nb">list</span><span class="p">)</span> <span class="k">else</span> <span class="n">payload</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;,&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="n">type_string</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&quot;typing.Dict&quot;</span><span class="p">)</span> <span class="ow">or</span> <span class="n">type_string</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&quot;typing.Mapping&quot;</span><span class="p">):</span>
<span class="k">if</span> <span class="n">json_payload</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">return</span> <span class="n">json_payload</span>
<span class="k">return</span> <span class="nb">dict</span><span class="p">(</span><span class="n">payload</span><span class="p">)</span>
<span class="k">if</span> <span class="n">type_string</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&quot;typing.Set&quot;</span><span class="p">):</span>
<span class="k">if</span> <span class="n">json_payload</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">return</span> <span class="nb">set</span><span class="p">(</span><span class="n">json_payload</span><span class="p">)</span>
<span class="n">_set_type</span> <span class="o">=</span> <span class="n">_extract_type_of</span><span class="p">(</span><span class="n">type_string</span><span class="p">)</span>
<span class="k">return</span> <span class="nb">set</span><span class="p">(</span>
<span class="n">payload</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">payload</span><span class="p">,</span> <span class="nb">list</span><span class="p">)</span>
<span class="k">else</span> <span class="p">[</span><span class="n">_instantiate</span><span class="p">(</span><span class="n">_set_type</span><span class="p">,</span> <span class="n">p</span><span class="p">)</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">payload</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;,&quot;</span><span class="p">)]</span>
<span class="p">)</span>
<span class="k">if</span> <span class="n">type_string</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&quot;typing.Tuple&quot;</span><span class="p">):</span>
<span class="k">if</span> <span class="n">json_payload</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">return</span> <span class="nb">tuple</span><span class="p">(</span><span class="n">json_payload</span><span class="p">)</span>
<span class="n">_tuple_type</span> <span class="o">=</span> <span class="n">_extract_type_of</span><span class="p">(</span><span class="n">type_string</span><span class="p">)</span>
<span class="k">return</span> <span class="nb">tuple</span><span class="p">(</span>
<span class="n">payload</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">payload</span><span class="p">,</span> <span class="nb">list</span><span class="p">)</span>
<span class="k">else</span> <span class="p">[</span><span class="n">_instantiate</span><span class="p">(</span><span class="n">_tuple_type</span><span class="p">,</span> <span class="n">p</span><span class="p">)</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">payload</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;,&quot;</span><span class="p">)]</span>
<span class="p">)</span>
<span class="k">if</span> <span class="n">type_string</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&quot;typing.Optional&quot;</span><span class="p">):</span>
<span class="n">inner_type</span> <span class="o">=</span> <span class="n">_extract_type_of</span><span class="p">(</span><span class="n">type_string</span><span class="p">)</span>
<span class="k">if</span> <span class="n">inner_type</span><span class="p">:</span>
<span class="k">return</span> <span class="n">_instantiate</span><span class="p">(</span><span class="n">inner_type</span><span class="p">,</span> <span class="n">payload</span><span class="p">,</span> <span class="n">is_json</span><span class="p">,</span> <span class="n">extra_init_data</span><span class="p">)</span>
<span class="k">return</span> <span class="n">payload</span>
<span class="c1"># Handle regular class instantiation</span>
<span class="n">parts</span> <span class="o">=</span> <span class="n">type_string</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;.&quot;</span><span class="p">)</span>
<span class="n">module_path</span> <span class="o">=</span> <span class="s2">&quot;.&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">parts</span><span class="p">[:</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span>
<span class="n">class_name</span> <span class="o">=</span> <span class="n">parts</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
<span class="k">try</span><span class="p">:</span>
<span class="c1"># Import the module</span>
<span class="n">module</span> <span class="o">=</span> <span class="n">importlib</span><span class="o">.</span><span class="n">import_module</span><span class="p">(</span><span class="n">module_path</span><span class="p">)</span>
<span class="c1"># Get the class</span>
<span class="bp">cls</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">module</span><span class="p">,</span> <span class="n">class_name</span><span class="p">)</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">payload</span><span class="p">,</span> <span class="bp">cls</span><span class="p">):</span>
<span class="k">return</span> <span class="n">payload</span>
<span class="c1"># Instantiate with payload</span>
<span class="k">if</span> <span class="n">json_payload</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">_args</span> <span class="o">=</span> <span class="n">merge_extra_init_data</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">json_payload</span><span class="p">,</span> <span class="n">extra_init_data</span> <span class="ow">or</span> <span class="p">{})</span>
<span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="s2">&quot;from_dict&quot;</span><span class="p">):</span>
<span class="k">return</span> <span class="bp">cls</span><span class="o">.</span><span class="n">from_dict</span><span class="p">(</span><span class="n">_args</span><span class="p">)</span>
<span class="k">elif</span> <span class="nb">hasattr</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="s2">&quot;create&quot;</span><span class="p">):</span>
<span class="k">return</span> <span class="bp">cls</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="o">**</span><span class="n">_args</span><span class="p">)</span>
<span class="k">return</span> <span class="bp">cls</span><span class="p">(</span><span class="o">**</span><span class="n">_args</span><span class="p">)</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">payload</span><span class="p">,</span> <span class="nb">dict</span><span class="p">):</span>
<span class="n">_args</span> <span class="o">=</span> <span class="n">merge_extra_init_data</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">payload</span><span class="p">,</span> <span class="n">extra_init_data</span> <span class="ow">or</span> <span class="p">{})</span>
<span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="s2">&quot;from_dict&quot;</span><span class="p">):</span>
<span class="k">return</span> <span class="bp">cls</span><span class="o">.</span><span class="n">from_dict</span><span class="p">(</span><span class="n">_args</span><span class="p">)</span>
<span class="k">elif</span> <span class="nb">hasattr</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="s2">&quot;create&quot;</span><span class="p">):</span>
<span class="k">return</span> <span class="bp">cls</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="o">**</span><span class="n">_args</span><span class="p">)</span>
<span class="k">return</span> <span class="bp">cls</span><span class="p">(</span><span class="o">**</span><span class="n">_args</span><span class="p">)</span>
<span class="k">return</span> <span class="bp">cls</span><span class="p">(</span><span class="n">payload</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">ImportError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">ImportError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Could not import module &#39;</span><span class="si">{</span><span class="n">module_path</span><span class="si">}</span><span class="s2">&#39;&quot;</span><span class="p">)</span> <span class="kn">from</span><span class="w"> </span><span class="nn">e</span>
<span class="k">except</span> <span class="ne">AttributeError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">ImportError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Module &#39;</span><span class="si">{</span><span class="n">module_path</span><span class="si">}</span><span class="s2">&#39; has no class &#39;</span><span class="si">{</span><span class="n">class_name</span><span class="si">}</span><span class="s2">&#39;&quot;</span><span class="p">)</span> <span class="kn">from</span><span class="w"> </span><span class="nn">e</span>
<span class="k">except</span> <span class="ne">TypeError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Failed to instantiate </span><span class="si">{</span><span class="n">type_string</span><span class="si">}</span><span class="s2"> with payload </span><span class="si">{</span><span class="n">payload</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span> <span class="kn">from</span><span class="w"> </span><span class="nn">e</span>
</pre></div>
</div>
</div>
<footer>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2024, CleverThis.</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>
@@ -0,0 +1,383 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" data-content_root="../../../">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>amqp.config.amq_configuration &mdash; AMQ Adapter Python 1.0 documentation</title>
<link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=03e43079" />
<link rel="stylesheet" type="text/css" href="../../../_static/css/theme.css?v=e59714d7" />
<script src="../../../_static/jquery.js?v=5d32c60e"></script>
<script src="../../../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
<script src="../../../_static/documentation_options.js?v=f2a433a1"></script>
<script src="../../../_static/doctools.js?v=9bcbadda"></script>
<script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
<script src="../../../_static/js/theme.js"></script>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="../../../index.html" class="icon icon-home">
AMQ Adapter Python
</a>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" aria-label="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.html">AMQP Package</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.config.html">Configuration Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.adapter.html">Adapter Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.service.html">Service Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.router.html">Router Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.model.html">Model Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.rabbitmq.html">RabbitMQ Module</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="../../../index.html">AMQ Adapter Python</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="../../../index.html" class="icon icon-home" aria-label="Home"></a></li>
<li class="breadcrumb-item"><a href="../../index.html">Module code</a></li>
<li class="breadcrumb-item active">amqp.config.amq_configuration</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<h1>Source code for amqp.config.amq_configuration</h1><div class="highlight"><pre>
<span></span><span class="kn">import</span><span class="w"> </span><span class="nn">configparser</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">inspect</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">os</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.adapter.logging_utils</span><span class="w"> </span><span class="kn">import</span> <span class="n">logging_error</span><span class="p">,</span> <span class="n">logging_warning</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd">Convert configuration from properties file to an object.</span>
<span class="sd">&quot;&quot;&quot;</span>
<div class="viewcode-block" id="AMQAdapter">
<a class="viewcode-back" href="../../../modules/amqp.config.html#amqp.config.amq_configuration.AMQAdapter">[docs]</a>
<span class="k">class</span><span class="w"> </span><span class="nc">AMQAdapter</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> configuration with prefix &#39;cm.amq-adapter&#39;</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">PREFIX</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">&quot;cm.amq-adapter.&quot;</span>
<div class="viewcode-block" id="AMQAdapter.__init__">
<a class="viewcode-back" href="../../../modules/amqp.config.html#amqp.config.amq_configuration.AMQAdapter.__init__">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">config</span><span class="p">:</span> <span class="n">configparser</span><span class="o">.</span><span class="n">ConfigParser</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> cm.amq-adapter.service-name=amq-adapter</span>
<span class="sd"> cm.amq-adapter.generator-id=164</span>
<span class="sd"> cm.amq-adapter.route-mapping=</span>
<span class="sd"> :param config: config parser to read configuration values</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">generator_id</span> <span class="o">=</span> <span class="mi">0</span>
<span class="bp">self</span><span class="o">.</span><span class="n">service_name</span> <span class="o">=</span> <span class="n">config</span><span class="o">.</span><span class="n">get</span><span class="p">(</span>
<span class="s2">&quot;CleverMicro-AMQ&quot;</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">PREFIX</span> <span class="o">+</span> <span class="s2">&quot;service-name&quot;</span><span class="p">,</span>
<span class="n">fallback</span><span class="o">=</span><span class="s2">&quot;amq-python-adapter-&quot;</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">generator_id</span><span class="p">),</span>
<span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">route_mapping</span> <span class="o">=</span> <span class="n">config</span><span class="o">.</span><span class="n">get</span><span class="p">(</span>
<span class="s2">&quot;CleverMicro-AMQ&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">PREFIX</span> <span class="o">+</span> <span class="s2">&quot;route-mapping&quot;</span><span class="p">,</span> <span class="n">fallback</span><span class="o">=</span><span class="kc">None</span>
<span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">require_authenticated_user</span> <span class="o">=</span> <span class="n">config</span><span class="o">.</span><span class="n">getboolean</span><span class="p">(</span>
<span class="s2">&quot;CleverMicro-AMQ&quot;</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">PREFIX</span> <span class="o">+</span> <span class="s2">&quot;require-authenticated-user&quot;</span><span class="p">,</span>
<span class="n">fallback</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
<span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">backpressure_enabled</span> <span class="o">=</span> <span class="n">config</span><span class="o">.</span><span class="n">getboolean</span><span class="p">(</span>
<span class="s2">&quot;CleverMicro-AMQ&quot;</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">PREFIX</span> <span class="o">+</span> <span class="s2">&quot;default-backpressure-enabled&quot;</span><span class="p">,</span>
<span class="n">fallback</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
<span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">callbacks_enabled</span> <span class="o">=</span> <span class="n">config</span><span class="o">.</span><span class="n">getboolean</span><span class="p">(</span>
<span class="s2">&quot;CleverMicro-AMQ&quot;</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">PREFIX</span> <span class="o">+</span> <span class="s2">&quot;callbacks-enabled&quot;</span><span class="p">,</span>
<span class="n">fallback</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
<span class="p">)</span>
<span class="c1"># these 2 shall be provided by Docker swarm, format is a random alphanumeric string</span>
<span class="bp">self</span><span class="o">.</span><span class="n">swarm_service_id</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span><span class="s2">&quot;SWARM_SERVICE_ID&quot;</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="s2">&quot;clever-amqp-service&quot;</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">swarm_task_id</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span><span class="s2">&quot;SWARM_TASK_ID&quot;</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="s2">&quot;python-adapter&quot;</span><span class="p">)</span>
<span class="c1">#</span>
<span class="c1"># Consul related configuration</span>
<span class="bp">self</span><span class="o">.</span><span class="n">consul_port</span> <span class="o">=</span> <span class="p">(</span>
<span class="nb">int</span><span class="p">(</span>
<span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span>
<span class="s2">&quot;CONSUL_PORT&quot;</span><span class="p">,</span>
<span class="n">config</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;CleverMicro-AMQ&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">PREFIX</span> <span class="o">+</span> <span class="s2">&quot;consul-port&quot;</span><span class="p">,</span> <span class="n">fallback</span><span class="o">=</span><span class="s2">&quot;8500&quot;</span><span class="p">),</span>
<span class="p">)</span>
<span class="p">)</span>
<span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span><span class="s2">&quot;CONSUL_PORT&quot;</span><span class="p">)</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span>
<span class="k">else</span> <span class="n">config</span><span class="o">.</span><span class="n">getint</span><span class="p">(</span><span class="s2">&quot;CleverMicro-AMQ&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">PREFIX</span> <span class="o">+</span> <span class="s2">&quot;consul-port&quot;</span><span class="p">,</span> <span class="n">fallback</span><span class="o">=</span><span class="mi">8500</span><span class="p">)</span>
<span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">consul_host</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span>
<span class="s2">&quot;CONSUL_HOST&quot;</span><span class="p">,</span>
<span class="n">config</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;CleverMicro-AMQ&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">PREFIX</span> <span class="o">+</span> <span class="s2">&quot;consul-host&quot;</span><span class="p">,</span> <span class="n">fallback</span><span class="o">=</span><span class="s2">&quot;consul&quot;</span><span class="p">),</span>
<span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">consul_max_retries</span> <span class="o">=</span> <span class="p">(</span>
<span class="nb">int</span><span class="p">(</span>
<span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span>
<span class="s2">&quot;CONSUL_MAX_RETRIES&quot;</span><span class="p">,</span>
<span class="n">config</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;CleverMicro-AMQ&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">PREFIX</span> <span class="o">+</span> <span class="s2">&quot;consul-max-retries&quot;</span><span class="p">,</span> <span class="n">fallback</span><span class="o">=</span><span class="s2">&quot;5&quot;</span><span class="p">),</span>
<span class="p">)</span>
<span class="p">)</span>
<span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span><span class="s2">&quot;CONSUL_MAX_RETRIES&quot;</span><span class="p">)</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span>
<span class="k">else</span> <span class="n">config</span><span class="o">.</span><span class="n">getint</span><span class="p">(</span><span class="s2">&quot;CleverMicro-AMQ&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">PREFIX</span> <span class="o">+</span> <span class="s2">&quot;consul-max-retries&quot;</span><span class="p">,</span> <span class="n">fallback</span><span class="o">=</span><span class="mi">5</span><span class="p">)</span>
<span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">consul_initial_retry_delay</span> <span class="o">=</span> <span class="p">(</span>
<span class="nb">float</span><span class="p">(</span>
<span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span>
<span class="s2">&quot;CONSUL_INITIAL_RETRY_DELAY&quot;</span><span class="p">,</span>
<span class="n">config</span><span class="o">.</span><span class="n">get</span><span class="p">(</span>
<span class="s2">&quot;CleverMicro-AMQ&quot;</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">PREFIX</span> <span class="o">+</span> <span class="s2">&quot;consul-initial-retry-delay&quot;</span><span class="p">,</span>
<span class="n">fallback</span><span class="o">=</span><span class="s2">&quot;0.2&quot;</span><span class="p">,</span>
<span class="p">),</span>
<span class="p">)</span>
<span class="p">)</span>
<span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span><span class="s2">&quot;CONSUL_INITIAL_RETRY_DELAY&quot;</span><span class="p">)</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span>
<span class="k">else</span> <span class="n">config</span><span class="o">.</span><span class="n">getfloat</span><span class="p">(</span>
<span class="s2">&quot;CleverMicro-AMQ&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">PREFIX</span> <span class="o">+</span> <span class="s2">&quot;consul-initial-retry-delay&quot;</span><span class="p">,</span> <span class="n">fallback</span><span class="o">=</span><span class="mf">0.2</span>
<span class="p">)</span>
<span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">consul_counter_key</span> <span class="o">=</span> <span class="p">(</span>
<span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span>
<span class="s2">&quot;CONSUL_COUNTER_KEY&quot;</span><span class="p">,</span>
<span class="n">config</span><span class="o">.</span><span class="n">get</span><span class="p">(</span>
<span class="s2">&quot;CleverMicro-AMQ&quot;</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">PREFIX</span> <span class="o">+</span> <span class="s2">&quot;consul-counter-key&quot;</span><span class="p">,</span>
<span class="n">fallback</span><span class="o">=</span><span class="s2">&quot;service/ids/counter&quot;</span><span class="p">,</span>
<span class="p">),</span>
<span class="p">)</span>
<span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span><span class="s2">&quot;CONSUL_COUNTER_KEY&quot;</span><span class="p">)</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span>
<span class="k">else</span> <span class="n">config</span><span class="o">.</span><span class="n">get</span><span class="p">(</span>
<span class="s2">&quot;CleverMicro-AMQ&quot;</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">PREFIX</span> <span class="o">+</span> <span class="s2">&quot;consul-counter-key&quot;</span><span class="p">,</span>
<span class="n">fallback</span><span class="o">=</span><span class="s2">&quot;service/ids/counter&quot;</span><span class="p">,</span>
<span class="p">)</span>
<span class="p">)</span></div>
<div class="viewcode-block" id="AMQAdapter.adapter_prefix">
<a class="viewcode-back" href="../../../modules/amqp.config.html#amqp.config.amq_configuration.AMQAdapter.adapter_prefix">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">adapter_prefix</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="k">return</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">service_name</span><span class="si">}</span><span class="s2">-</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">generator_id</span><span class="si">}</span><span class="s2">-&quot;</span></div>
</div>
<div class="viewcode-block" id="Dispatch">
<a class="viewcode-back" href="../../../modules/amqp.config.html#amqp.config.amq_configuration.Dispatch">[docs]</a>
<span class="k">class</span><span class="w"> </span><span class="nc">Dispatch</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> configuration with prefix &#39;cm.dispatch&#39;</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">PREFIX</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">&quot;cm.dispatch.&quot;</span>
<div class="viewcode-block" id="Dispatch.__init__">
<a class="viewcode-back" href="../../../modules/amqp.config.html#amqp.config.amq_configuration.Dispatch.__init__">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">config</span><span class="p">:</span> <span class="n">configparser</span><span class="o">.</span><span class="n">ConfigParser</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> cm.dispatch.use-dlq=true</span>
<span class="sd"> cm.dispatch.amq-host=rabbitmq</span>
<span class="sd"> cm.dispatch.amq-port=5672</span>
<span class="sd"> cm.dispatch.amq-port-tls=5671</span>
<span class="sd"> cm.dispatch.service-host=</span>
<span class="sd"> cm.dispatch.service-port=8080</span>
<span class="sd"> :param config: config parser to read configuration values</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">use_dlq</span> <span class="o">=</span> <span class="n">config</span><span class="o">.</span><span class="n">getboolean</span><span class="p">(</span><span class="s2">&quot;CleverMicro-AMQ&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">PREFIX</span> <span class="o">+</span> <span class="s2">&quot;use-dlq&quot;</span><span class="p">,</span> <span class="n">fallback</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">amq_host</span> <span class="o">=</span> <span class="n">config</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;CleverMicro-AMQ&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">PREFIX</span> <span class="o">+</span> <span class="s2">&quot;amq-host&quot;</span><span class="p">,</span> <span class="n">fallback</span><span class="o">=</span><span class="s2">&quot;rabbitmq&quot;</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">amq_port</span> <span class="o">=</span> <span class="n">config</span><span class="o">.</span><span class="n">getint</span><span class="p">(</span><span class="s2">&quot;CleverMicro-AMQ&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">PREFIX</span> <span class="o">+</span> <span class="s2">&quot;amq-port&quot;</span><span class="p">,</span> <span class="n">fallback</span><span class="o">=</span><span class="mi">5672</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">amq_port_tls</span> <span class="o">=</span> <span class="n">config</span><span class="o">.</span><span class="n">getint</span><span class="p">(</span>
<span class="s2">&quot;CleverMicro-AMQ&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">PREFIX</span> <span class="o">+</span> <span class="s2">&quot;amq-port-tls&quot;</span><span class="p">,</span> <span class="n">fallback</span><span class="o">=</span><span class="mi">5671</span>
<span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">service_host</span> <span class="o">=</span> <span class="n">config</span><span class="o">.</span><span class="n">get</span><span class="p">(</span>
<span class="s2">&quot;CleverMicro-AMQ&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">PREFIX</span> <span class="o">+</span> <span class="s2">&quot;service-host&quot;</span><span class="p">,</span> <span class="n">fallback</span><span class="o">=</span><span class="s2">&quot;localhost&quot;</span>
<span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">service_port</span> <span class="o">=</span> <span class="n">config</span><span class="o">.</span><span class="n">getint</span><span class="p">(</span>
<span class="s2">&quot;CleverMicro-AMQ&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">PREFIX</span> <span class="o">+</span> <span class="s2">&quot;service-port&quot;</span><span class="p">,</span> <span class="n">fallback</span><span class="o">=</span><span class="mi">8080</span>
<span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">rabbit_mq_user</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span><span class="s2">&quot;RABBIT_MQ_USER&quot;</span><span class="p">,</span> <span class="s2">&quot;springuser&quot;</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">rabbit_mq_password</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span><span class="s2">&quot;RABBIT_MQ_PASSWORD&quot;</span><span class="p">,</span> <span class="s2">&quot;TheCleverWho&quot;</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">rabbit_mq_url</span> <span class="o">=</span> <span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;amqp://</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">rabbit_mq_user</span><span class="si">}</span><span class="s2">:</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">rabbit_mq_password</span><span class="si">}</span><span class="s2">@</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">amq_host</span><span class="si">}</span><span class="s2">/&quot;</span>
<span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">download_dir</span> <span class="o">=</span> <span class="n">config</span><span class="o">.</span><span class="n">get</span><span class="p">(</span>
<span class="s2">&quot;CleverMicro-AMQ&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">PREFIX</span> <span class="o">+</span> <span class="s2">&quot;download-dir&quot;</span><span class="p">,</span> <span class="n">fallback</span><span class="o">=</span><span class="s2">&quot;downloaded_files&quot;</span>
<span class="p">)</span></div>
</div>
<div class="viewcode-block" id="Backpressure">
<a class="viewcode-back" href="../../../modules/amqp.config.html#amqp.config.amq_configuration.Backpressure">[docs]</a>
<span class="k">class</span><span class="w"> </span><span class="nc">Backpressure</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> configuration with prefix &#39;cm.backpressure&#39;</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">PREFIX</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">&quot;cm.backpressure.&quot;</span>
<div class="viewcode-block" id="Backpressure.__init__">
<a class="viewcode-back" href="../../../modules/amqp.config.html#amqp.config.amq_configuration.Backpressure.__init__">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">config</span><span class="p">:</span> <span class="n">configparser</span><span class="o">.</span><span class="n">ConfigParser</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> cm.backpressure.threshold=20</span>
<span class="sd"> cm.backpressure.time-window=3000</span>
<span class="sd"> :param config: config parser to read configuration values</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">threshold_load</span> <span class="o">=</span> <span class="n">config</span><span class="o">.</span><span class="n">getint</span><span class="p">(</span>
<span class="s2">&quot;CleverMicro-AMQ&quot;</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">PREFIX</span> <span class="o">+</span> <span class="s2">&quot;threshold&quot;</span><span class="p">,</span>
<span class="n">fallback</span><span class="o">=</span><span class="nb">int</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span><span class="s2">&quot;PARALLEL_WORKERS&quot;</span><span class="p">,</span> <span class="mi">1</span><span class="p">)),</span>
<span class="p">)</span>
<span class="c1"># time-window in seconds, duration between backpressure reports</span>
<span class="bp">self</span><span class="o">.</span><span class="n">time_window</span> <span class="o">=</span> <span class="n">config</span><span class="o">.</span><span class="n">getint</span><span class="p">(</span>
<span class="s2">&quot;CleverMicro-AMQ&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">PREFIX</span> <span class="o">+</span> <span class="s2">&quot;time-window&quot;</span><span class="p">,</span> <span class="n">fallback</span><span class="o">=</span><span class="mi">10</span>
<span class="p">)</span>
<span class="c1"># Define maximum CPU usage before triggering backpressure OVERLOAD alert</span>
<span class="bp">self</span><span class="o">.</span><span class="n">threshold_cpu</span> <span class="o">=</span> <span class="n">config</span><span class="o">.</span><span class="n">getint</span><span class="p">(</span>
<span class="s2">&quot;CleverMicro-AMQ&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">PREFIX</span> <span class="o">+</span> <span class="s2">&quot;threshold-cpu&quot;</span><span class="p">,</span> <span class="n">fallback</span><span class="o">=</span><span class="mi">90</span>
<span class="p">)</span>
<span class="c1"># Define the time window length, in seconds, during which, if CPU usage is consistently above the threshold, the system will trigger OVERLOAD alert</span>
<span class="bp">self</span><span class="o">.</span><span class="n">cpu_overload_duration</span> <span class="o">=</span> <span class="n">config</span><span class="o">.</span><span class="n">getint</span><span class="p">(</span>
<span class="s2">&quot;CleverMicro-AMQ&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">PREFIX</span> <span class="o">+</span> <span class="s2">&quot;cpu-overload-duration&quot;</span><span class="p">,</span> <span class="n">fallback</span><span class="o">=</span><span class="mi">30</span>
<span class="p">)</span>
<span class="c1"># Define the time window length, in seconds, during which, if no request is made to the Service, the system will trigger IDLE alert</span>
<span class="bp">self</span><span class="o">.</span><span class="n">idle_duration</span> <span class="o">=</span> <span class="n">config</span><span class="o">.</span><span class="n">getint</span><span class="p">(</span>
<span class="s2">&quot;CleverMicro-AMQ&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">PREFIX</span> <span class="o">+</span> <span class="s2">&quot;idle-duration&quot;</span><span class="p">,</span> <span class="n">fallback</span><span class="o">=</span><span class="mi">30</span>
<span class="p">)</span>
<span class="c1"># Flag to enable/disable CPU monitoring</span>
<span class="bp">self</span><span class="o">.</span><span class="n">cpu_monitoring_enabled</span> <span class="o">=</span> <span class="n">config</span><span class="o">.</span><span class="n">getboolean</span><span class="p">(</span>
<span class="s2">&quot;CleverMicro-AMQ&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">PREFIX</span> <span class="o">+</span> <span class="s2">&quot;cpu-monitoring-enabled&quot;</span><span class="p">,</span> <span class="n">fallback</span><span class="o">=</span><span class="kc">False</span>
<span class="p">)</span></div>
</div>
<div class="viewcode-block" id="AMQConfiguration">
<a class="viewcode-back" href="../../../modules/amqp.config.html#amqp.config.amq_configuration.AMQConfiguration">[docs]</a>
<span class="k">class</span><span class="w"> </span><span class="nc">AMQConfiguration</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Top level configuration context holder / object</span>
<span class="sd"> &quot;&quot;&quot;</span>
<div class="viewcode-block" id="AMQConfiguration.__init__">
<a class="viewcode-back" href="../../../modules/amqp.config.html#amqp.config.amq_configuration.AMQConfiguration.__init__">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">config_file_name</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="kc">None</span><span class="p">):</span>
<span class="n">config</span> <span class="o">=</span> <span class="n">configparser</span><span class="o">.</span><span class="n">ConfigParser</span><span class="p">()</span>
<span class="c1"># Read the application.properties file</span>
<span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">config_file_name</span><span class="p">):</span>
<span class="n">config</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="n">config_file_name</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># Get the directory of the caller (the module where this function is called)</span>
<span class="n">caller_frame</span> <span class="o">=</span> <span class="n">inspect</span><span class="o">.</span><span class="n">stack</span><span class="p">()[</span><span class="mi">1</span><span class="p">]</span> <span class="c1"># 0 is current_availability frame, 1 is caller</span>
<span class="n">caller_module</span> <span class="o">=</span> <span class="n">inspect</span><span class="o">.</span><span class="n">getmodule</span><span class="p">(</span><span class="n">caller_frame</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
<span class="k">if</span> <span class="n">caller_module</span><span class="p">:</span>
<span class="n">caller_dir</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">dirname</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">abspath</span><span class="p">(</span><span class="n">caller_module</span><span class="o">.</span><span class="vm">__file__</span><span class="p">))</span>
<span class="n">config_file_path</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">caller_dir</span><span class="p">,</span> <span class="n">config_file_name</span><span class="p">)</span>
<span class="n">config</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="n">config_file_path</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">logging_error</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Configuration file not found: </span><span class="si">{</span><span class="n">config_file_name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="n">logging_warning</span><span class="p">(</span>
<span class="s2">&quot;Defaulting to preset values, which will likely be wrong, causing errors.&quot;</span>
<span class="p">)</span>
<span class="c1"># Override values with environment variables</span>
<span class="k">for</span> <span class="n">section</span> <span class="ow">in</span> <span class="n">config</span><span class="o">.</span><span class="n">sections</span><span class="p">():</span>
<span class="k">for</span> <span class="n">option</span> <span class="ow">in</span> <span class="n">config</span><span class="o">.</span><span class="n">options</span><span class="p">(</span><span class="n">section</span><span class="p">):</span>
<span class="c1"># env_var = f&quot;{section.upper()}_{option.upper()}&quot;</span>
<span class="k">if</span> <span class="n">option</span> <span class="ow">in</span> <span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="p">:</span>
<span class="n">config</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="n">section</span><span class="p">,</span> <span class="n">option</span><span class="p">,</span> <span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="p">[</span><span class="n">option</span><span class="p">])</span>
<span class="c1">#</span>
<span class="c1"># Add individual config areas</span>
<span class="c1">#</span>
<span class="bp">self</span><span class="o">.</span><span class="n">amq_adapter</span><span class="p">:</span> <span class="n">AMQAdapter</span> <span class="o">=</span> <span class="n">AMQAdapter</span><span class="p">(</span><span class="n">config</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">dispatch</span><span class="p">:</span> <span class="n">Dispatch</span> <span class="o">=</span> <span class="n">Dispatch</span><span class="p">(</span><span class="n">config</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">backpressure</span><span class="p">:</span> <span class="n">Backpressure</span> <span class="o">=</span> <span class="n">Backpressure</span><span class="p">(</span><span class="n">config</span><span class="p">)</span></div>
<div class="viewcode-block" id="AMQConfiguration.get_unique_instance_id">
<a class="viewcode-back" href="../../../modules/amqp.config.html#amqp.config.amq_configuration.AMQConfiguration.get_unique_instance_id">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">get_unique_instance_id</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Get a unique instance ID for this AMQ service.</span>
<span class="sd"> Returns:</span>
<span class="sd"> int: A unique instance ID</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">instance_id</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">:</span>
<span class="n">logging_warning</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Generated unique instance ID: </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">instance_id</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">instance_id</span></div>
</div>
</pre></div>
</div>
</div>
<footer>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2024, CleverThis.</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>
@@ -0,0 +1,589 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" data-content_root="../../../">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>amqp.model.model &mdash; AMQ Adapter Python 1.0 documentation</title>
<link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=03e43079" />
<link rel="stylesheet" type="text/css" href="../../../_static/css/theme.css?v=e59714d7" />
<script src="../../../_static/jquery.js?v=5d32c60e"></script>
<script src="../../../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
<script src="../../../_static/documentation_options.js?v=f2a433a1"></script>
<script src="../../../_static/doctools.js?v=9bcbadda"></script>
<script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
<script src="../../../_static/js/theme.js"></script>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="../../../index.html" class="icon icon-home">
AMQ Adapter Python
</a>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" aria-label="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.html">AMQP Package</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.config.html">Configuration Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.adapter.html">Adapter Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.service.html">Service Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.router.html">Router Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.model.html">Model Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.rabbitmq.html">RabbitMQ Module</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="../../../index.html">AMQ Adapter Python</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="../../../index.html" class="icon icon-home" aria-label="Home"></a></li>
<li class="breadcrumb-item"><a href="../../index.html">Module code</a></li>
<li class="breadcrumb-item active">amqp.model.model</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<h1>Source code for amqp.model.model</h1><div class="highlight"><pre>
<span></span><span class="kn">import</span><span class="w"> </span><span class="nn">base64</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">json</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">dataclasses</span><span class="w"> </span><span class="kn">import</span> <span class="n">dataclass</span><span class="p">,</span> <span class="n">field</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">enum</span><span class="w"> </span><span class="kn">import</span> <span class="n">Enum</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Dict</span><span class="p">,</span> <span class="n">List</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">aio_pika.abc</span><span class="w"> </span><span class="kn">import</span> <span class="n">AbstractRobustConnection</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.model.service_message_type</span><span class="w"> </span><span class="kn">import</span> <span class="n">ServiceMessageType</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.model.snowflake_id</span><span class="w"> </span><span class="kn">import</span> <span class="n">SnowflakeId</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.router.utils</span><span class="w"> </span><span class="kn">import</span> <span class="n">sanitize_as_rabbitmq_name</span>
<span class="n">RS</span> <span class="o">=</span> <span class="s2">&quot;:&quot;</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd">Define the structure of messages used in Clever Micro</span>
<span class="sd">&quot;&quot;&quot;</span>
<div class="viewcode-block" id="DataMessageMagicByte">
<a class="viewcode-back" href="../../../modules/amqp.model.html#amqp.model.model.DataMessageMagicByte">[docs]</a>
<span class="k">class</span><span class="w"> </span><span class="nc">DataMessageMagicByte</span><span class="p">(</span><span class="n">Enum</span><span class="p">):</span>
<span class="n">HTTP_REQUEST</span> <span class="o">=</span> <span class="s2">&quot;A&quot;</span>
<span class="n">RPC_REQUEST</span> <span class="o">=</span> <span class="s2">&quot;R&quot;</span></div>
<div class="viewcode-block" id="CleverMicroMessage">
<a class="viewcode-back" href="../../../modules/amqp.model.html#amqp.model.model.CleverMicroMessage">[docs]</a>
<span class="nd">@dataclass</span>
<span class="k">class</span><span class="w"> </span><span class="nc">CleverMicroMessage</span><span class="p">:</span>
<span class="n">DEFAULT_CONTENT_TYPE</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;application/octet-stream&quot;</span><span class="p">]</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> The common structure of a message that transfers the user request to the Service and back. All data related messages</span>
<span class="sd"> conform to this base structure:</span>
<span class="sd"> magic - identifies the message type (REST, RPC, DataResponse)</span>
<span class="sd"> id - unique message ID</span>
<span class="sd"> m_field - method name (for REST style calls) or service name (for RPC style calls) or response code for DataResponse</span>
<span class="sd"> d_field - domain name (for REST style calls) or module name (for RPC style calls) or error code for DataResponse</span>
<span class="sd"> p_field - path (for REST style calls) or method name (for RPC style calls) or error cause for DataResponse</span>
<span class="sd"> headers - headers of the message (e.g. Content-Type, Accept, etc.)</span>
<span class="sd"> trace_info - trace information (e.g. trace ID, span ID, etc. for Jaeger trace monitor)</span>
<span class="sd"> base64body - the body of the message encoded in base64</span>
<span class="sd"> &quot;&quot;&quot;</span>
<div class="viewcode-block" id="CleverMicroMessage.__init__">
<a class="viewcode-back" href="../../../modules/amqp.model.html#amqp.model.model.CleverMicroMessage.__init__">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span>
<span class="n">magic</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
<span class="nb">id</span><span class="p">:</span> <span class="n">SnowflakeId</span><span class="p">,</span>
<span class="n">m_field</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
<span class="n">d_field</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
<span class="n">p_field</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
<span class="n">headers</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]],</span>
<span class="n">trace_info</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">str</span><span class="p">],</span>
<span class="n">base64body</span><span class="p">:</span> <span class="nb">bytes</span><span class="p">,</span>
<span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_magic</span> <span class="o">=</span> <span class="n">magic</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_id</span><span class="p">:</span> <span class="n">SnowflakeId</span> <span class="o">=</span> <span class="nb">id</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_m_field</span> <span class="o">=</span> <span class="n">m_field</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_d_field</span> <span class="o">=</span> <span class="n">d_field</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_p_field</span> <span class="o">=</span> <span class="n">p_field</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_headers</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]]</span> <span class="o">=</span> <span class="n">headers</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_trace_info</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="n">trace_info</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_base64body</span><span class="p">:</span> <span class="nb">bytes</span> <span class="o">=</span> <span class="n">base64body</span></div>
<div class="viewcode-block" id="CleverMicroMessage.magic">
<a class="viewcode-back" href="../../../modules/amqp.model.html#amqp.model.model.CleverMicroMessage.magic">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">magic</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_magic</span></div>
<div class="viewcode-block" id="CleverMicroMessage.id">
<a class="viewcode-back" href="../../../modules/amqp.model.html#amqp.model.model.CleverMicroMessage.id">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">id</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_id</span></div>
<div class="viewcode-block" id="CleverMicroMessage.m_field">
<a class="viewcode-back" href="../../../modules/amqp.model.html#amqp.model.model.CleverMicroMessage.m_field">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">m_field</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_m_field</span></div>
<div class="viewcode-block" id="CleverMicroMessage.d_field">
<a class="viewcode-back" href="../../../modules/amqp.model.html#amqp.model.model.CleverMicroMessage.d_field">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">d_field</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_d_field</span></div>
<div class="viewcode-block" id="CleverMicroMessage.p_field">
<a class="viewcode-back" href="../../../modules/amqp.model.html#amqp.model.model.CleverMicroMessage.p_field">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">p_field</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_p_field</span></div>
<div class="viewcode-block" id="CleverMicroMessage.headers">
<a class="viewcode-back" href="../../../modules/amqp.model.html#amqp.model.model.CleverMicroMessage.headers">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">headers</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]]:</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_headers</span></div>
<div class="viewcode-block" id="CleverMicroMessage.trace_info">
<a class="viewcode-back" href="../../../modules/amqp.model.html#amqp.model.model.CleverMicroMessage.trace_info">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">trace_info</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">str</span><span class="p">]:</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_trace_info</span></div>
<div class="viewcode-block" id="CleverMicroMessage.base64body">
<a class="viewcode-back" href="../../../modules/amqp.model.html#amqp.model.model.CleverMicroMessage.base64body">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">base64body</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bytes</span><span class="p">:</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_base64body</span></div>
<div class="viewcode-block" id="CleverMicroMessage.body">
<a class="viewcode-back" href="../../../modules/amqp.model.html#amqp.model.model.CleverMicroMessage.body">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">body</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bytes</span><span class="p">:</span>
<span class="k">return</span> <span class="n">base64</span><span class="o">.</span><span class="n">b64decode</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">base64body</span><span class="p">())</span></div>
<div class="viewcode-block" id="CleverMicroMessage.content_type">
<a class="viewcode-back" href="../../../modules/amqp.model.html#amqp.model.model.CleverMicroMessage.content_type">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">content_type</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">headers</span><span class="p">()</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;Content-Type&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">DEFAULT_CONTENT_TYPE</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span></div>
<div class="viewcode-block" id="CleverMicroMessage.return_address">
<a class="viewcode-back" href="../../../modules/amqp.model.html#amqp.model.model.CleverMicroMessage.return_address">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">return_address</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">headers</span><span class="p">()</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;Return-Address&quot;</span><span class="p">,</span> <span class="s2">&quot;&quot;</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span></div>
</div>
<div class="viewcode-block" id="DataMessage">
<a class="viewcode-back" href="../../../modules/amqp.model.html#amqp.model.model.DataMessage">[docs]</a>
<span class="k">class</span><span class="w"> </span><span class="nc">DataMessage</span><span class="p">(</span><span class="n">CleverMicroMessage</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> The class represents a structure of a message that transfers the user request to the Service.</span>
<span class="sd"> It may also be used to make a call/request between services.</span>
<span class="sd"> The response to this call is in format of DataResponse class.</span>
<span class="sd"> See DataMessageFactory for code to instantiate, serialize and deserialize the class</span>
<span class="sd"> &quot;&quot;&quot;</span>
<div class="viewcode-block" id="DataMessage.__init__">
<a class="viewcode-back" href="../../../modules/amqp.model.html#amqp.model.model.DataMessage.__init__">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span>
<span class="n">magic</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
<span class="nb">id</span><span class="p">:</span> <span class="n">SnowflakeId</span><span class="p">,</span>
<span class="n">method</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
<span class="n">domain</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
<span class="n">path</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
<span class="n">headers</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]],</span>
<span class="n">trace_info</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">str</span><span class="p">],</span>
<span class="n">base64body</span><span class="p">:</span> <span class="nb">bytes</span><span class="p">,</span>
<span class="p">):</span>
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="n">magic</span><span class="p">,</span> <span class="nb">id</span><span class="p">,</span> <span class="n">method</span><span class="p">,</span> <span class="n">domain</span><span class="p">,</span> <span class="n">path</span><span class="p">,</span> <span class="n">headers</span><span class="p">,</span> <span class="n">trace_info</span><span class="p">,</span> <span class="n">base64body</span><span class="p">)</span></div>
<div class="viewcode-block" id="DataMessage.method">
<a class="viewcode-back" href="../../../modules/amqp.model.html#amqp.model.model.DataMessage.method">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">method</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">m_field</span><span class="p">()</span></div>
<div class="viewcode-block" id="DataMessage.domain">
<a class="viewcode-back" href="../../../modules/amqp.model.html#amqp.model.model.DataMessage.domain">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">domain</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">d_field</span><span class="p">()</span></div>
<div class="viewcode-block" id="DataMessage.path">
<a class="viewcode-back" href="../../../modules/amqp.model.html#amqp.model.model.DataMessage.path">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">path</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">p_field</span><span class="p">()</span></div>
<div class="viewcode-block" id="DataMessage.routing_key">
<a class="viewcode-back" href="../../../modules/amqp.model.html#amqp.model.model.DataMessage.routing_key">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">routing_key</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="k">return</span> <span class="n">sanitize_as_rabbitmq_name</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">d_field</span><span class="p">()</span><span class="si">}</span><span class="s2">.</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">p_field</span><span class="p">()</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span></div>
</div>
<div class="viewcode-block" id="MultipartDataMessage">
<a class="viewcode-back" href="../../../modules/amqp.model.html#amqp.model.model.MultipartDataMessage">[docs]</a>
<span class="k">class</span><span class="w"> </span><span class="nc">MultipartDataMessage</span><span class="p">(</span><span class="n">DataMessage</span><span class="p">):</span>
<div class="viewcode-block" id="MultipartDataMessage.__init__">
<a class="viewcode-back" href="../../../modules/amqp.model.html#amqp.model.model.MultipartDataMessage.__init__">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">DataMessage</span><span class="p">,</span> <span class="n">extra_data</span><span class="p">:</span> <span class="nb">dict</span><span class="p">):</span>
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span>
<span class="n">message</span><span class="o">.</span><span class="n">magic</span><span class="p">(),</span>
<span class="n">message</span><span class="o">.</span><span class="n">id</span><span class="p">(),</span>
<span class="n">message</span><span class="o">.</span><span class="n">method</span><span class="p">(),</span>
<span class="n">message</span><span class="o">.</span><span class="n">domain</span><span class="p">(),</span>
<span class="n">message</span><span class="o">.</span><span class="n">path</span><span class="p">(),</span>
<span class="n">message</span><span class="o">.</span><span class="n">headers</span><span class="p">(),</span>
<span class="n">message</span><span class="o">.</span><span class="n">trace_info</span><span class="p">(),</span>
<span class="n">message</span><span class="o">.</span><span class="n">base64body</span><span class="p">(),</span>
<span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">extra_data</span> <span class="o">=</span> <span class="n">extra_data</span></div>
</div>
<div class="viewcode-block" id="AMQMessage">
<a class="viewcode-back" href="../../../modules/amqp.model.html#amqp.model.model.AMQMessage">[docs]</a>
<span class="nd">@dataclass</span>
<span class="k">class</span><span class="w"> </span><span class="nc">AMQMessage</span><span class="p">(</span><span class="n">DataMessage</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Expand the core DataMessage type to include the channel, which is required to create a dedicated queue</span>
<span class="sd"> in case the response should initiate file download.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">_connection</span><span class="p">:</span> <span class="n">AbstractRobustConnection</span> <span class="o">=</span> <span class="n">field</span><span class="p">(</span><span class="nb">repr</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span> <span class="c1"># Don&#39;t show in repr</span>
<div class="viewcode-block" id="AMQMessage.__init__">
<a class="viewcode-back" href="../../../modules/amqp.model.html#amqp.model.model.AMQMessage.__init__">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">data_message</span><span class="p">:</span> <span class="n">DataMessage</span><span class="p">,</span> <span class="n">connection</span><span class="p">:</span> <span class="n">AbstractRobustConnection</span><span class="p">):</span>
<span class="c1"># Initialize the parent DataMessage with all properties from the input data_message</span>
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span>
<span class="n">magic</span><span class="o">=</span><span class="n">data_message</span><span class="o">.</span><span class="n">magic</span><span class="p">(),</span>
<span class="nb">id</span><span class="o">=</span><span class="n">data_message</span><span class="o">.</span><span class="n">id</span><span class="p">(),</span>
<span class="n">method</span><span class="o">=</span><span class="n">data_message</span><span class="o">.</span><span class="n">method</span><span class="p">(),</span>
<span class="n">domain</span><span class="o">=</span><span class="n">data_message</span><span class="o">.</span><span class="n">domain</span><span class="p">(),</span>
<span class="n">path</span><span class="o">=</span><span class="n">data_message</span><span class="o">.</span><span class="n">path</span><span class="p">(),</span>
<span class="n">headers</span><span class="o">=</span><span class="n">data_message</span><span class="o">.</span><span class="n">headers</span><span class="p">(),</span>
<span class="n">trace_info</span><span class="o">=</span><span class="n">data_message</span><span class="o">.</span><span class="n">trace_info</span><span class="p">(),</span>
<span class="n">base64body</span><span class="o">=</span><span class="n">data_message</span><span class="o">.</span><span class="n">base64body</span><span class="p">(),</span>
<span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_connection</span> <span class="o">=</span> <span class="n">connection</span>
<span class="bp">self</span><span class="o">.</span><span class="n">extra_data</span> <span class="o">=</span> <span class="n">data_message</span><span class="o">.</span><span class="n">extra_data</span> <span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">data_message</span><span class="p">,</span> <span class="s2">&quot;extra_data&quot;</span><span class="p">)</span> <span class="k">else</span> <span class="p">{}</span></div>
<span class="nd">@property</span>
<span class="k">def</span><span class="w"> </span><span class="nf">connection</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">AbstractRobustConnection</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Get the AMQP connection associated with this message&quot;&quot;&quot;</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_connection</span></div>
<div class="viewcode-block" id="DataResponse">
<a class="viewcode-back" href="../../../modules/amqp.model.html#amqp.model.model.DataResponse">[docs]</a>
<span class="k">class</span><span class="w"> </span><span class="nc">DataResponse</span><span class="p">(</span><span class="n">CleverMicroMessage</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> The response message to REST &amp; RPC style calls (note: the request is made with DataMessage)</span>
<span class="sd"> See DataResponseFactory for code to instantiate, serialize and deserialize the class</span>
<span class="sd"> &quot;&quot;&quot;</span>
<div class="viewcode-block" id="DataResponse.__init__">
<a class="viewcode-back" href="../../../modules/amqp.model.html#amqp.model.model.DataResponse.__init__">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span>
<span class="n">magic</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
<span class="nb">id</span><span class="p">:</span> <span class="n">SnowflakeId</span><span class="p">,</span>
<span class="n">response_code</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
<span class="n">content_type</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
<span class="n">error</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
<span class="n">error_cause</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
<span class="n">headers</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]],</span>
<span class="n">trace_info</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">str</span><span class="p">],</span>
<span class="n">base64body</span><span class="p">:</span> <span class="nb">bytes</span><span class="p">,</span>
<span class="p">):</span>
<span class="k">if</span> <span class="n">headers</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">headers</span> <span class="o">=</span> <span class="p">{}</span>
<span class="n">headers</span><span class="p">[</span><span class="s2">&quot;Content-Type&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="n">content_type</span><span class="p">]</span>
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span>
<span class="n">magic</span><span class="p">,</span>
<span class="nb">id</span><span class="p">,</span>
<span class="n">response_code</span><span class="p">,</span>
<span class="n">error</span><span class="p">,</span>
<span class="n">error_cause</span><span class="p">,</span>
<span class="n">headers</span><span class="p">,</span>
<span class="n">trace_info</span><span class="p">,</span>
<span class="n">base64body</span><span class="p">,</span>
<span class="p">)</span></div>
<div class="viewcode-block" id="DataResponse.response_code">
<a class="viewcode-back" href="../../../modules/amqp.model.html#amqp.model.model.DataResponse.response_code">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">response_code</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">m_field</span><span class="p">()</span></div>
<div class="viewcode-block" id="DataResponse.error">
<a class="viewcode-back" href="../../../modules/amqp.model.html#amqp.model.model.DataResponse.error">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">error</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">d_field</span><span class="p">()</span></div>
<div class="viewcode-block" id="DataResponse.error_cause">
<a class="viewcode-back" href="../../../modules/amqp.model.html#amqp.model.model.DataResponse.error_cause">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">error_cause</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">p_field</span><span class="p">()</span></div>
</div>
<div class="viewcode-block" id="AMQRoute">
<a class="viewcode-back" href="../../../modules/amqp.model.html#amqp.model.model.AMQRoute">[docs]</a>
<span class="nd">@dataclass</span><span class="p">(</span><span class="n">frozen</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="k">class</span><span class="w"> </span><span class="nc">AMQRoute</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Configuration item representing one AMQRoute. Adapter uses this to declare the Exchange</span>
<span class="sd"> and/or queue and bind the key as routing expression.</span>
<span class="sd"> :param component_name: a service/component name that this route points to (owner of the route)</span>
<span class="sd"> :param exchange: RabbitMQ exchange name</span>
<span class="sd"> :param queue: RabbitMQ queue name</span>
<span class="sd"> :param key: RabbitMQ TOPIC Exchange routing key</span>
<span class="sd"> :param timeout: Timeout in milliseconds, how long to wait for reply, or not waiting if less then 1</span>
<span class="sd"> :param valid_until: optional timestamp (millis from epoch) after which the route is ignored</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">component_name</span><span class="p">:</span> <span class="nb">str</span>
<span class="n">exchange</span><span class="p">:</span> <span class="nb">str</span>
<span class="n">queue</span><span class="p">:</span> <span class="nb">str</span>
<span class="n">key</span><span class="p">:</span> <span class="nb">str</span>
<span class="n">timeout</span><span class="p">:</span> <span class="nb">int</span>
<span class="n">valid_until</span><span class="p">:</span> <span class="nb">int</span>
<span class="n">FORMAT</span> <span class="o">=</span> <span class="s2">&quot;Component-Name:Exchange-Name:Queue-Name:Routing-Key:Timeout:Valid-Until&quot;</span>
<span class="k">def</span><span class="w"> </span><span class="fm">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">component_name</span><span class="si">}{</span><span class="n">RS</span><span class="si">}{</span><span class="bp">self</span><span class="o">.</span><span class="n">exchange</span><span class="si">}{</span><span class="n">RS</span><span class="si">}{</span><span class="bp">self</span><span class="o">.</span><span class="n">queue</span><span class="si">}{</span><span class="n">RS</span><span class="si">}{</span><span class="bp">self</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">RS</span><span class="si">}{</span><span class="bp">self</span><span class="o">.</span><span class="n">timeout</span><span class="si">}{</span><span class="n">RS</span><span class="si">}{</span><span class="bp">self</span><span class="o">.</span><span class="n">valid_until</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="p">)</span>
<span class="k">def</span><span class="w"> </span><span class="fm">__eq__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">other</span><span class="p">,</span> <span class="n">AMQRoute</span><span class="p">):</span>
<span class="k">return</span> <span class="p">(</span>
<span class="bp">self</span><span class="o">.</span><span class="n">component_name</span> <span class="o">==</span> <span class="n">other</span><span class="o">.</span><span class="n">component_name</span>
<span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">queue</span> <span class="o">==</span> <span class="n">other</span><span class="o">.</span><span class="n">queue</span>
<span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">key</span> <span class="o">==</span> <span class="n">other</span><span class="o">.</span><span class="n">key</span>
<span class="p">)</span>
<span class="k">return</span> <span class="kc">False</span>
<span class="nd">@property</span>
<span class="k">def</span><span class="w"> </span><span class="nf">primary_key</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Build the unique identifier of the route</span>
<span class="sd"> :return primary key</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">component_name</span><span class="si">}{</span><span class="n">RS</span><span class="si">}{</span><span class="bp">self</span><span class="o">.</span><span class="n">queue</span><span class="si">}{</span><span class="n">RS</span><span class="si">}{</span><span class="bp">self</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2">&quot;</span>
<div class="viewcode-block" id="AMQRoute.as_string">
<a class="viewcode-back" href="../../../modules/amqp.model.html#amqp.model.model.AMQRoute.as_string">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">as_string</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="fm">__str__</span><span class="p">()</span></div>
</div>
<span class="c1"># Ensure backward compatibility</span>
<span class="n">AMQResponse</span> <span class="o">=</span> <span class="n">DataResponse</span>
<div class="viewcode-block" id="ServiceMessage">
<a class="viewcode-back" href="../../../modules/amqp.model.html#amqp.model.model.ServiceMessage">[docs]</a>
<span class="nd">@dataclass</span><span class="p">(</span><span class="n">frozen</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="k">class</span><span class="w"> </span><span class="nc">ServiceMessage</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> The CleverMicro service message that is used to communicate the internal state of the AMQ channel.</span>
<span class="sd"> In v0.2 it supports service discovery / route registration and Backpressure status notification.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="nb">id</span><span class="p">:</span> <span class="n">SnowflakeId</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">payload_type</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">message_type</span><span class="p">:</span> <span class="n">ServiceMessageType</span> <span class="o">=</span> <span class="n">ServiceMessageType</span><span class="o">.</span><span class="n">UNKNOWN</span>
<span class="n">recipient_name</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">reply_to</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">trace_info</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="n">field</span><span class="p">(</span><span class="n">default_factory</span><span class="o">=</span><span class="nb">dict</span><span class="p">)</span>
<span class="n">message</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="kc">None</span>
<div class="viewcode-block" id="ServiceMessage.is_valid">
<a class="viewcode-back" href="../../../modules/amqp.model.html#amqp.model.model.ServiceMessage.is_valid">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">is_valid</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">message_type</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span></div>
</div>
<div class="viewcode-block" id="ScalingRequestAlert">
<a class="viewcode-back" href="../../../modules/amqp.model.html#amqp.model.model.ScalingRequestAlert">[docs]</a>
<span class="k">class</span><span class="w"> </span><span class="nc">ScalingRequestAlert</span><span class="p">(</span><span class="n">Enum</span><span class="p">):</span>
<span class="n">OVERLOAD</span> <span class="o">=</span> <span class="s2">&quot;OVERLOAD&quot;</span>
<span class="n">IDLE</span> <span class="o">=</span> <span class="s2">&quot;IDLE&quot;</span>
<span class="n">UPDATE</span> <span class="o">=</span> <span class="s2">&quot;UPDATE&quot;</span>
<span class="n">SCALE_UP</span> <span class="o">=</span> <span class="s2">&quot;SCALE_UP&quot;</span>
<span class="n">SCALE_DOWN</span> <span class="o">=</span> <span class="s2">&quot;SCALE_DOWN&quot;</span></div>
<div class="viewcode-block" id="ScalingRequest">
<a class="viewcode-back" href="../../../modules/amqp.model.html#amqp.model.model.ScalingRequest">[docs]</a>
<span class="nd">@dataclass</span><span class="p">(</span><span class="n">frozen</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="k">class</span><span class="w"> </span><span class="nc">ScalingRequest</span><span class="p">:</span>
<span class="n">service_id</span><span class="p">:</span> <span class="nb">str</span>
<span class="n">task_id</span><span class="p">:</span> <span class="nb">str</span>
<span class="n">max_availability</span><span class="p">:</span> <span class="nb">int</span>
<span class="n">current_availability</span><span class="p">:</span> <span class="nb">int</span>
<span class="n">request_type</span><span class="p">:</span> <span class="n">ScalingRequestAlert</span>
<span class="n">version</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">1</span>
<div class="viewcode-block" id="ScalingRequest.to_json">
<a class="viewcode-back" href="../../../modules/amqp.model.html#amqp.model.model.ScalingRequest.to_json">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">to_json</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Converts the object to a JSON string matching the Java structure&quot;&quot;&quot;</span>
<span class="k">return</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span>
<span class="p">{</span>
<span class="s2">&quot;version&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">version</span><span class="p">,</span>
<span class="s2">&quot;serviceId&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">service_id</span><span class="p">,</span>
<span class="s2">&quot;taskId&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">task_id</span><span class="p">,</span>
<span class="s2">&quot;maxAvailability&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_availability</span><span class="p">,</span>
<span class="s2">&quot;currentAvailability&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">current_availability</span><span class="p">,</span>
<span class="s2">&quot;requestType&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">request_type</span><span class="o">.</span><span class="n">value</span><span class="p">,</span> <span class="c1"># Using .value for Enum serialization</span>
<span class="p">},</span>
<span class="n">indent</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span>
<span class="p">)</span></div>
<div class="viewcode-block" id="ScalingRequest.from_json">
<a class="viewcode-back" href="../../../modules/amqp.model.html#amqp.model.model.ScalingRequest.from_json">[docs]</a>
<span class="nd">@classmethod</span>
<span class="k">def</span><span class="w"> </span><span class="nf">from_json</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">json_str</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="s2">&quot;ScalingRequest&quot;</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Creates a ScalingRequest from a JSON string&quot;&quot;&quot;</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">json_str</span><span class="p">)</span>
<span class="k">return</span> <span class="bp">cls</span><span class="p">(</span>
<span class="n">service_id</span><span class="o">=</span><span class="n">data</span><span class="p">[</span><span class="s2">&quot;serviceId&quot;</span><span class="p">],</span>
<span class="n">task_id</span><span class="o">=</span><span class="n">data</span><span class="p">[</span><span class="s2">&quot;taskId&quot;</span><span class="p">],</span>
<span class="n">max_availability</span><span class="o">=</span><span class="n">data</span><span class="p">[</span><span class="s2">&quot;maxAvailability&quot;</span><span class="p">],</span>
<span class="n">current_availability</span><span class="o">=</span><span class="n">data</span><span class="p">[</span><span class="s2">&quot;currentAvailability&quot;</span><span class="p">],</span>
<span class="n">request_type</span><span class="o">=</span><span class="n">ScalingRequestAlert</span><span class="p">(</span><span class="n">data</span><span class="p">[</span><span class="s2">&quot;requestType&quot;</span><span class="p">]),</span> <span class="c1"># Convert string to Enum</span>
<span class="p">)</span></div>
</div>
<div class="viewcode-block" id="AMQErrorMessage">
<a class="viewcode-back" href="../../../modules/amqp.model.html#amqp.model.model.AMQErrorMessage">[docs]</a>
<span class="k">class</span><span class="w"> </span><span class="nc">AMQErrorMessage</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> The error response message to RPC style call (note: the request is made with DataMessage)</span>
<span class="sd"> &quot;&quot;&quot;</span>
<div class="viewcode-block" id="AMQErrorMessage.__init__">
<a class="viewcode-back" href="../../../modules/amqp.model.html#amqp.model.model.AMQErrorMessage.__init__">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span>
<span class="n">response_code</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span>
<span class="n">error</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
<span class="n">detail</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
<span class="n">content_type</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">&quot;application/json&quot;</span><span class="p">,</span>
<span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">response_code</span> <span class="o">=</span> <span class="n">response_code</span>
<span class="bp">self</span><span class="o">.</span><span class="n">error</span> <span class="o">=</span> <span class="n">error</span>
<span class="bp">self</span><span class="o">.</span><span class="n">detail</span> <span class="o">=</span> <span class="n">detail</span>
<span class="bp">self</span><span class="o">.</span><span class="n">content_type</span> <span class="o">=</span> <span class="n">content_type</span></div>
<div class="viewcode-block" id="AMQErrorMessage.serialize">
<a class="viewcode-back" href="../../../modules/amqp.model.html#amqp.model.model.AMQErrorMessage.serialize">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">serialize</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bytes</span><span class="p">:</span>
<span class="k">return</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span>
<span class="p">{</span>
<span class="s2">&quot;response_code&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">response_code</span><span class="p">,</span>
<span class="s2">&quot;error&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">error</span><span class="p">,</span>
<span class="s2">&quot;detail&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">detail</span><span class="p">,</span>
<span class="p">}</span>
<span class="p">)</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s2">&quot;utf-8&quot;</span><span class="p">)</span></div>
</div>
</pre></div>
</div>
</div>
<footer>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2024, CleverThis.</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>
@@ -0,0 +1,120 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" data-content_root="../../../">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>amqp.model.service_message_type &mdash; AMQ Adapter Python 1.0 documentation</title>
<link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=03e43079" />
<link rel="stylesheet" type="text/css" href="../../../_static/css/theme.css?v=e59714d7" />
<script src="../../../_static/jquery.js?v=5d32c60e"></script>
<script src="../../../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
<script src="../../../_static/documentation_options.js?v=f2a433a1"></script>
<script src="../../../_static/doctools.js?v=9bcbadda"></script>
<script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
<script src="../../../_static/js/theme.js"></script>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="../../../index.html" class="icon icon-home">
AMQ Adapter Python
</a>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" aria-label="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.html">AMQP Package</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.config.html">Configuration Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.adapter.html">Adapter Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.service.html">Service Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.router.html">Router Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.model.html">Model Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.rabbitmq.html">RabbitMQ Module</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="../../../index.html">AMQ Adapter Python</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="../../../index.html" class="icon icon-home" aria-label="Home"></a></li>
<li class="breadcrumb-item"><a href="../../index.html">Module code</a></li>
<li class="breadcrumb-item active">amqp.model.service_message_type</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<h1>Source code for amqp.model.service_message_type</h1><div class="highlight"><pre>
<span></span><span class="kn">from</span><span class="w"> </span><span class="nn">enum</span><span class="w"> </span><span class="kn">import</span> <span class="n">Enum</span><span class="p">,</span> <span class="n">auto</span>
<div class="viewcode-block" id="ServiceMessageType">
<a class="viewcode-back" href="../../../modules/amqp.model.html#amqp.model.model.ServiceMessageType">[docs]</a>
<span class="k">class</span><span class="w"> </span><span class="nc">ServiceMessageType</span><span class="p">(</span><span class="n">Enum</span><span class="p">):</span>
<span class="n">ROUTING_DATA_REQUEST</span> <span class="o">=</span> <span class="n">auto</span><span class="p">()</span>
<span class="n">ROUTING_DATA</span> <span class="o">=</span> <span class="n">auto</span><span class="p">()</span>
<span class="n">ROUTING_DATA_REMOVE</span> <span class="o">=</span> <span class="n">auto</span><span class="p">()</span>
<span class="n">ROUTING_DATA_REPLACE</span> <span class="o">=</span> <span class="n">auto</span><span class="p">()</span>
<span class="n">BACKPRESSURE</span> <span class="o">=</span> <span class="n">auto</span><span class="p">()</span>
<span class="n">UNKNOWN</span> <span class="o">=</span> <span class="n">auto</span><span class="p">()</span></div>
</pre></div>
</div>
</div>
<footer>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2024, CleverThis.</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>
@@ -0,0 +1,204 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" data-content_root="../../../">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>amqp.model.snowflake_id &mdash; AMQ Adapter Python 1.0 documentation</title>
<link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=03e43079" />
<link rel="stylesheet" type="text/css" href="../../../_static/css/theme.css?v=e59714d7" />
<script src="../../../_static/jquery.js?v=5d32c60e"></script>
<script src="../../../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
<script src="../../../_static/documentation_options.js?v=f2a433a1"></script>
<script src="../../../_static/doctools.js?v=9bcbadda"></script>
<script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
<script src="../../../_static/js/theme.js"></script>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="../../../index.html" class="icon icon-home">
AMQ Adapter Python
</a>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" aria-label="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.html">AMQP Package</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.config.html">Configuration Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.adapter.html">Adapter Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.service.html">Service Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.router.html">Router Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.model.html">Model Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.rabbitmq.html">RabbitMQ Module</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="../../../index.html">AMQ Adapter Python</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="../../../index.html" class="icon icon-home" aria-label="Home"></a></li>
<li class="breadcrumb-item"><a href="../../index.html">Module code</a></li>
<li class="breadcrumb-item active">amqp.model.snowflake_id</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<h1>Source code for amqp.model.snowflake_id</h1><div class="highlight"><pre>
<span></span><span class="kn">import</span><span class="w"> </span><span class="nn">struct</span>
<div class="viewcode-block" id="SnowflakeId">
<a class="viewcode-back" href="../../../modules/amqp.model.html#amqp.model.snowflake_id.SnowflakeId">[docs]</a>
<span class="k">class</span><span class="w"> </span><span class="nc">SnowflakeId</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> see https://en.wikipedia.org/wiki/Snowflake_ID</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">SNOWFLAKE_ID_WIDTH</span> <span class="o">=</span> <span class="p">(</span>
<span class="mi">10</span> <span class="c1"># with in bytes (8 bits each), can be more than long int width (8 bytes)</span>
<span class="p">)</span>
<div class="viewcode-block" id="SnowflakeId.__init__">
<a class="viewcode-back" href="../../../modules/amqp.model.html#amqp.model.snowflake_id.SnowflakeId.__init__">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">hi_bits_or_bytes</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">lo_bits</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">bits</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span>
<span class="k">if</span> <span class="n">lo_bits</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">if</span> <span class="n">hi_bits_or_bytes</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">i</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">shift</span> <span class="o">=</span> <span class="mi">8</span> <span class="c1"># starting from Hi value, which is only 2 bytes wide</span>
<span class="n">n</span> <span class="o">=</span> <span class="mi">1</span>
<span class="k">while</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="nb">len</span><span class="p">(</span><span class="n">hi_bits_or_bytes</span><span class="p">)</span> <span class="ow">and</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="bp">self</span><span class="o">.</span><span class="n">SNOWFLAKE_ID_WIDTH</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">bits</span><span class="p">[</span><span class="n">n</span><span class="p">]</span> <span class="o">|=</span> <span class="n">hi_bits_or_bytes</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&lt;&lt;</span> <span class="n">shift</span>
<span class="k">if</span> <span class="n">shift</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
<span class="n">n</span> <span class="o">-=</span> <span class="mi">1</span>
<span class="n">shift</span> <span class="o">=</span> <span class="mi">56</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">shift</span> <span class="o">-=</span> <span class="mi">8</span>
<span class="n">i</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="k">else</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">bits</span> <span class="o">=</span> <span class="p">[</span><span class="n">lo_bits</span><span class="p">,</span> <span class="n">hi_bits_or_bytes</span><span class="p">]</span></div>
<div class="viewcode-block" id="SnowflakeId.from_hex">
<a class="viewcode-back" href="../../../modules/amqp.model.html#amqp.model.snowflake_id.SnowflakeId.from_hex">[docs]</a>
<span class="nd">@staticmethod</span>
<span class="k">def</span><span class="w"> </span><span class="nf">from_hex</span><span class="p">(</span><span class="n">_input</span><span class="p">):</span>
<span class="n">expected_length</span> <span class="o">=</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">SnowflakeId</span><span class="o">.</span><span class="n">SNOWFLAKE_ID_WIDTH</span>
<span class="k">if</span> <span class="n">_input</span> <span class="ow">is</span> <span class="kc">None</span> <span class="ow">or</span> <span class="nb">len</span><span class="p">(</span><span class="n">_input</span><span class="p">)</span> <span class="o">&lt;</span> <span class="n">expected_length</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;MessageId is </span><span class="si">{</span><span class="n">SnowflakeId</span><span class="o">.</span><span class="n">SNOWFLAKE_ID_WIDTH</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mi">8</span><span class="si">}</span><span class="s2"> bits wide, it is represented by HEX string &quot;</span>
<span class="sa">f</span><span class="s2">&quot;of length: </span><span class="si">{</span><span class="n">expected_length</span><span class="si">}</span><span class="s2">, real input: [</span><span class="si">{</span><span class="n">_input</span><span class="si">}</span><span class="s2">] of length: </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">_input</span><span class="p">)</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="n">_input</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="mi">0</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="p">)</span>
<span class="n">bits</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span>
<span class="n">n</span> <span class="o">=</span> <span class="mi">1</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">expected_length</span><span class="p">,</span> <span class="mi">2</span><span class="p">):</span>
<span class="k">if</span> <span class="n">i</span> <span class="o">==</span> <span class="n">expected_length</span> <span class="o">-</span> <span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="mi">8</span><span class="p">):</span>
<span class="n">n</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">bits</span><span class="p">[</span><span class="n">n</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">bits</span><span class="p">[</span><span class="n">n</span><span class="p">]</span> <span class="o">&lt;&lt;</span> <span class="mi">8</span><span class="p">)</span> <span class="o">|</span> <span class="nb">int</span><span class="p">(</span><span class="n">_input</span><span class="p">[</span><span class="n">i</span> <span class="p">:</span> <span class="n">i</span> <span class="o">+</span> <span class="mi">2</span><span class="p">],</span> <span class="mi">16</span><span class="p">)</span>
<span class="k">return</span> <span class="n">SnowflakeId</span><span class="p">(</span><span class="n">bits</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">bits</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span></div>
<span class="k">def</span><span class="w"> </span><span class="fm">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">_hex</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">bits</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="si">:</span><span class="s2">016X</span><span class="si">}{</span><span class="bp">self</span><span class="o">.</span><span class="n">bits</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="si">:</span><span class="s2">016X</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="n">_val</span> <span class="o">=</span> <span class="p">(</span>
<span class="n">_hex</span>
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">_hex</span><span class="p">)</span> <span class="o">&lt;=</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">SnowflakeId</span><span class="o">.</span><span class="n">SNOWFLAKE_ID_WIDTH</span>
<span class="k">else</span> <span class="n">_hex</span><span class="p">[(</span><span class="o">-</span><span class="mi">2</span> <span class="o">*</span> <span class="n">SnowflakeId</span><span class="o">.</span><span class="n">SNOWFLAKE_ID_WIDTH</span><span class="p">)</span> <span class="p">:]</span>
<span class="p">)</span>
<span class="k">return</span> <span class="n">_val</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span>
<span class="k">def</span><span class="w"> </span><span class="fm">__eq__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">other</span><span class="p">,</span> <span class="n">SnowflakeId</span><span class="p">):</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">bits</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="n">other</span><span class="o">.</span><span class="n">bits</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">bits</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="n">other</span><span class="o">.</span><span class="n">bits</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="k">return</span> <span class="kc">False</span>
<span class="k">def</span><span class="w"> </span><span class="fm">__lt__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">bits</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">other</span><span class="o">.</span><span class="n">bits</span><span class="p">[</span><span class="mi">1</span><span class="p">]:</span>
<span class="k">return</span> <span class="kc">True</span>
<span class="k">elif</span> <span class="bp">self</span><span class="o">.</span><span class="n">bits</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">&gt;</span> <span class="n">other</span><span class="o">.</span><span class="n">bits</span><span class="p">[</span><span class="mi">1</span><span class="p">]:</span>
<span class="k">return</span> <span class="kc">False</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">bits</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">other</span><span class="o">.</span><span class="n">bits</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<div class="viewcode-block" id="SnowflakeId.get_bytes">
<a class="viewcode-back" href="../../../modules/amqp.model.html#amqp.model.snowflake_id.SnowflakeId.get_bytes">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">get_bytes</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">high</span> <span class="o">=</span> <span class="n">struct</span><span class="o">.</span><span class="n">pack</span><span class="p">(</span><span class="s2">&quot;!Q&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">bits</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
<span class="n">low</span> <span class="o">=</span> <span class="n">struct</span><span class="o">.</span><span class="n">pack</span><span class="p">(</span><span class="s2">&quot;!Q&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">bits</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
<span class="k">return</span> <span class="n">high</span><span class="p">[</span><span class="o">-</span><span class="mi">2</span><span class="p">:]</span> <span class="o">+</span> <span class="n">low</span></div>
<div class="viewcode-block" id="SnowflakeId.get_bits">
<a class="viewcode-back" href="../../../modules/amqp.model.html#amqp.model.snowflake_id.SnowflakeId.get_bits">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">get_bits</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">bits</span></div>
<div class="viewcode-block" id="SnowflakeId.as_string">
<a class="viewcode-back" href="../../../modules/amqp.model.html#amqp.model.snowflake_id.SnowflakeId.as_string">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">as_string</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="fm">__str__</span><span class="p">()</span></div>
</div>
</pre></div>
</div>
</div>
<footer>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2024, CleverThis.</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>
@@ -0,0 +1,374 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" data-content_root="../../../">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>amqp.rabbitmq.rabbit_mq_client &mdash; AMQ Adapter Python 1.0 documentation</title>
<link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=03e43079" />
<link rel="stylesheet" type="text/css" href="../../../_static/css/theme.css?v=e59714d7" />
<script src="../../../_static/jquery.js?v=5d32c60e"></script>
<script src="../../../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
<script src="../../../_static/documentation_options.js?v=f2a433a1"></script>
<script src="../../../_static/doctools.js?v=9bcbadda"></script>
<script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
<script src="../../../_static/js/theme.js"></script>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="../../../index.html" class="icon icon-home">
AMQ Adapter Python
</a>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" aria-label="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.html">AMQP Package</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.config.html">Configuration Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.adapter.html">Adapter Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.service.html">Service Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.router.html">Router Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.model.html">Model Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.rabbitmq.html">RabbitMQ Module</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="../../../index.html">AMQ Adapter Python</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="../../../index.html" class="icon icon-home" aria-label="Home"></a></li>
<li class="breadcrumb-item"><a href="../../index.html">Module code</a></li>
<li class="breadcrumb-item active">amqp.rabbitmq.rabbit_mq_client</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<h1>Source code for amqp.rabbitmq.rabbit_mq_client</h1><div class="highlight"><pre>
<span></span><span class="kn">import</span><span class="w"> </span><span class="nn">logging</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Optional</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">aio_pika</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">aio_pika.abc</span><span class="w"> </span><span class="kn">import</span> <span class="n">AbstractRobustExchange</span><span class="p">,</span> <span class="n">AbstractRobustQueue</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">pika.exchange_type</span><span class="w"> </span><span class="kn">import</span> <span class="n">ExchangeType</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.adapter.data_message_factory</span><span class="w"> </span><span class="kn">import</span> <span class="n">DataMessageFactory</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.adapter.logging_utils</span><span class="w"> </span><span class="kn">import</span> <span class="p">(</span>
<span class="n">logging_debug</span><span class="p">,</span>
<span class="n">logging_error</span><span class="p">,</span>
<span class="n">logging_info</span><span class="p">,</span>
<span class="n">logging_warning</span><span class="p">,</span>
<span class="p">)</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.model.model</span><span class="w"> </span><span class="kn">import</span> <span class="n">AMQRoute</span><span class="p">,</span> <span class="n">DataMessage</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.router.router_base</span><span class="w"> </span><span class="kn">import</span> <span class="p">(</span>
<span class="n">AMQ_REPLY_TO_EXCHANGE</span><span class="p">,</span>
<span class="n">AMQ_RPC_EXCHANGE</span><span class="p">,</span>
<span class="n">DLQ_EXCHANGE</span><span class="p">,</span>
<span class="p">)</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.router.utils</span><span class="w"> </span><span class="kn">import</span> <span class="n">sanitize_as_rabbitmq_name</span>
<div class="viewcode-block" id="RabbitMQClient">
<a class="viewcode-back" href="../../../modules/amqp.rabbitmq.html#amqp.rabbitmq.rabbit_mq_client.RabbitMQClient">[docs]</a>
<span class="k">class</span><span class="w"> </span><span class="nc">RabbitMQClient</span><span class="p">:</span>
<span class="n">PREFETCH_COUNT</span> <span class="o">=</span> <span class="mi">1</span>
<span class="n">DLQ_ARGS</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&quot;x-dead-letter-exchange&quot;</span><span class="p">:</span> <span class="n">DLQ_EXCHANGE</span><span class="p">}</span>
<div class="viewcode-block" id="RabbitMQClient.__init__">
<a class="viewcode-back" href="../../../modules/amqp.rabbitmq.html#amqp.rabbitmq.rabbit_mq_client.RabbitMQClient.__init__">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">configuration</span><span class="p">,</span> <span class="n">router</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">channel</span><span class="p">:</span> <span class="n">aio_pika</span><span class="o">.</span><span class="n">RobustChannel</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span>
<span class="bp">self</span><span class="o">.</span><span class="n">connection</span><span class="p">:</span> <span class="n">aio_pika</span><span class="o">.</span><span class="n">RobustConnection</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span>
<span class="bp">self</span><span class="o">.</span><span class="n">rpc_exchange</span><span class="p">:</span> <span class="n">aio_pika</span><span class="o">.</span><span class="n">RobustExchange</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span>
<span class="bp">self</span><span class="o">.</span><span class="n">reply_exchange</span><span class="p">:</span> <span class="n">aio_pika</span><span class="o">.</span><span class="n">RobustExchange</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span>
<span class="bp">self</span><span class="o">.</span><span class="n">amq_configuration</span> <span class="o">=</span> <span class="n">configuration</span>
<span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s2">&quot;*******************************************&quot;</span><span class="p">)</span>
<span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span>
<span class="s2">&quot;******** RabbitMQClient.init(): </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">amq_configuration</span><span class="o">.</span><span class="n">dispatch</span><span class="o">.</span><span class="n">amq_host</span><span class="p">,</span>
<span class="p">)</span>
<span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s2">&quot;*******************************************&quot;</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">router</span> <span class="o">=</span> <span class="n">router</span>
<span class="c1"># this.meterRegistry = new PrometheusMeterRegistry(PrometheusConfig.DEFAULT);</span>
<span class="bp">self</span><span class="o">.</span><span class="n">reply_to_exchange</span><span class="p">:</span> <span class="n">AbstractRobustExchange</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="p">(</span>
<span class="kc">None</span> <span class="c1"># when sending response to RPC request</span>
<span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">reply_to_queue</span><span class="p">:</span> <span class="n">AbstractRobustQueue</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="p">(</span>
<span class="kc">None</span> <span class="c1"># when receiving response to RPC request</span>
<span class="p">)</span></div>
<div class="viewcode-block" id="RabbitMQClient.init">
<a class="viewcode-back" href="../../../modules/amqp.rabbitmq.html#amqp.rabbitmq.rabbit_mq_client.RabbitMQClient.init">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">init</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">loop</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">AbstractRobustExchange</span><span class="p">:</span>
<span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">setup_amq_channel</span><span class="p">(</span><span class="n">loop</span><span class="p">)</span>
<span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">router</span><span class="o">.</span><span class="n">init_routing_paths_consumer</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">router</span><span class="o">.</span><span class="n">channel</span><span class="p">)</span>
<span class="n">cm_reply_to_queue</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">router</span><span class="o">.</span><span class="n">get_reply_to_queue_name</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">reply_to_queue</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">channel</span><span class="o">.</span><span class="n">declare_queue</span><span class="p">(</span>
<span class="n">name</span><span class="o">=</span><span class="n">cm_reply_to_queue</span><span class="p">,</span> <span class="n">durable</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">exclusive</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">auto_delete</span><span class="o">=</span><span class="kc">False</span>
<span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">reply_to_exchange</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">channel</span><span class="o">.</span><span class="n">declare_exchange</span><span class="p">(</span>
<span class="n">AMQ_REPLY_TO_EXCHANGE</span><span class="p">,</span> <span class="nb">type</span><span class="o">=</span><span class="n">ExchangeType</span><span class="o">.</span><span class="n">direct</span>
<span class="p">)</span>
<span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">reply_to_queue</span><span class="o">.</span><span class="n">bind</span><span class="p">(</span>
<span class="n">exchange</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">reply_to_exchange</span><span class="p">,</span> <span class="n">routing_key</span><span class="o">=</span><span class="n">cm_reply_to_queue</span>
<span class="p">)</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">reply_to_exchange</span></div>
<div class="viewcode-block" id="RabbitMQClient.cleanup">
<a class="viewcode-back" href="../../../modules/amqp.rabbitmq.html#amqp.rabbitmq.rabbit_mq_client.RabbitMQClient.cleanup">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">cleanup</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">logging_info</span><span class="p">(</span><span class="s2">&quot;RabbitMQClient.cleanup()&quot;</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">router</span><span class="o">.</span><span class="n">cleanup</span><span class="p">()</span> <span class="c1"># de-register route(s)</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">router</span><span class="o">.</span><span class="n">is_open</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">channel</span><span class="p">):</span>
<span class="k">try</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">channel</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
<span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span><span class="o">.</span><span class="n">is_closed</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">connection</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="n">logging_error</span><span class="p">(</span>
<span class="s2">&quot;RabbitMQClient.PreDestroy cleanup - connection close error: </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span>
<span class="n">e</span><span class="p">,</span>
<span class="p">)</span></div>
<div class="viewcode-block" id="RabbitMQClient.register_inbound_routes">
<a class="viewcode-back" href="../../../modules/amqp.rabbitmq.html#amqp.rabbitmq.rabbit_mq_client.RabbitMQClient.register_inbound_routes">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">register_inbound_routes</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">route_mapping</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">callback</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Register inbound routes for the AMQ adapter. The route mapping is a comma-separated string that contains</span>
<span class="sd"> list of routes. A route is the mapping of domain and path to the exchange and queue name.</span>
<span class="sd"> This method declare (and thus create) the queue and exchange, bind them together using the</span>
<span class="sd"> regex-like routing expression given in the route.</span>
<span class="sd"> After this the Service is listening on (consuming from) the queue for incoming messages.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">router</span><span class="o">.</span><span class="n">is_open</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">channel</span><span class="p">):</span>
<span class="n">queue_args</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">DLQ_ARGS</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">amq_configuration</span><span class="o">.</span><span class="n">dispatch</span><span class="o">.</span><span class="n">use_dlq</span> <span class="k">else</span> <span class="kc">None</span>
<span class="n">logging_info</span><span class="p">(</span><span class="s2">&quot;RabbitMQClient register routes, cfg mapping: [</span><span class="si">%s</span><span class="s2">]&quot;</span><span class="p">,</span> <span class="n">route_mapping</span><span class="p">)</span>
<span class="c1"># convert the comma-separated string into list of AMQRoute objects</span>
<span class="n">requested_routes</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">router</span><span class="o">.</span><span class="n">unwrap_route_list</span><span class="p">(</span><span class="n">route_mapping</span><span class="p">)</span>
<span class="k">for</span> <span class="n">route</span> <span class="ow">in</span> <span class="n">requested_routes</span><span class="p">:</span>
<span class="k">try</span><span class="p">:</span>
<span class="c1"># Note: AMQRoute allows one of the exchange or queue to be None, in which case the default is used</span>
<span class="n">queue_name</span> <span class="o">=</span> <span class="p">(</span>
<span class="n">route</span><span class="o">.</span><span class="n">queue</span> <span class="k">if</span> <span class="n">route</span><span class="o">.</span><span class="n">queue</span> <span class="k">else</span> <span class="bp">self</span><span class="o">.</span><span class="n">router</span><span class="o">.</span><span class="n">get_consume_queue_name</span><span class="p">()</span>
<span class="p">)</span>
<span class="n">logging_info</span><span class="p">(</span><span class="s2">&quot;RabbitMQClient register route: [</span><span class="si">%s</span><span class="s2">]&quot;</span><span class="p">,</span> <span class="n">route</span><span class="p">)</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">amq_configuration</span><span class="o">.</span><span class="n">amq_adapter</span><span class="o">.</span><span class="n">callbacks_enabled</span><span class="p">:</span>
<span class="n">queue</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">AbstractRobustQueue</span><span class="p">]</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">channel</span><span class="o">.</span><span class="n">declare_queue</span><span class="p">(</span>
<span class="n">name</span><span class="o">=</span><span class="n">queue_name</span><span class="p">,</span>
<span class="n">durable</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
<span class="n">exclusive</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
<span class="n">auto_delete</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
<span class="n">arguments</span><span class="o">=</span><span class="n">queue_args</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">queue</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">_exchange_name</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="n">route</span><span class="o">.</span><span class="n">exchange</span> <span class="k">if</span> <span class="n">route</span><span class="o">.</span><span class="n">exchange</span> <span class="k">else</span> <span class="n">AMQ_RPC_EXCHANGE</span>
<span class="n">exchange</span><span class="p">:</span> <span class="n">AbstractRobustExchange</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">channel</span><span class="o">.</span><span class="n">declare_exchange</span><span class="p">(</span>
<span class="n">name</span><span class="o">=</span><span class="n">_exchange_name</span><span class="p">,</span> <span class="nb">type</span><span class="o">=</span><span class="n">ExchangeType</span><span class="o">.</span><span class="n">topic</span>
<span class="p">)</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">amq_configuration</span><span class="o">.</span><span class="n">amq_adapter</span><span class="o">.</span><span class="n">callbacks_enabled</span><span class="p">:</span>
<span class="k">await</span> <span class="n">queue</span><span class="o">.</span><span class="n">bind</span><span class="p">(</span><span class="n">exchange</span><span class="p">,</span> <span class="n">route</span><span class="o">.</span><span class="n">key</span><span class="p">)</span>
<span class="n">_c_tag</span> <span class="o">=</span> <span class="k">await</span> <span class="n">queue</span><span class="o">.</span><span class="n">consume</span><span class="p">(</span><span class="n">callback</span><span class="p">,</span> <span class="n">no_ack</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">_c_tag</span> <span class="o">=</span> <span class="kc">None</span>
<span class="c1"># Register the route with the router and publish its detail to other adapters</span>
<span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">router</span><span class="o">.</span><span class="n">register_route</span><span class="p">(</span>
<span class="n">AMQRoute</span><span class="p">(</span>
<span class="n">route</span><span class="o">.</span><span class="n">component_name</span><span class="p">,</span>
<span class="n">_exchange_name</span><span class="p">,</span>
<span class="n">queue_name</span><span class="p">,</span>
<span class="n">sanitize_as_rabbitmq_name</span><span class="p">(</span><span class="n">route</span><span class="o">.</span><span class="n">key</span><span class="p">),</span>
<span class="n">route</span><span class="o">.</span><span class="n">timeout</span><span class="p">,</span>
<span class="n">route</span><span class="o">.</span><span class="n">valid_until</span><span class="p">,</span>
<span class="p">)</span>
<span class="p">)</span>
<span class="n">logging_info</span><span class="p">(</span>
<span class="s2">&quot; [</span><span class="si">%s</span><span class="s2">] AMQ connection initialized for route: </span><span class="si">%s</span><span class="s2">, listens on: </span><span class="si">%s</span><span class="s2">/</span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span>
<span class="n">_c_tag</span><span class="p">,</span>
<span class="n">route</span><span class="p">,</span>
<span class="n">exchange</span><span class="p">,</span>
<span class="n">queue_name</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">err</span><span class="p">:</span>
<span class="n">logging_error</span><span class="p">(</span><span class="s2">&quot;Callback registration INCOMPLETE, </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">err</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">logging_warning</span><span class="p">(</span><span class="s2">&quot;Channel is null, cannot register routes.&quot;</span><span class="p">)</span></div>
<div class="viewcode-block" id="RabbitMQClient.register_data_reply_callback">
<a class="viewcode-back" href="../../../modules/amqp.rabbitmq.html#amqp.rabbitmq.rabbit_mq_client.RabbitMQClient.register_data_reply_callback">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">register_data_reply_callback</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">rpc_callback</span><span class="p">):</span>
<span class="n">_c_tag</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">reply_to_queue</span><span class="o">.</span><span class="n">consume</span><span class="p">(</span><span class="n">callback</span><span class="o">=</span><span class="n">rpc_callback</span><span class="p">,</span> <span class="n">no_ack</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">logging_info</span><span class="p">(</span>
<span class="s2">&quot; [</span><span class="si">%s</span><span class="s2">] RabbitMQClient register data reply callback on queue: </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span>
<span class="n">_c_tag</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">reply_to_queue</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
<span class="p">)</span></div>
<div class="viewcode-block" id="RabbitMQClient.setup_amq_channel">
<a class="viewcode-back" href="../../../modules/amqp.rabbitmq.html#amqp.rabbitmq.rabbit_mq_client.RabbitMQClient.setup_amq_channel">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">setup_amq_channel</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">loop</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Set up the RabbitMQ connection</span>
<span class="sd"> :return: nothing, it applies changes to instance variables</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;RabbitMQClient.setupAMQ, connecting to RabbitMQ at </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">amq_configuration</span><span class="o">.</span><span class="n">dispatch</span><span class="o">.</span><span class="n">amq_host</span><span class="si">}</span><span class="s2">:</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">amq_configuration</span><span class="o">.</span><span class="n">dispatch</span><span class="o">.</span><span class="n">amq_port</span><span class="si">}</span><span class="s2">, loop=</span><span class="si">{</span><span class="n">loop</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">connection</span> <span class="o">=</span> <span class="k">await</span> <span class="n">aio_pika</span><span class="o">.</span><span class="n">connect_robust</span><span class="p">(</span>
<span class="n">host</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">amq_configuration</span><span class="o">.</span><span class="n">dispatch</span><span class="o">.</span><span class="n">amq_host</span><span class="p">,</span>
<span class="n">port</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">amq_configuration</span><span class="o">.</span><span class="n">dispatch</span><span class="o">.</span><span class="n">amq_port</span><span class="p">,</span>
<span class="n">login</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">amq_configuration</span><span class="o">.</span><span class="n">dispatch</span><span class="o">.</span><span class="n">rabbit_mq_user</span><span class="p">,</span>
<span class="n">password</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">amq_configuration</span><span class="o">.</span><span class="n">dispatch</span><span class="o">.</span><span class="n">rabbit_mq_password</span><span class="p">,</span>
<span class="n">loop</span><span class="o">=</span><span class="n">loop</span><span class="p">,</span>
<span class="p">)</span>
<span class="n">logging_debug</span><span class="p">(</span>
<span class="s2">&quot;RabbitMQClient.setupAMQ, got connection, open=</span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">connection</span><span class="o">.</span><span class="n">is_closed</span><span class="p">,</span>
<span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">channel</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span><span class="o">.</span><span class="n">channel</span><span class="p">()</span>
<span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">channel</span><span class="o">.</span><span class="n">set_qos</span><span class="p">(</span><span class="n">prefetch_count</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">PREFETCH_COUNT</span><span class="p">)</span>
<span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">router</span><span class="o">.</span><span class="n">init_internal_routing_paths</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">channel</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">router</span><span class="o">.</span><span class="n">set_route_added_notifier</span><span class="p">(</span>
<span class="k">lambda</span> <span class="n">route</span><span class="p">:</span> <span class="n">logging_debug</span><span class="p">(</span>
<span class="s2">&quot; RouteAdded, setting up metrics: amqp.adapter.exchange.</span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span>
<span class="n">route</span><span class="o">.</span><span class="n">exchange</span><span class="p">,</span>
<span class="p">)</span>
<span class="p">)</span></div>
<div class="viewcode-block" id="RabbitMQClient.send_message">
<a class="viewcode-back" href="../../../modules/amqp.rabbitmq.html#amqp.rabbitmq.rabbit_mq_client.RabbitMQClient.send_message">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">send_message</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">DataMessage</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> The API routine that sends a datagram message (DataMessage) to the destination. The Destination</span>
<span class="sd"> is determined from the DataMessage metadata section, using `domain` and `path` as key.</span>
<span class="sd"> :param message: message to send</span>
<span class="sd"> :return: nothing (void) as submitting message to RabbitMQ exchange does not return anything</span>
<span class="sd"> meaningful. There will be asynch ACK later that will confirm the message was sent to RMQ.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">route</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">router</span><span class="o">.</span><span class="n">find_route_by_message</span><span class="p">(</span><span class="n">message</span><span class="p">)</span>
<span class="k">if</span> <span class="n">route</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">rpc_exchange</span><span class="p">:</span>
<span class="k">if</span> <span class="n">route</span><span class="o">.</span><span class="n">timeout</span> <span class="o">&lt;=</span> <span class="mi">0</span><span class="p">:</span>
<span class="c1"># No response expected</span>
<span class="n">pika_message</span><span class="p">:</span> <span class="n">aio_pika</span><span class="o">.</span><span class="n">message</span><span class="o">.</span><span class="n">Message</span> <span class="o">=</span> <span class="n">aio_pika</span><span class="o">.</span><span class="n">message</span><span class="o">.</span><span class="n">Message</span><span class="p">(</span>
<span class="n">body</span><span class="o">=</span><span class="n">DataMessageFactory</span><span class="o">.</span><span class="n">serialize</span><span class="p">(</span><span class="n">message</span><span class="p">),</span>
<span class="n">content_encoding</span><span class="o">=</span><span class="s2">&quot;utf-8&quot;</span><span class="p">,</span>
<span class="n">delivery_mode</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">rpc_exchange</span><span class="o">.</span><span class="n">publish</span><span class="p">(</span>
<span class="n">message</span><span class="o">=</span><span class="n">pika_message</span><span class="p">,</span>
<span class="n">routing_key</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">router</span><span class="o">.</span><span class="n">get_routing_key</span><span class="p">(</span>
<span class="n">message</span>
<span class="p">),</span> <span class="c1"># context path is a routing key</span>
<span class="p">)</span>
<span class="n">logging_info</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Msg Publish (no-reply), messageId: </span><span class="si">{</span><span class="n">message</span><span class="o">.</span><span class="n">id</span><span class="p">()</span><span class="si">}</span><span class="s2">, to: </span><span class="si">{</span><span class="n">route</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># This is RPC call, there should be response</span>
<span class="n">pika_message</span><span class="p">:</span> <span class="n">aio_pika</span><span class="o">.</span><span class="n">message</span><span class="o">.</span><span class="n">Message</span> <span class="o">=</span> <span class="n">aio_pika</span><span class="o">.</span><span class="n">message</span><span class="o">.</span><span class="n">Message</span><span class="p">(</span>
<span class="n">body</span><span class="o">=</span><span class="n">DataMessageFactory</span><span class="o">.</span><span class="n">serialize</span><span class="p">(</span><span class="n">message</span><span class="p">),</span>
<span class="n">content_encoding</span><span class="o">=</span><span class="s2">&quot;utf-8&quot;</span><span class="p">,</span>
<span class="n">delivery_mode</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span>
<span class="n">correlation_id</span><span class="o">=</span><span class="nb">str</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">id</span><span class="p">()),</span>
<span class="n">reply_to</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">router</span><span class="o">.</span><span class="n">get_reply_to_queue_name</span><span class="p">(),</span>
<span class="p">)</span>
<span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">rpc_exchange</span><span class="o">.</span><span class="n">publish</span><span class="p">(</span>
<span class="n">message</span><span class="o">=</span><span class="n">pika_message</span><span class="p">,</span>
<span class="n">routing_key</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">router</span><span class="o">.</span><span class="n">get_routing_key</span><span class="p">(</span>
<span class="n">message</span>
<span class="p">),</span> <span class="c1"># context path is a routing key</span>
<span class="p">)</span>
<span class="n">logging_info</span><span class="p">(</span>
<span class="s2">&quot;Msg Publish (RPC call), messageId: </span><span class="si">%s</span><span class="s2">, to: </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span>
<span class="n">message</span><span class="o">.</span><span class="n">id</span><span class="p">()</span><span class="o">.</span><span class="n">as_string</span><span class="p">(),</span>
<span class="n">route</span><span class="o">.</span><span class="n">as_string</span><span class="p">(),</span>
<span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">logging_warning</span><span class="p">(</span>
<span class="s2">&quot;Message not sent, no route for </span><span class="si">%s</span><span class="s2">/</span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span>
<span class="n">message</span><span class="o">.</span><span class="n">domain</span><span class="p">(),</span>
<span class="n">message</span><span class="o">.</span><span class="n">path</span><span class="p">(),</span>
<span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">err</span><span class="p">:</span>
<span class="n">logging_error</span><span class="p">(</span><span class="s2">&quot;Send message failed: </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">err</span><span class="p">)</span></div>
<div class="viewcode-block" id="RabbitMQClient.request_routes">
<a class="viewcode-back" href="../../../modules/amqp.rabbitmq.html#amqp.rabbitmq.rabbit_mq_client.RabbitMQClient.request_routes">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">request_routes</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">router</span><span class="o">.</span><span class="n">request_routes_from_adapters</span><span class="p">()</span></div>
<div class="viewcode-block" id="RabbitMQClient.find_route">
<a class="viewcode-back" href="../../../modules/amqp.rabbitmq.html#amqp.rabbitmq.rabbit_mq_client.RabbitMQClient.find_route">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">find_route</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">domain</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">path</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">AMQRoute</span><span class="p">:</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">router</span><span class="o">.</span><span class="n">find_route</span><span class="p">(</span><span class="n">domain</span><span class="p">,</span> <span class="n">path</span><span class="p">)</span></div>
</div>
</pre></div>
</div>
</div>
<footer>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2024, CleverThis.</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>
@@ -0,0 +1,397 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" data-content_root="../../../">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>amqp.rabbitmq.user_management_service_client &mdash; AMQ Adapter Python 1.0 documentation</title>
<link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=03e43079" />
<link rel="stylesheet" type="text/css" href="../../../_static/css/theme.css?v=e59714d7" />
<script src="../../../_static/jquery.js?v=5d32c60e"></script>
<script src="../../../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
<script src="../../../_static/documentation_options.js?v=f2a433a1"></script>
<script src="../../../_static/doctools.js?v=9bcbadda"></script>
<script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
<script src="../../../_static/js/theme.js"></script>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="../../../index.html" class="icon icon-home">
AMQ Adapter Python
</a>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" aria-label="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.html">AMQP Package</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.config.html">Configuration Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.adapter.html">Adapter Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.service.html">Service Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.router.html">Router Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.model.html">Model Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.rabbitmq.html">RabbitMQ Module</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="../../../index.html">AMQ Adapter Python</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="../../../index.html" class="icon icon-home" aria-label="Home"></a></li>
<li class="breadcrumb-item"><a href="../../index.html">Module code</a></li>
<li class="breadcrumb-item active">amqp.rabbitmq.user_management_service_client</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<h1>Source code for amqp.rabbitmq.user_management_service_client</h1><div class="highlight"><pre>
<span></span><span class="kn">import</span><span class="w"> </span><span class="nn">asyncio</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">json</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">logging</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">uuid</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Any</span><span class="p">,</span> <span class="n">Dict</span><span class="p">,</span> <span class="n">List</span><span class="p">,</span> <span class="n">Optional</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">aio_pika</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">aio_pika</span><span class="w"> </span><span class="kn">import</span> <span class="n">Message</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">aio_pika.abc</span><span class="w"> </span><span class="kn">import</span> <span class="n">AbstractIncomingMessage</span><span class="p">,</span> <span class="n">AbstractRobustChannel</span><span class="p">,</span> <span class="n">AbstractRobustConnection</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.adapter.logging_utils</span><span class="w"> </span><span class="kn">import</span> <span class="n">logging_debug</span><span class="p">,</span> <span class="n">logging_error</span><span class="p">,</span> <span class="n">logging_info</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.config.amq_configuration</span><span class="w"> </span><span class="kn">import</span> <span class="n">AMQConfiguration</span>
<div class="viewcode-block" id="UserManagementServiceException">
<a class="viewcode-back" href="../../../modules/amqp.rabbitmq.html#amqp.rabbitmq.user_management_service_client.UserManagementServiceException">[docs]</a>
<span class="k">class</span><span class="w"> </span><span class="nc">UserManagementServiceException</span><span class="p">(</span><span class="ne">Exception</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Exception raised for errors in the User Management Service.&quot;&quot;&quot;</span>
<div class="viewcode-block" id="UserManagementServiceException.__init__">
<a class="viewcode-back" href="../../../modules/amqp.rabbitmq.html#amqp.rabbitmq.user_management_service_client.UserManagementServiceException.__init__">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">exception_type</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">additional_info</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">exception_type</span> <span class="o">=</span> <span class="n">exception_type</span>
<span class="bp">self</span><span class="o">.</span><span class="n">message</span> <span class="o">=</span> <span class="n">message</span>
<span class="bp">self</span><span class="o">.</span><span class="n">additional_info</span> <span class="o">=</span> <span class="n">additional_info</span> <span class="ow">or</span> <span class="p">{}</span>
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">exception_type</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">message</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span></div>
</div>
<div class="viewcode-block" id="UserManagementServiceClient">
<a class="viewcode-back" href="../../../modules/amqp.rabbitmq.html#amqp.rabbitmq.user_management_service_client.UserManagementServiceClient">[docs]</a>
<span class="k">class</span><span class="w"> </span><span class="nc">UserManagementServiceClient</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Client for the User Management Service that communicates over RabbitMQ.</span>
<span class="sd"> Supports operations for token, user, group, tenant, and permission services.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="c1"># Exchange name for User Management Service</span>
<span class="n">EXCHANGE_NAME</span> <span class="o">=</span> <span class="s2">&quot;cleverthis.clevermicro.auth.endpoints&quot;</span>
<span class="c1"># Service routing keys</span>
<span class="n">TOKEN_SERVICE</span> <span class="o">=</span> <span class="s2">&quot;token-service-v1&quot;</span>
<span class="n">USER_SERVICE</span> <span class="o">=</span> <span class="s2">&quot;user-service-v1&quot;</span>
<span class="n">GROUP_SERVICE</span> <span class="o">=</span> <span class="s2">&quot;group-service-v1&quot;</span>
<span class="n">TENANT_SERVICE</span> <span class="o">=</span> <span class="s2">&quot;tenant-service-v1&quot;</span>
<span class="n">PERMISSION_SERVICE</span> <span class="o">=</span> <span class="s2">&quot;permission-service-v1&quot;</span>
<span class="c1"># Response queue name</span>
<span class="n">RESPONSE_QUEUE_NAME</span> <span class="o">=</span> <span class="s2">&quot;user-management-service-cleverswarm&quot;</span>
<div class="viewcode-block" id="UserManagementServiceClient.__init__">
<a class="viewcode-back" href="../../../modules/amqp.rabbitmq.html#amqp.rabbitmq.user_management_service_client.UserManagementServiceClient.__init__">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">configuration</span><span class="p">:</span> <span class="n">AMQConfiguration</span><span class="p">,</span> <span class="n">loop</span><span class="p">:</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">AbstractEventLoop</span> <span class="o">=</span> <span class="kc">None</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Initialize the User Management Service client.</span>
<span class="sd"> </span>
<span class="sd"> Args:</span>
<span class="sd"> configuration: AMQ configuration</span>
<span class="sd"> loop: Event loop to use (optional)</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">amq_configuration</span> <span class="o">=</span> <span class="n">configuration</span>
<span class="bp">self</span><span class="o">.</span><span class="n">loop</span> <span class="o">=</span> <span class="n">loop</span> <span class="ow">or</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">get_event_loop</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">connection</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">AbstractRobustConnection</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
<span class="bp">self</span><span class="o">.</span><span class="n">channel</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">AbstractRobustChannel</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
<span class="bp">self</span><span class="o">.</span><span class="n">exchange</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">aio_pika</span><span class="o">.</span><span class="n">RobustExchange</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
<span class="bp">self</span><span class="o">.</span><span class="n">response_queue</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">aio_pika</span><span class="o">.</span><span class="n">RobustQueue</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
<span class="bp">self</span><span class="o">.</span><span class="n">response_consumer_tag</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
<span class="bp">self</span><span class="o">.</span><span class="n">futures</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">Future</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
<span class="bp">self</span><span class="o">.</span><span class="n">initialized</span> <span class="o">=</span> <span class="kc">False</span></div>
<div class="viewcode-block" id="UserManagementServiceClient.initialize">
<a class="viewcode-back" href="../../../modules/amqp.rabbitmq.html#amqp.rabbitmq.user_management_service_client.UserManagementServiceClient.initialize">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">initialize</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Initialize the RabbitMQ connection and set up the exchange and response queue.&quot;&quot;&quot;</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">initialized</span><span class="p">:</span>
<span class="k">return</span>
<span class="k">try</span><span class="p">:</span>
<span class="c1"># Connect to RabbitMQ</span>
<span class="bp">self</span><span class="o">.</span><span class="n">connection</span> <span class="o">=</span> <span class="k">await</span> <span class="n">aio_pika</span><span class="o">.</span><span class="n">connect_robust</span><span class="p">(</span>
<span class="n">host</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">amq_configuration</span><span class="o">.</span><span class="n">dispatch</span><span class="o">.</span><span class="n">amq_host</span><span class="p">,</span>
<span class="n">port</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">amq_configuration</span><span class="o">.</span><span class="n">dispatch</span><span class="o">.</span><span class="n">amq_port</span><span class="p">,</span>
<span class="n">login</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">amq_configuration</span><span class="o">.</span><span class="n">dispatch</span><span class="o">.</span><span class="n">rabbit_mq_user</span><span class="p">,</span>
<span class="n">password</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">amq_configuration</span><span class="o">.</span><span class="n">dispatch</span><span class="o">.</span><span class="n">rabbit_mq_password</span><span class="p">,</span>
<span class="n">loop</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">loop</span><span class="p">,</span>
<span class="p">)</span>
<span class="c1"># Create channel</span>
<span class="bp">self</span><span class="o">.</span><span class="n">channel</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span><span class="o">.</span><span class="n">channel</span><span class="p">()</span>
<span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">channel</span><span class="o">.</span><span class="n">set_qos</span><span class="p">(</span><span class="n">prefetch_count</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
<span class="c1"># Declare exchange</span>
<span class="bp">self</span><span class="o">.</span><span class="n">exchange</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">channel</span><span class="o">.</span><span class="n">declare_exchange</span><span class="p">(</span>
<span class="n">name</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">EXCHANGE_NAME</span><span class="p">,</span>
<span class="nb">type</span><span class="o">=</span><span class="n">aio_pika</span><span class="o">.</span><span class="n">ExchangeType</span><span class="o">.</span><span class="n">TOPIC</span><span class="p">,</span>
<span class="n">durable</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
<span class="p">)</span>
<span class="c1"># Declare response queue</span>
<span class="bp">self</span><span class="o">.</span><span class="n">response_queue</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">channel</span><span class="o">.</span><span class="n">declare_queue</span><span class="p">(</span>
<span class="n">name</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">RESPONSE_QUEUE_NAME</span><span class="p">,</span>
<span class="n">durable</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
<span class="n">exclusive</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
<span class="n">auto_delete</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
<span class="p">)</span>
<span class="c1"># Start consuming responses</span>
<span class="bp">self</span><span class="o">.</span><span class="n">response_consumer_tag</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">response_queue</span><span class="o">.</span><span class="n">consume</span><span class="p">(</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_on_response_callback</span><span class="p">,</span>
<span class="n">no_ack</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
<span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">initialized</span> <span class="o">=</span> <span class="kc">True</span>
<span class="n">logging_info</span><span class="p">(</span><span class="s2">&quot;User Management Service client initialized&quot;</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="n">logging_error</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Failed to initialize User Management Service client: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span> <span class="ow">and</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span><span class="o">.</span><span class="n">is_closed</span><span class="p">:</span>
<span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
<span class="k">raise</span></div>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_on_response_callback</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">AbstractIncomingMessage</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Handle responses from the User Management Service.</span>
<span class="sd"> </span>
<span class="sd"> Args:</span>
<span class="sd"> message: The incoming message</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">correlation_id</span> <span class="o">=</span> <span class="n">message</span><span class="o">.</span><span class="n">correlation_id</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">correlation_id</span><span class="p">:</span>
<span class="n">logging_error</span><span class="p">(</span><span class="s2">&quot;Received response without correlation ID&quot;</span><span class="p">)</span>
<span class="k">await</span> <span class="n">message</span><span class="o">.</span><span class="n">ack</span><span class="p">()</span>
<span class="k">return</span>
<span class="n">future</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">futures</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">correlation_id</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">future</span><span class="p">:</span>
<span class="n">logging_error</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;No pending request found for correlation ID: </span><span class="si">{</span><span class="n">correlation_id</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">await</span> <span class="n">message</span><span class="o">.</span><span class="n">ack</span><span class="p">()</span>
<span class="k">return</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">response_data</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">body</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s1">&#39;utf-8&#39;</span><span class="p">))</span>
<span class="n">logging_debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Received response: </span><span class="si">{</span><span class="n">response_data</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="n">future</span><span class="o">.</span><span class="n">set_result</span><span class="p">(</span><span class="n">response_data</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="n">future</span><span class="o">.</span><span class="n">set_exception</span><span class="p">(</span><span class="n">e</span><span class="p">)</span>
<span class="k">await</span> <span class="n">message</span><span class="o">.</span><span class="n">ack</span><span class="p">()</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="n">logging_error</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Error processing response: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">await</span> <span class="n">message</span><span class="o">.</span><span class="n">ack</span><span class="p">()</span>
<div class="viewcode-block" id="UserManagementServiceClient.close">
<a class="viewcode-back" href="../../../modules/amqp.rabbitmq.html#amqp.rabbitmq.user_management_service_client.UserManagementServiceClient.close">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">close</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Close the RabbitMQ connection.&quot;&quot;&quot;</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span> <span class="ow">and</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span><span class="o">.</span><span class="n">is_closed</span><span class="p">:</span>
<span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">initialized</span> <span class="o">=</span> <span class="kc">False</span>
<span class="n">logging_info</span><span class="p">(</span><span class="s2">&quot;User Management Service client closed&quot;</span><span class="p">)</span></div>
<div class="viewcode-block" id="UserManagementServiceClient.call_service">
<a class="viewcode-back" href="../../../modules/amqp.rabbitmq.html#amqp.rabbitmq.user_management_service_client.UserManagementServiceClient.call_service">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">call_service</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span> <span class="n">service</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">method</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">args</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
<span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Call a method on a User Management Service.</span>
<span class="sd"> </span>
<span class="sd"> Args:</span>
<span class="sd"> service: Service routing key (e.g., &#39;token-service-v1&#39;)</span>
<span class="sd"> method: Method name to call</span>
<span class="sd"> args: Method arguments</span>
<span class="sd"> </span>
<span class="sd"> Returns:</span>
<span class="sd"> Response data</span>
<span class="sd"> </span>
<span class="sd"> Raises:</span>
<span class="sd"> UserManagementServiceException: If the service returns an error</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">initialized</span><span class="p">:</span>
<span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">initialize</span><span class="p">()</span>
<span class="n">correlation_id</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">uuid</span><span class="o">.</span><span class="n">uuid4</span><span class="p">())</span>
<span class="n">future</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">loop</span><span class="o">.</span><span class="n">create_future</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">futures</span><span class="p">[</span><span class="n">correlation_id</span><span class="p">]</span> <span class="o">=</span> <span class="n">future</span>
<span class="n">request_data</span> <span class="o">=</span> <span class="p">{</span>
<span class="s2">&quot;method&quot;</span><span class="p">:</span> <span class="n">method</span><span class="p">,</span>
<span class="s2">&quot;args&quot;</span><span class="p">:</span> <span class="n">args</span> <span class="ow">or</span> <span class="p">{},</span>
<span class="p">}</span>
<span class="n">message</span> <span class="o">=</span> <span class="n">Message</span><span class="p">(</span>
<span class="n">body</span><span class="o">=</span><span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">request_data</span><span class="p">)</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s1">&#39;utf-8&#39;</span><span class="p">),</span>
<span class="n">content_type</span><span class="o">=</span><span class="s1">&#39;application/json&#39;</span><span class="p">,</span>
<span class="n">correlation_id</span><span class="o">=</span><span class="n">correlation_id</span><span class="p">,</span>
<span class="n">reply_to</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">RESPONSE_QUEUE_NAME</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">exchange</span><span class="o">.</span><span class="n">publish</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">routing_key</span><span class="o">=</span><span class="n">service</span><span class="p">)</span>
<span class="n">logging_info</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Sent request to </span><span class="si">{</span><span class="n">service</span><span class="si">}</span><span class="s2">.</span><span class="si">{</span><span class="n">method</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">args</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="c1"># Wait for response</span>
<span class="n">response</span> <span class="o">=</span> <span class="k">await</span> <span class="n">future</span>
<span class="c1"># Process response</span>
<span class="k">if</span> <span class="n">response</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;type&quot;</span><span class="p">)</span> <span class="o">==</span> <span class="s2">&quot;OK&quot;</span><span class="p">:</span>
<span class="k">return</span> <span class="n">response</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;result&quot;</span><span class="p">,</span> <span class="p">[])</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">raise</span> <span class="n">UserManagementServiceException</span><span class="p">(</span>
<span class="n">response</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;exception&quot;</span><span class="p">,</span> <span class="s2">&quot;unknown_error&quot;</span><span class="p">),</span>
<span class="n">response</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;message&quot;</span><span class="p">,</span> <span class="s2">&quot;Unknown error&quot;</span><span class="p">),</span>
<span class="n">response</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;additional_info&quot;</span><span class="p">,</span> <span class="p">{})</span>
<span class="p">)</span>
<span class="k">except</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">CancelledError</span><span class="p">:</span>
<span class="k">raise</span>
<span class="k">except</span> <span class="n">UserManagementServiceException</span><span class="p">:</span>
<span class="k">raise</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="n">logging_error</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Error calling service </span><span class="si">{</span><span class="n">service</span><span class="si">}</span><span class="s2">.</span><span class="si">{</span><span class="n">method</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">raise</span>
<span class="k">finally</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">futures</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="n">correlation_id</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span></div>
<div class="viewcode-block" id="UserManagementServiceClient.validate_token">
<a class="viewcode-back" href="../../../modules/amqp.rabbitmq.html#amqp.rabbitmq.user_management_service_client.UserManagementServiceClient.validate_token">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">validate_token</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">token</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Validate a JWT token.</span>
<span class="sd"> </span>
<span class="sd"> Args:</span>
<span class="sd"> token: JWT token to validate</span>
<span class="sd"> </span>
<span class="sd"> Returns:</span>
<span class="sd"> Token information</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">call_service</span><span class="p">(</span>
<span class="n">service</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">TOKEN_SERVICE</span><span class="p">,</span>
<span class="n">method</span><span class="o">=</span><span class="s2">&quot;validateToken&quot;</span><span class="p">,</span>
<span class="n">args</span><span class="o">=</span><span class="p">{</span><span class="s2">&quot;token&quot;</span><span class="p">:</span> <span class="n">token</span><span class="p">}</span>
<span class="p">)</span></div>
<div class="viewcode-block" id="UserManagementServiceClient.query_user_by_id">
<a class="viewcode-back" href="../../../modules/amqp.rabbitmq.html#amqp.rabbitmq.user_management_service_client.UserManagementServiceClient.query_user_by_id">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">query_user_by_id</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">user_id</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Query user information by user ID.</span>
<span class="sd"> </span>
<span class="sd"> Args:</span>
<span class="sd"> user_id: User ID</span>
<span class="sd"> </span>
<span class="sd"> Returns:</span>
<span class="sd"> User information</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">call_service</span><span class="p">(</span>
<span class="n">service</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">USER_SERVICE</span><span class="p">,</span>
<span class="n">method</span><span class="o">=</span><span class="s2">&quot;queryUserById&quot;</span><span class="p">,</span>
<span class="n">args</span><span class="o">=</span><span class="p">{</span><span class="s2">&quot;userId&quot;</span><span class="p">:</span> <span class="n">user_id</span><span class="p">}</span>
<span class="p">)</span></div>
<div class="viewcode-block" id="UserManagementServiceClient.list_users_in_group">
<a class="viewcode-back" href="../../../modules/amqp.rabbitmq.html#amqp.rabbitmq.user_management_service_client.UserManagementServiceClient.list_users_in_group">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">list_users_in_group</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">group_id</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">List</span><span class="p">[</span><span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]]:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> List users in a group.</span>
<span class="sd"> </span>
<span class="sd"> Args:</span>
<span class="sd"> group_id: Group ID</span>
<span class="sd"> </span>
<span class="sd"> Returns:</span>
<span class="sd"> List of users</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">call_service</span><span class="p">(</span>
<span class="n">service</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">GROUP_SERVICE</span><span class="p">,</span>
<span class="n">method</span><span class="o">=</span><span class="s2">&quot;listUsersInGroup&quot;</span><span class="p">,</span>
<span class="n">args</span><span class="o">=</span><span class="p">{</span><span class="s2">&quot;groupId&quot;</span><span class="p">:</span> <span class="n">group_id</span><span class="p">}</span>
<span class="p">)</span></div>
</div>
</pre></div>
</div>
</div>
<footer>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2024, CleverThis.</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>
@@ -0,0 +1,209 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" data-content_root="../../../">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>amqp.router.route_database &mdash; AMQ Adapter Python 1.0 documentation</title>
<link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=03e43079" />
<link rel="stylesheet" type="text/css" href="../../../_static/css/theme.css?v=e59714d7" />
<script src="../../../_static/jquery.js?v=5d32c60e"></script>
<script src="../../../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
<script src="../../../_static/documentation_options.js?v=f2a433a1"></script>
<script src="../../../_static/doctools.js?v=9bcbadda"></script>
<script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
<script src="../../../_static/js/theme.js"></script>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="../../../index.html" class="icon icon-home">
AMQ Adapter Python
</a>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" aria-label="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.html">AMQP Package</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.config.html">Configuration Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.adapter.html">Adapter Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.service.html">Service Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.router.html">Router Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.model.html">Model Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.rabbitmq.html">RabbitMQ Module</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="../../../index.html">AMQ Adapter Python</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="../../../index.html" class="icon icon-home" aria-label="Home"></a></li>
<li class="breadcrumb-item"><a href="../../index.html">Module code</a></li>
<li class="breadcrumb-item active">amqp.router.route_database</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<h1>Source code for amqp.router.route_database</h1><div class="highlight"><pre>
<span></span><span class="kn">import</span><span class="w"> </span><span class="nn">re</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Optional</span><span class="p">,</span> <span class="n">Set</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.adapter.logging_utils</span><span class="w"> </span><span class="kn">import</span> <span class="n">logging_info</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.model.model</span><span class="w"> </span><span class="kn">import</span> <span class="n">AMQRoute</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.router.utils</span><span class="w"> </span><span class="kn">import</span> <span class="n">sanitize_as_rabbitmq_name</span>
<div class="viewcode-block" id="RouteDatabase">
<a class="viewcode-back" href="../../../modules/amqp.router.html#amqp.router.route_database.RouteDatabase">[docs]</a>
<span class="k">class</span><span class="w"> </span><span class="nc">RouteDatabase</span><span class="p">:</span>
<div class="viewcode-block" id="RouteDatabase.__init__">
<a class="viewcode-back" href="../../../modules/amqp.router.html#amqp.router.route_database.RouteDatabase.__init__">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">routes</span><span class="p">:</span> <span class="n">Set</span><span class="p">[</span><span class="n">AMQRoute</span><span class="p">]</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span></div>
<div class="viewcode-block" id="RouteDatabase.get_routes">
<a class="viewcode-back" href="../../../modules/amqp.router.html#amqp.router.route_database.RouteDatabase.get_routes">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">get_routes</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Set</span><span class="p">[</span><span class="n">AMQRoute</span><span class="p">]:</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">routes</span></div>
<div class="viewcode-block" id="RouteDatabase.pattern">
<a class="viewcode-back" href="../../../modules/amqp.router.html#amqp.router.route_database.RouteDatabase.pattern">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">pattern</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">routing_key</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">re</span><span class="o">.</span><span class="n">Pattern</span><span class="p">:</span>
<span class="n">breaker</span> <span class="o">=</span> <span class="kc">False</span>
<span class="n">tokens</span> <span class="o">=</span> <span class="n">routing_key</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;.&quot;</span><span class="p">)</span>
<span class="n">counter</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">tokens</span><span class="p">)</span>
<span class="n">regex_parts</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">token</span> <span class="ow">in</span> <span class="n">tokens</span><span class="p">:</span>
<span class="n">counter</span> <span class="o">-=</span> <span class="mi">1</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">breaker</span><span class="p">:</span>
<span class="k">if</span> <span class="n">token</span> <span class="o">==</span> <span class="s2">&quot;&quot;</span><span class="p">:</span>
<span class="n">res</span> <span class="o">=</span> <span class="s2">&quot;[^</span><span class="se">\\</span><span class="s2">.]*&quot;</span>
<span class="k">elif</span> <span class="n">token</span> <span class="o">==</span> <span class="s2">&quot;#&quot;</span><span class="p">:</span>
<span class="n">breaker</span> <span class="o">=</span> <span class="kc">True</span>
<span class="n">res</span> <span class="o">=</span> <span class="s2">&quot;.*$&quot;</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">res</span> <span class="o">=</span> <span class="n">token</span>
<span class="k">if</span> <span class="n">counter</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">breaker</span><span class="p">:</span>
<span class="n">res</span> <span class="o">+=</span> <span class="s2">&quot;</span><span class="se">\\</span><span class="s2">.&quot;</span>
<span class="n">regex_parts</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">res</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">regex_parts</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s2">&quot;&quot;</span><span class="p">)</span>
<span class="n">regex</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="nb">filter</span><span class="p">(</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span> <span class="o">!=</span> <span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="n">regex_parts</span><span class="p">))</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">routing_key</span><span class="p">:</span>
<span class="k">return</span> <span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="s2">&quot;.*&quot;</span><span class="p">)</span>
<span class="k">return</span> <span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="n">regex</span><span class="p">)</span></div>
<div class="viewcode-block" id="RouteDatabase.matches">
<a class="viewcode-back" href="../../../modules/amqp.router.html#amqp.router.route_database.RouteDatabase.matches">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">matches</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">routing_key_from_route</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">routing_key_from_message</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
<span class="n">route_pattern</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">pattern</span><span class="p">(</span><span class="n">routing_key_from_route</span><span class="p">)</span>
<span class="k">return</span> <span class="nb">bool</span><span class="p">(</span><span class="n">route_pattern</span><span class="o">.</span><span class="n">match</span><span class="p">(</span><span class="n">sanitize_as_rabbitmq_name</span><span class="p">(</span><span class="n">routing_key_from_message</span><span class="p">)))</span></div>
<div class="viewcode-block" id="RouteDatabase.wrap_routes">
<a class="viewcode-back" href="../../../modules/amqp.router.html#amqp.router.route_database.RouteDatabase.wrap_routes">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">wrap_routes</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="k">return</span> <span class="s2">&quot;,&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">route</span><span class="p">)</span> <span class="k">for</span> <span class="n">route</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">routes</span><span class="p">)</span></div>
<div class="viewcode-block" id="RouteDatabase.find_route">
<a class="viewcode-back" href="../../../modules/amqp.router.html#amqp.router.route_database.RouteDatabase.find_route">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">find_route</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">domain</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">path</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">AMQRoute</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">routing_key</span> <span class="o">=</span> <span class="n">sanitize_as_rabbitmq_name</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">domain</span><span class="si">}</span><span class="s2">.</span><span class="si">{</span><span class="n">path</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="n">logging_info</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;findRoute key:</span><span class="si">{</span><span class="n">routing_key</span><span class="si">}</span><span class="s2"> in:</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">wrap_routes</span><span class="p">()</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">for</span> <span class="n">route</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">routes</span><span class="p">:</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">matches</span><span class="p">(</span><span class="n">route</span><span class="o">.</span><span class="n">key</span><span class="p">,</span> <span class="n">routing_key</span><span class="p">):</span>
<span class="k">return</span> <span class="n">route</span>
<span class="k">return</span> <span class="kc">None</span></div>
<div class="viewcode-block" id="RouteDatabase.find_route_by_service">
<a class="viewcode-back" href="../../../modules/amqp.router.html#amqp.router.route_database.RouteDatabase.find_route_by_service">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">find_route_by_service</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">service_name</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Optional</span><span class="p">[</span><span class="n">AMQRoute</span><span class="p">]:</span>
<span class="n">logging_info</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;findRoute service_name:</span><span class="si">{</span><span class="n">service_name</span><span class="si">}</span><span class="s2"> in:</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">wrap_routes</span><span class="p">()</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">for</span> <span class="n">route</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">routes</span><span class="p">:</span>
<span class="k">if</span> <span class="n">route</span><span class="o">.</span><span class="n">component_name</span> <span class="o">==</span> <span class="n">service_name</span><span class="p">:</span>
<span class="k">return</span> <span class="n">route</span>
<span class="k">return</span> <span class="kc">None</span></div>
<div class="viewcode-block" id="RouteDatabase.add_route">
<a class="viewcode-back" href="../../../modules/amqp.router.html#amqp.router.route_database.RouteDatabase.add_route">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">add_route</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">route</span><span class="p">:</span> <span class="n">AMQRoute</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
<span class="k">if</span> <span class="n">route</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">routes</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">routes</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">route</span><span class="p">)</span>
<span class="k">return</span> <span class="kc">True</span>
<span class="k">return</span> <span class="kc">False</span></div>
<div class="viewcode-block" id="RouteDatabase.remove_route">
<a class="viewcode-back" href="../../../modules/amqp.router.html#amqp.router.route_database.RouteDatabase.remove_route">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">remove_route</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">route</span><span class="p">:</span> <span class="n">AMQRoute</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
<span class="k">return</span> <span class="n">route</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">routes</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">routes</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">route</span><span class="p">)</span></div>
</div>
</pre></div>
</div>
</div>
<footer>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2024, CleverThis.</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>
@@ -0,0 +1,258 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" data-content_root="../../../">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>amqp.router.router_base &mdash; AMQ Adapter Python 1.0 documentation</title>
<link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=03e43079" />
<link rel="stylesheet" type="text/css" href="../../../_static/css/theme.css?v=e59714d7" />
<script src="../../../_static/jquery.js?v=5d32c60e"></script>
<script src="../../../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
<script src="../../../_static/documentation_options.js?v=f2a433a1"></script>
<script src="../../../_static/doctools.js?v=9bcbadda"></script>
<script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
<script src="../../../_static/js/theme.js"></script>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="../../../index.html" class="icon icon-home">
AMQ Adapter Python
</a>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" aria-label="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.html">AMQP Package</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.config.html">Configuration Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.adapter.html">Adapter Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.service.html">Service Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.router.html">Router Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.model.html">Model Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.rabbitmq.html">RabbitMQ Module</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="../../../index.html">AMQ Adapter Python</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="../../../index.html" class="icon icon-home" aria-label="Home"></a></li>
<li class="breadcrumb-item"><a href="../../index.html">Module code</a></li>
<li class="breadcrumb-item active">amqp.router.router_base</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<h1>Source code for amqp.router.router_base</h1><div class="highlight"><pre>
<span></span><span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Callable</span><span class="p">,</span> <span class="n">List</span><span class="p">,</span> <span class="n">Optional</span><span class="p">,</span> <span class="n">Set</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.adapter.amq_route_factory</span><span class="w"> </span><span class="kn">import</span> <span class="n">NULL_ROUTE</span><span class="p">,</span> <span class="n">AMQRouteFactory</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.adapter.logging_utils</span><span class="w"> </span><span class="kn">import</span> <span class="n">logging_debug</span><span class="p">,</span> <span class="n">logging_error</span><span class="p">,</span> <span class="n">logging_info</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.model.model</span><span class="w"> </span><span class="kn">import</span> <span class="n">AMQRoute</span><span class="p">,</span> <span class="n">DataMessage</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.router.route_database</span><span class="w"> </span><span class="kn">import</span> <span class="n">RouteDatabase</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.router.utils</span><span class="w"> </span><span class="kn">import</span> <span class="n">sanitize_as_rabbitmq_name</span>
<span class="n">CM_REQUEST_EXCHANGE</span> <span class="o">=</span> <span class="s2">&quot;CM-Request&quot;</span>
<span class="n">CM_RESPONSE_EXCHANGE</span> <span class="o">=</span> <span class="s2">&quot;CM-Response&quot;</span>
<span class="n">CM_C_REQ_QUEUE</span> <span class="o">=</span> <span class="s2">&quot;C-REQ&quot;</span>
<span class="n">CM_C_RESP_QUEUE</span> <span class="o">=</span> <span class="s2">&quot;C-RESP&quot;</span>
<span class="n">CM_C_AMQ_QUEUE</span> <span class="o">=</span> <span class="s2">&quot;C-AMQ&quot;</span>
<span class="n">CM_P_RESP_QUEUE</span> <span class="o">=</span> <span class="s2">&quot;P-RESP&quot;</span>
<span class="n">CM_P_REPLY_TO</span> <span class="o">=</span> <span class="s2">&quot;P-REPLY-TO&quot;</span>
<span class="n">ANY_RECIPIENT</span> <span class="o">=</span> <span class="s2">&quot;*&quot;</span>
<span class="n">AMQ_RPC_EXCHANGE</span> <span class="o">=</span> <span class="s2">&quot;AMQ-RPC&quot;</span>
<span class="n">AMQ_REPLY_TO_EXCHANGE</span> <span class="o">=</span> <span class="s2">&quot;AMQ-REPLY-TO&quot;</span>
<span class="n">DLQ_EXCHANGE</span> <span class="o">=</span> <span class="s2">&quot;DLX&quot;</span>
<div class="viewcode-block" id="RouterBase">
<a class="viewcode-back" href="../../../modules/amqp.router.html#amqp.router.router_base.RouterBase">[docs]</a>
<span class="k">class</span><span class="w"> </span><span class="nc">RouterBase</span><span class="p">:</span>
<div class="viewcode-block" id="RouterBase.__init__">
<a class="viewcode-back" href="../../../modules/amqp.router.html#amqp.router.router_base.RouterBase.__init__">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">route_database</span> <span class="o">=</span> <span class="n">RouteDatabase</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">own_routes</span><span class="p">:</span> <span class="n">Set</span><span class="p">[</span><span class="n">AMQRoute</span><span class="p">]</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">route_added_notifier</span><span class="p">:</span> <span class="n">Callable</span><span class="p">[[</span><span class="n">AMQRoute</span><span class="p">],</span> <span class="kc">None</span><span class="p">]</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span>
<span class="bp">self</span><span class="o">.</span><span class="n">route_removed_notifier</span><span class="p">:</span> <span class="n">Callable</span><span class="p">[[</span><span class="n">AMQRoute</span><span class="p">],</span> <span class="kc">None</span><span class="p">]</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span></div>
<div class="viewcode-block" id="RouterBase.get_routing_key">
<a class="viewcode-back" href="../../../modules/amqp.router.html#amqp.router.router_base.RouterBase.get_routing_key">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">get_routing_key</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">DataMessage</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="k">return</span> <span class="n">sanitize_as_rabbitmq_name</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">message</span><span class="o">.</span><span class="n">domain</span><span class="p">()</span><span class="si">}</span><span class="s2">.</span><span class="si">{</span><span class="n">message</span><span class="o">.</span><span class="n">path</span><span class="p">()</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span></div>
<div class="viewcode-block" id="RouterBase.wrap_routes">
<a class="viewcode-back" href="../../../modules/amqp.router.html#amqp.router.router_base.RouterBase.wrap_routes">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">wrap_routes</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">route_database</span><span class="o">.</span><span class="n">wrap_routes</span><span class="p">()</span></div>
<div class="viewcode-block" id="RouterBase.wrap_own_routes">
<a class="viewcode-back" href="../../../modules/amqp.router.html#amqp.router.router_base.RouterBase.wrap_own_routes">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">wrap_own_routes</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="k">return</span> <span class="s2">&quot;,&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">route</span><span class="p">)</span> <span class="k">for</span> <span class="n">route</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">own_routes</span><span class="p">)</span></div>
<div class="viewcode-block" id="RouterBase.unwrap_route_list">
<a class="viewcode-back" href="../../../modules/amqp.router.html#amqp.router.router_base.RouterBase.unwrap_route_list">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">unwrap_route_list</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">route_string</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">List</span><span class="p">[</span><span class="n">AMQRoute</span><span class="p">]:</span>
<span class="n">logging_debug</span><span class="p">(</span><span class="s2">&quot;RouterMaster.unwrapRoutes, route(s): </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">route_string</span><span class="p">)</span>
<span class="n">routes</span> <span class="o">=</span> <span class="p">[</span><span class="n">AMQRouteFactory</span><span class="o">.</span><span class="n">from_string</span><span class="p">(</span><span class="n">route_str</span><span class="p">)</span> <span class="k">for</span> <span class="n">route_str</span> <span class="ow">in</span> <span class="n">route_string</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;,&quot;</span><span class="p">)]</span>
<span class="k">return</span> <span class="p">[</span><span class="n">route</span> <span class="k">for</span> <span class="n">route</span> <span class="ow">in</span> <span class="n">routes</span> <span class="k">if</span> <span class="n">route</span> <span class="o">!=</span> <span class="n">NULL_ROUTE</span><span class="p">]</span></div>
<div class="viewcode-block" id="RouterBase.get_routes">
<a class="viewcode-back" href="../../../modules/amqp.router.html#amqp.router.router_base.RouterBase.get_routes">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">get_routes</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Set</span><span class="p">[</span><span class="n">AMQRoute</span><span class="p">]:</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">route_database</span><span class="o">.</span><span class="n">get_routes</span><span class="p">()</span></div>
<div class="viewcode-block" id="RouterBase.find_route">
<a class="viewcode-back" href="../../../modules/amqp.router.html#amqp.router.router_base.RouterBase.find_route">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">find_route</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">domain</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">path</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">AMQRoute</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">route_database</span><span class="o">.</span><span class="n">find_route</span><span class="p">(</span><span class="n">domain</span><span class="p">,</span> <span class="n">path</span><span class="p">)</span></div>
<div class="viewcode-block" id="RouterBase.find_route_by_message">
<a class="viewcode-back" href="../../../modules/amqp.router.html#amqp.router.router_base.RouterBase.find_route_by_message">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">find_route_by_message</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">DataMessage</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">AMQRoute</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">route_database</span><span class="o">.</span><span class="n">find_route</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">domain</span><span class="p">(),</span> <span class="n">message</span><span class="o">.</span><span class="n">path</span><span class="p">())</span></div>
<div class="viewcode-block" id="RouterBase.find_route_by_service">
<a class="viewcode-back" href="../../../modules/amqp.router.html#amqp.router.router_base.RouterBase.find_route_by_service">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">find_route_by_service</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">service_name</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Optional</span><span class="p">[</span><span class="n">AMQRoute</span><span class="p">]:</span>
<span class="n">_route</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">AMQRoute</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">route_database</span><span class="o">.</span><span class="n">find_route_by_service</span><span class="p">(</span><span class="n">service_name</span><span class="p">)</span>
<span class="k">if</span> <span class="n">_route</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">for</span> <span class="n">route</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">own_routes</span><span class="p">:</span>
<span class="k">if</span> <span class="n">route</span><span class="o">.</span><span class="n">component_name</span> <span class="o">==</span> <span class="n">service_name</span><span class="p">:</span>
<span class="n">_route</span> <span class="o">=</span> <span class="n">route</span>
<span class="k">return</span> <span class="n">_route</span></div>
<div class="viewcode-block" id="RouterBase.add_routes">
<a class="viewcode-back" href="../../../modules/amqp.router.html#amqp.router.router_base.RouterBase.add_routes">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">add_routes</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">amq_route_list</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">unwrap_route_list</span><span class="p">(</span><span class="n">message</span><span class="p">)</span>
<span class="n">logging_info</span><span class="p">(</span><span class="s2">&quot; [DBG] RouterMaster.addRoute [</span><span class="si">%d</span><span class="s2">]: </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">amq_route_list</span><span class="p">),</span> <span class="n">message</span><span class="p">)</span>
<span class="k">for</span> <span class="n">route</span> <span class="ow">in</span> <span class="n">amq_route_list</span><span class="p">:</span>
<span class="n">logging_info</span><span class="p">(</span><span class="s2">&quot;RouterMaster.addRoute, adding route: </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">route</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">route</span><span class="o">.</span><span class="n">exchange</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">route</span><span class="o">.</span><span class="n">queue</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">route</span><span class="o">.</span><span class="n">key</span><span class="p">:</span>
<span class="n">logging_error</span><span class="p">(</span>
<span class="s2">&quot;Cannot setup AMQ Exchange for &#39;</span><span class="si">%s</span><span class="s2">&#39;, at least one of &quot;</span>
<span class="s2">&quot;Exchange, Queue and/or Key must be present in the routing string. &quot;</span>
<span class="s2">&quot;Expected format is &#39;</span><span class="si">%s</span><span class="s2">&#39;&quot;</span><span class="p">,</span>
<span class="n">route</span><span class="p">,</span>
<span class="n">AMQRoute</span><span class="o">.</span><span class="n">FORMAT</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">if</span> <span class="n">route</span><span class="o">.</span><span class="n">exchange</span> <span class="o">!=</span> <span class="n">DLQ_EXCHANGE</span><span class="p">:</span>
<span class="n">is_new_route</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">route_database</span><span class="o">.</span><span class="n">add_route</span><span class="p">(</span><span class="n">route</span><span class="p">)</span>
<span class="k">if</span> <span class="n">is_new_route</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">route_added_notifier</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">route_added_notifier</span><span class="p">(</span><span class="n">route</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">err</span><span class="p">:</span>
<span class="n">logging_error</span><span class="p">(</span><span class="s2">&quot;add_routes error: </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">err</span><span class="p">)</span></div>
<div class="viewcode-block" id="RouterBase.set_route_added_notifier">
<a class="viewcode-back" href="../../../modules/amqp.router.html#amqp.router.router_base.RouterBase.set_route_added_notifier">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">set_route_added_notifier</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">callback</span><span class="p">:</span> <span class="n">Callable</span><span class="p">[[</span><span class="n">AMQRoute</span><span class="p">],</span> <span class="kc">None</span><span class="p">]):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">route_added_notifier</span> <span class="o">=</span> <span class="n">callback</span></div>
<div class="viewcode-block" id="RouterBase.remove_routes">
<a class="viewcode-back" href="../../../modules/amqp.router.html#amqp.router.router_base.RouterBase.remove_routes">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">remove_routes</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">to_remove</span> <span class="o">=</span> <span class="p">[</span><span class="n">AMQRouteFactory</span><span class="o">.</span><span class="n">from_string</span><span class="p">(</span><span class="n">route_str</span><span class="p">)</span> <span class="k">for</span> <span class="n">route_str</span> <span class="ow">in</span> <span class="n">message</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;,&quot;</span><span class="p">)]</span>
<span class="n">removed_count</span> <span class="o">=</span> <span class="nb">sum</span><span class="p">(</span><span class="mi">1</span> <span class="k">for</span> <span class="n">route</span> <span class="ow">in</span> <span class="n">to_remove</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">remove_route</span><span class="p">(</span><span class="n">route</span><span class="p">))</span>
<span class="n">logging_info</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;RouterMaster.removeRoutes(): </span><span class="si">{</span><span class="n">message</span><span class="si">}</span><span class="s2">, removed=</span><span class="si">{</span><span class="n">removed_count</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">IOError</span> <span class="k">as</span> <span class="n">err</span><span class="p">:</span>
<span class="n">logging_error</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Can&#39;t remove route(s): </span><span class="si">{</span><span class="n">err</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span></div>
<div class="viewcode-block" id="RouterBase.remove_route">
<a class="viewcode-back" href="../../../modules/amqp.router.html#amqp.router.router_base.RouterBase.remove_route">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">remove_route</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">route</span><span class="p">:</span> <span class="n">AMQRoute</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
<span class="n">is_route_removed</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">route_database</span><span class="o">.</span><span class="n">remove_route</span><span class="p">(</span><span class="n">route</span><span class="p">)</span>
<span class="k">if</span> <span class="n">is_route_removed</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">route_removed_notifier</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">route_removed_notifier</span><span class="p">(</span><span class="n">route</span><span class="p">)</span>
<span class="k">return</span> <span class="n">is_route_removed</span></div>
<div class="viewcode-block" id="RouterBase.add_route">
<a class="viewcode-back" href="../../../modules/amqp.router.html#amqp.router.router_base.RouterBase.add_route">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">add_route</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">route</span><span class="p">:</span> <span class="n">AMQRoute</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">route_database</span><span class="o">.</span><span class="n">add_route</span><span class="p">(</span><span class="n">route</span><span class="p">)</span></div>
<div class="viewcode-block" id="RouterBase.add_own_route">
<a class="viewcode-back" href="../../../modules/amqp.router.html#amqp.router.router_base.RouterBase.add_own_route">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">add_own_route</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">route</span><span class="p">:</span> <span class="n">AMQRoute</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">own_routes</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">route</span><span class="p">)</span></div>
</div>
</pre></div>
</div>
</div>
<footer>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2024, CleverThis.</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>
@@ -0,0 +1,328 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" data-content_root="../../../">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>amqp.router.router_consumer &mdash; AMQ Adapter Python 1.0 documentation</title>
<link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=03e43079" />
<link rel="stylesheet" type="text/css" href="../../../_static/css/theme.css?v=e59714d7" />
<script src="../../../_static/jquery.js?v=5d32c60e"></script>
<script src="../../../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
<script src="../../../_static/documentation_options.js?v=f2a433a1"></script>
<script src="../../../_static/doctools.js?v=9bcbadda"></script>
<script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
<script src="../../../_static/js/theme.js"></script>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="../../../index.html" class="icon icon-home">
AMQ Adapter Python
</a>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" aria-label="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.html">AMQP Package</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.config.html">Configuration Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.adapter.html">Adapter Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.service.html">Service Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.router.html">Router Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.model.html">Model Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.rabbitmq.html">RabbitMQ Module</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="../../../index.html">AMQ Adapter Python</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="../../../index.html" class="icon icon-home" aria-label="Home"></a></li>
<li class="breadcrumb-item"><a href="../../index.html">Module code</a></li>
<li class="breadcrumb-item active">amqp.router.router_consumer</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<h1>Source code for amqp.router.router_consumer</h1><div class="highlight"><pre>
<span></span><span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Set</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">aio_pika.abc</span><span class="w"> </span><span class="kn">import</span> <span class="p">(</span>
<span class="n">AbstractIncomingMessage</span><span class="p">,</span>
<span class="n">AbstractRobustChannel</span><span class="p">,</span>
<span class="n">AbstractRobustQueue</span><span class="p">,</span>
<span class="p">)</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.adapter.amq_route_factory</span><span class="w"> </span><span class="kn">import</span> <span class="n">AMQRouteFactory</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.adapter.logging_utils</span><span class="w"> </span><span class="kn">import</span> <span class="p">(</span>
<span class="n">logging_debug</span><span class="p">,</span>
<span class="n">logging_error</span><span class="p">,</span>
<span class="n">logging_info</span><span class="p">,</span>
<span class="n">logging_warning</span><span class="p">,</span>
<span class="p">)</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.config.amq_configuration</span><span class="w"> </span><span class="kn">import</span> <span class="n">AMQConfiguration</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.model.model</span><span class="w"> </span><span class="kn">import</span> <span class="n">AMQRoute</span><span class="p">,</span> <span class="n">ServiceMessage</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.model.service_message_type</span><span class="w"> </span><span class="kn">import</span> <span class="n">ServiceMessageType</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.router.router_base</span><span class="w"> </span><span class="kn">import</span> <span class="p">(</span>
<span class="n">ANY_RECIPIENT</span><span class="p">,</span>
<span class="n">CM_C_REQ_QUEUE</span><span class="p">,</span>
<span class="n">CM_REQUEST_EXCHANGE</span><span class="p">,</span>
<span class="n">CM_RESPONSE_EXCHANGE</span><span class="p">,</span>
<span class="p">)</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.router.router_producer</span><span class="w"> </span><span class="kn">import</span> <span class="n">RouterProducer</span>
<div class="viewcode-block" id="RouterConsumer">
<a class="viewcode-back" href="../../../modules/amqp.router.html#amqp.router.router_consumer.RouterConsumer">[docs]</a>
<span class="k">class</span><span class="w"> </span><span class="nc">RouterConsumer</span><span class="p">(</span><span class="n">RouterProducer</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> * Contains Consumer logic. The logic here:</span>
<span class="sd"> * Sets a listener on CM_C_REQ_QUEUE queue to receive routing data requests</span>
<span class="sd"> * Upon receipt of routing data request, responds on CM_RESPONSE_EXCHANGE with local routing data.</span>
<span class="sd"> * It also proactively pushes the local routing data to CM_RESPONSE_EXCHANGE on startup to</span>
<span class="sd"> * notify the other (excluding self) Producers about its presence.</span>
<span class="sd"> *</span>
<span class="sd"> * Consumer is also Producer (Consumer sits alongside the CM Service, and anytime the Service needs</span>
<span class="sd"> * to communicate with other Service, it can do so via the Adapter). Therefore, the Producer</span>
<span class="sd"> * capability is also required.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<div class="viewcode-block" id="RouterConsumer.__init__">
<a class="viewcode-back" href="../../../modules/amqp.router.html#amqp.router.router_consumer.RouterConsumer.__init__">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">configuration</span><span class="p">:</span> <span class="n">AMQConfiguration</span><span class="p">):</span>
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="n">configuration</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">amqRouteFactory</span> <span class="o">=</span> <span class="n">AMQRouteFactory</span><span class="p">()</span>
<span class="n">logging_info</span><span class="p">(</span><span class="s2">&quot;RouterConsumer.&lt;init&gt;&quot;</span><span class="p">)</span></div>
<div class="viewcode-block" id="RouterConsumer.init_routing_paths_consumer">
<a class="viewcode-back" href="../../../modules/amqp.router.html#amqp.router.router_consumer.RouterConsumer.init_routing_paths_consumer">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">init_routing_paths_consumer</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">_channel</span><span class="p">:</span> <span class="n">AbstractRobustChannel</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> * Initialize router according to Consumer mode.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">logging_info</span><span class="p">(</span>
<span class="s2">&quot;RouterConsumer.initConsumerRouter, channel open: </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">is_open</span><span class="p">(</span><span class="n">_channel</span><span class="p">),</span>
<span class="p">)</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">is_open</span><span class="p">(</span><span class="n">_channel</span><span class="p">):</span>
<span class="k">try</span><span class="p">:</span>
<span class="c1"># 1. declare a Queue to receive the RoutingData requests</span>
<span class="n">_cm_request_queue</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="p">(</span>
<span class="bp">self</span><span class="o">.</span><span class="n">amq_configuration</span><span class="o">.</span><span class="n">amq_adapter</span><span class="o">.</span><span class="n">adapter_prefix</span><span class="p">()</span> <span class="o">+</span> <span class="n">CM_C_REQ_QUEUE</span>
<span class="p">)</span>
<span class="n">_queue</span><span class="p">:</span> <span class="n">AbstractRobustQueue</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">channel</span><span class="o">.</span><span class="n">declare_queue</span><span class="p">(</span>
<span class="n">name</span><span class="o">=</span><span class="n">_cm_request_queue</span><span class="p">,</span>
<span class="n">durable</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
<span class="n">exclusive</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
<span class="n">auto_delete</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
<span class="p">)</span>
<span class="c1"># 1a. bind queue to CM_REQUEST_EXCHANGE w/o any conditions (empty routing key)</span>
<span class="k">await</span> <span class="n">_queue</span><span class="o">.</span><span class="n">bind</span><span class="p">(</span><span class="n">exchange</span><span class="o">=</span><span class="n">CM_REQUEST_EXCHANGE</span><span class="p">,</span> <span class="n">routing_key</span><span class="o">=</span><span class="s2">&quot;&quot;</span><span class="p">)</span>
<span class="c1"># 1b. Service adapter mode - listens on Request queue and replies to Response queue</span>
<span class="n">_c_tag</span> <span class="o">=</span> <span class="k">await</span> <span class="n">_queue</span><span class="o">.</span><span class="n">consume</span><span class="p">(</span>
<span class="n">callback</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">handle_routing_data_request_message</span><span class="p">,</span> <span class="n">no_ack</span><span class="o">=</span><span class="kc">False</span>
<span class="p">)</span>
<span class="n">logging_info</span><span class="p">(</span>
<span class="s2">&quot; [</span><span class="si">%s</span><span class="s2">] RouterConsumer listens for RouteDataRequests on: </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span>
<span class="n">_c_tag</span><span class="p">,</span>
<span class="n">_cm_request_queue</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">ioe</span><span class="p">:</span>
<span class="n">logging_error</span><span class="p">(</span><span class="s2">&quot;RouterConsumer FATAL: cannot initialize, </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">ioe</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">logging_error</span><span class="p">(</span><span class="s2">&quot;RouterConsumer FATAL: cannot initialize, RabbitMQ channel is not open.&quot;</span><span class="p">)</span></div>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> * ServiceMessageType.ROUTING_DATA_REQUEST handler listening on queue &#39;CleverMicroRequest&#39;</span>
<span class="sd"> &quot;&quot;&quot;</span>
<div class="viewcode-block" id="RouterConsumer.handle_routing_data_request_message">
<a class="viewcode-back" href="../../../modules/amqp.router.html#amqp.router.router_consumer.RouterConsumer.handle_routing_data_request_message">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">handle_routing_data_request_message</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">AbstractIncomingMessage</span><span class="p">):</span>
<span class="c1"># some debug statements, TODO - remove for prod release</span>
<span class="n">delivery_tag</span> <span class="o">=</span> <span class="n">message</span><span class="o">.</span><span class="n">delivery_tag</span>
<span class="n">debug</span> <span class="o">=</span> <span class="s2">&quot;Delivery.Properties = &quot;</span> <span class="o">+</span> <span class="n">message</span><span class="o">.</span><span class="n">properties</span><span class="o">.</span><span class="fm">__str__</span><span class="p">()</span>
<span class="n">logging_debug</span><span class="p">(</span>
<span class="s2">&quot; ******[</span><span class="si">%s</span><span class="s2">] (ROUTING_DATA_REQ) tag: </span><span class="si">%s</span><span class="s2">, env: </span><span class="si">%s</span><span class="s2">, props: </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span>
<span class="n">delivery_tag</span><span class="p">,</span>
<span class="n">message</span><span class="o">.</span><span class="n">consumer_tag</span><span class="p">,</span>
<span class="n">message</span><span class="o">.</span><span class="n">properties</span><span class="p">,</span>
<span class="n">debug</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">await</span> <span class="n">message</span><span class="o">.</span><span class="n">ack</span><span class="p">(</span><span class="kc">False</span><span class="p">)</span>
<span class="n">cm_message</span><span class="p">:</span> <span class="n">ServiceMessage</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">service_message_factory</span><span class="o">.</span><span class="n">from_bytes</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">body</span><span class="p">)</span>
<span class="n">route_mapping</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">wrap_own_routes</span><span class="p">()</span>
<span class="n">logging_debug</span><span class="p">(</span>
<span class="s2">&quot;******[</span><span class="si">%s</span><span class="s2">] (ROUTING_DATA_REQ) msg=</span><span class="si">%s</span><span class="s2">, routeMap=[</span><span class="si">%s</span><span class="s2">]&quot;</span><span class="p">,</span>
<span class="n">delivery_tag</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">service_message_factory</span><span class="o">.</span><span class="n">to_string</span><span class="p">(</span><span class="n">cm_message</span><span class="p">),</span>
<span class="n">route_mapping</span><span class="p">,</span>
<span class="p">)</span>
<span class="c1"># Reply only if self adapter has own routeMapping (e.g. API-gateway-side adapter has none)</span>
<span class="k">if</span> <span class="p">(</span>
<span class="n">cm_message</span><span class="o">.</span><span class="n">is_valid</span><span class="p">()</span>
<span class="ow">and</span> <span class="n">cm_message</span><span class="o">.</span><span class="n">message_type</span> <span class="o">==</span> <span class="n">ServiceMessageType</span><span class="o">.</span><span class="n">ROUTING_DATA_REQUEST</span>
<span class="ow">and</span> <span class="n">route_mapping</span>
<span class="p">):</span>
<span class="k">if</span> <span class="n">cm_message</span><span class="o">.</span><span class="n">reply_to</span> <span class="o">!=</span> <span class="bp">self</span><span class="o">.</span><span class="n">amq_configuration</span><span class="o">.</span><span class="n">amq_adapter</span><span class="o">.</span><span class="n">service_name</span><span class="p">:</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">service_message</span><span class="p">:</span> <span class="n">ServiceMessage</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">service_message_factory</span><span class="o">.</span><span class="n">of</span><span class="p">(</span>
<span class="n">ServiceMessageType</span><span class="o">.</span><span class="n">ROUTING_DATA</span><span class="p">,</span>
<span class="n">route_mapping</span><span class="p">,</span>
<span class="n">cm_message</span><span class="o">.</span><span class="n">reply_to</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">publish_service_message</span><span class="p">(</span><span class="n">service_message</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">cm_response_exchange</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">err</span><span class="p">:</span>
<span class="n">logging_error</span><span class="p">(</span>
<span class="s2">&quot;******[</span><span class="si">%s</span><span class="s2">] (ROUTING_DATA_REQ) Response to queue: </span><span class="si">%s</span><span class="s2"> failed: </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span>
<span class="n">delivery_tag</span><span class="p">,</span>
<span class="n">CM_RESPONSE_EXCHANGE</span><span class="p">,</span>
<span class="n">err</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">logging_info</span><span class="p">(</span>
<span class="s2">&quot;******[</span><span class="si">%s</span><span class="s2">] (ROUTING_DATA_REQ) [</span><span class="si">%s</span><span class="s2">] Ignore request originated by ourselves.&quot;</span><span class="p">,</span>
<span class="n">delivery_tag</span><span class="p">,</span>
<span class="nb">str</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">body</span><span class="p">),</span>
<span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">logging_error</span><span class="p">(</span>
<span class="s2">&quot;******[</span><span class="si">%s</span><span class="s2">] (ROUTING_DATA_REQ) [</span><span class="si">%s</span><span class="s2">] produces invalid or no CM msg type.&quot;</span><span class="p">,</span>
<span class="n">delivery_tag</span><span class="p">,</span>
<span class="nb">str</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">body</span><span class="p">),</span>
<span class="p">)</span></div>
<div class="viewcode-block" id="RouterConsumer.register_route">
<a class="viewcode-back" href="../../../modules/amqp.router.html#amqp.router.router_consumer.RouterConsumer.register_route">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">register_route</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">route</span><span class="p">:</span> <span class="n">AMQRoute</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> * Called in Consumer (Service Adapter) context. Registers the routing data for self Service</span>
<span class="sd"> * with the Master router by sending own routing data to Master via CleverMicroResponse queue.</span>
<span class="sd"> * :param route: route to register with Master</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">is_open</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">channel</span><span class="p">)</span> <span class="ow">and</span> <span class="n">route</span><span class="o">.</span><span class="n">queue</span><span class="p">:</span>
<span class="n">serviceMessage</span><span class="p">:</span> <span class="n">ServiceMessage</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">service_message_factory</span><span class="o">.</span><span class="n">of</span><span class="p">(</span>
<span class="n">ServiceMessageType</span><span class="o">.</span><span class="n">ROUTING_DATA</span><span class="p">,</span> <span class="n">route</span><span class="o">.</span><span class="n">as_string</span><span class="p">(),</span> <span class="n">ANY_RECIPIENT</span>
<span class="p">)</span>
<span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">publish_service_message</span><span class="p">(</span><span class="n">serviceMessage</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">cm_response_exchange</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add_own_route</span><span class="p">(</span><span class="n">route</span><span class="p">)</span>
<span class="n">logging_info</span><span class="p">(</span><span class="s2">&quot;RouterConsumer registered Route: </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">route</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">logging_warning</span><span class="p">(</span>
<span class="s2">&quot;RouterConsumer couldn&#39;t register route data: </span><span class="si">%s</span><span class="s2"> channel isn&#39;t open.&quot;</span><span class="p">,</span>
<span class="n">CM_RESPONSE_EXCHANGE</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">ioe</span><span class="p">:</span>
<span class="n">logging_error</span><span class="p">(</span><span class="s2">&quot;RouterConsumer failed register route data: </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">ioe</span><span class="p">)</span></div>
<div class="viewcode-block" id="RouterConsumer.remove_route_on_cleanup">
<a class="viewcode-back" href="../../../modules/amqp.router.html#amqp.router.router_consumer.RouterConsumer.remove_route_on_cleanup">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">remove_route_on_cleanup</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">route</span><span class="p">:</span> <span class="n">AMQRoute</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> * Unregister / remove route from the list</span>
<span class="sd"> * :param route: route to remove</span>
<span class="sd"> * :return result of remove operation</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">logging_info</span><span class="p">(</span><span class="s2">&quot;RouterConsumer.removeRoute, route: </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">route</span><span class="o">.</span><span class="n">as_string</span><span class="p">())</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">service_message</span><span class="p">:</span> <span class="n">ServiceMessage</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">service_message_factory</span><span class="o">.</span><span class="n">of</span><span class="p">(</span>
<span class="n">ServiceMessageType</span><span class="o">.</span><span class="n">ROUTING_DATA_REMOVE</span><span class="p">,</span> <span class="n">route</span><span class="o">.</span><span class="n">as_string</span><span class="p">(),</span> <span class="n">ANY_RECIPIENT</span>
<span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">publish_service_message</span><span class="p">(</span><span class="n">service_message</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">cm_response_exchange</span><span class="p">):</span>
<span class="n">logging_warning</span><span class="p">(</span>
<span class="s2">&quot;RouterConsumer couldn&#39;t remove current_availability route: </span><span class="si">%s</span><span class="s2">, channel not open.&quot;</span><span class="p">,</span>
<span class="n">route</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">ioe</span><span class="p">:</span>
<span class="n">logging_error</span><span class="p">(</span><span class="s2">&quot;RouterConsumer failed remove current_availability route: </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">ioe</span><span class="p">)</span>
<span class="n">result</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">remove_route</span><span class="p">(</span><span class="n">route</span><span class="p">)</span>
<span class="k">return</span> <span class="n">result</span></div>
<div class="viewcode-block" id="RouterConsumer.cleanup">
<a class="viewcode-back" href="../../../modules/amqp.router.html#amqp.router.router_consumer.RouterConsumer.cleanup">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">cleanup</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> * Cleanup - de-register routes with master.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">routes</span><span class="p">:</span> <span class="n">Set</span><span class="p">[</span><span class="n">AMQRoute</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_routes</span><span class="p">()</span>
<span class="n">logging_info</span><span class="p">(</span><span class="s2">&quot;RouterConsumer.cleanup() [</span><span class="si">%d</span><span class="s2">]: </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">routes</span><span class="p">),</span> <span class="bp">self</span><span class="o">.</span><span class="n">wrap_routes</span><span class="p">())</span>
<span class="n">not_removed</span> <span class="o">=</span> <span class="nb">sum</span><span class="p">(</span>
<span class="mi">1</span> <span class="k">for</span> <span class="n">r</span> <span class="ow">in</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">remove_route_on_cleanup</span><span class="p">(</span><span class="n">route</span><span class="p">)</span> <span class="k">for</span> <span class="n">route</span> <span class="ow">in</span> <span class="n">routes</span><span class="p">)</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">r</span>
<span class="p">)</span>
<span class="k">if</span> <span class="n">not_removed</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
<span class="n">logging_warning</span><span class="p">(</span>
<span class="s2">&quot;</span><span class="si">%d</span><span class="s2"> route(s) not removed. self may lead to failed delivery on self route&quot;</span><span class="p">,</span>
<span class="n">not_removed</span><span class="p">,</span>
<span class="p">)</span></div>
</div>
</pre></div>
</div>
</div>
<footer>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2024, CleverThis.</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>
@@ -0,0 +1,362 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" data-content_root="../../../">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>amqp.router.router_producer &mdash; AMQ Adapter Python 1.0 documentation</title>
<link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=03e43079" />
<link rel="stylesheet" type="text/css" href="../../../_static/css/theme.css?v=e59714d7" />
<script src="../../../_static/jquery.js?v=5d32c60e"></script>
<script src="../../../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
<script src="../../../_static/documentation_options.js?v=f2a433a1"></script>
<script src="../../../_static/doctools.js?v=9bcbadda"></script>
<script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
<script src="../../../_static/js/theme.js"></script>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="../../../index.html" class="icon icon-home">
AMQ Adapter Python
</a>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" aria-label="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.html">AMQP Package</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.config.html">Configuration Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.adapter.html">Adapter Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.service.html">Service Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.router.html">Router Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.model.html">Model Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.rabbitmq.html">RabbitMQ Module</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="../../../index.html">AMQ Adapter Python</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="../../../index.html" class="icon icon-home" aria-label="Home"></a></li>
<li class="breadcrumb-item"><a href="../../index.html">Module code</a></li>
<li class="breadcrumb-item active">amqp.router.router_producer</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<h1>Source code for amqp.router.router_producer</h1><div class="highlight"><pre>
<span></span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">* Maps the request to RabbitMQ exchange. Handles the service discovery logic.</span>
<span class="sd">*</span>
<span class="sd">* Router can be either in &#39;Master&#39; or &#39;Service (Consumer)&#39; modes. &#39;Master&#39; mode is the outward</span>
<span class="sd">* facing side that receives the requests and routes it to queue associated with requested service.</span>
<span class="sd">* &#39;Service&#39; mode is consumer side for given service, which receives the message from AMQ and</span>
<span class="sd">* forwards it to the application.</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">aio_pika</span><span class="w"> </span><span class="kn">import</span> <span class="n">Message</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">aio_pika.abc</span><span class="w"> </span><span class="kn">import</span> <span class="p">(</span>
<span class="n">AbstractIncomingMessage</span><span class="p">,</span>
<span class="n">AbstractRobustChannel</span><span class="p">,</span>
<span class="n">AbstractRobustConnection</span><span class="p">,</span>
<span class="n">AbstractRobustExchange</span><span class="p">,</span>
<span class="n">AbstractRobustQueue</span><span class="p">,</span>
<span class="p">)</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">pika.exchange_type</span><span class="w"> </span><span class="kn">import</span> <span class="n">ExchangeType</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.adapter.logging_utils</span><span class="w"> </span><span class="kn">import</span> <span class="p">(</span>
<span class="n">logging_debug</span><span class="p">,</span>
<span class="n">logging_error</span><span class="p">,</span>
<span class="n">logging_info</span><span class="p">,</span>
<span class="n">logging_warning</span><span class="p">,</span>
<span class="p">)</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.adapter.service_message_factory</span><span class="w"> </span><span class="kn">import</span> <span class="n">ServiceMessageFactory</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.config.amq_configuration</span><span class="w"> </span><span class="kn">import</span> <span class="n">AMQConfiguration</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.model.model</span><span class="w"> </span><span class="kn">import</span> <span class="n">ServiceMessage</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.model.service_message_type</span><span class="w"> </span><span class="kn">import</span> <span class="n">ServiceMessageType</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.router.router_base</span><span class="w"> </span><span class="kn">import</span> <span class="p">(</span>
<span class="n">ANY_RECIPIENT</span><span class="p">,</span>
<span class="n">CM_C_AMQ_QUEUE</span><span class="p">,</span>
<span class="n">CM_P_REPLY_TO</span><span class="p">,</span>
<span class="n">CM_P_RESP_QUEUE</span><span class="p">,</span>
<span class="n">CM_REQUEST_EXCHANGE</span><span class="p">,</span>
<span class="n">CM_RESPONSE_EXCHANGE</span><span class="p">,</span>
<span class="n">RouterBase</span><span class="p">,</span>
<span class="p">)</span>
<div class="viewcode-block" id="RouterProducer">
<a class="viewcode-back" href="../../../modules/amqp.router.html#amqp.router.router_producer.RouterProducer">[docs]</a>
<span class="k">class</span><span class="w"> </span><span class="nc">RouterProducer</span><span class="p">(</span><span class="n">RouterBase</span><span class="p">):</span>
<div class="viewcode-block" id="RouterProducer.__init__">
<a class="viewcode-back" href="../../../modules/amqp.router.html#amqp.router.router_producer.RouterProducer.__init__">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">configuration</span><span class="p">:</span> <span class="n">AMQConfiguration</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> * Initialize router - need to supply the config values and RabbitMQ channel.</span>
<span class="sd"> * :param configuration: adapter&#39;s configuration reference.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">connection</span><span class="p">:</span> <span class="n">AbstractRobustConnection</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span>
<span class="bp">self</span><span class="o">.</span><span class="n">service_message_factory</span> <span class="o">=</span> <span class="n">ServiceMessageFactory</span><span class="p">(</span><span class="n">configuration</span><span class="o">.</span><span class="n">amq_adapter</span><span class="o">.</span><span class="n">service_name</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">amq_configuration</span><span class="p">:</span> <span class="n">AMQConfiguration</span> <span class="o">=</span> <span class="n">configuration</span>
<span class="bp">self</span><span class="o">.</span><span class="n">channel</span><span class="p">:</span> <span class="n">AbstractRobustChannel</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span>
<span class="bp">self</span><span class="o">.</span><span class="n">cm_request_exchange</span><span class="p">:</span> <span class="n">AbstractRobustExchange</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span>
<span class="bp">self</span><span class="o">.</span><span class="n">cm_response_exchange</span><span class="p">:</span> <span class="n">AbstractRobustExchange</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">logging_info</span><span class="p">(</span>
<span class="s2">&quot;RouterProducer.&lt;init&gt;: </span><span class="si">%s</span><span class="s2">, route: </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">amq_configuration</span><span class="o">.</span><span class="n">amq_adapter</span><span class="o">.</span><span class="n">service_name</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">amq_configuration</span><span class="o">.</span><span class="n">amq_adapter</span><span class="o">.</span><span class="n">route_mapping</span><span class="p">,</span>
<span class="p">)</span></div>
<div class="viewcode-block" id="RouterProducer.init_internal_routing_paths">
<a class="viewcode-back" href="../../../modules/amqp.router.html#amqp.router.router_producer.RouterProducer.init_internal_routing_paths">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">init_internal_routing_paths</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">channel</span><span class="p">:</span> <span class="n">AbstractRobustChannel</span> <span class="o">|</span> <span class="kc">None</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> * Initialize internal routes for ServiceMessages.</span>
<span class="sd"> * The logic here sets a producer and listener on CleverMicroRequest/CleverMicroResponse queues</span>
<span class="sd"> * created to enable the service discovery.</span>
<span class="sd"> * The Producer mode sends out routing data request on CleverMicroRequest and listens</span>
<span class="sd"> * on CleverMicroResponse for any service responding with its routing data.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">channel</span> <span class="o">=</span> <span class="n">channel</span>
<span class="n">logging_info</span><span class="p">(</span>
<span class="s2">&quot;RouterProducer.initRoutingPaths, channel open: </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">is_open</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">channel</span><span class="p">),</span>
<span class="p">)</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">is_open</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">channel</span><span class="p">):</span>
<span class="k">try</span><span class="p">:</span>
<span class="c1"># **** set up the service discovery internal exchanges ****</span>
<span class="c1"># 1. declare RequestExchange to where to publish the RoutingData requests</span>
<span class="bp">self</span><span class="o">.</span><span class="n">cm_request_exchange</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">channel</span><span class="o">.</span><span class="n">declare_exchange</span><span class="p">(</span>
<span class="n">name</span><span class="o">=</span><span class="n">CM_REQUEST_EXCHANGE</span><span class="p">,</span> <span class="nb">type</span><span class="o">=</span><span class="n">ExchangeType</span><span class="o">.</span><span class="n">fanout</span>
<span class="p">)</span>
<span class="c1">#</span>
<span class="c1"># 2. declare ResponseExchange where to publish current_availability RoutingData (response to</span>
<span class="c1"># a RoutingData request)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">cm_response_exchange</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">channel</span><span class="o">.</span><span class="n">declare_exchange</span><span class="p">(</span>
<span class="n">name</span><span class="o">=</span><span class="n">CM_RESPONSE_EXCHANGE</span><span class="p">,</span> <span class="nb">type</span><span class="o">=</span><span class="n">ExchangeType</span><span class="o">.</span><span class="n">fanout</span>
<span class="p">)</span>
<span class="c1"># 2a. declare a Response queue for Routing Data replies from Services</span>
<span class="n">_cm_response_queue</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_response_queue_name</span><span class="p">()</span>
<span class="n">_response_queue</span><span class="p">:</span> <span class="n">AbstractRobustQueue</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">channel</span><span class="o">.</span><span class="n">declare_queue</span><span class="p">(</span>
<span class="n">name</span><span class="o">=</span><span class="n">_cm_response_queue</span><span class="p">,</span>
<span class="n">durable</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
<span class="n">exclusive</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
<span class="n">auto_delete</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
<span class="n">arguments</span><span class="o">=</span><span class="p">{},</span>
<span class="p">)</span>
<span class="c1"># 2b. bind queue to CM_RESPONSE_EXCHANGE w/o any conditions (empty routing key)</span>
<span class="k">await</span> <span class="n">_response_queue</span><span class="o">.</span><span class="n">bind</span><span class="p">(</span><span class="n">exchange</span><span class="o">=</span><span class="n">CM_RESPONSE_EXCHANGE</span><span class="p">,</span> <span class="n">routing_key</span><span class="o">=</span><span class="s2">&quot;#&quot;</span><span class="p">)</span>
<span class="c1"># 2c. listen for incoming RoutingData messages</span>
<span class="n">_c_tag</span> <span class="o">=</span> <span class="k">await</span> <span class="n">_response_queue</span><span class="o">.</span><span class="n">consume</span><span class="p">(</span>
<span class="n">callback</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">handle_routing_data_message</span><span class="p">,</span> <span class="n">no_ack</span><span class="o">=</span><span class="kc">False</span>
<span class="p">)</span>
<span class="n">logging_info</span><span class="p">(</span>
<span class="s2">&quot; [</span><span class="si">%s</span><span class="s2">] Routing master listens for Route updates on </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span>
<span class="n">_c_tag</span><span class="p">,</span>
<span class="n">_cm_response_queue</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">ioe</span><span class="p">:</span>
<span class="n">logging_error</span><span class="p">(</span><span class="s2">&quot;RouterProducer FATAL: cannot initialize, </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">ioe</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">logging_error</span><span class="p">(</span><span class="s2">&quot;RouterProducer FATAL: cannot initialize, RabbitMQ channel is not open.&quot;</span><span class="p">)</span></div>
<div class="viewcode-block" id="RouterProducer.handle_routing_data_message">
<a class="viewcode-back" href="../../../modules/amqp.router.html#amqp.router.router_producer.RouterProducer.handle_routing_data_message">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">handle_routing_data_message</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">AbstractIncomingMessage</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> * Handler for CLEVER_MICRO_RESPONSE queue messages. Used in Master mode to handle receipt of</span>
<span class="sd"> * routing data, invokes addRoute or removeRoute depending on the type of the message.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">logging_info</span><span class="p">(</span>
<span class="s2">&quot;[</span><span class="si">%s</span><span class="s2">] Received ROUTING DATA: [</span><span class="si">%s</span><span class="s2">], msgId=</span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span>
<span class="n">message</span><span class="o">.</span><span class="n">delivery_tag</span><span class="p">,</span>
<span class="n">message</span><span class="o">.</span><span class="n">body</span><span class="p">,</span>
<span class="n">message</span><span class="o">.</span><span class="n">message_id</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">await</span> <span class="n">message</span><span class="o">.</span><span class="n">ack</span><span class="p">(</span><span class="n">multiple</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">cm_message</span><span class="p">:</span> <span class="n">ServiceMessage</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">service_message_factory</span><span class="o">.</span><span class="n">from_bytes</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">body</span><span class="p">)</span>
<span class="c1"># ignore the message if it comes from ourselves (even if from different instance)</span>
<span class="n">logging_debug</span><span class="p">(</span>
<span class="s2">&quot;******[</span><span class="si">%s</span><span class="s2">] ROUTING_DATA, msg=</span><span class="si">%s</span><span class="s2">, routeMap=[</span><span class="si">%s</span><span class="s2">] sn=</span><span class="si">%s</span><span class="s2">, replyTo=</span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span>
<span class="n">message</span><span class="o">.</span><span class="n">delivery_tag</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">service_message_factory</span><span class="o">.</span><span class="n">to_string</span><span class="p">(</span><span class="n">cm_message</span><span class="p">),</span>
<span class="bp">self</span><span class="o">.</span><span class="n">amq_configuration</span><span class="o">.</span><span class="n">amq_adapter</span><span class="o">.</span><span class="n">route_mapping</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">amq_configuration</span><span class="o">.</span><span class="n">amq_adapter</span><span class="o">.</span><span class="n">service_name</span><span class="p">,</span>
<span class="n">cm_message</span><span class="o">.</span><span class="n">reply_to</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">if</span> <span class="p">(</span>
<span class="n">cm_message</span><span class="o">.</span><span class="n">is_valid</span><span class="p">()</span>
<span class="ow">and</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">amq_configuration</span><span class="o">.</span><span class="n">amq_adapter</span><span class="o">.</span><span class="n">service_name</span> <span class="o">==</span> <span class="n">cm_message</span><span class="o">.</span><span class="n">reply_to</span>
<span class="p">):</span>
<span class="k">if</span> <span class="n">cm_message</span><span class="o">.</span><span class="n">message_type</span> <span class="o">==</span> <span class="n">ServiceMessageType</span><span class="o">.</span><span class="n">ROUTING_DATA</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add_routes</span><span class="p">(</span><span class="n">cm_message</span><span class="o">.</span><span class="n">message</span><span class="p">)</span>
<span class="k">if</span> <span class="n">cm_message</span><span class="o">.</span><span class="n">message_type</span> <span class="o">==</span> <span class="n">ServiceMessageType</span><span class="o">.</span><span class="n">ROUTING_DATA_REMOVE</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">remove_routes</span><span class="p">(</span><span class="n">cm_message</span><span class="o">.</span><span class="n">message</span><span class="p">)</span></div>
<div class="viewcode-block" id="RouterProducer.request_routes_from_adapters">
<a class="viewcode-back" href="../../../modules/amqp.router.html#amqp.router.router_producer.RouterProducer.request_routes_from_adapters">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">request_routes_from_adapters</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> * Send a broadcast message prompting all listening adapters to reply with own routing data.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">logging_info</span><span class="p">(</span>
<span class="s2">&quot;RouterProducer.requestRoutesFromAdapters, queue name: </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span>
<span class="n">CM_REQUEST_EXCHANGE</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">serviceMessage</span><span class="p">:</span> <span class="n">ServiceMessage</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">service_message_factory</span><span class="o">.</span><span class="n">of</span><span class="p">(</span>
<span class="n">ServiceMessageType</span><span class="o">.</span><span class="n">ROUTING_DATA_REQUEST</span><span class="p">,</span> <span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="n">ANY_RECIPIENT</span>
<span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">publish_service_message</span><span class="p">(</span><span class="n">serviceMessage</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">cm_request_exchange</span><span class="p">):</span>
<span class="n">logging_warning</span><span class="p">(</span>
<span class="s2">&quot;RouterProducer could not request route data: </span><span class="si">%s</span><span class="s2"> channel is not open.&quot;</span><span class="p">,</span>
<span class="n">CM_REQUEST_EXCHANGE</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">ioe</span><span class="p">:</span>
<span class="n">logging_error</span><span class="p">(</span><span class="s2">&quot;RouterProducer failed request routing data: </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">ioe</span><span class="p">)</span></div>
<div class="viewcode-block" id="RouterProducer.publish_service_message">
<a class="viewcode-back" href="../../../modules/amqp.router.html#amqp.router.router_producer.RouterProducer.publish_service_message">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">publish_service_message</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">ServiceMessage</span><span class="p">,</span> <span class="n">exchange</span><span class="p">:</span> <span class="n">AbstractRobustExchange</span>
<span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> * Publishes a service message to the service queue and logs success log entry.</span>
<span class="sd"> *</span>
<span class="sd"> * :param message: Service Message to be sent</span>
<span class="sd"> * :param exchange: target exchange name where to publish the message</span>
<span class="sd"> * :return True if channel is open, False otherwise</span>
<span class="sd"> * @throws IOException if something else goes wrong</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">is_open</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">channel</span><span class="p">):</span>
<span class="n">binary_content</span><span class="p">:</span> <span class="nb">bytes</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">service_message_factory</span><span class="o">.</span><span class="n">serialize</span><span class="p">(</span><span class="n">message</span><span class="p">)</span>
<span class="n">pika_message</span><span class="p">:</span> <span class="n">Message</span> <span class="o">=</span> <span class="n">Message</span><span class="p">(</span>
<span class="n">body</span><span class="o">=</span><span class="n">binary_content</span><span class="p">,</span>
<span class="n">content_encoding</span><span class="o">=</span><span class="s2">&quot;utf-8&quot;</span><span class="p">,</span>
<span class="n">delivery_mode</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span>
<span class="n">content_type</span><span class="o">=</span><span class="s2">&quot;application/octet-stream&quot;</span><span class="p">,</span>
<span class="n">headers</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
<span class="n">priority</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span>
<span class="n">correlation_id</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">await</span> <span class="n">exchange</span><span class="o">.</span><span class="n">publish</span><span class="p">(</span><span class="n">message</span><span class="o">=</span><span class="n">pika_message</span><span class="p">,</span> <span class="n">routing_key</span><span class="o">=</span><span class="s2">&quot;&quot;</span><span class="p">)</span>
<span class="n">logging_info</span><span class="p">(</span>
<span class="s2">&quot;Service Message Published to </span><span class="si">%s</span><span class="s2">, msg: </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span>
<span class="n">exchange</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
<span class="nb">str</span><span class="p">(</span><span class="n">binary_content</span><span class="p">),</span>
<span class="p">)</span>
<span class="k">return</span> <span class="kc">True</span>
<span class="k">return</span> <span class="kc">False</span></div>
<div class="viewcode-block" id="RouterProducer.get_reply_to_queue_name">
<a class="viewcode-back" href="../../../modules/amqp.router.html#amqp.router.router_producer.RouterProducer.get_reply_to_queue_name">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">get_reply_to_queue_name</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> * self should create a unique name for self process and also when there&#39;s several instances.</span>
<span class="sd"> * @return unique reply-to queue name.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">amq_configuration</span><span class="o">.</span><span class="n">amq_adapter</span><span class="o">.</span><span class="n">adapter_prefix</span><span class="p">()</span> <span class="o">+</span> <span class="n">CM_P_REPLY_TO</span></div>
<div class="viewcode-block" id="RouterProducer.get_response_queue_name">
<a class="viewcode-back" href="../../../modules/amqp.router.html#amqp.router.router_producer.RouterProducer.get_response_queue_name">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">get_response_queue_name</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> * self should create a unique name for self process and also when there&#39;s several instances.</span>
<span class="sd"> * @return unique reply-to queue name.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">amq_configuration</span><span class="o">.</span><span class="n">amq_adapter</span><span class="o">.</span><span class="n">adapter_prefix</span><span class="p">()</span> <span class="o">+</span> <span class="n">CM_P_RESP_QUEUE</span></div>
<div class="viewcode-block" id="RouterProducer.get_consume_queue_name">
<a class="viewcode-back" href="../../../modules/amqp.router.html#amqp.router.router_producer.RouterProducer.get_consume_queue_name">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">get_consume_queue_name</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> * self should create a unique name for self process and also when there&#39;s several instances.</span>
<span class="sd"> * @return unique reply-to queue name.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">amq_configuration</span><span class="o">.</span><span class="n">amq_adapter</span><span class="o">.</span><span class="n">adapter_prefix</span><span class="p">()</span> <span class="o">+</span> <span class="n">CM_C_AMQ_QUEUE</span></div>
<div class="viewcode-block" id="RouterProducer.is_open">
<a class="viewcode-back" href="../../../modules/amqp.router.html#amqp.router.router_producer.RouterProducer.is_open">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">is_open</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">_channel</span><span class="p">:</span> <span class="n">AbstractRobustChannel</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> * Test if the channel is usable (opened).</span>
<span class="sd"> * :param _channel: the channel</span>
<span class="sd"> * :return True if the channel is opened.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="n">_channel</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">_channel</span><span class="o">.</span><span class="n">is_closed</span></div>
</div>
</pre></div>
</div>
</div>
<footer>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2024, CleverThis.</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>
@@ -0,0 +1,156 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" data-content_root="../../../">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>amqp.router.utils &mdash; AMQ Adapter Python 1.0 documentation</title>
<link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=03e43079" />
<link rel="stylesheet" type="text/css" href="../../../_static/css/theme.css?v=e59714d7" />
<script src="../../../_static/jquery.js?v=5d32c60e"></script>
<script src="../../../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
<script src="../../../_static/documentation_options.js?v=f2a433a1"></script>
<script src="../../../_static/doctools.js?v=9bcbadda"></script>
<script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
<script src="../../../_static/js/theme.js"></script>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="../../../index.html" class="icon icon-home">
AMQ Adapter Python
</a>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" aria-label="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.html">AMQP Package</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.config.html">Configuration Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.adapter.html">Adapter Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.service.html">Service Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.router.html">Router Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.model.html">Model Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.rabbitmq.html">RabbitMQ Module</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="../../../index.html">AMQ Adapter Python</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="../../../index.html" class="icon icon-home" aria-label="Home"></a></li>
<li class="breadcrumb-item"><a href="../../index.html">Module code</a></li>
<li class="breadcrumb-item active">amqp.router.utils</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<h1>Source code for amqp.router.utils</h1><div class="highlight"><pre>
<span></span><span class="kn">import</span><span class="w"> </span><span class="nn">asyncio</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">re</span>
<span class="n">pattern</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="sa">r</span><span class="s2">&quot;[^a-zA-Z0-9.#/\-]&quot;</span><span class="p">)</span>
<span class="n">AWAIT_SLEEP</span> <span class="o">=</span> <span class="mf">0.05</span> <span class="c1"># seconds</span>
<div class="viewcode-block" id="sanitize_as_rabbitmq_name">
<a class="viewcode-back" href="../../../modules/amqp.router.html#amqp.router.utils.sanitize_as_rabbitmq_name">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">sanitize_as_rabbitmq_name</span><span class="p">(</span><span class="n">input_str</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="n">matcher</span> <span class="o">=</span> <span class="n">pattern</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="n">input_str</span><span class="p">)</span>
<span class="n">token</span> <span class="o">=</span> <span class="n">input_str</span><span class="p">[:</span> <span class="n">matcher</span><span class="o">.</span><span class="n">start</span><span class="p">()]</span> <span class="k">if</span> <span class="n">matcher</span> <span class="k">else</span> <span class="n">input_str</span>
<span class="k">return</span> <span class="n">sanitize_as_rabbitmq_domain_name</span><span class="p">(</span><span class="n">token</span><span class="p">)</span></div>
<div class="viewcode-block" id="sanitize_as_rabbitmq_domain_name">
<a class="viewcode-back" href="../../../modules/amqp.router.html#amqp.router.utils.sanitize_as_rabbitmq_domain_name">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">sanitize_as_rabbitmq_domain_name</span><span class="p">(</span><span class="n">token</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="c1"># Step 1: Replace non-alphanumeric characters (except periods) with a period</span>
<span class="n">step1</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">sub</span><span class="p">(</span><span class="sa">r</span><span class="s2">&quot;[^A-Za-z0-9.#]&quot;</span><span class="p">,</span> <span class="s2">&quot;.&quot;</span><span class="p">,</span> <span class="n">token</span><span class="p">)</span>
<span class="c1"># Step 2: Replace multiple consecutive periods with a single period</span>
<span class="n">step2</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">sub</span><span class="p">(</span><span class="sa">r</span><span class="s2">&quot;\.+&quot;</span><span class="p">,</span> <span class="s2">&quot;.&quot;</span><span class="p">,</span> <span class="n">step1</span><span class="p">)</span>
<span class="c1"># Step 3: Remove trailing &#39;.&#39; character, if applicable</span>
<span class="n">step_last_char</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">step2</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span>
<span class="k">return</span> <span class="n">step2</span><span class="p">[:</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="k">if</span> <span class="n">step_last_char</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="ow">and</span> <span class="n">step2</span><span class="p">[</span><span class="n">step_last_char</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;.&quot;</span> <span class="k">else</span> <span class="n">step2</span></div>
<div class="viewcode-block" id="await_future">
<a class="viewcode-back" href="../../../modules/amqp.router.html#amqp.router.utils.await_future">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">await_future</span><span class="p">(</span><span class="n">future</span><span class="p">:</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">Future</span><span class="p">,</span> <span class="n">sleep_time</span><span class="o">=</span><span class="n">AWAIT_SLEEP</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Wait for a future to complete.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">while</span> <span class="ow">not</span> <span class="n">future</span><span class="o">.</span><span class="n">done</span><span class="p">():</span>
<span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="n">sleep_time</span><span class="p">)</span></div>
<div class="viewcode-block" id="await_result">
<a class="viewcode-back" href="../../../modules/amqp.router.html#amqp.router.utils.await_result">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">await_result</span><span class="p">(</span><span class="n">future</span><span class="p">:</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">Future</span><span class="p">,</span> <span class="n">sleep_time</span><span class="o">=</span><span class="n">AWAIT_SLEEP</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Wait for a future to complete and return its result.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">await</span> <span class="n">await_future</span><span class="p">(</span><span class="n">future</span><span class="p">,</span> <span class="n">sleep_time</span><span class="o">=</span><span class="n">sleep_time</span><span class="p">)</span>
<span class="k">return</span> <span class="n">future</span><span class="o">.</span><span class="n">result</span><span class="p">()</span></div>
</pre></div>
</div>
</div>
<footer>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2024, CleverThis.</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>
@@ -0,0 +1,692 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" data-content_root="../../../">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>amqp.service.amq_message_handler &mdash; AMQ Adapter Python 1.0 documentation</title>
<link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=03e43079" />
<link rel="stylesheet" type="text/css" href="../../../_static/css/theme.css?v=e59714d7" />
<script src="../../../_static/jquery.js?v=5d32c60e"></script>
<script src="../../../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
<script src="../../../_static/documentation_options.js?v=f2a433a1"></script>
<script src="../../../_static/doctools.js?v=9bcbadda"></script>
<script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
<script src="../../../_static/js/theme.js"></script>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="../../../index.html" class="icon icon-home">
AMQ Adapter Python
</a>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" aria-label="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.html">AMQP Package</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.config.html">Configuration Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.adapter.html">Adapter Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.service.html">Service Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.router.html">Router Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.model.html">Model Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.rabbitmq.html">RabbitMQ Module</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="../../../index.html">AMQ Adapter Python</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="../../../index.html" class="icon icon-home" aria-label="Home"></a></li>
<li class="breadcrumb-item"><a href="../../index.html">Module code</a></li>
<li class="breadcrumb-item active">amqp.service.amq_message_handler</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<h1>Source code for amqp.service.amq_message_handler</h1><div class="highlight"><pre>
<span></span><span class="kn">import</span><span class="w"> </span><span class="nn">asyncio</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">importlib</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">inspect</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">os</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">threading</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">time</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">asyncio</span><span class="w"> </span><span class="kn">import</span> <span class="n">AbstractEventLoop</span><span class="p">,</span> <span class="n">Future</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Any</span><span class="p">,</span> <span class="n">Dict</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">aio_pika</span><span class="w"> </span><span class="kn">import</span> <span class="n">Message</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">aio_pika.abc</span><span class="w"> </span><span class="kn">import</span> <span class="n">AbstractIncomingMessage</span><span class="p">,</span> <span class="n">AbstractRobustExchange</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">opentelemetry</span><span class="w"> </span><span class="kn">import</span> <span class="n">trace</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">opentelemetry.trace</span><span class="w"> </span><span class="kn">import</span> <span class="n">Tracer</span><span class="p">,</span> <span class="n">TraceState</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">opentelemetry.trace.propagation.tracecontext</span><span class="w"> </span><span class="kn">import</span> <span class="n">TraceContextTextMapPropagator</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">pika.exchange_type</span><span class="w"> </span><span class="kn">import</span> <span class="n">ExchangeType</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.adapter.backpressure_handler</span><span class="w"> </span><span class="kn">import</span> <span class="n">BackpressureHandler</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.adapter.cleverthis_service_adapter</span><span class="w"> </span><span class="kn">import</span> <span class="n">AMQMessage</span><span class="p">,</span> <span class="n">CleverThisServiceAdapter</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.adapter.data_message_factory</span><span class="w"> </span><span class="kn">import</span> <span class="n">DataMessageFactory</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.adapter.data_response_factory</span><span class="w"> </span><span class="kn">import</span> <span class="n">DataResponseFactory</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.adapter.file_handler</span><span class="w"> </span><span class="kn">import</span> <span class="n">FileHandler</span><span class="p">,</span> <span class="n">StreamingFileHandler</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.adapter.logging_utils</span><span class="w"> </span><span class="kn">import</span> <span class="n">logging_debug</span><span class="p">,</span> <span class="n">logging_error</span><span class="p">,</span> <span class="n">logging_info</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.adapter.serializer</span><span class="w"> </span><span class="kn">import</span> <span class="n">map_as_string</span><span class="p">,</span> <span class="n">parse_map_string</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.adapter.service_message_factory</span><span class="w"> </span><span class="kn">import</span> <span class="n">ServiceMessageFactory</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.config.amq_configuration</span><span class="w"> </span><span class="kn">import</span> <span class="n">AMQConfiguration</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.model.model</span><span class="w"> </span><span class="kn">import</span> <span class="p">(</span>
<span class="n">DataMessage</span><span class="p">,</span>
<span class="n">DataMessageMagicByte</span><span class="p">,</span>
<span class="n">DataResponse</span><span class="p">,</span>
<span class="n">MultipartDataMessage</span><span class="p">,</span>
<span class="p">)</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.rabbitmq.rabbit_mq_client</span><span class="w"> </span><span class="kn">import</span> <span class="n">RabbitMQClient</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.router.utils</span><span class="w"> </span><span class="kn">import</span> <span class="n">sanitize_as_rabbitmq_name</span>
<div class="viewcode-block" id="collect_trace_info">
<a class="viewcode-back" href="../../../modules/amqp.service.html#amqp.service.amq_message_handler.collect_trace_info">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">collect_trace_info</span><span class="p">():</span>
<span class="n">trace_map</span> <span class="o">=</span> <span class="p">{}</span>
<span class="n">TraceContextTextMapPropagator</span><span class="p">()</span><span class="o">.</span><span class="n">inject</span><span class="p">(</span>
<span class="n">carrier</span><span class="o">=</span><span class="n">trace_map</span><span class="p">,</span> <span class="n">context</span><span class="o">=</span><span class="n">trace</span><span class="o">.</span><span class="n">context_api</span><span class="o">.</span><span class="n">get_current</span><span class="p">()</span>
<span class="p">)</span>
<span class="k">return</span> <span class="n">trace_map</span></div>
<div class="viewcode-block" id="get_default_trace_state">
<a class="viewcode-back" href="../../../modules/amqp.service.html#amqp.service.amq_message_handler.get_default_trace_state">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">get_default_trace_state</span><span class="p">():</span>
<span class="k">return</span> <span class="n">TraceState</span><span class="p">(</span><span class="n">entries</span><span class="o">=</span><span class="p">{})</span></div>
<div class="viewcode-block" id="set_text">
<a class="viewcode-back" href="../../../modules/amqp.service.html#amqp.service.amq_message_handler.set_text">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">set_text</span><span class="p">(</span><span class="n">carrier</span><span class="p">,</span> <span class="n">key</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
<span class="n">carrier</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span></div>
<div class="viewcode-block" id="invoke_command">
<a class="viewcode-back" href="../../../modules/amqp.service.html#amqp.service.amq_message_handler.invoke_command">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">invoke_command</span><span class="p">(</span>
<span class="n">package_name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">class_name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">function_name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">msg_id</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="n">kwargs</span><span class="o">=</span><span class="kc">None</span>
<span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Any</span><span class="p">:</span>
<span class="k">if</span> <span class="n">kwargs</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">kwargs</span> <span class="o">=</span> <span class="p">{}</span>
<span class="k">try</span><span class="p">:</span>
<span class="c1"># 1. Dynamically import the package</span>
<span class="n">logging_info</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Attempting to import package: </span><span class="si">{</span><span class="n">package_name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="n">package</span> <span class="o">=</span> <span class="n">importlib</span><span class="o">.</span><span class="n">import_module</span><span class="p">(</span><span class="n">package_name</span><span class="p">)</span>
<span class="n">logging_info</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Package &#39;</span><span class="si">{</span><span class="n">package_name</span><span class="si">}</span><span class="s2">&#39; imported successfully.&quot;</span><span class="p">)</span>
<span class="n">target_callable</span> <span class="o">=</span> <span class="kc">None</span>
<span class="k">if</span> <span class="n">class_name</span> <span class="o">==</span> <span class="s2">&quot;__global__&quot;</span><span class="p">:</span>
<span class="c1"># 2. Handle global function invocation</span>
<span class="n">logging_info</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Attempting to find global function: </span><span class="si">{</span><span class="n">function_name</span><span class="si">}</span><span class="s2"> in </span><span class="si">{</span><span class="n">package_name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="n">target_callable</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">package</span><span class="p">,</span> <span class="n">function_name</span><span class="p">)</span>
<span class="n">logging_info</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Global function &#39;</span><span class="si">{</span><span class="n">function_name</span><span class="si">}</span><span class="s2">&#39; found.&quot;</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># 3. Handle class method invocation</span>
<span class="n">logging_info</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Attempting to find class: </span><span class="si">{</span><span class="n">class_name</span><span class="si">}</span><span class="s2"> in </span><span class="si">{</span><span class="n">package_name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="n">target_class</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">package</span><span class="p">,</span> <span class="n">class_name</span><span class="p">)</span>
<span class="n">logging_info</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Class &#39;</span><span class="si">{</span><span class="n">class_name</span><span class="si">}</span><span class="s2">&#39; found. Instantiating...&quot;</span><span class="p">)</span>
<span class="c1"># Instantiate the class. Assuming a default constructor or one that doesn&#39;t</span>
<span class="c1"># require arguments from kwargs for initialization.</span>
<span class="c1"># If the class __init__ needs specific arguments, this part might need adjustment</span>
<span class="c1"># based on how those arguments are provided.</span>
<span class="n">instance</span> <span class="o">=</span> <span class="n">target_class</span><span class="p">()</span>
<span class="n">logging_info</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Instance of &#39;</span><span class="si">{</span><span class="n">class_name</span><span class="si">}</span><span class="s2">&#39; created.&quot;</span><span class="p">)</span>
<span class="n">logging_info</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Attempting to find method: </span><span class="si">{</span><span class="n">function_name</span><span class="si">}</span><span class="s2"> in class </span><span class="si">{</span><span class="n">class_name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="n">target_callable</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">instance</span><span class="p">,</span> <span class="n">function_name</span><span class="p">)</span>
<span class="n">logging_info</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Method &#39;</span><span class="si">{</span><span class="n">function_name</span><span class="si">}</span><span class="s2">&#39; found.&quot;</span><span class="p">)</span>
<span class="c1"># 4. Invoke the function/method</span>
<span class="n">logging_info</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Invoking &#39;</span><span class="si">{</span><span class="n">function_name</span><span class="si">}</span><span class="s2">&#39; with arguments: </span><span class="si">{</span><span class="n">kwargs</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="n">inspect</span><span class="o">.</span><span class="n">iscoroutinefunction</span><span class="p">(</span><span class="n">target_callable</span><span class="p">):</span>
<span class="n">result</span> <span class="o">=</span> <span class="k">await</span> <span class="n">target_callable</span><span class="p">(</span><span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
<span class="n">logging_info</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Asynchronous function &#39;</span><span class="si">{</span><span class="n">function_name</span><span class="si">}</span><span class="s2">&#39; invoked. Result: </span><span class="si">{</span><span class="n">result</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">result</span> <span class="o">=</span> <span class="n">target_callable</span><span class="p">(</span><span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
<span class="n">logging_info</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Synchronous function &#39;</span><span class="si">{</span><span class="n">function_name</span><span class="si">}</span><span class="s2">&#39; invoked. Result: </span><span class="si">{</span><span class="n">result</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="n">response</span><span class="p">:</span> <span class="n">DataResponse</span> <span class="o">=</span> <span class="n">DataResponseFactory</span><span class="o">.</span><span class="n">of</span><span class="p">(</span>
<span class="nb">id</span><span class="o">=</span><span class="n">msg_id</span><span class="p">,</span>
<span class="n">response_code</span><span class="o">=</span><span class="mi">200</span><span class="p">,</span>
<span class="n">content_type</span><span class="o">=</span><span class="s2">&quot;text/plain&quot;</span><span class="p">,</span>
<span class="n">body</span><span class="o">=</span><span class="n">result</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s2">&quot;utf-8&quot;</span><span class="p">),</span>
<span class="n">trace_info</span><span class="o">=</span><span class="n">collect_trace_info</span><span class="p">(),</span>
<span class="n">error</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
<span class="n">error_cause</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
<span class="p">)</span>
<span class="n">response</span><span class="o">.</span><span class="n">_magic</span> <span class="o">=</span> <span class="n">DataMessageMagicByte</span><span class="o">.</span><span class="n">RPC_REQUEST</span><span class="o">.</span><span class="n">value</span>
<span class="k">return</span> <span class="n">response</span>
<span class="k">except</span> <span class="ne">ModuleNotFoundError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="n">logging_error</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Error: Package &#39;</span><span class="si">{</span><span class="n">package_name</span><span class="si">}</span><span class="s2">&#39; not found. </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">raise</span>
<span class="k">except</span> <span class="ne">AttributeError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="n">logging_error</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;Error: Class &#39;</span><span class="si">{</span><span class="n">class_name</span><span class="si">}</span><span class="s2">&#39; or function/method &#39;</span><span class="si">{</span><span class="n">function_name</span><span class="si">}</span><span class="s2">&#39; not found in &#39;</span><span class="si">{</span><span class="n">package_name</span><span class="si">}</span><span class="s2">&#39;. </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="p">)</span>
<span class="k">raise</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="n">logging_error</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;An unexpected error occurred during invocation: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">raise</span></div>
<div class="viewcode-block" id="DataMessageHandler">
<a class="viewcode-back" href="../../../modules/amqp.service.html#amqp.service.amq_message_handler.DataMessageHandler">[docs]</a>
<span class="k">class</span><span class="w"> </span><span class="nc">DataMessageHandler</span><span class="p">:</span>
<div class="viewcode-block" id="DataMessageHandler.__init__">
<a class="viewcode-back" href="../../../modules/amqp.service.html#amqp.service.amq_message_handler.DataMessageHandler.__init__">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span>
<span class="n">service_adapter</span><span class="p">:</span> <span class="n">CleverThisServiceAdapter</span><span class="p">,</span>
<span class="n">tracer</span><span class="p">:</span> <span class="n">Tracer</span><span class="p">,</span>
<span class="n">message_factory</span><span class="p">:</span> <span class="n">DataMessageFactory</span><span class="p">,</span>
<span class="n">service_message_factory</span><span class="p">:</span> <span class="n">ServiceMessageFactory</span><span class="p">,</span>
<span class="n">reply_to_exchange</span><span class="p">:</span> <span class="n">AbstractRobustExchange</span><span class="p">,</span>
<span class="n">rabbit_mq_client</span><span class="p">:</span> <span class="n">RabbitMQClient</span><span class="p">,</span>
<span class="n">amq_configuration</span><span class="p">:</span> <span class="n">AMQConfiguration</span><span class="p">,</span>
<span class="n">loop</span><span class="p">,</span>
<span class="n">backpressure_handler</span><span class="p">:</span> <span class="n">BackpressureHandler</span><span class="p">,</span>
<span class="n">file_handler</span><span class="p">:</span> <span class="n">FileHandler</span> <span class="o">=</span> <span class="n">StreamingFileHandler</span><span class="p">(),</span>
<span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">service_adapter</span><span class="p">:</span> <span class="n">CleverThisServiceAdapter</span> <span class="o">=</span> <span class="n">service_adapter</span>
<span class="bp">self</span><span class="o">.</span><span class="n">tracer</span> <span class="o">=</span> <span class="n">tracer</span>
<span class="bp">self</span><span class="o">.</span><span class="n">message_factory</span><span class="p">:</span> <span class="n">DataMessageFactory</span> <span class="o">=</span> <span class="n">message_factory</span>
<span class="bp">self</span><span class="o">.</span><span class="n">service_message_factory</span><span class="p">:</span> <span class="n">ServiceMessageFactory</span> <span class="o">=</span> <span class="n">service_message_factory</span>
<span class="bp">self</span><span class="o">.</span><span class="n">reply_to_exchange</span><span class="p">:</span> <span class="n">AbstractRobustExchange</span> <span class="o">=</span> <span class="n">reply_to_exchange</span>
<span class="bp">self</span><span class="o">.</span><span class="n">rabbit_mq_client</span><span class="p">:</span> <span class="n">RabbitMQClient</span> <span class="o">=</span> <span class="n">rabbit_mq_client</span>
<span class="bp">self</span><span class="o">.</span><span class="n">rabbit_mq_url</span> <span class="o">=</span> <span class="n">amq_configuration</span><span class="o">.</span><span class="n">dispatch</span><span class="o">.</span><span class="n">rabbit_mq_url</span>
<span class="bp">self</span><span class="o">.</span><span class="n">output_dir</span> <span class="o">=</span> <span class="n">amq_configuration</span><span class="o">.</span><span class="n">dispatch</span><span class="o">.</span><span class="n">download_dir</span>
<span class="bp">self</span><span class="o">.</span><span class="n">loop</span> <span class="o">=</span> <span class="n">loop</span>
<span class="bp">self</span><span class="o">.</span><span class="n">service_adapter</span><span class="o">.</span><span class="n">loop</span> <span class="o">=</span> <span class="n">loop</span>
<span class="c1"># Dictionary to store outstanding Futures</span>
<span class="bp">self</span><span class="o">.</span><span class="n">outstanding</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">Future</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
<span class="bp">self</span><span class="o">.</span><span class="n">reply_to</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span>
<span class="bp">self</span><span class="o">.</span><span class="n">file_handler</span><span class="p">:</span> <span class="n">FileHandler</span> <span class="o">=</span> <span class="n">file_handler</span>
<span class="bp">self</span><span class="o">.</span><span class="n">backpressure_handler</span><span class="p">:</span> <span class="n">BackpressureHandler</span> <span class="o">=</span> <span class="n">backpressure_handler</span></div>
<div class="viewcode-block" id="DataMessageHandler.inbound_data_message_callback_as_thread">
<a class="viewcode-back" href="../../../modules/amqp.service.html#amqp.service.amq_message_handler.DataMessageHandler.inbound_data_message_callback_as_thread">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">inbound_data_message_callback_as_thread</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">AbstractIncomingMessage</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> The callback method that is called when a DataMessage is received from RabbitMQ, starts new Thread.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">threading</span><span class="o">.</span><span class="n">Thread</span><span class="p">(</span>
<span class="n">target</span><span class="o">=</span><span class="k">lambda</span><span class="p">:</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">inbound_data_message_callback_no_thread</span><span class="p">(</span><span class="n">message</span><span class="p">))</span>
<span class="p">)</span><span class="o">.</span><span class="n">start</span><span class="p">()</span></div>
<div class="viewcode-block" id="DataMessageHandler.inbound_data_message_callback_no_thread">
<a class="viewcode-back" href="../../../modules/amqp.service.html#amqp.service.amq_message_handler.DataMessageHandler.inbound_data_message_callback_no_thread">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">inbound_data_message_callback_no_thread</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">AbstractIncomingMessage</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Receives the DataMessage as bytes from RabbitMQ queue and deserializes it to the DataMessage object</span>
<span class="sd"> Ensures Jaeger trace-id propagation.</span>
<span class="sd"> Invokes custom handler/mapper/adapter method that corresponds to this message</span>
<span class="sd"> :param message:</span>
<span class="sd"> :return:</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">start</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span>
<span class="n">amq_message</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">reconstitute_data_message</span><span class="p">(</span><span class="n">message</span><span class="p">)</span>
<span class="k">if</span> <span class="n">amq_message</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">ensure_trace_info</span><span class="p">(</span><span class="n">amq_message</span><span class="p">)</span>
<span class="k">if</span> <span class="n">amq_message</span><span class="o">.</span><span class="n">magic</span><span class="p">()</span> <span class="o">==</span> <span class="n">DataMessageMagicByte</span><span class="o">.</span><span class="n">HTTP_REQUEST</span><span class="o">.</span><span class="n">value</span><span class="p">:</span>
<span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">run_http_request_magic</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">amq_message</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">loop</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">amq_message</span><span class="o">.</span><span class="n">magic</span><span class="p">()</span> <span class="o">==</span> <span class="n">DataMessageMagicByte</span><span class="o">.</span><span class="n">RPC_REQUEST</span><span class="o">.</span><span class="n">value</span><span class="p">:</span>
<span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">run_rpc_request</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">amq_message</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">loop</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">logging_error</span><span class="p">(</span>
<span class="s2">&quot;Unknown MAGIC value: [</span><span class="si">%s</span><span class="s2">], don&#39;t know how to interpret the message&quot;</span><span class="p">,</span>
<span class="n">amq_message</span><span class="o">.</span><span class="n">magic</span><span class="p">(),</span>
<span class="p">)</span>
<span class="n">asyncio</span><span class="o">.</span><span class="n">run_coroutine_threadsafe</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">nack</span><span class="p">(</span><span class="n">requeue</span><span class="o">=</span><span class="kc">False</span><span class="p">),</span> <span class="bp">self</span><span class="o">.</span><span class="n">loop</span><span class="p">)</span>
<span class="k">return</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">logging_error</span><span class="p">(</span><span class="s2">&quot;######[</span><span class="si">%s</span><span class="s2">] No valid AMQ Message present.&quot;</span><span class="p">,</span> <span class="n">message</span><span class="o">.</span><span class="n">delivery_tag</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">record_duration</span><span class="p">(</span><span class="n">start</span><span class="p">,</span> <span class="n">message</span><span class="o">.</span><span class="n">delivery_tag</span><span class="p">)</span>
<span class="n">asyncio</span><span class="o">.</span><span class="n">run_coroutine_threadsafe</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">ack</span><span class="p">(</span><span class="n">multiple</span><span class="o">=</span><span class="kc">False</span><span class="p">),</span> <span class="bp">self</span><span class="o">.</span><span class="n">loop</span><span class="p">)</span></div>
<div class="viewcode-block" id="DataMessageHandler.run_http_request_magic">
<a class="viewcode-back" href="../../../modules/amqp.service.html#amqp.service.amq_message_handler.DataMessageHandler.run_http_request_magic">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run_http_request_magic</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span>
<span class="n">message</span><span class="p">:</span> <span class="n">AbstractIncomingMessage</span><span class="p">,</span>
<span class="n">amq_message</span><span class="p">:</span> <span class="n">DataMessage</span><span class="p">,</span>
<span class="n">loop</span><span class="p">:</span> <span class="n">AbstractEventLoop</span><span class="p">,</span>
<span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Synchronous version of on_message method. This is a wrapper around the async on_message method.</span>
<span class="sd"> It also counts parallel executions and handles backpressure.</span>
<span class="sd"> :param message: RabbitMQ raw message</span>
<span class="sd"> :param amq_message: DataMessage</span>
<span class="sd"> :param loop: Event loop</span>
<span class="sd"> :return: DataResponse</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="c1"># Increment the counter for parallel executions and check resource availability</span>
<span class="bp">self</span><span class="o">.</span><span class="n">backpressure_handler</span><span class="o">.</span><span class="n">increase_current_load</span><span class="p">()</span>
<span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">backpressure_handler</span><span class="o">.</span><span class="n">check_overload_condition</span><span class="p">()</span>
<span class="n">logging_info</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;PARALLEL: Current Capacity [</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">backpressure_handler</span><span class="o">.</span><span class="n">current_availability</span><span class="si">}</span><span class="s2">] of [</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">backpressure_handler</span><span class="o">.</span><span class="n">max_availability</span><span class="si">}</span><span class="s2">]&quot;</span>
<span class="p">)</span>
<span class="k">if</span> <span class="n">message</span><span class="o">.</span><span class="n">reply_to</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">reply_to</span> <span class="o">=</span> <span class="n">message</span><span class="o">.</span><span class="n">reply_to</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">_a_message</span> <span class="o">=</span> <span class="n">AMQMessage</span><span class="p">(</span><span class="n">amq_message</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">rabbit_mq_client</span><span class="o">.</span><span class="n">connection</span><span class="p">)</span>
<span class="n">_response</span><span class="p">:</span> <span class="n">DataResponse</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">service_adapter</span><span class="o">.</span><span class="n">on_message</span><span class="p">(</span><span class="n">_a_message</span><span class="p">)</span>
<span class="n">logging_debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Result in thread: </span><span class="si">{</span><span class="n">_response</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">send_reply</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">reply_to</span><span class="p">,</span> <span class="n">_response</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="n">logging_error</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Processing message: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="n">asyncio</span><span class="o">.</span><span class="n">run_coroutine_threadsafe</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">nack</span><span class="p">(</span><span class="n">requeue</span><span class="o">=</span><span class="kc">False</span><span class="p">),</span> <span class="n">loop</span><span class="o">=</span><span class="n">loop</span><span class="p">)</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">amq_message</span><span class="p">,</span> <span class="n">MultipartDataMessage</span><span class="p">):</span>
<span class="c1"># remove the downloaded files from the output_dir</span>
<span class="k">for</span> <span class="n">file_id</span><span class="p">,</span> <span class="n">filename</span> <span class="ow">in</span> <span class="n">amq_message</span><span class="o">.</span><span class="n">extra_data</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">logging_info</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;[</span><span class="si">{</span><span class="n">message</span><span class="o">.</span><span class="n">delivery_tag</span><span class="si">}</span><span class="s2">] Deleting file: </span><span class="si">{</span><span class="n">file_id</span><span class="si">}</span><span class="s2"> in </span><span class="si">{</span><span class="n">filename</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="p">)</span>
<span class="n">os</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">OSError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="n">logging_error</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Deleting file </span><span class="si">{</span><span class="n">filename</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="n">logging_error</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Request handler: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">backpressure_handler</span><span class="o">.</span><span class="n">decrease_current_load</span><span class="p">()</span></div>
<div class="viewcode-block" id="DataMessageHandler.run_rpc_request">
<a class="viewcode-back" href="../../../modules/amqp.service.html#amqp.service.amq_message_handler.DataMessageHandler.run_rpc_request">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run_rpc_request</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span>
<span class="n">message</span><span class="p">:</span> <span class="n">AbstractIncomingMessage</span><span class="p">,</span>
<span class="n">amq_message</span><span class="p">:</span> <span class="n">DataMessage</span><span class="p">,</span>
<span class="n">loop</span><span class="p">:</span> <span class="n">AbstractEventLoop</span><span class="p">,</span>
<span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Synchronous version of on_message method. This is a wrapper around the async on_message method.</span>
<span class="sd"> It also counts parallel executions and handles backpressure.</span>
<span class="sd"> :param message: RabbitMQ raw message</span>
<span class="sd"> :param amq_message: DataMessage</span>
<span class="sd"> :param loop: Event loop</span>
<span class="sd"> :return: DataResponse</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="c1"># Increment the counter for parallel executions and check resource availability</span>
<span class="bp">self</span><span class="o">.</span><span class="n">backpressure_handler</span><span class="o">.</span><span class="n">increase_current_load</span><span class="p">()</span>
<span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">backpressure_handler</span><span class="o">.</span><span class="n">check_overload_condition</span><span class="p">()</span>
<span class="n">logging_info</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;PARALLEL: Current Capacity [</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">backpressure_handler</span><span class="o">.</span><span class="n">current_availability</span><span class="si">}</span><span class="s2">] of [</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">backpressure_handler</span><span class="o">.</span><span class="n">max_availability</span><span class="si">}</span><span class="s2">]&quot;</span>
<span class="p">)</span>
<span class="k">if</span> <span class="n">message</span><span class="o">.</span><span class="n">reply_to</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">reply_to</span> <span class="o">=</span> <span class="n">message</span><span class="o">.</span><span class="n">reply_to</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">_a_message</span> <span class="o">=</span> <span class="n">AMQMessage</span><span class="p">(</span><span class="n">amq_message</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">rabbit_mq_client</span><span class="o">.</span><span class="n">connection</span><span class="p">)</span>
<span class="n">_response</span><span class="p">:</span> <span class="n">DataResponse</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">on_rpc</span><span class="p">(</span><span class="n">_a_message</span><span class="p">)</span>
<span class="n">logging_debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Result in thread: </span><span class="si">{</span><span class="n">_response</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">send_reply</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">reply_to</span><span class="p">,</span> <span class="n">_response</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="n">logging_error</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Processing message: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="n">asyncio</span><span class="o">.</span><span class="n">run_coroutine_threadsafe</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">nack</span><span class="p">(</span><span class="n">requeue</span><span class="o">=</span><span class="kc">False</span><span class="p">),</span> <span class="n">loop</span><span class="o">=</span><span class="n">loop</span><span class="p">)</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">amq_message</span><span class="p">,</span> <span class="n">MultipartDataMessage</span><span class="p">):</span>
<span class="c1"># remove the downloaded files from the output_dir</span>
<span class="k">for</span> <span class="n">file_id</span><span class="p">,</span> <span class="n">filename</span> <span class="ow">in</span> <span class="n">amq_message</span><span class="o">.</span><span class="n">extra_data</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">logging_info</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;[</span><span class="si">{</span><span class="n">message</span><span class="o">.</span><span class="n">delivery_tag</span><span class="si">}</span><span class="s2">] Deleting file: </span><span class="si">{</span><span class="n">file_id</span><span class="si">}</span><span class="s2"> in </span><span class="si">{</span><span class="n">filename</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="p">)</span>
<span class="n">os</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">OSError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="n">logging_error</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Deleting file </span><span class="si">{</span><span class="n">filename</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="n">logging_error</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Request handler: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">backpressure_handler</span><span class="o">.</span><span class="n">decrease_current_load</span><span class="p">()</span></div>
<div class="viewcode-block" id="DataMessageHandler.on_rpc">
<a class="viewcode-back" href="../../../modules/amqp.service.html#amqp.service.amq_message_handler.DataMessageHandler.on_rpc">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">on_rpc</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">a_message</span><span class="p">:</span> <span class="n">AMQMessage</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">DataResponse</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Dynamically invokes a function or a class method from a specified package.</span>
<span class="sd"> Args:</span>
<span class="sd"> a_message (AMQMessage): The message containing the package, class, and function details.</span>
<span class="sd"> Args encoded in the AMQMessage:</span>
<span class="sd"> package_name (str): The name of the Python package to import.</span>
<span class="sd"> class_name (str): The name of the class within the package.</span>
<span class="sd"> Use &#39;__global__&#39; if the function_name refers to a global function</span>
<span class="sd"> in the package.</span>
<span class="sd"> function_name (str): The name of the function or method to invoke.</span>
<span class="sd"> kwargs (Dict[str, Any]): A dictionary of keyword arguments to pass to the function/method (in the body).</span>
<span class="sd"> Returns:</span>
<span class="sd"> Any: The return value of the invoked function or method.</span>
<span class="sd"> Raises:</span>
<span class="sd"> ModuleNotFoundError: If the specified package cannot be imported.</span>
<span class="sd"> AttributeError: If the specified class or function/method does not exist.</span>
<span class="sd"> Exception: For any other errors during invocation.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">package_name</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="n">a_message</span><span class="o">.</span><span class="n">method</span><span class="p">()</span>
<span class="n">class_name</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="n">a_message</span><span class="o">.</span><span class="n">domain</span><span class="p">()</span>
<span class="n">function_name</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="n">a_message</span><span class="o">.</span><span class="n">path</span><span class="p">()</span>
<span class="n">kwargs</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]</span> <span class="o">=</span> <span class="n">parse_map_string</span><span class="p">(</span><span class="n">a_message</span><span class="o">.</span><span class="n">_base64body</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s2">&quot;utf-8&quot;</span><span class="p">))</span>
<span class="k">return</span> <span class="k">await</span> <span class="n">invoke_command</span><span class="p">(</span>
<span class="n">package_name</span><span class="p">,</span> <span class="n">class_name</span><span class="p">,</span> <span class="n">function_name</span><span class="p">,</span> <span class="n">a_message</span><span class="o">.</span><span class="n">id</span><span class="p">()</span><span class="o">.</span><span class="n">as_string</span><span class="p">(),</span> <span class="n">kwargs</span>
<span class="p">)</span></div>
<div class="viewcode-block" id="DataMessageHandler.reconstitute_data_message">
<a class="viewcode-back" href="../../../modules/amqp.service.html#amqp.service.amq_message_handler.DataMessageHandler.reconstitute_data_message">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">reconstitute_data_message</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">AbstractIncomingMessage</span>
<span class="p">)</span> <span class="o">-&gt;</span> <span class="n">DataMessage</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> DataMessage may be serialized as string in separate queue (addressing == 1) or be a MultiPart message with</span>
<span class="sd"> files streamed over individual queues, one per file.</span>
<span class="sd"> This function uses &#39;addressing&#39; mode from message headers to determine how to deserialize (reconstitute)</span>
<span class="sd"> the original message.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">amq_message</span><span class="p">:</span> <span class="n">DataMessage</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">delivery_tag</span> <span class="o">=</span> <span class="n">message</span><span class="o">.</span><span class="n">delivery_tag</span>
<span class="n">addressing</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="n">message</span><span class="o">.</span><span class="n">headers</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;clevermicro.addressing&quot;</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
<span class="k">if</span> <span class="n">addressing</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
<span class="n">amq_message</span> <span class="o">=</span> <span class="n">DataMessageFactory</span><span class="o">.</span><span class="n">from_bytes</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">body</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">amq_message</span> <span class="o">=</span> <span class="k">await</span> <span class="n">DataMessageFactory</span><span class="o">.</span><span class="n">from_stream</span><span class="p">(</span>
<span class="n">message</span><span class="o">.</span><span class="n">body</span><span class="p">,</span> <span class="n">rabbitmq_url</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">rabbit_mq_url</span><span class="p">,</span> <span class="n">loop</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">loop</span>
<span class="p">)</span>
<span class="n">logging_info</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;######[</span><span class="si">{</span><span class="n">delivery_tag</span><span class="si">}</span><span class="s2">] AMQ Message from stream: </span><span class="si">{</span><span class="n">amq_message</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="n">amq_message</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">extra_data</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">file_handler</span><span class="o">.</span><span class="n">on_message</span><span class="p">(</span>
<span class="n">message</span><span class="o">=</span><span class="n">message</span><span class="p">,</span>
<span class="n">json_data</span><span class="o">=</span><span class="n">amq_message</span><span class="o">.</span><span class="n">body</span><span class="p">(),</span>
<span class="n">rabbitmq_url</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">rabbit_mq_url</span><span class="p">,</span>
<span class="n">loop</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">loop</span><span class="p">,</span>
<span class="n">output_dir</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">output_dir</span><span class="p">,</span>
<span class="p">)</span>
<span class="n">logging_info</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;######[</span><span class="si">{</span><span class="n">delivery_tag</span><span class="si">}</span><span class="s2">] Multipart download result: </span><span class="si">{</span><span class="n">extra_data</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="n">amq_message</span> <span class="o">=</span> <span class="n">MultipartDataMessage</span><span class="p">(</span><span class="n">amq_message</span><span class="p">,</span> <span class="n">extra_data</span><span class="p">)</span>
<span class="k">if</span> <span class="n">amq_message</span><span class="p">:</span>
<span class="n">logging_info</span><span class="p">(</span>
<span class="s2">&quot;######[</span><span class="si">%s</span><span class="s2">] AMQ Message received, ctag=</span><span class="si">%s</span><span class="s2">, msgId=</span><span class="si">%s</span><span class="s2">, </span><span class="si">%s</span><span class="s2">:</span><span class="si">%s</span><span class="s2">, traceInfo=</span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span>
<span class="n">message</span><span class="o">.</span><span class="n">delivery_tag</span><span class="p">,</span>
<span class="n">message</span><span class="o">.</span><span class="n">consumer_tag</span><span class="p">,</span>
<span class="n">amq_message</span><span class="o">.</span><span class="n">id</span><span class="p">(),</span>
<span class="n">amq_message</span><span class="o">.</span><span class="n">method</span><span class="p">(),</span>
<span class="n">amq_message</span><span class="o">.</span><span class="n">path</span><span class="p">(),</span>
<span class="n">map_as_string</span><span class="p">(</span><span class="n">amq_message</span><span class="o">.</span><span class="n">trace_info</span><span class="p">()),</span>
<span class="p">)</span>
<span class="k">return</span> <span class="n">amq_message</span></div>
<div class="viewcode-block" id="DataMessageHandler.ensure_trace_info">
<a class="viewcode-back" href="../../../modules/amqp.service.html#amqp.service.amq_message_handler.DataMessageHandler.ensure_trace_info">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">ensure_trace_info</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">amq_message</span><span class="p">:</span> <span class="n">DataMessage</span><span class="p">):</span>
<span class="n">propagator</span> <span class="o">=</span> <span class="n">TraceContextTextMapPropagator</span><span class="p">()</span>
<span class="n">context</span> <span class="o">=</span> <span class="n">propagator</span><span class="o">.</span><span class="n">extract</span><span class="p">(</span>
<span class="n">carrier</span><span class="o">=</span><span class="n">amq_message</span><span class="o">.</span><span class="n">trace_info</span><span class="p">(),</span> <span class="n">context</span><span class="o">=</span><span class="n">trace</span><span class="o">.</span><span class="n">context_api</span><span class="o">.</span><span class="n">get_current</span><span class="p">()</span>
<span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">tracer</span><span class="o">.</span><span class="n">start_span</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&quot;AMQ-Adapter-Consumer&quot;</span><span class="p">,</span> <span class="n">context</span><span class="o">=</span><span class="n">context</span><span class="p">)</span></div>
<span class="c1"># logging_info(&quot;CTX=%s&quot;, context)</span>
<span class="c1"># current_span = self.tracer.start_span(&quot;AMQ-Adapter.Processing.Request&quot;, parent=parent_span)</span>
<span class="c1"># context_with_span = trace.set_span_in_context(current_span, context)</span>
<span class="c1"># logging.info(&quot; [*] CTX2=%s&quot;, context_with_span)</span>
<span class="c1"># propagator.inject(context_with_span, amq_message.trace_info, self.set_text)</span>
<span class="c1"># logging.info(&quot; [***] NEW TI=%s CTX=%s SCOPE=%s&quot;,</span>
<span class="c1"># map_as_string(amq_message.trace_info()), context_with_span, context)</span>
<div class="viewcode-block" id="DataMessageHandler.record_duration">
<a class="viewcode-back" href="../../../modules/amqp.service.html#amqp.service.amq_message_handler.DataMessageHandler.record_duration">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">record_duration</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">start</span><span class="p">,</span> <span class="n">delivery_tag</span><span class="p">):</span>
<span class="k">global</span> <span class="n">last_backpressure_event_time</span>
<span class="n">last_backpressure_event_time</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span>
<span class="n">logging_info</span><span class="p">(</span>
<span class="s2">&quot;######[</span><span class="si">%s</span><span class="s2">] Done, single ACK: </span><span class="si">%s</span><span class="s2">ms.&quot;</span><span class="p">,</span>
<span class="n">delivery_tag</span><span class="p">,</span>
<span class="n">last_backpressure_event_time</span> <span class="o">-</span> <span class="n">start</span><span class="p">,</span>
<span class="p">)</span></div>
<div class="viewcode-block" id="DataMessageHandler.send_reply">
<a class="viewcode-back" href="../../../modules/amqp.service.html#amqp.service.amq_message_handler.DataMessageHandler.send_reply">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">send_reply</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">reply_to</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">response</span><span class="p">:</span> <span class="n">DataResponse</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> The Service side code. When the CleverXXX service has output ready, in DataResponse object,</span>
<span class="sd"> call this method to return the reply back to the caller</span>
<span class="sd"> :param reply_to:connection.channel</span>
<span class="sd"> :param response:</span>
<span class="sd"> :return:</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="n">reply_to</span><span class="p">:</span>
<span class="n">pika_message</span><span class="p">:</span> <span class="n">Message</span> <span class="o">=</span> <span class="n">Message</span><span class="p">(</span>
<span class="n">body</span><span class="o">=</span><span class="n">DataResponseFactory</span><span class="o">.</span><span class="n">serialize</span><span class="p">(</span><span class="n">response</span><span class="p">),</span>
<span class="n">correlation_id</span><span class="o">=</span><span class="n">response</span><span class="o">.</span><span class="n">id</span><span class="p">(),</span>
<span class="n">content_type</span><span class="o">=</span><span class="p">(</span>
<span class="n">response</span><span class="o">.</span><span class="n">content_type</span><span class="p">()[</span><span class="mi">0</span><span class="p">]</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">content_type</span><span class="p">(),</span> <span class="nb">list</span><span class="p">)</span>
<span class="k">else</span> <span class="n">response</span><span class="o">.</span><span class="n">content_type</span><span class="p">()</span>
<span class="p">),</span>
<span class="p">)</span>
<span class="n">_res</span> <span class="o">=</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">run_coroutine_threadsafe</span><span class="p">(</span>
<span class="bp">self</span><span class="o">.</span><span class="n">reply_to_exchange</span><span class="o">.</span><span class="n">publish</span><span class="p">(</span><span class="n">message</span><span class="o">=</span><span class="n">pika_message</span><span class="p">,</span> <span class="n">routing_key</span><span class="o">=</span><span class="n">reply_to</span><span class="p">),</span>
<span class="bp">self</span><span class="o">.</span><span class="n">loop</span><span class="p">,</span>
<span class="p">)</span>
<span class="n">logging_debug</span><span class="p">(</span>
<span class="s2">&quot;###### DONE Reply Published to exchg:(</span><span class="si">%s</span><span class="s2">) To=</span><span class="si">%s</span><span class="s2">, res=</span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">reply_to_exchange</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
<span class="n">reply_to</span><span class="p">,</span>
<span class="n">_res</span><span class="p">,</span>
<span class="p">)</span></div>
<div class="viewcode-block" id="DataMessageHandler.reply_received_callback">
<a class="viewcode-back" href="../../../modules/amqp.service.html#amqp.service.amq_message_handler.DataMessageHandler.reply_received_callback">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">reply_received_callback</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">AbstractIncomingMessage</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> The handler for reply for DataMessage that we sent out earlier -</span>
<span class="sd"> the code matches the received response with the original request and passes the response to the caller.</span>
<span class="sd"> :param message:</span>
<span class="sd"> :return:</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">reply_id</span> <span class="o">=</span> <span class="n">message</span><span class="o">.</span><span class="n">correlation_id</span>
<span class="n">delivery_tag</span> <span class="o">=</span> <span class="n">message</span><span class="o">.</span><span class="n">delivery_tag</span>
<span class="n">debug</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;######[</span><span class="si">{</span><span class="n">delivery_tag</span><span class="si">}</span><span class="s2">] (RPC REPLY) env: </span><span class="si">{</span><span class="n">message</span><span class="o">.</span><span class="n">headers</span><span class="si">}</span><span class="s2">, props: </span><span class="si">{</span><span class="n">message</span><span class="o">.</span><span class="n">properties</span><span class="si">}</span><span class="s2">, BODY: </span><span class="si">{</span><span class="n">message</span><span class="o">.</span><span class="n">body</span><span class="o">.</span><span class="n">decode</span><span class="p">()</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="n">logging_debug</span><span class="p">(</span><span class="n">debug</span><span class="p">)</span>
<span class="c1"># TODO - figure out implementation of this part, as this is sending reply back either to a service,</span>
<span class="c1"># or to the user</span>
<span class="n">logging_info</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;OUTSTANDING RECV: </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">outstanding</span><span class="si">}</span><span class="s2">, size=</span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">outstanding</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="n">future</span><span class="p">:</span> <span class="n">Future</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">outstanding</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="n">reply_id</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
<span class="c1"># if reply is None:</span>
<span class="c1"># logging.warn(&quot; [W] ######[%s] IGNORING REPLY. No outstanding request for ID %s&quot;,</span>
<span class="c1"># delivery_tag, reply_id)</span>
<span class="c1"># else:</span>
<span class="c1"># result = DataResponseFactory.from_bytes(body)</span>
<span class="c1"># reply.tracing_span().end()</span>
<span class="c1"># TODO - figure out the right response format (not needed for Clever Swarm v0.1)</span>
<span class="c1"># that currently runs Java version, this method here is for the future compatibility to enable</span>
<span class="c1"># internal, service-2-service communication, and the proper response type will be decided than</span>
<span class="c1"># reply.response().set_result(Response.ok(result.body, content_type).build())</span>
<span class="k">if</span> <span class="n">future</span><span class="p">:</span>
<span class="n">response</span><span class="p">:</span> <span class="n">DataResponse</span> <span class="o">=</span> <span class="n">DataResponseFactory</span><span class="o">.</span><span class="n">from_bytes</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">body</span><span class="p">)</span>
<span class="c1"># Complete the Future with the response data</span>
<span class="n">future</span><span class="o">.</span><span class="n">set_result</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">body</span><span class="p">())</span>
<span class="k">await</span> <span class="n">message</span><span class="o">.</span><span class="n">ack</span><span class="p">(</span><span class="n">multiple</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span></div>
<div class="viewcode-block" id="DataMessageHandler.send_rpc">
<a class="viewcode-back" href="../../../modules/amqp.service.html#amqp.service.amq_message_handler.DataMessageHandler.send_rpc">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">send_rpc</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">route</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">DataMessage</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Future</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Sends an RPC message to the specified route and returns a Future that will be completed</span>
<span class="sd"> when the response is received.</span>
<span class="sd"> :param route: AMQRoute object containing exchange and routing information</span>
<span class="sd"> :param message: DataMessage to be sent</span>
<span class="sd"> :return: Future that will be completed with the response payload</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="c1"># Create a Future to be completed when the response is received</span>
<span class="n">future</span> <span class="o">=</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">Future</span><span class="p">()</span>
<span class="c1"># Store the future in the outstanding dictionary using the message ID as the key</span>
<span class="n">message_id</span> <span class="o">=</span> <span class="n">message</span><span class="o">.</span><span class="n">id</span><span class="p">()</span><span class="o">.</span><span class="n">as_string</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">outstanding</span><span class="p">[</span><span class="n">message_id</span><span class="p">]</span> <span class="o">=</span> <span class="n">future</span>
<span class="c1"># Create a Pika message with the correlation ID set to the message ID</span>
<span class="n">pika_message</span> <span class="o">=</span> <span class="n">Message</span><span class="p">(</span>
<span class="n">body</span><span class="o">=</span><span class="n">DataMessageFactory</span><span class="o">.</span><span class="n">serialize</span><span class="p">(</span><span class="n">message</span><span class="p">),</span>
<span class="n">correlation_id</span><span class="o">=</span><span class="n">message_id</span><span class="p">,</span>
<span class="n">reply_to</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">rabbit_mq_client</span><span class="o">.</span><span class="n">router</span><span class="o">.</span><span class="n">get_reply_to_queue_name</span><span class="p">(),</span>
<span class="n">content_type</span><span class="o">=</span><span class="p">(</span>
<span class="n">message</span><span class="o">.</span><span class="n">content_type</span><span class="p">()[</span><span class="mi">0</span><span class="p">]</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">content_type</span><span class="p">(),</span> <span class="nb">list</span><span class="p">)</span>
<span class="k">else</span> <span class="n">message</span><span class="o">.</span><span class="n">content_type</span><span class="p">()</span>
<span class="p">),</span>
<span class="p">)</span>
<span class="c1"># Get the exchange from the route</span>
<span class="n">rpc_exchange_name</span> <span class="o">=</span> <span class="n">route</span><span class="o">.</span><span class="n">exchange</span>
<span class="n">exchange</span><span class="p">:</span> <span class="n">AbstractRobustExchange</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">rabbit_mq_client</span><span class="o">.</span><span class="n">channel</span><span class="o">.</span><span class="n">declare_exchange</span><span class="p">(</span>
<span class="n">name</span><span class="o">=</span><span class="n">rpc_exchange_name</span><span class="p">,</span> <span class="nb">type</span><span class="o">=</span><span class="n">ExchangeType</span><span class="o">.</span><span class="n">topic</span>
<span class="p">)</span>
<span class="c1"># Publish the message to the exchange with the component name as the routing key</span>
<span class="k">await</span> <span class="n">exchange</span><span class="o">.</span><span class="n">publish</span><span class="p">(</span>
<span class="n">message</span><span class="o">=</span><span class="n">pika_message</span><span class="p">,</span> <span class="n">routing_key</span><span class="o">=</span><span class="n">sanitize_as_rabbitmq_name</span><span class="p">(</span><span class="n">route</span><span class="o">.</span><span class="n">component_name</span><span class="p">)</span>
<span class="p">)</span>
<span class="n">logging_debug</span><span class="p">(</span>
<span class="s2">&quot;###### RPC Request Published to exchg:(</span><span class="si">%s</span><span class="s2">) routing_key=</span><span class="si">%s</span><span class="s2">, msgId=</span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span>
<span class="n">rpc_exchange_name</span><span class="p">,</span>
<span class="n">route</span><span class="o">.</span><span class="n">component_name</span><span class="p">,</span>
<span class="n">message_id</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">return</span> <span class="n">future</span></div>
<div class="viewcode-block" id="DataMessageHandler.send_command">
<a class="viewcode-back" href="../../../modules/amqp.service.html#amqp.service.amq_message_handler.DataMessageHandler.send_command">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">send_command</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">route</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">DataMessage</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Sends an RPC message to the specified route and returns a Future that will be completed</span>
<span class="sd"> when the response is received.</span>
<span class="sd"> :param route: AMQRoute object containing exchange and routing information</span>
<span class="sd"> :param message: DataMessage to be sent</span>
<span class="sd"> :return: Future that will be completed with the response payload</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">rmq_body</span> <span class="o">=</span> <span class="n">DataMessageFactory</span><span class="o">.</span><span class="n">serialize</span><span class="p">(</span><span class="n">message</span><span class="p">)</span>
<span class="n">cid</span> <span class="o">=</span> <span class="n">message</span><span class="o">.</span><span class="n">id</span><span class="p">()</span><span class="o">.</span><span class="n">as_string</span><span class="p">()</span>
<span class="n">ctype</span> <span class="o">=</span> <span class="p">(</span>
<span class="n">message</span><span class="o">.</span><span class="n">content_type</span><span class="p">()[</span><span class="mi">0</span><span class="p">]</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">content_type</span><span class="p">(),</span> <span class="nb">list</span><span class="p">)</span>
<span class="k">else</span> <span class="n">message</span><span class="o">.</span><span class="n">content_type</span><span class="p">()</span>
<span class="p">)</span>
<span class="nb">print</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;Sending RPC command to route: </span><span class="si">{</span><span class="n">route</span><span class="si">}</span><span class="s2">, message ID: </span><span class="si">{</span><span class="n">cid</span><span class="si">}</span><span class="s2"> with body: </span><span class="si">{</span><span class="n">rmq_body</span><span class="si">}</span><span class="s2"> correlation ID: </span><span class="si">{</span><span class="n">cid</span><span class="si">}</span><span class="s2">, content type: </span><span class="si">{</span><span class="n">ctype</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="p">)</span>
<span class="c1"># Create a Pika message with the correlation ID set to the message ID</span>
<span class="n">pika_message</span> <span class="o">=</span> <span class="n">Message</span><span class="p">(</span>
<span class="n">body</span><span class="o">=</span><span class="n">rmq_body</span><span class="p">,</span>
<span class="n">correlation_id</span><span class="o">=</span><span class="n">cid</span><span class="p">,</span>
<span class="n">content_type</span><span class="o">=</span><span class="n">ctype</span><span class="p">,</span>
<span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;SENDING RPC COMMAND: </span><span class="si">{</span><span class="n">pika_message</span><span class="o">.</span><span class="n">body</span><span class="si">}</span><span class="s2"> with ID: </span><span class="si">{</span><span class="n">message</span><span class="o">.</span><span class="n">id</span><span class="p">()</span><span class="o">.</span><span class="n">as_string</span><span class="p">()</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="c1"># Get the exchange from the route</span>
<span class="n">rpc_exchange_name</span> <span class="o">=</span> <span class="n">route</span><span class="o">.</span><span class="n">exchange</span>
<span class="n">exchange</span><span class="p">:</span> <span class="n">AbstractRobustExchange</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">rabbit_mq_client</span><span class="o">.</span><span class="n">channel</span><span class="o">.</span><span class="n">declare_exchange</span><span class="p">(</span>
<span class="n">name</span><span class="o">=</span><span class="n">rpc_exchange_name</span><span class="p">,</span> <span class="nb">type</span><span class="o">=</span><span class="n">ExchangeType</span><span class="o">.</span><span class="n">topic</span>
<span class="p">)</span>
<span class="c1"># Publish the message to the exchange with the component name as the routing key</span>
<span class="k">await</span> <span class="n">exchange</span><span class="o">.</span><span class="n">publish</span><span class="p">(</span>
<span class="n">message</span><span class="o">=</span><span class="n">pika_message</span><span class="p">,</span> <span class="n">routing_key</span><span class="o">=</span><span class="n">sanitize_as_rabbitmq_name</span><span class="p">(</span><span class="n">route</span><span class="o">.</span><span class="n">component_name</span><span class="p">)</span>
<span class="p">)</span>
<span class="n">logging_info</span><span class="p">(</span>
<span class="s2">&quot;###### RPC Request Published to exchg:(</span><span class="si">%s</span><span class="s2">) routing_key=</span><span class="si">%s</span><span class="s2">, msgId=</span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span>
<span class="n">rpc_exchange_name</span><span class="p">,</span>
<span class="n">route</span><span class="o">.</span><span class="n">component_name</span><span class="p">,</span>
<span class="n">message</span><span class="o">.</span><span class="n">id</span><span class="p">()</span><span class="o">.</span><span class="n">as_string</span><span class="p">(),</span>
<span class="p">)</span>
<span class="k">return</span> <span class="kc">True</span></div>
</div>
</pre></div>
</div>
</div>
<footer>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2024, CleverThis.</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>
@@ -0,0 +1,431 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" data-content_root="../../../">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>amqp.service.amq_service &mdash; AMQ Adapter Python 1.0 documentation</title>
<link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=03e43079" />
<link rel="stylesheet" type="text/css" href="../../../_static/css/theme.css?v=e59714d7" />
<script src="../../../_static/jquery.js?v=5d32c60e"></script>
<script src="../../../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
<script src="../../../_static/documentation_options.js?v=f2a433a1"></script>
<script src="../../../_static/doctools.js?v=9bcbadda"></script>
<script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
<script src="../../../_static/js/theme.js"></script>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="../../../index.html" class="icon icon-home">
AMQ Adapter Python
</a>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" aria-label="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.html">AMQP Package</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.config.html">Configuration Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.adapter.html">Adapter Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.service.html">Service Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.router.html">Router Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.model.html">Model Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.rabbitmq.html">RabbitMQ Module</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="../../../index.html">AMQ Adapter Python</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="../../../index.html" class="icon icon-home" aria-label="Home"></a></li>
<li class="breadcrumb-item"><a href="../../index.html">Module code</a></li>
<li class="breadcrumb-item active">amqp.service.amq_service</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<h1>Source code for amqp.service.amq_service</h1><div class="highlight"><pre>
<span></span><span class="kn">import</span><span class="w"> </span><span class="nn">asyncio</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">logging</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">logging.config</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">os</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">asyncio</span><span class="w"> </span><span class="kn">import</span> <span class="n">Future</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">threading</span><span class="w"> </span><span class="kn">import</span> <span class="n">Thread</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">AsyncIterator</span><span class="p">,</span> <span class="n">Optional</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">aio_pika.abc</span><span class="w"> </span><span class="kn">import</span> <span class="n">AbstractRobustExchange</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.adapter.amq_route_factory</span><span class="w"> </span><span class="kn">import</span> <span class="n">AMQRouteFactory</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.adapter.backpressure_handler</span><span class="w"> </span><span class="kn">import</span> <span class="n">BackpressureHandler</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.adapter.consul_global_id_generator</span><span class="w"> </span><span class="kn">import</span> <span class="n">get_unique_instance_id</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.adapter.data_message_factory</span><span class="w"> </span><span class="kn">import</span> <span class="n">DataMessageFactory</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.adapter.logging_utils</span><span class="w"> </span><span class="kn">import</span> <span class="n">logging_error</span><span class="p">,</span> <span class="n">logging_info</span><span class="p">,</span> <span class="n">logging_warning</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.adapter.service_message_factory</span><span class="w"> </span><span class="kn">import</span> <span class="n">ServiceMessageFactory</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.config.amq_configuration</span><span class="w"> </span><span class="kn">import</span> <span class="n">AMQConfiguration</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.model.model</span><span class="w"> </span><span class="kn">import</span> <span class="n">AMQRoute</span><span class="p">,</span> <span class="n">DataMessage</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.rabbitmq.rabbit_mq_client</span><span class="w"> </span><span class="kn">import</span> <span class="n">RabbitMQClient</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.router.router_consumer</span><span class="w"> </span><span class="kn">import</span> <span class="n">RouterConsumer</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.service.amq_message_handler</span><span class="w"> </span><span class="kn">import</span> <span class="n">DataMessageHandler</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">amqp.service.tracing</span><span class="w"> </span><span class="kn">import</span> <span class="n">TracingConfig</span><span class="p">,</span> <span class="n">initialize_telemetry</span>
<span class="n">logging</span><span class="o">.</span><span class="n">basicConfig</span><span class="p">(</span><span class="n">level</span><span class="o">=</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">)</span>
<span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;CWD = </span><span class="si">{</span><span class="n">os</span><span class="o">.</span><span class="n">getcwd</span><span class="p">()</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="n">logging_conf_path</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">getcwd</span><span class="p">(),</span> <span class="s2">&quot;amqp&quot;</span><span class="p">,</span> <span class="s2">&quot;service&quot;</span><span class="p">,</span> <span class="s2">&quot;logging.conf&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">logging_conf_path</span><span class="p">):</span>
<span class="n">logging</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">fileConfig</span><span class="p">(</span><span class="n">logging_conf_path</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">logging_conf_path</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">getcwd</span><span class="p">(),</span> <span class="s2">&quot;logging.conf&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">logging_conf_path</span><span class="p">):</span>
<span class="n">logging</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">fileConfig</span><span class="p">(</span><span class="n">logging_conf_path</span><span class="p">)</span>
<div class="viewcode-block" id="AMQService">
<a class="viewcode-back" href="../../../modules/amqp.service.html#amqp.service.amq_service.AMQService">[docs]</a>
<span class="k">class</span><span class="w"> </span><span class="nc">AMQService</span><span class="p">:</span>
<span class="n">CLEVER_AMQP_CLIENT_VERSION</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span><span class="s2">&quot;CLEVER_AMQP_CLIENT_VERSION&quot;</span><span class="p">)</span>
<span class="n">MAX_WAIT</span> <span class="o">=</span> <span class="mi">300</span> <span class="c1"># defaults to 5 minutes (300 seconds)</span>
<div class="viewcode-block" id="AMQService.__init__">
<a class="viewcode-back" href="../../../modules/amqp.service.html#amqp.service.amq_service.AMQService.__init__">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">amq_configuration</span><span class="p">:</span> <span class="n">AMQConfiguration</span><span class="p">,</span> <span class="n">service_adapter</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s2">&quot;***********************************************&quot;</span><span class="p">)</span>
<span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s2">&quot;************** AMQ Service ***************&quot;</span><span class="p">)</span>
<span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s2">&quot;***********************************************&quot;</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">loop</span> <span class="o">=</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">new_event_loop</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">amq_configuration</span> <span class="o">=</span> <span class="n">amq_configuration</span>
<span class="bp">self</span><span class="o">.</span><span class="n">service_adapter</span> <span class="o">=</span> <span class="n">service_adapter</span>
<span class="bp">self</span><span class="o">.</span><span class="n">unique_id</span> <span class="o">=</span> <span class="n">get_unique_instance_id</span><span class="p">(</span><span class="n">amq_configuration</span><span class="o">.</span><span class="n">amq_adapter</span><span class="p">)</span>
<span class="n">amq_configuration</span><span class="o">.</span><span class="n">amq_adapter</span><span class="o">.</span><span class="n">generator_id</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">unique_id</span>
<span class="bp">self</span><span class="o">.</span><span class="n">data_message_factory</span> <span class="o">=</span> <span class="n">DataMessageFactory</span><span class="o">.</span><span class="n">get_instance</span><span class="p">(</span>
<span class="bp">self</span><span class="o">.</span><span class="n">unique_id</span> <span class="o">&amp;</span> <span class="n">DataMessageFactory</span><span class="o">.</span><span class="n">MACHINE_ID_MASK</span>
<span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">router</span> <span class="o">=</span> <span class="n">RouterConsumer</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">amq_configuration</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">rabbit_mq_client</span> <span class="o">=</span> <span class="n">RabbitMQClient</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">amq_configuration</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">router</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">tracer</span> <span class="o">=</span> <span class="n">initialize_telemetry</span><span class="p">(</span>
<span class="n">tracing_config</span><span class="o">=</span><span class="n">TracingConfig</span><span class="p">(</span>
<span class="n">service_name</span><span class="o">=</span><span class="n">amq_configuration</span><span class="o">.</span><span class="n">amq_adapter</span><span class="o">.</span><span class="n">service_name</span><span class="p">,</span>
<span class="n">service_version</span><span class="o">=</span><span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span><span class="s2">&quot;SERVICE_VERSION&quot;</span><span class="p">,</span> <span class="s2">&quot;unknown&quot;</span><span class="p">),</span>
<span class="p">)</span>
<span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">amq_data_message_handler</span> <span class="o">=</span> <span class="kc">None</span>
<span class="bp">self</span><span class="o">.</span><span class="n">service_message_factory</span> <span class="o">=</span> <span class="n">ServiceMessageFactory</span><span class="p">(</span>
<span class="bp">self</span><span class="o">.</span><span class="n">amq_configuration</span><span class="o">.</span><span class="n">amq_adapter</span><span class="o">.</span><span class="n">service_name</span>
<span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">backpressure_thread</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">Thread</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
<span class="bp">self</span><span class="o">.</span><span class="n">backpressure_handler</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">BackpressureHandler</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
<span class="bp">self</span><span class="o">.</span><span class="n">maximum_availability</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span>
<span class="bp">self</span><span class="o">.</span><span class="n">future</span><span class="p">:</span> <span class="n">Future</span> <span class="o">=</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">Future</span><span class="p">()</span></div>
<span class="c1"># =======================================================================</span>
<span class="c1"># =======================================================================</span>
<span class="c1"># ============== P u b l i c A P I M e t h o d s ===================</span>
<span class="c1"># =======================================================================</span>
<span class="c1"># =======================================================================</span>
<div class="viewcode-block" id="AMQService.run">
<a class="viewcode-back" href="../../../modules/amqp.service.html#amqp.service.amq_service.AMQService.run">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Start the AMQ service, initializing RabbitMQ connection and message handlers.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="c1"># self.init(loop) will initialize RabbitMQ connection</span>
<span class="n">asyncio</span><span class="o">.</span><span class="n">set_event_loop</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">loop</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">loop</span><span class="o">.</span><span class="n">run_until_complete</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">init</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">loop</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">service_adapter</span><span class="p">))</span>
<span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s2">&quot;***********************************************&quot;</span><span class="p">)</span>
<span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s2">&quot;****** AMQ Service Init Complete *********&quot;</span><span class="p">)</span>
<span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s2">&quot;***********************************************&quot;</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">future</span><span class="o">.</span><span class="n">set_result</span><span class="p">(</span><span class="kc">True</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">loop</span><span class="o">.</span><span class="n">run_forever</span><span class="p">()</span></div>
<div class="viewcode-block" id="AMQService.backpressure">
<a class="viewcode-back" href="../../../modules/amqp.service.html#amqp.service.amq_service.AMQService.backpressure">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">backpressure</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">current_availability</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">maximum</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Send Backpressure event to the Management Service. The Backpressure logic determines the type of the event</span>
<span class="sd"> based on the current_availability and maximum values.</span>
<span class="sd"> - OVERLOAD event is triggered immediately when the current_availability value is below threshold</span>
<span class="sd"> typically set to 10% of the maximum value, or 0 if no maximum is provided.</span>
<span class="sd"> - IDLE event is triggered when the current_availability value exeeds 80% of the maximum value or is greater</span>
<span class="sd"> than 0 if no maximum is provided.</span>
<span class="sd"> - UPDATE event is sent if neither OVERLOAD nor IDLE conditions are met, indicating that the backpressure is</span>
<span class="sd"> within acceptable limits.</span>
<span class="sd"> :param current_availability: Currently available capacity.</span>
<span class="sd"> :param maximum: Maximum value of the backpressure metric. If undefined or set to lt 0 (e.g. -1),</span>
<span class="sd"> the maximum is than determined from max value of current_availability seen over the time.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">backpressure_handler</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="c1"># watch maximum &amp; current value to always have some valid maximum reference</span>
<span class="k">if</span> <span class="n">maximum</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">:</span>
<span class="k">if</span> <span class="n">current_availability</span> <span class="o">&gt;</span> <span class="bp">self</span><span class="o">.</span><span class="n">maximum_availability</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">maximum_availability</span> <span class="o">=</span> <span class="n">current_availability</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">if</span> <span class="n">maximum</span> <span class="o">&gt;</span> <span class="bp">self</span><span class="o">.</span><span class="n">maximum_availability</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">maximum_availability</span> <span class="o">=</span> <span class="n">maximum</span>
<span class="n">asyncio</span><span class="o">.</span><span class="n">run_coroutine_threadsafe</span><span class="p">(</span>
<span class="bp">self</span><span class="o">.</span><span class="n">backpressure_handler</span><span class="o">.</span><span class="n">update_backpressure_value</span><span class="p">(</span>
<span class="n">current_availability</span><span class="p">,</span> <span class="n">maximum</span> <span class="k">if</span> <span class="n">maximum</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="k">else</span> <span class="bp">self</span><span class="o">.</span><span class="n">maximum_availability</span>
<span class="p">),</span>
<span class="n">loop</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">backpressure_handler</span><span class="o">.</span><span class="n">loop</span><span class="p">,</span>
<span class="p">)</span></div>
<div class="viewcode-block" id="AMQService.rpc">
<a class="viewcode-back" href="../../../modules/amqp.service.html#amqp.service.amq_service.AMQService.rpc">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">rpc</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">service_name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">fq_method_name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Future</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Send a Remote Procedure Call (RPC) message to the AMQ service.</span>
<span class="sd"> :param service_name: The service name to receive the RPC message.</span>
<span class="sd"> :param fq_method_name: The fully qualified method name to execute the RPC message.</span>
<span class="sd"> :param kwargs: Additional keyword arguments to be passed to the RPC method.</span>
<span class="sd"> :return: A Future that resolves when the RPC response is received.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">route</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">AMQRoute</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">router</span><span class="o">.</span><span class="n">find_route_by_service</span><span class="p">(</span><span class="n">service_name</span><span class="p">)</span>
<span class="k">if</span> <span class="n">route</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">message</span><span class="p">:</span> <span class="n">DataMessage</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">data_message_factory</span><span class="o">.</span><span class="n">create_rpc_message</span><span class="p">(</span>
<span class="n">fq_method_name</span><span class="o">=</span><span class="n">fq_method_name</span><span class="p">,</span>
<span class="n">swarm_id</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">amq_configuration</span><span class="o">.</span><span class="n">amq_adapter</span><span class="o">.</span><span class="n">swarm_task_id</span><span class="p">,</span>
<span class="o">**</span><span class="n">kwargs</span><span class="p">,</span>
<span class="p">)</span>
<span class="n">result</span><span class="p">:</span> <span class="n">Future</span> <span class="o">=</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">run_coroutine_threadsafe</span><span class="p">(</span>
<span class="bp">self</span><span class="o">.</span><span class="n">amq_data_message_handler</span><span class="o">.</span><span class="n">send_rpc</span><span class="p">(</span><span class="n">route</span><span class="p">,</span> <span class="n">message</span><span class="p">),</span>
<span class="n">loop</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">backpressure_handler</span><span class="o">.</span><span class="n">loop</span><span class="p">,</span>
<span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">set_outstanding_future</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">result</span><span class="p">)</span>
<span class="k">return</span> <span class="n">result</span>
<span class="n">result</span> <span class="o">=</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">Future</span><span class="p">()</span>
<span class="n">result</span><span class="o">.</span><span class="n">set_exception</span><span class="p">(</span>
<span class="ne">NameError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;No route exists. Service &#39;</span><span class="si">{</span><span class="n">service_name</span><span class="si">}</span><span class="s2">&#39; not found in routing table.&quot;</span><span class="p">)</span>
<span class="p">)</span>
<span class="k">return</span> <span class="n">result</span></div>
<div class="viewcode-block" id="AMQService.command">
<a class="viewcode-back" href="../../../modules/amqp.service.html#amqp.service.amq_service.AMQService.command">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">command</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">service_name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">fq_method_name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Send a unidirectional Command message to the AMQ service.</span>
<span class="sd"> :param service_name: The service name to receive the RPC message.</span>
<span class="sd"> :param fq_method_name: The fully qualified method name to execute the RPC message.</span>
<span class="sd"> :param kwargs: Additional keyword arguments to be passed to the RPC method.</span>
<span class="sd"> :return: A Future that resolves when the RPC response is received.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">route</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">AMQRoute</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">router</span><span class="o">.</span><span class="n">find_route_by_service</span><span class="p">(</span><span class="n">service_name</span><span class="p">)</span>
<span class="k">if</span> <span class="n">route</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">m</span><span class="p">:</span> <span class="n">DataMessage</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">data_message_factory</span><span class="o">.</span><span class="n">create_rpc_message</span><span class="p">(</span>
<span class="n">fq_method_name</span><span class="o">=</span><span class="n">fq_method_name</span><span class="p">,</span>
<span class="n">swarm_id</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">amq_configuration</span><span class="o">.</span><span class="n">amq_adapter</span><span class="o">.</span><span class="n">swarm_task_id</span><span class="p">,</span>
<span class="n">args</span><span class="o">=</span><span class="n">kwargs</span><span class="p">,</span>
<span class="p">)</span>
<span class="n">asyncio</span><span class="o">.</span><span class="n">run_coroutine_threadsafe</span><span class="p">(</span>
<span class="bp">self</span><span class="o">.</span><span class="n">amq_data_message_handler</span><span class="o">.</span><span class="n">send_command</span><span class="p">(</span><span class="n">route</span><span class="p">,</span> <span class="n">m</span><span class="p">),</span>
<span class="n">loop</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">backpressure_handler</span><span class="o">.</span><span class="n">loop</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">return</span> <span class="kc">True</span>
<span class="k">return</span> <span class="kc">False</span></div>
<div class="viewcode-block" id="AMQService.data_message_generator">
<a class="viewcode-back" href="../../../modules/amqp.service.html#amqp.service.amq_service.AMQService.data_message_generator">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">data_message_generator</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">route</span><span class="p">:</span> <span class="n">AMQRoute</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">AsyncIterator</span><span class="p">[</span><span class="n">DataMessage</span><span class="p">]:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> An async iterator that blocks until messages arrive, processes them,</span>
<span class="sd"> and continues in a loop.</span>
<span class="sd"> :param queue_name: The name of the queue to consume messages from</span>
<span class="sd"> :yield: The processed DataResponse for each message</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="c1"># Get a channel from the connection</span>
<span class="n">channel</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">rabbit_mq_client</span><span class="o">.</span><span class="n">channel</span>
<span class="n">queue_args</span> <span class="o">=</span> <span class="p">(</span>
<span class="bp">self</span><span class="o">.</span><span class="n">rabbit_mq_client</span><span class="o">.</span><span class="n">DLQ_ARGS</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">amq_configuration</span><span class="o">.</span><span class="n">dispatch</span><span class="o">.</span><span class="n">use_dlq</span> <span class="k">else</span> <span class="kc">None</span>
<span class="p">)</span>
<span class="n">queue</span> <span class="o">=</span> <span class="k">await</span> <span class="n">channel</span><span class="o">.</span><span class="n">declare_queue</span><span class="p">(</span>
<span class="n">route</span><span class="o">.</span><span class="n">queue</span><span class="p">,</span>
<span class="n">durable</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
<span class="n">exclusive</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
<span class="n">auto_delete</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
<span class="n">arguments</span><span class="o">=</span><span class="n">queue_args</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">await</span> <span class="n">queue</span><span class="o">.</span><span class="n">bind</span><span class="p">(</span><span class="n">route</span><span class="o">.</span><span class="n">exchange</span><span class="p">,</span> <span class="n">route</span><span class="o">.</span><span class="n">key</span><span class="p">)</span>
<span class="c1"># Start consuming without a callback</span>
<span class="k">async</span> <span class="k">with</span> <span class="n">queue</span><span class="o">.</span><span class="n">iterator</span><span class="p">()</span> <span class="k">as</span> <span class="n">queue_iter</span><span class="p">:</span>
<span class="k">async</span> <span class="k">for</span> <span class="n">message</span> <span class="ow">in</span> <span class="n">queue_iter</span><span class="p">:</span>
<span class="k">try</span><span class="p">:</span>
<span class="c1"># Process the message using the same logic as in inbound_data_message_callback_no_thread</span>
<span class="n">data_message</span><span class="p">:</span> <span class="n">DataMessage</span> <span class="o">=</span> <span class="p">(</span>
<span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">amq_data_message_handler</span><span class="o">.</span><span class="n">reconstitute_data_message</span><span class="p">(</span><span class="n">message</span><span class="p">)</span>
<span class="p">)</span>
<span class="n">success</span> <span class="o">=</span> <span class="k">yield</span> <span class="n">data_message</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">success</span><span class="p">:</span>
<span class="n">logging_warning</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Message processing failed for </span><span class="si">{</span><span class="n">data_message</span><span class="o">.</span><span class="n">id</span><span class="p">()</span><span class="si">}</span><span class="s2">.&quot;</span><span class="p">)</span>
<span class="c1"># Nack the message without requeuing in case of failure</span>
<span class="k">await</span> <span class="n">message</span><span class="o">.</span><span class="n">nack</span><span class="p">(</span><span class="n">requeue</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">await</span> <span class="n">message</span><span class="o">.</span><span class="n">ack</span><span class="p">()</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="n">logging_error</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Error processing message: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="c1"># Nack the message without requeuing in case of error</span>
<span class="k">await</span> <span class="n">message</span><span class="o">.</span><span class="n">nack</span><span class="p">(</span><span class="n">requeue</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span></div>
<div class="viewcode-block" id="AMQService.get_unique_instance_id">
<a class="viewcode-back" href="../../../modules/amqp.service.html#amqp.service.amq_service.AMQService.get_unique_instance_id">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">get_unique_instance_id</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Provides cluster-wide unique instance ID for this AMQ service instance.</span>
<span class="sd"> This ID is used to identify the service instance in the cluster and is unique across all instances.</span>
<span class="sd"> IDs are managed by shared Consul KV store, ensuring that even if multiple instances of the service are running,</span>
<span class="sd"> they will each have unique ID.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">unique_id</span></div>
<span class="c1"># =======================================================================</span>
<span class="c1"># ====================== Internal Methods ============================</span>
<span class="c1"># =======================================================================</span>
<div class="viewcode-block" id="AMQService.init">
<a class="viewcode-back" href="../../../modules/amqp.service.html#amqp.service.amq_service.AMQService.init">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">init</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">loop</span><span class="p">,</span> <span class="n">service_adapter</span><span class="p">):</span>
<span class="n">_reply_to_exchange</span><span class="p">:</span> <span class="n">AbstractRobustExchange</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">rabbit_mq_client</span><span class="o">.</span><span class="n">init</span><span class="p">(</span><span class="n">loop</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">backpressure_handler</span> <span class="o">=</span> <span class="n">BackpressureHandler</span><span class="p">(</span>
<span class="n">channel</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">rabbit_mq_client</span><span class="o">.</span><span class="n">channel</span><span class="p">,</span>
<span class="n">loop</span><span class="o">=</span><span class="n">loop</span><span class="p">,</span>
<span class="n">config</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">amq_configuration</span><span class="p">,</span>
<span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">amq_data_message_handler</span> <span class="o">=</span> <span class="n">DataMessageHandler</span><span class="p">(</span>
<span class="n">service_adapter</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">tracer</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">data_message_factory</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">service_message_factory</span><span class="p">,</span>
<span class="n">_reply_to_exchange</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">rabbit_mq_client</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">amq_configuration</span><span class="p">,</span>
<span class="n">loop</span><span class="o">=</span><span class="n">loop</span><span class="p">,</span>
<span class="n">backpressure_handler</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">backpressure_handler</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">register_routes</span><span class="p">()</span>
<span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">rabbit_mq_client</span><span class="o">.</span><span class="n">request_routes</span><span class="p">()</span>
<span class="n">logging_info</span><span class="p">(</span><span class="s2">&quot;Starting backpressure monitor thread&quot;</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">backpressure_thread</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">backpressure_handler</span><span class="o">.</span><span class="n">start_backpressure_monitor</span><span class="p">()</span></div>
<div class="viewcode-block" id="AMQService.cleanup">
<a class="viewcode-back" href="../../../modules/amqp.service.html#amqp.service.amq_service.AMQService.cleanup">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">cleanup</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">logging_info</span><span class="p">(</span><span class="s2">&quot;AMQService.cleanup() rmqc=</span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">rabbit_mq_client</span><span class="p">)</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">rabbit_mq_client</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">rabbit_mq_client</span><span class="o">.</span><span class="n">cleanup</span><span class="p">()</span></div>
<div class="viewcode-block" id="AMQService.reinitialize_if_disconnected">
<a class="viewcode-back" href="../../../modules/amqp.service.html#amqp.service.amq_service.AMQService.reinitialize_if_disconnected">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">reinitialize_if_disconnected</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">rabbit_mq_client</span><span class="o">.</span><span class="n">channel</span> <span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">rabbit_mq_client</span><span class="o">.</span><span class="n">channel</span><span class="o">.</span><span class="n">is_closed</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">rabbit_mq_client</span> <span class="o">=</span> <span class="n">RabbitMQClient</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">amq_configuration</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">router</span><span class="p">)</span>
<span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">rabbit_mq_client</span><span class="o">.</span><span class="n">init</span><span class="p">(</span><span class="n">loop</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">loop</span><span class="p">)</span>
<span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">register_routes</span><span class="p">()</span>
<span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">rabbit_mq_client</span><span class="o">.</span><span class="n">request_routes</span><span class="p">()</span></div>
<div class="viewcode-block" id="AMQService.register_routes">
<a class="viewcode-back" href="../../../modules/amqp.service.html#amqp.service.amq_service.AMQService.register_routes">[docs]</a>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">register_routes</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">AbstractRobustExchange</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">route_mapping</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">amq_configuration</span><span class="o">.</span><span class="n">amq_adapter</span><span class="o">.</span><span class="n">route_mapping</span>
<span class="k">if</span> <span class="n">AMQRouteFactory</span><span class="o">.</span><span class="n">validate</span><span class="p">(</span><span class="n">route_mapping</span><span class="p">):</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">rabbit_mq_client</span><span class="o">.</span><span class="n">register_inbound_routes</span><span class="p">(</span>
<span class="n">route_mapping</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">amq_data_message_handler</span><span class="o">.</span><span class="n">inbound_data_message_callback_no_thread</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">return</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">rabbit_mq_client</span><span class="o">.</span><span class="n">register_data_reply_callback</span><span class="p">(</span>
<span class="bp">self</span><span class="o">.</span><span class="n">amq_data_message_handler</span><span class="o">.</span><span class="n">reply_received_callback</span>
<span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span><span class="n">e</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">route_mapping</span><span class="p">:</span>
<span class="n">logging_warning</span><span class="p">(</span>
<span class="s2">&quot;route [</span><span class="si">%s</span><span class="s2">] failed validation, no routes were registered.&quot;</span><span class="p">,</span>
<span class="n">route_mapping</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">return</span> <span class="kc">None</span></div>
<div class="viewcode-block" id="AMQService.set_outstanding_future">
<a class="viewcode-back" href="../../../modules/amqp.service.html#amqp.service.amq_service.AMQService.set_outstanding_future">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">set_outstanding_future</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">DataMessage</span><span class="p">,</span> <span class="n">future</span><span class="p">:</span> <span class="n">Future</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">amq_data_message_handler</span><span class="o">.</span><span class="n">outstanding</span><span class="p">[</span><span class="nb">str</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">id</span><span class="p">())]</span> <span class="o">=</span> <span class="n">future</span></div>
<div class="viewcode-block" id="AMQService.remove_outstanding_future">
<a class="viewcode-back" href="../../../modules/amqp.service.html#amqp.service.amq_service.AMQService.remove_outstanding_future">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">remove_outstanding_future</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message_id</span><span class="p">:</span> <span class="nb">str</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">amq_data_message_handler</span><span class="o">.</span><span class="n">outstanding</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="n">message_id</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span></div>
</div>
</pre></div>
</div>
</div>
<footer>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2024, CleverThis.</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>
@@ -0,0 +1,327 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" data-content_root="../../../">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>amqp.service.tracing &mdash; AMQ Adapter Python 1.0 documentation</title>
<link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=03e43079" />
<link rel="stylesheet" type="text/css" href="../../../_static/css/theme.css?v=e59714d7" />
<script src="../../../_static/jquery.js?v=5d32c60e"></script>
<script src="../../../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
<script src="../../../_static/documentation_options.js?v=f2a433a1"></script>
<script src="../../../_static/doctools.js?v=9bcbadda"></script>
<script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
<script src="../../../_static/js/theme.js"></script>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="../../../index.html" class="icon icon-home">
AMQ Adapter Python
</a>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" aria-label="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.html">AMQP Package</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.config.html">Configuration Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.adapter.html">Adapter Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.service.html">Service Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.router.html">Router Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.model.html">Model Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules/amqp.rabbitmq.html">RabbitMQ Module</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="../../../index.html">AMQ Adapter Python</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="../../../index.html" class="icon icon-home" aria-label="Home"></a></li>
<li class="breadcrumb-item"><a href="../../index.html">Module code</a></li>
<li class="breadcrumb-item active">amqp.service.tracing</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<h1>Source code for amqp.service.tracing</h1><div class="highlight"><pre>
<span></span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">OpenTelemetry configuration for tracing and metrics.</span>
<span class="sd">This module provides functionality to initialize and configure OpenTelemetry</span>
<span class="sd">for both tracing (Jaeger via OTLP) and metrics (Prometheus) in the AMQ adapter.</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">logging</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">os</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">dataclasses</span><span class="w"> </span><span class="kn">import</span> <span class="n">dataclass</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Any</span><span class="p">,</span> <span class="n">Dict</span><span class="p">,</span> <span class="n">Optional</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">opentelemetry</span><span class="w"> </span><span class="kn">import</span> <span class="n">metrics</span><span class="p">,</span> <span class="n">trace</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">opentelemetry.exporter.otlp.proto.grpc.trace_exporter</span><span class="w"> </span><span class="kn">import</span> <span class="n">OTLPSpanExporter</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">opentelemetry.exporter.prometheus</span><span class="w"> </span><span class="kn">import</span> <span class="n">PrometheusMetricReader</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">opentelemetry.sdk.metrics</span><span class="w"> </span><span class="kn">import</span> <span class="n">MeterProvider</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">opentelemetry.sdk.metrics.export</span><span class="w"> </span><span class="kn">import</span> <span class="n">PeriodicExportingMetricReader</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">opentelemetry.sdk.resources</span><span class="w"> </span><span class="kn">import</span> <span class="n">SERVICE_NAME</span><span class="p">,</span> <span class="n">SERVICE_VERSION</span><span class="p">,</span> <span class="n">Resource</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">opentelemetry.sdk.trace</span><span class="w"> </span><span class="kn">import</span> <span class="n">TracerProvider</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">opentelemetry.sdk.trace.export</span><span class="w"> </span><span class="kn">import</span> <span class="n">BatchSpanProcessor</span><span class="p">,</span> <span class="n">ConsoleSpanExporter</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">opentelemetry.trace</span><span class="w"> </span><span class="kn">import</span> <span class="n">Tracer</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">prometheus_client</span><span class="w"> </span><span class="kn">import</span> <span class="n">start_http_server</span>
<span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="vm">__name__</span><span class="p">)</span>
<div class="viewcode-block" id="TracingConfig">
<a class="viewcode-back" href="../../../modules/amqp.service.html#amqp.service.tracing.TracingConfig">[docs]</a>
<span class="nd">@dataclass</span>
<span class="k">class</span><span class="w"> </span><span class="nc">TracingConfig</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Configuration for OpenTelemetry tracing.&quot;&quot;&quot;</span>
<span class="n">service_name</span><span class="p">:</span> <span class="nb">str</span>
<span class="n">service_version</span><span class="p">:</span> <span class="nb">str</span>
<span class="n">otlp_endpoint</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">&quot;http://localhost:4317&quot;</span> <span class="c1"># Default Jaeger OTLP endpoint</span>
<span class="n">insecure</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">True</span>
<span class="n">debug</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span>
<span class="n">additional_attributes</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]]</span> <span class="o">=</span> <span class="kc">None</span></div>
<div class="viewcode-block" id="MetricsConfig">
<a class="viewcode-back" href="../../../modules/amqp.service.html#amqp.service.tracing.MetricsConfig">[docs]</a>
<span class="nd">@dataclass</span>
<span class="k">class</span><span class="w"> </span><span class="nc">MetricsConfig</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Configuration for OpenTelemetry metrics.&quot;&quot;&quot;</span>
<span class="n">prometheus_port</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">9464</span>
<span class="n">prometheus_host</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">&quot;localhost&quot;</span>
<span class="n">export_interval_millis</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">30000</span>
<span class="n">additional_attributes</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]]</span> <span class="o">=</span> <span class="kc">None</span></div>
<div class="viewcode-block" id="create_resource">
<a class="viewcode-back" href="../../../modules/amqp.service.html#amqp.service.tracing.create_resource">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">create_resource</span><span class="p">(</span><span class="n">config</span><span class="p">:</span> <span class="n">TracingConfig</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Resource</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Create an OpenTelemetry resource with service information.&quot;&quot;&quot;</span>
<span class="n">attributes</span> <span class="o">=</span> <span class="p">{</span>
<span class="n">SERVICE_NAME</span><span class="p">:</span> <span class="n">config</span><span class="o">.</span><span class="n">service_name</span><span class="p">,</span>
<span class="n">SERVICE_VERSION</span><span class="p">:</span> <span class="n">config</span><span class="o">.</span><span class="n">service_version</span><span class="p">,</span>
<span class="p">}</span>
<span class="k">if</span> <span class="n">config</span><span class="o">.</span><span class="n">additional_attributes</span><span class="p">:</span>
<span class="n">attributes</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">config</span><span class="o">.</span><span class="n">additional_attributes</span><span class="p">)</span>
<span class="k">return</span> <span class="n">Resource</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">attributes</span><span class="p">)</span></div>
<div class="viewcode-block" id="setup_otlp_exporter">
<a class="viewcode-back" href="../../../modules/amqp.service.html#amqp.service.tracing.setup_otlp_exporter">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">setup_otlp_exporter</span><span class="p">(</span><span class="n">config</span><span class="p">:</span> <span class="n">TracingConfig</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">OTLPSpanExporter</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Configure and create an OTLP exporter for Jaeger.&quot;&quot;&quot;</span>
<span class="k">return</span> <span class="n">OTLPSpanExporter</span><span class="p">(</span><span class="n">endpoint</span><span class="o">=</span><span class="n">config</span><span class="o">.</span><span class="n">otlp_endpoint</span><span class="p">,</span> <span class="n">insecure</span><span class="o">=</span><span class="n">config</span><span class="o">.</span><span class="n">insecure</span><span class="p">)</span></div>
<div class="viewcode-block" id="setup_trace_provider">
<a class="viewcode-back" href="../../../modules/amqp.service.html#amqp.service.tracing.setup_trace_provider">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">setup_trace_provider</span><span class="p">(</span><span class="n">config</span><span class="p">:</span> <span class="n">TracingConfig</span><span class="p">,</span> <span class="n">resource</span><span class="p">:</span> <span class="n">Resource</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">TracerProvider</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Set up the TracerProvider with OTLP exporter.&quot;&quot;&quot;</span>
<span class="n">provider</span> <span class="o">=</span> <span class="n">TracerProvider</span><span class="p">(</span><span class="n">resource</span><span class="o">=</span><span class="n">resource</span><span class="p">)</span>
<span class="c1"># Add OTLP exporter for Jaeger</span>
<span class="n">otlp_exporter</span> <span class="o">=</span> <span class="n">setup_otlp_exporter</span><span class="p">(</span><span class="n">config</span><span class="p">)</span>
<span class="n">provider</span><span class="o">.</span><span class="n">add_span_processor</span><span class="p">(</span><span class="n">BatchSpanProcessor</span><span class="p">(</span><span class="n">otlp_exporter</span><span class="p">))</span>
<span class="c1"># Add console exporter in debug mode</span>
<span class="k">if</span> <span class="n">config</span><span class="o">.</span><span class="n">debug</span><span class="p">:</span>
<span class="n">provider</span><span class="o">.</span><span class="n">add_span_processor</span><span class="p">(</span><span class="n">BatchSpanProcessor</span><span class="p">(</span><span class="n">ConsoleSpanExporter</span><span class="p">()))</span>
<span class="k">return</span> <span class="n">provider</span></div>
<div class="viewcode-block" id="setup_metrics_provider">
<a class="viewcode-back" href="../../../modules/amqp.service.html#amqp.service.tracing.setup_metrics_provider">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">setup_metrics_provider</span><span class="p">(</span><span class="n">config</span><span class="p">:</span> <span class="n">MetricsConfig</span><span class="p">,</span> <span class="n">resource</span><span class="p">:</span> <span class="n">Resource</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">MeterProvider</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Set up the MeterProvider with Prometheus export.&quot;&quot;&quot;</span>
<span class="k">try</span><span class="p">:</span>
<span class="c1"># Start Prometheus HTTP server</span>
<span class="n">start_http_server</span><span class="p">(</span><span class="n">port</span><span class="o">=</span><span class="n">config</span><span class="o">.</span><span class="n">prometheus_port</span><span class="p">,</span> <span class="n">addr</span><span class="o">=</span><span class="n">config</span><span class="o">.</span><span class="n">prometheus_host</span><span class="p">)</span>
<span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;Started Prometheus metrics server on </span><span class="si">{</span><span class="n">config</span><span class="o">.</span><span class="n">prometheus_host</span><span class="si">}</span><span class="s2">:</span><span class="si">{</span><span class="n">config</span><span class="o">.</span><span class="n">prometheus_port</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="p">)</span>
<span class="c1"># Create Prometheus reader</span>
<span class="n">prometheus_reader</span> <span class="o">=</span> <span class="n">PrometheusMetricReader</span><span class="p">()</span>
<span class="c1"># Create periodic reader for custom metrics</span>
<span class="n">periodic_reader</span> <span class="o">=</span> <span class="n">PeriodicExportingMetricReader</span><span class="p">(</span>
<span class="n">prometheus_reader</span><span class="p">,</span> <span class="n">export_interval_millis</span><span class="o">=</span><span class="n">config</span><span class="o">.</span><span class="n">export_interval_millis</span>
<span class="p">)</span>
<span class="c1"># Create and configure meter provider</span>
<span class="k">return</span> <span class="n">MeterProvider</span><span class="p">(</span><span class="n">resource</span><span class="o">=</span><span class="n">resource</span><span class="p">,</span> <span class="n">metric_readers</span><span class="o">=</span><span class="p">[</span><span class="n">prometheus_reader</span><span class="p">,</span> <span class="n">periodic_reader</span><span class="p">])</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="n">logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Failed to set up metrics provider: </span><span class="si">{</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="c1"># Return a no-op meter provider</span>
<span class="k">return</span> <span class="n">MeterProvider</span><span class="p">(</span><span class="n">resource</span><span class="o">=</span><span class="n">resource</span><span class="p">)</span></div>
<div class="viewcode-block" id="initialize_telemetry">
<a class="viewcode-back" href="../../../modules/amqp.service.html#amqp.service.tracing.initialize_telemetry">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">initialize_telemetry</span><span class="p">(</span>
<span class="n">tracing_config</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">TracingConfig</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
<span class="n">metrics_config</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">MetricsConfig</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
<span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Tracer</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Initialize OpenTelemetry with tracing and metrics.</span>
<span class="sd"> Args:</span>
<span class="sd"> tracing_config: Configuration for tracing</span>
<span class="sd"> metrics_config: Configuration for metrics</span>
<span class="sd"> Returns:</span>
<span class="sd"> Tracer: Configured OpenTelemetry tracer</span>
<span class="sd"> Example:</span>
<span class="sd"> ```python</span>
<span class="sd"> config = TracingConfig(</span>
<span class="sd"> service_name=&quot;amq-adapter&quot;,</span>
<span class="sd"> service_version=&quot;1.0.0&quot;,</span>
<span class="sd"> otlp_endpoint=&quot;http://jaeger:4317&quot;,</span>
<span class="sd"> debug=True</span>
<span class="sd"> )</span>
<span class="sd"> metrics_config = MetricsConfig(</span>
<span class="sd"> prometheus_port=9464,</span>
<span class="sd"> prometheus_host=&quot;0.0.0.0&quot;</span>
<span class="sd"> )</span>
<span class="sd"> tracer = initialize_telemetry(config, metrics_config)</span>
<span class="sd"> ```</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="c1"># Use default configs if none provided</span>
<span class="k">if</span> <span class="n">tracing_config</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">tracing_config</span> <span class="o">=</span> <span class="n">TracingConfig</span><span class="p">(</span>
<span class="n">service_name</span><span class="o">=</span><span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span><span class="s2">&quot;SERVICE_NAME&quot;</span><span class="p">,</span> <span class="s2">&quot;amq-adapter&quot;</span><span class="p">),</span>
<span class="n">service_version</span><span class="o">=</span><span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span><span class="s2">&quot;SERVICE_VERSION&quot;</span><span class="p">,</span> <span class="s2">&quot;unknown&quot;</span><span class="p">),</span>
<span class="n">otlp_endpoint</span><span class="o">=</span><span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span><span class="s2">&quot;OTEL_EXPORTER_OTLP_ENDPOINT&quot;</span><span class="p">,</span> <span class="s2">&quot;http://localhost:4317&quot;</span><span class="p">),</span>
<span class="n">insecure</span><span class="o">=</span><span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span><span class="s2">&quot;OTEL_INSECURE_MODE&quot;</span><span class="p">,</span> <span class="s2">&quot;true&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="o">==</span> <span class="s2">&quot;true&quot;</span><span class="p">,</span>
<span class="n">debug</span><span class="o">=</span><span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span><span class="s2">&quot;OTEL_DEBUG&quot;</span><span class="p">,</span> <span class="s2">&quot;false&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="o">==</span> <span class="s2">&quot;true&quot;</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">if</span> <span class="n">metrics_config</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">metrics_config</span> <span class="o">=</span> <span class="n">MetricsConfig</span><span class="p">(</span>
<span class="n">prometheus_port</span><span class="o">=</span><span class="nb">int</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span><span class="s2">&quot;PROMETHEUS_PORT&quot;</span><span class="p">,</span> <span class="s2">&quot;9464&quot;</span><span class="p">)),</span>
<span class="n">prometheus_host</span><span class="o">=</span><span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span><span class="s2">&quot;PROMETHEUS_HOST&quot;</span><span class="p">,</span> <span class="s2">&quot;localhost&quot;</span><span class="p">),</span>
<span class="n">export_interval_millis</span><span class="o">=</span><span class="nb">int</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span><span class="s2">&quot;METRICS_EXPORT_INTERVAL&quot;</span><span class="p">,</span> <span class="s2">&quot;30000&quot;</span><span class="p">)),</span>
<span class="p">)</span>
<span class="k">try</span><span class="p">:</span>
<span class="c1"># Create resource</span>
<span class="n">resource</span> <span class="o">=</span> <span class="n">create_resource</span><span class="p">(</span><span class="n">tracing_config</span><span class="p">)</span>
<span class="c1"># Set up tracing</span>
<span class="n">provider</span> <span class="o">=</span> <span class="n">setup_trace_provider</span><span class="p">(</span><span class="n">tracing_config</span><span class="p">,</span> <span class="n">resource</span><span class="p">)</span>
<span class="n">trace</span><span class="o">.</span><span class="n">set_tracer_provider</span><span class="p">(</span><span class="n">provider</span><span class="p">)</span>
<span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Initialized tracing for service </span><span class="si">{</span><span class="n">tracing_config</span><span class="o">.</span><span class="n">service_name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="c1"># Set up metrics</span>
<span class="n">metrics_provider</span> <span class="o">=</span> <span class="n">setup_metrics_provider</span><span class="p">(</span><span class="n">metrics_config</span><span class="p">,</span> <span class="n">resource</span><span class="p">)</span>
<span class="n">metrics</span><span class="o">.</span><span class="n">set_meter_provider</span><span class="p">(</span><span class="n">metrics_provider</span><span class="p">)</span>
<span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s2">&quot;Initialized metrics export&quot;</span><span class="p">)</span>
<span class="c1"># Return configured tracer</span>
<span class="k">return</span> <span class="n">trace</span><span class="o">.</span><span class="n">get_tracer</span><span class="p">(</span>
<span class="n">tracing_config</span><span class="o">.</span><span class="n">service_name</span><span class="p">,</span>
<span class="n">tracing_config</span><span class="o">.</span><span class="n">service_version</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="n">logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Failed to initialize telemetry: </span><span class="si">{</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="c1"># Return a no-op tracer in case of failure</span>
<span class="k">return</span> <span class="n">trace</span><span class="o">.</span><span class="n">get_tracer</span><span class="p">(</span><span class="s2">&quot;no-op&quot;</span><span class="p">)</span></div>
<div class="viewcode-block" id="create_span">
<a class="viewcode-back" href="../../../modules/amqp.service.html#amqp.service.tracing.create_span">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">create_span</span><span class="p">(</span><span class="n">tracer</span><span class="p">:</span> <span class="n">Tracer</span><span class="p">,</span> <span class="n">name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">attributes</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Create a new span with the given name and attributes.</span>
<span class="sd"> Args:</span>
<span class="sd"> tracer: The OpenTelemetry tracer</span>
<span class="sd"> name: Name of the span</span>
<span class="sd"> attributes: Optional attributes to add to the span</span>
<span class="sd"> Returns:</span>
<span class="sd"> A context manager that creates and manages a span</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="n">tracer</span><span class="o">.</span><span class="n">start_as_current_span</span><span class="p">(</span>
<span class="n">name</span><span class="p">,</span>
<span class="n">attributes</span><span class="o">=</span><span class="n">attributes</span> <span class="ow">or</span> <span class="p">{},</span>
<span class="p">)</span></div>
</pre></div>
</div>
</div>
<footer>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2024, CleverThis.</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>
+134
View File
@@ -0,0 +1,134 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" data-content_root="../">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Overview: module code &mdash; AMQ Adapter Python 1.0 documentation</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css?v=03e43079" />
<link rel="stylesheet" type="text/css" href="../_static/css/theme.css?v=e59714d7" />
<script src="../_static/jquery.js?v=5d32c60e"></script>
<script src="../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
<script src="../_static/documentation_options.js?v=f2a433a1"></script>
<script src="../_static/doctools.js?v=9bcbadda"></script>
<script src="../_static/sphinx_highlight.js?v=dc90522c"></script>
<script src="../_static/js/theme.js"></script>
<link rel="index" title="Index" href="../genindex.html" />
<link rel="search" title="Search" href="../search.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="../index.html" class="icon icon-home">
AMQ Adapter Python
</a>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" aria-label="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../modules/amqp.html">AMQP Package</a></li>
<li class="toctree-l1"><a class="reference internal" href="../modules/amqp.config.html">Configuration Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../modules/amqp.adapter.html">Adapter Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../modules/amqp.service.html">Service Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../modules/amqp.router.html">Router Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../modules/amqp.model.html">Model Module</a></li>
<li class="toctree-l1"><a class="reference internal" href="../modules/amqp.rabbitmq.html">RabbitMQ Module</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="../index.html">AMQ Adapter Python</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li>
<li class="breadcrumb-item active">Overview: module code</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<h1>All modules for which code is available</h1>
<ul><li><a href="amqp/adapter/amq_route_factory.html">amqp.adapter.amq_route_factory</a></li>
<li><a href="amqp/adapter/backpressure_handler.html">amqp.adapter.backpressure_handler</a></li>
<li><a href="amqp/adapter/cleverthis_service_adapter.html">amqp.adapter.cleverthis_service_adapter</a></li>
<li><a href="amqp/adapter/consul_global_id_generator.html">amqp.adapter.consul_global_id_generator</a></li>
<li><a href="amqp/adapter/data_message_factory.html">amqp.adapter.data_message_factory</a></li>
<li><a href="amqp/adapter/data_parser.html">amqp.adapter.data_parser</a></li>
<li><a href="amqp/adapter/data_response_factory.html">amqp.adapter.data_response_factory</a></li>
<li><a href="amqp/adapter/file_handler.html">amqp.adapter.file_handler</a></li>
<li><a href="amqp/adapter/logging_utils.html">amqp.adapter.logging_utils</a></li>
<li><a href="amqp/adapter/pydantic_serializer.html">amqp.adapter.pydantic_serializer</a></li>
<li><a href="amqp/adapter/serializer.html">amqp.adapter.serializer</a></li>
<li><a href="amqp/adapter/service_message_factory.html">amqp.adapter.service_message_factory</a></li>
<li><a href="amqp/adapter/trace_info_adapter.html">amqp.adapter.trace_info_adapter</a></li>
<li><a href="amqp/adapter/type_descriptor.html">amqp.adapter.type_descriptor</a></li>
<li><a href="amqp/config/amq_configuration.html">amqp.config.amq_configuration</a></li>
<li><a href="amqp/model/model.html">amqp.model.model</a></li>
<li><a href="amqp/model/service_message_type.html">amqp.model.service_message_type</a></li>
<li><a href="amqp/model/snowflake_id.html">amqp.model.snowflake_id</a></li>
<li><a href="amqp/rabbitmq/rabbit_mq_client.html">amqp.rabbitmq.rabbit_mq_client</a></li>
<li><a href="amqp/rabbitmq/user_management_service_client.html">amqp.rabbitmq.user_management_service_client</a></li>
<li><a href="amqp/router/route_database.html">amqp.router.route_database</a></li>
<li><a href="amqp/router/router_base.html">amqp.router.router_base</a></li>
<li><a href="amqp/router/router_consumer.html">amqp.router.router_consumer</a></li>
<li><a href="amqp/router/router_producer.html">amqp.router.router_producer</a></li>
<li><a href="amqp/router/utils.html">amqp.router.utils</a></li>
<li><a href="amqp/service/amq_message_handler.html">amqp.service.amq_message_handler</a></li>
<li><a href="amqp/service/amq_service.html">amqp.service.amq_service</a></li>
<li><a href="amqp/service/tracing.html">amqp.service.tracing</a></li>
</ul>
</div>
</div>
<footer>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2024, CleverThis.</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>
@@ -0,0 +1,23 @@
AMQ Adapter Python API Documentation
====================================
Welcome to the AMQ Adapter Python API documentation. This library provides a Python implementation of the AMQ adapter for routing traffic over RabbitMQ to intended services with automated service discovery.
.. toctree::
:maxdepth: 2
:caption: Contents:
modules/amqp
modules/amqp.config
modules/amqp.adapter
modules/amqp.service
modules/amqp.router
modules/amqp.model
modules/amqp.rabbitmq
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
@@ -0,0 +1,77 @@
Adapter Module
=============
.. automodule:: amqp.adapter
:members:
:undoc-members:
:show-inheritance:
.. automodule:: amqp.adapter.cleverthis_service_adapter
:members:
:undoc-members:
:show-inheritance:
.. automodule:: amqp.adapter.amq_route_factory
:members:
:undoc-members:
:show-inheritance:
.. automodule:: amqp.adapter.backpressure_handler
:members:
:undoc-members:
:show-inheritance:
.. automodule:: amqp.adapter.consul_global_id_generator
:members:
:undoc-members:
:show-inheritance:
.. automodule:: amqp.adapter.data_message_factory
:members:
:undoc-members:
:show-inheritance:
.. automodule:: amqp.adapter.data_parser
:members:
:undoc-members:
:show-inheritance:
.. automodule:: amqp.adapter.data_response_factory
:members:
:undoc-members:
:show-inheritance:
.. automodule:: amqp.adapter.file_handler
:members:
:undoc-members:
:show-inheritance:
.. automodule:: amqp.adapter.logging_utils
:members:
:undoc-members:
:show-inheritance:
.. automodule:: amqp.adapter.pydantic_serializer
:members:
:undoc-members:
:show-inheritance:
.. automodule:: amqp.adapter.serializer
:members:
:undoc-members:
:show-inheritance:
.. automodule:: amqp.adapter.service_message_factory
:members:
:undoc-members:
:show-inheritance:
.. automodule:: amqp.adapter.trace_info_adapter
:members:
:undoc-members:
:show-inheritance:
.. automodule:: amqp.adapter.type_descriptor
:members:
:undoc-members:
:show-inheritance:
@@ -0,0 +1,12 @@
Configuration Module
===================
.. automodule:: amqp.config
:members:
:undoc-members:
:show-inheritance:
.. automodule:: amqp.config.amq_configuration
:members:
:undoc-members:
:show-inheritance:
@@ -0,0 +1,22 @@
Model Module
===========
.. automodule:: amqp.model
:members:
:undoc-members:
:show-inheritance:
.. automodule:: amqp.model.model
:members:
:undoc-members:
:show-inheritance:
.. automodule:: amqp.model.service_message_type
:members:
:undoc-members:
:show-inheritance:
.. automodule:: amqp.model.snowflake_id
:members:
:undoc-members:
:show-inheritance:
@@ -0,0 +1,17 @@
RabbitMQ Module
==============
.. automodule:: amqp.rabbitmq
:members:
:undoc-members:
:show-inheritance:
.. automodule:: amqp.rabbitmq.rabbit_mq_client
:members:
:undoc-members:
:show-inheritance:
.. automodule:: amqp.rabbitmq.user_management_service_client
:members:
:undoc-members:
:show-inheritance:
@@ -0,0 +1,32 @@
Router Module
============
.. automodule:: amqp.router
:members:
:undoc-members:
:show-inheritance:
.. automodule:: amqp.router.router_base
:members:
:undoc-members:
:show-inheritance:
.. automodule:: amqp.router.router_consumer
:members:
:undoc-members:
:show-inheritance:
.. automodule:: amqp.router.router_producer
:members:
:undoc-members:
:show-inheritance:
.. automodule:: amqp.router.route_database
:members:
:undoc-members:
:show-inheritance:
.. automodule:: amqp.router.utils
:members:
:undoc-members:
:show-inheritance:
@@ -0,0 +1,7 @@
AMQP Package
===========
.. automodule:: amqp
:members:
:undoc-members:
:show-inheritance:
@@ -0,0 +1,22 @@
Service Module
=============
.. automodule:: amqp.service
:members:
:undoc-members:
:show-inheritance:
.. automodule:: amqp.service.amq_service
:members:
:undoc-members:
:show-inheritance:
.. automodule:: amqp.service.amq_message_handler
:members:
:undoc-members:
:show-inheritance:
.. automodule:: amqp.service.tracing
:members:
:undoc-members:
:show-inheritance:
@@ -0,0 +1,123 @@
/* Compatability shim for jQuery and underscores.js.
*
* Copyright Sphinx contributors
* Released under the two clause BSD licence
*/
/**
* small helper function to urldecode strings
*
* See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL
*/
jQuery.urldecode = function(x) {
if (!x) {
return x
}
return decodeURIComponent(x.replace(/\+/g, ' '));
};
/**
* small helper function to urlencode strings
*/
jQuery.urlencode = encodeURIComponent;
/**
* This function returns the parsed url parameters of the
* current request. Multiple values per key are supported,
* it will always return arrays of strings for the value parts.
*/
jQuery.getQueryParameters = function(s) {
if (typeof s === 'undefined')
s = document.location.search;
var parts = s.substr(s.indexOf('?') + 1).split('&');
var result = {};
for (var i = 0; i < parts.length; i++) {
var tmp = parts[i].split('=', 2);
var key = jQuery.urldecode(tmp[0]);
var value = jQuery.urldecode(tmp[1]);
if (key in result)
result[key].push(value);
else
result[key] = [value];
}
return result;
};
/**
* highlight a given string on a jquery object by wrapping it in
* span elements with the given class name.
*/
jQuery.fn.highlightText = function(text, className) {
function highlight(node, addItems) {
if (node.nodeType === 3) {
var val = node.nodeValue;
var pos = val.toLowerCase().indexOf(text);
if (pos >= 0 &&
!jQuery(node.parentNode).hasClass(className) &&
!jQuery(node.parentNode).hasClass("nohighlight")) {
var span;
var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg");
if (isInSVG) {
span = document.createElementNS("http://www.w3.org/2000/svg", "tspan");
} else {
span = document.createElement("span");
span.className = className;
}
span.appendChild(document.createTextNode(val.substr(pos, text.length)));
node.parentNode.insertBefore(span, node.parentNode.insertBefore(
document.createTextNode(val.substr(pos + text.length)),
node.nextSibling));
node.nodeValue = val.substr(0, pos);
if (isInSVG) {
var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
var bbox = node.parentElement.getBBox();
rect.x.baseVal.value = bbox.x;
rect.y.baseVal.value = bbox.y;
rect.width.baseVal.value = bbox.width;
rect.height.baseVal.value = bbox.height;
rect.setAttribute('class', className);
addItems.push({
"parent": node.parentNode,
"target": rect});
}
}
}
else if (!jQuery(node).is("button, select, textarea")) {
jQuery.each(node.childNodes, function() {
highlight(this, addItems);
});
}
}
var addItems = [];
var result = this.each(function() {
highlight(this, addItems);
});
for (var i = 0; i < addItems.length; ++i) {
jQuery(addItems[i].parent).before(addItems[i].target);
}
return result;
};
/*
* backward compatibility for jQuery.browser
* This will be supported until firefox bug is fixed.
*/
if (!jQuery.browser) {
jQuery.uaMatch = function(ua) {
ua = ua.toLowerCase();
var match = /(chrome)[ \/]([\w.]+)/.exec(ua) ||
/(webkit)[ \/]([\w.]+)/.exec(ua) ||
/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) ||
/(msie) ([\w.]+)/.exec(ua) ||
ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) ||
[];
return {
browser: match[ 1 ] || "",
version: match[ 2 ] || "0"
};
};
jQuery.browser = {};
jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true;
}
+906
View File
@@ -0,0 +1,906 @@
/*
* Sphinx stylesheet -- basic theme.
*/
/* -- main layout ----------------------------------------------------------- */
div.clearer {
clear: both;
}
div.section::after {
display: block;
content: '';
clear: left;
}
/* -- relbar ---------------------------------------------------------------- */
div.related {
width: 100%;
font-size: 90%;
}
div.related h3 {
display: none;
}
div.related ul {
margin: 0;
padding: 0 0 0 10px;
list-style: none;
}
div.related li {
display: inline;
}
div.related li.right {
float: right;
margin-right: 5px;
}
/* -- sidebar --------------------------------------------------------------- */
div.sphinxsidebarwrapper {
padding: 10px 5px 0 10px;
}
div.sphinxsidebar {
float: left;
width: 230px;
margin-left: -100%;
font-size: 90%;
word-wrap: break-word;
overflow-wrap : break-word;
}
div.sphinxsidebar ul {
list-style: none;
}
div.sphinxsidebar ul ul,
div.sphinxsidebar ul.want-points {
margin-left: 20px;
list-style: square;
}
div.sphinxsidebar ul ul {
margin-top: 0;
margin-bottom: 0;
}
div.sphinxsidebar form {
margin-top: 10px;
}
div.sphinxsidebar input {
border: 1px solid #98dbcc;
font-family: sans-serif;
font-size: 1em;
}
div.sphinxsidebar #searchbox form.search {
overflow: hidden;
}
div.sphinxsidebar #searchbox input[type="text"] {
float: left;
width: 80%;
padding: 0.25em;
box-sizing: border-box;
}
div.sphinxsidebar #searchbox input[type="submit"] {
float: left;
width: 20%;
border-left: none;
padding: 0.25em;
box-sizing: border-box;
}
img {
border: 0;
max-width: 100%;
}
/* -- search page ----------------------------------------------------------- */
ul.search {
margin-top: 10px;
}
ul.search li {
padding: 5px 0;
}
ul.search li a {
font-weight: bold;
}
ul.search li p.context {
color: #888;
margin: 2px 0 0 30px;
text-align: left;
}
ul.keywordmatches li.goodmatch a {
font-weight: bold;
}
/* -- index page ------------------------------------------------------------ */
table.contentstable {
width: 90%;
margin-left: auto;
margin-right: auto;
}
table.contentstable p.biglink {
line-height: 150%;
}
a.biglink {
font-size: 1.3em;
}
span.linkdescr {
font-style: italic;
padding-top: 5px;
font-size: 90%;
}
/* -- general index --------------------------------------------------------- */
table.indextable {
width: 100%;
}
table.indextable td {
text-align: left;
vertical-align: top;
}
table.indextable ul {
margin-top: 0;
margin-bottom: 0;
list-style-type: none;
}
table.indextable > tbody > tr > td > ul {
padding-left: 0em;
}
table.indextable tr.pcap {
height: 10px;
}
table.indextable tr.cap {
margin-top: 10px;
background-color: #f2f2f2;
}
img.toggler {
margin-right: 3px;
margin-top: 3px;
cursor: pointer;
}
div.modindex-jumpbox {
border-top: 1px solid #ddd;
border-bottom: 1px solid #ddd;
margin: 1em 0 1em 0;
padding: 0.4em;
}
div.genindex-jumpbox {
border-top: 1px solid #ddd;
border-bottom: 1px solid #ddd;
margin: 1em 0 1em 0;
padding: 0.4em;
}
/* -- domain module index --------------------------------------------------- */
table.modindextable td {
padding: 2px;
border-collapse: collapse;
}
/* -- general body styles --------------------------------------------------- */
div.body {
min-width: 360px;
max-width: 800px;
}
div.body p, div.body dd, div.body li, div.body blockquote {
-moz-hyphens: auto;
-ms-hyphens: auto;
-webkit-hyphens: auto;
hyphens: auto;
}
a.headerlink {
visibility: hidden;
}
a:visited {
color: #551A8B;
}
h1:hover > a.headerlink,
h2:hover > a.headerlink,
h3:hover > a.headerlink,
h4:hover > a.headerlink,
h5:hover > a.headerlink,
h6:hover > a.headerlink,
dt:hover > a.headerlink,
caption:hover > a.headerlink,
p.caption:hover > a.headerlink,
div.code-block-caption:hover > a.headerlink {
visibility: visible;
}
div.body p.caption {
text-align: inherit;
}
div.body td {
text-align: left;
}
.first {
margin-top: 0 !important;
}
p.rubric {
margin-top: 30px;
font-weight: bold;
}
img.align-left, figure.align-left, .figure.align-left, object.align-left {
clear: left;
float: left;
margin-right: 1em;
}
img.align-right, figure.align-right, .figure.align-right, object.align-right {
clear: right;
float: right;
margin-left: 1em;
}
img.align-center, figure.align-center, .figure.align-center, object.align-center {
display: block;
margin-left: auto;
margin-right: auto;
}
img.align-default, figure.align-default, .figure.align-default {
display: block;
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left;
}
.align-center {
text-align: center;
}
.align-default {
text-align: center;
}
.align-right {
text-align: right;
}
/* -- sidebars -------------------------------------------------------------- */
div.sidebar,
aside.sidebar {
margin: 0 0 0.5em 1em;
border: 1px solid #ddb;
padding: 7px;
background-color: #ffe;
width: 40%;
float: right;
clear: right;
overflow-x: auto;
}
p.sidebar-title {
font-weight: bold;
}
nav.contents,
aside.topic,
div.admonition, div.topic, blockquote {
clear: left;
}
/* -- topics ---------------------------------------------------------------- */
nav.contents,
aside.topic,
div.topic {
border: 1px solid #ccc;
padding: 7px;
margin: 10px 0 10px 0;
}
p.topic-title {
font-size: 1.1em;
font-weight: bold;
margin-top: 10px;
}
/* -- admonitions ----------------------------------------------------------- */
div.admonition {
margin-top: 10px;
margin-bottom: 10px;
padding: 7px;
}
div.admonition dt {
font-weight: bold;
}
p.admonition-title {
margin: 0px 10px 5px 0px;
font-weight: bold;
}
div.body p.centered {
text-align: center;
margin-top: 25px;
}
/* -- content of sidebars/topics/admonitions -------------------------------- */
div.sidebar > :last-child,
aside.sidebar > :last-child,
nav.contents > :last-child,
aside.topic > :last-child,
div.topic > :last-child,
div.admonition > :last-child {
margin-bottom: 0;
}
div.sidebar::after,
aside.sidebar::after,
nav.contents::after,
aside.topic::after,
div.topic::after,
div.admonition::after,
blockquote::after {
display: block;
content: '';
clear: both;
}
/* -- tables ---------------------------------------------------------------- */
table.docutils {
margin-top: 10px;
margin-bottom: 10px;
border: 0;
border-collapse: collapse;
}
table.align-center {
margin-left: auto;
margin-right: auto;
}
table.align-default {
margin-left: auto;
margin-right: auto;
}
table caption span.caption-number {
font-style: italic;
}
table caption span.caption-text {
}
table.docutils td, table.docutils th {
padding: 1px 8px 1px 5px;
border-top: 0;
border-left: 0;
border-right: 0;
border-bottom: 1px solid #aaa;
}
th {
text-align: left;
padding-right: 5px;
}
table.citation {
border-left: solid 1px gray;
margin-left: 1px;
}
table.citation td {
border-bottom: none;
}
th > :first-child,
td > :first-child {
margin-top: 0px;
}
th > :last-child,
td > :last-child {
margin-bottom: 0px;
}
/* -- figures --------------------------------------------------------------- */
div.figure, figure {
margin: 0.5em;
padding: 0.5em;
}
div.figure p.caption, figcaption {
padding: 0.3em;
}
div.figure p.caption span.caption-number,
figcaption span.caption-number {
font-style: italic;
}
div.figure p.caption span.caption-text,
figcaption span.caption-text {
}
/* -- field list styles ----------------------------------------------------- */
table.field-list td, table.field-list th {
border: 0 !important;
}
.field-list ul {
margin: 0;
padding-left: 1em;
}
.field-list p {
margin: 0;
}
.field-name {
-moz-hyphens: manual;
-ms-hyphens: manual;
-webkit-hyphens: manual;
hyphens: manual;
}
/* -- hlist styles ---------------------------------------------------------- */
table.hlist {
margin: 1em 0;
}
table.hlist td {
vertical-align: top;
}
/* -- object description styles --------------------------------------------- */
.sig {
font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
}
.sig-name, code.descname {
background-color: transparent;
font-weight: bold;
}
.sig-name {
font-size: 1.1em;
}
code.descname {
font-size: 1.2em;
}
.sig-prename, code.descclassname {
background-color: transparent;
}
.optional {
font-size: 1.3em;
}
.sig-paren {
font-size: larger;
}
.sig-param.n {
font-style: italic;
}
/* C++ specific styling */
.sig-inline.c-texpr,
.sig-inline.cpp-texpr {
font-family: unset;
}
.sig.c .k, .sig.c .kt,
.sig.cpp .k, .sig.cpp .kt {
color: #0033B3;
}
.sig.c .m,
.sig.cpp .m {
color: #1750EB;
}
.sig.c .s, .sig.c .sc,
.sig.cpp .s, .sig.cpp .sc {
color: #067D17;
}
/* -- other body styles ----------------------------------------------------- */
ol.arabic {
list-style: decimal;
}
ol.loweralpha {
list-style: lower-alpha;
}
ol.upperalpha {
list-style: upper-alpha;
}
ol.lowerroman {
list-style: lower-roman;
}
ol.upperroman {
list-style: upper-roman;
}
:not(li) > ol > li:first-child > :first-child,
:not(li) > ul > li:first-child > :first-child {
margin-top: 0px;
}
:not(li) > ol > li:last-child > :last-child,
:not(li) > ul > li:last-child > :last-child {
margin-bottom: 0px;
}
ol.simple ol p,
ol.simple ul p,
ul.simple ol p,
ul.simple ul p {
margin-top: 0;
}
ol.simple > li:not(:first-child) > p,
ul.simple > li:not(:first-child) > p {
margin-top: 0;
}
ol.simple p,
ul.simple p {
margin-bottom: 0;
}
aside.footnote > span,
div.citation > span {
float: left;
}
aside.footnote > span:last-of-type,
div.citation > span:last-of-type {
padding-right: 0.5em;
}
aside.footnote > p {
margin-left: 2em;
}
div.citation > p {
margin-left: 4em;
}
aside.footnote > p:last-of-type,
div.citation > p:last-of-type {
margin-bottom: 0em;
}
aside.footnote > p:last-of-type:after,
div.citation > p:last-of-type:after {
content: "";
clear: both;
}
dl.field-list {
display: grid;
grid-template-columns: fit-content(30%) auto;
}
dl.field-list > dt {
font-weight: bold;
word-break: break-word;
padding-left: 0.5em;
padding-right: 5px;
}
dl.field-list > dd {
padding-left: 0.5em;
margin-top: 0em;
margin-left: 0em;
margin-bottom: 0em;
}
dl {
margin-bottom: 15px;
}
dd > :first-child {
margin-top: 0px;
}
dd ul, dd table {
margin-bottom: 10px;
}
dd {
margin-top: 3px;
margin-bottom: 10px;
margin-left: 30px;
}
.sig dd {
margin-top: 0px;
margin-bottom: 0px;
}
.sig dl {
margin-top: 0px;
margin-bottom: 0px;
}
dl > dd:last-child,
dl > dd:last-child > :last-child {
margin-bottom: 0;
}
dt:target, span.highlighted {
background-color: #fbe54e;
}
rect.highlighted {
fill: #fbe54e;
}
dl.glossary dt {
font-weight: bold;
font-size: 1.1em;
}
.versionmodified {
font-style: italic;
}
.system-message {
background-color: #fda;
padding: 5px;
border: 3px solid red;
}
.footnote:target {
background-color: #ffa;
}
.line-block {
display: block;
margin-top: 1em;
margin-bottom: 1em;
}
.line-block .line-block {
margin-top: 0;
margin-bottom: 0;
margin-left: 1.5em;
}
.guilabel, .menuselection {
font-family: sans-serif;
}
.accelerator {
text-decoration: underline;
}
.classifier {
font-style: oblique;
}
.classifier:before {
font-style: normal;
margin: 0 0.5em;
content: ":";
display: inline-block;
}
abbr, acronym {
border-bottom: dotted 1px;
cursor: help;
}
/* -- code displays --------------------------------------------------------- */
pre {
overflow: auto;
overflow-y: hidden; /* fixes display issues on Chrome browsers */
}
pre, div[class*="highlight-"] {
clear: both;
}
span.pre {
-moz-hyphens: none;
-ms-hyphens: none;
-webkit-hyphens: none;
hyphens: none;
white-space: nowrap;
}
div[class*="highlight-"] {
margin: 1em 0;
}
td.linenos pre {
border: 0;
background-color: transparent;
color: #aaa;
}
table.highlighttable {
display: block;
}
table.highlighttable tbody {
display: block;
}
table.highlighttable tr {
display: flex;
}
table.highlighttable td {
margin: 0;
padding: 0;
}
table.highlighttable td.linenos {
padding-right: 0.5em;
}
table.highlighttable td.code {
flex: 1;
overflow: hidden;
}
.highlight .hll {
display: block;
}
div.highlight pre,
table.highlighttable pre {
margin: 0;
}
div.code-block-caption + div {
margin-top: 0;
}
div.code-block-caption {
margin-top: 1em;
padding: 2px 5px;
font-size: small;
}
div.code-block-caption code {
background-color: transparent;
}
table.highlighttable td.linenos,
span.linenos,
div.highlight span.gp { /* gp: Generic.Prompt */
user-select: none;
-webkit-user-select: text; /* Safari fallback only */
-webkit-user-select: none; /* Chrome/Safari */
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* IE10+ */
}
div.code-block-caption span.caption-number {
padding: 0.1em 0.3em;
font-style: italic;
}
div.code-block-caption span.caption-text {
}
div.literal-block-wrapper {
margin: 1em 0;
}
code.xref, a code {
background-color: transparent;
font-weight: bold;
}
h1 code, h2 code, h3 code, h4 code, h5 code, h6 code {
background-color: transparent;
}
.viewcode-link {
float: right;
}
.viewcode-back {
float: right;
font-family: sans-serif;
}
div.viewcode-block:target {
margin: -1px -10px;
padding: 0 10px;
}
/* -- math display ---------------------------------------------------------- */
img.math {
vertical-align: middle;
}
div.body div.math p {
text-align: center;
}
span.eqno {
float: right;
}
span.eqno a.headerlink {
position: absolute;
z-index: 1;
}
div.math:hover a.headerlink {
visibility: visible;
}
/* -- printout stylesheet --------------------------------------------------- */
@media print {
div.document,
div.documentwrapper,
div.bodywrapper {
margin: 0 !important;
width: 100%;
}
div.sphinxsidebar,
div.related,
div.footer,
#top-link {
display: none;
}
}
@@ -0,0 +1 @@
.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-style:normal;font-weight:400;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#FontAwesome) format("svg")}.fa:before{font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1}.fa:before,a .fa{text-decoration:inherit}.fa:before,a .fa,li .fa{display:inline-block}li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before,.icon-book:before{content:"\f02d"}.fa-caret-down:before,.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before,.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before,.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before,.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60}.rst-versions .rst-current-version:after{clear:both;content:"";display:block}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions .rst-other-versions .rtd-current-item{font-weight:700}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}#flyout-search-form{padding:6px}
File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 433 KiB

Binary file not shown.
File diff suppressed because one or more lines are too long
+149
View File
@@ -0,0 +1,149 @@
/*
* Base JavaScript utilities for all Sphinx HTML documentation.
*/
"use strict";
const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([
"TEXTAREA",
"INPUT",
"SELECT",
"BUTTON",
]);
const _ready = (callback) => {
if (document.readyState !== "loading") {
callback();
} else {
document.addEventListener("DOMContentLoaded", callback);
}
};
/**
* Small JavaScript module for the documentation.
*/
const Documentation = {
init: () => {
Documentation.initDomainIndexTable();
Documentation.initOnKeyListeners();
},
/**
* i18n support
*/
TRANSLATIONS: {},
PLURAL_EXPR: (n) => (n === 1 ? 0 : 1),
LOCALE: "unknown",
// gettext and ngettext don't access this so that the functions
// can safely bound to a different name (_ = Documentation.gettext)
gettext: (string) => {
const translated = Documentation.TRANSLATIONS[string];
switch (typeof translated) {
case "undefined":
return string; // no translation
case "string":
return translated; // translation exists
default:
return translated[0]; // (singular, plural) translation tuple exists
}
},
ngettext: (singular, plural, n) => {
const translated = Documentation.TRANSLATIONS[singular];
if (typeof translated !== "undefined")
return translated[Documentation.PLURAL_EXPR(n)];
return n === 1 ? singular : plural;
},
addTranslations: (catalog) => {
Object.assign(Documentation.TRANSLATIONS, catalog.messages);
Documentation.PLURAL_EXPR = new Function(
"n",
`return (${catalog.plural_expr})`
);
Documentation.LOCALE = catalog.locale;
},
/**
* helper function to focus on search bar
*/
focusSearchBar: () => {
document.querySelectorAll("input[name=q]")[0]?.focus();
},
/**
* Initialise the domain index toggle buttons
*/
initDomainIndexTable: () => {
const toggler = (el) => {
const idNumber = el.id.substr(7);
const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`);
if (el.src.substr(-9) === "minus.png") {
el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`;
toggledRows.forEach((el) => (el.style.display = "none"));
} else {
el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`;
toggledRows.forEach((el) => (el.style.display = ""));
}
};
const togglerElements = document.querySelectorAll("img.toggler");
togglerElements.forEach((el) =>
el.addEventListener("click", (event) => toggler(event.currentTarget))
);
togglerElements.forEach((el) => (el.style.display = ""));
if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler);
},
initOnKeyListeners: () => {
// only install a listener if it is really needed
if (
!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS &&
!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS
)
return;
document.addEventListener("keydown", (event) => {
// bail for input elements
if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return;
// bail with special keys
if (event.altKey || event.ctrlKey || event.metaKey) return;
if (!event.shiftKey) {
switch (event.key) {
case "ArrowLeft":
if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break;
const prevLink = document.querySelector('link[rel="prev"]');
if (prevLink && prevLink.href) {
window.location.href = prevLink.href;
event.preventDefault();
}
break;
case "ArrowRight":
if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break;
const nextLink = document.querySelector('link[rel="next"]');
if (nextLink && nextLink.href) {
window.location.href = nextLink.href;
event.preventDefault();
}
break;
}
}
// some keyboard layouts may need Shift to get /
switch (event.key) {
case "/":
if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break;
Documentation.focusSearchBar();
event.preventDefault();
}
});
},
};
// quick alias for translations
const _ = Documentation.gettext;
_ready(Documentation.init);
@@ -0,0 +1,13 @@
const DOCUMENTATION_OPTIONS = {
VERSION: '1.0',
LANGUAGE: 'en',
COLLAPSE_INDEX: false,
BUILDER: 'html',
FILE_SUFFIX: '.html',
LINK_SUFFIX: '.html',
HAS_SOURCE: true,
SOURCELINK_SUFFIX: '.txt',
NAVIGATION_WITH_KEYS: false,
SHOW_SEARCH_SUMMARY: true,
ENABLE_SEARCH_SHORTCUTS: true,
};
Binary file not shown.
Binary file not shown.
Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More