feat: Integrate `licaeros` library for licensed AEROS API calls, centralizing request logic in `aeros_utils.py` and updating services to use it.

main
Cizz22 3 weeks ago
parent e740b46612
commit d6d6ab3631

@ -16,5 +16,7 @@ COLLECTOR_CREDENTIAL_PASSWORD=postgres
COLLECTOR_NAME=digital_aeros_fixed COLLECTOR_NAME=digital_aeros_fixed
AEROS_LICENSE_ID=20260218-Jre5VZieQfWXTq0G8ClpVSGszMf4UEUMLS5ENpWRVcoVSrNJckVZzXE
AEROS_LICENSE_SECRET=GmLIxf9fr8Ap5m1IYzkk4RPBFcm7UBvcd0eRdRQ03oRdxLHQA0d9oyhUk2ZlM3LVdRh1mkgYy5254bmCjFyWWc0oPFwNWYzNwDwnv50qy6SLRdaFnI0yZcfLbWQ7qCSj
WINDOWS_AEROS_BASE_URL=http://192.168.1.102:8800 WINDOWS_AEROS_BASE_URL=http://192.168.1.102:8800
TEMPORAL_URL=http://192.168.1.86:7233 TEMPORAL_URL=http://192.168.1.86:7233

23
poetry.lock generated

@ -1076,6 +1076,27 @@ MarkupSafe = ">=2.0"
[package.extras] [package.extras]
i18n = ["Babel (>=2.7)"] i18n = ["Babel (>=2.7)"]
[[package]]
name = "licaeros"
version = "0.1.0"
description = ""
optional = false
python-versions = "*"
groups = ["main"]
files = [
{file = "licaeros-0.1.0-cp310-cp310-linux_x86_64.whl", hash = "sha256:7ab820555c10edae6d8f391e71f0188463283ddbf60840a3baadb926bb78a6a9"},
{file = "licaeros-0.1.0-cp311-cp311-linux_x86_64.whl", hash = "sha256:70b6b753c96e6fa4912e0e9eddf8088ddc3c4b6947ca16dc4b19047d2ee4aedf"},
{file = "licaeros-0.1.0-cp312-cp312-linux_x86_64.whl", hash = "sha256:d89fe52a78637f2a72abf64f6a74445aad3899303cce7409f2d12fd277a0db00"},
]
[package.dependencies]
requests = "*"
[package.source]
type = "legacy"
url = "https://git.reliabilityindonesia.com/api/packages/DigitalTwin/pypi/simple"
reference = "licaeros-repo"
[[package]] [[package]]
name = "limits" name = "limits"
version = "3.13.0" version = "3.13.0"
@ -2823,4 +2844,4 @@ propcache = ">=0.2.1"
[metadata] [metadata]
lock-version = "2.1" lock-version = "2.1"
python-versions = "^3.11" python-versions = "^3.11"
content-hash = "9d61d2415a02d2e9a0be0850394cd0d8dbf178f7a419e726cc9b3b1c37d8d4d1" content-hash = "f75002a661bdae021c2906c1b44ba85cfe1835d37378a717ee9561e376603771"

@ -32,8 +32,14 @@ aiohttp = "^3.12.14"
ijson = "^3.4.0" ijson = "^3.4.0"
redis = "^7.1.0" redis = "^7.1.0"
clamd = "^1.0.2" clamd = "^1.0.2"
licaeros = "^0.1.0"
[[tool.poetry.source]]
name = "licaeros-repo"
url = "https://git.reliabilityindonesia.com/api/packages/DigitalTwin/pypi/simple/"
priority = "supplemental"
[build-system] [build-system]
requires = ["poetry-core"] requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api" build-backend = "poetry.core.masonry.api"

@ -7,7 +7,8 @@ from sqlalchemy import Delete, Select, func, desc, and_, text
from sqlalchemy.orm import selectinload from sqlalchemy.orm import selectinload
from src.auth.service import CurrentUser from src.auth.service import CurrentUser
from src.config import AEROS_BASE_URL, DEFAULT_PROJECT_NAME, RELIABILITY_SERVICE_API from src.config import DEFAULT_PROJECT_NAME, RELIABILITY_SERVICE_API
from src.aeros_utils import aeros_post
from src.database.core import CollectorDbSession, DbSession from src.database.core import CollectorDbSession, DbSession
from src.database.service import search_filter_sort_paginate from src.database.service import search_filter_sort_paginate
from .model import AerosEquipment, AerosEquipmentDetail, MasterEquipment, AerosEquipmentGroup, ReliabilityPredictNonRepairable from .model import AerosEquipment, AerosEquipmentDetail, MasterEquipment, AerosEquipmentGroup, ReliabilityPredictNonRepairable
@ -21,7 +22,7 @@ import json
import pandas as pd import pandas as pd
from src.aeros_simulation.service import get_aeros_schematic_by_name from src.aeros_simulation.service import get_aeros_schematic_by_name
client = httpx.AsyncClient(timeout=300.0) # Aeros session is managed in src.aeros_utils
log = logging.getLogger() log = logging.getLogger()
async def get_project(*, db_session: DbSession): async def get_project(*, db_session: DbSession):
@ -47,11 +48,13 @@ async def get_all(*, common):
updateNodeReq = {"projectName": project.project_name , "equipmentNames": reg_nodes} updateNodeReq = {"projectName": project.project_name , "equipmentNames": reg_nodes}
try: try:
response = await client.post( response = await aeros_post(
f"{AEROS_BASE_URL}/api/UpdateDisParams/GetUpdatedNodeDistributions", "/api/UpdateDisParams/GetUpdatedNodeDistributions",
json=updateNodeReq, json=updateNodeReq,
headers={"Content-Type": "application/json"}, headers={"Content-Type": "application/json"},
) )
response.raise_for_status() response.raise_for_status()
res = response.json() res = response.json()
@ -96,8 +99,8 @@ async def get_by_id(*, db_session: DbSession, id: UUID):
} }
try: try:
response = await client.post( response = await aeros_post(
f"{AEROS_BASE_URL}/api/UpdateDisParams/GetUpdatedNodeDistributions", "/api/UpdateDisParams/GetUpdatedNodeDistributions",
json=aerosNodeReq, json=aerosNodeReq,
headers={"Content-Type": "application/json"}, headers={"Content-Type": "application/json"},
) )
@ -124,8 +127,8 @@ async def get_aeros_equipment_by_location_tag(*, location_tag: Union[str, List[s
} }
try: try:
response = await client.post( response = await aeros_post(
f"{AEROS_BASE_URL}/api/UpdateDisParams/GetUpdatedNodeDistributions", "/api/UpdateDisParams/GetUpdatedNodeDistributions",
json=aerosNodeReq, json=aerosNodeReq,
headers={"Content-Type": "application/json"}, headers={"Content-Type": "application/json"},
) )
@ -157,8 +160,8 @@ async def update_node(
try: try:
response = await client.post( response = await aeros_post(
f"{AEROS_BASE_URL}/api/UpdateDisParams/UpdateEquipmentDistributions", "/api/UpdateDisParams/UpdateEquipmentDistributions",
json=updateNodeReq, json=updateNodeReq,
headers={"Content-Type": "application/json"}, headers={"Content-Type": "application/json"},
) )
@ -188,8 +191,8 @@ async def save_default_equipment(*, db_session: DbSession, project_name: str):
await db_session.execute(query) await db_session.execute(query)
try: try:
response = await client.post( response = await aeros_post(
f"{AEROS_BASE_URL}/api/UpdateDisParams/GetUpdatedNodeDistributions", "/api/UpdateDisParams/GetUpdatedNodeDistributions",
json=updateNodeReq, json=updateNodeReq,
headers={"Content-Type": "application/json"}, headers={"Content-Type": "application/json"},
) )

@ -9,7 +9,8 @@ from sqlalchemy.orm import selectinload
from src.aeros_equipment.service import save_default_equipment from src.aeros_equipment.service import save_default_equipment
from src.aeros_simulation.service import save_default_simulation_node from src.aeros_simulation.service import save_default_simulation_node
from src.auth.service import CurrentUser from src.auth.service import CurrentUser
from src.config import WINDOWS_AEROS_BASE_URL, AEROS_BASE_URL, CLAMAV_HOST, CLAMAV_PORT from src.config import WINDOWS_AEROS_BASE_URL, CLAMAV_HOST, CLAMAV_PORT
from src.aeros_utils import aeros_post
from src.database.core import DbSession from src.database.core import DbSession
from src.database.service import search_filter_sort_paginate from src.database.service import search_filter_sort_paginate
from src.utils import sanitize_filename from src.utils import sanitize_filename
@ -21,6 +22,8 @@ from .schema import AerosProjectInput, OverhaulScheduleCreate, OverhaulScheduleU
import asyncio import asyncio
ALLOWED_EXTENSIONS = {".aro"} ALLOWED_EXTENSIONS = {".aro"}
MAX_FILE_SIZE = 100 * 1024 * 1024 # 100MB MAX_FILE_SIZE = 100 * 1024 * 1024 # 100MB
# client = httpx.AsyncClient(timeout=300.0) # Managed in src.aeros_utils
# We still use a local client for WINDOWS_AEROS_BASE_URL if it's not managed by aeros_utils
client = httpx.AsyncClient(timeout=300.0) client = httpx.AsyncClient(timeout=300.0)
@ -166,9 +169,9 @@ async def import_aro_project(*, db_session: DbSession, aeros_project_in: AerosPr
# Update path to AEROS APP # Update path to AEROS APP
# Example BODy "C/dsad/dsad.aro" # Example BODy "C/dsad/dsad.aro"
try: try:
response = await client.post( response = await aeros_post(
f"{AEROS_BASE_URL}/api/Project/ImportAROFile", "/api/Project/ImportAROFile",
content=f'"{aro_path}"', data=f'"{aro_path}"',
headers={"Content-Type": "application/json"}, headers={"Content-Type": "application/json"},
) )
response.raise_for_status() response.raise_for_status()
@ -232,9 +235,9 @@ async def reset_project(*, db_session: DbSession):
project = await fetch_aro_record(db_session=db_session) project = await fetch_aro_record(db_session=db_session)
try: try:
response = await client.post( response = await aeros_post(
f"{AEROS_BASE_URL}/api/Project/ImportAROFile", "/api/Project/ImportAROFile",
content=f'"{project.aro_file_path}"', data=f'"{project.aro_file_path}"',
headers={"Content-Type": "application/json"}, headers={"Content-Type": "application/json"},
) )
response.raise_for_status() response.raise_for_status()

@ -8,11 +8,11 @@ import logging
import httpx import httpx
from fastapi import HTTPException, status from fastapi import HTTPException, status
import ijson import ijson
import requests
from sqlalchemy import delete, desc, select, update, and_ from sqlalchemy import delete, desc, select, update, and_
from sqlalchemy.orm import selectinload from sqlalchemy.orm import selectinload
from src.config import AEROS_BASE_URL, AEROS_BASE_URL_OLD, DEFAULT_PROJECT_NAME from src.config import DEFAULT_PROJECT_NAME
from src.aeros_utils import aeros_post
from src.database.core import DbSession from src.database.core import DbSession
from src.database.service import CommonParameters, search_filter_sort_paginate from src.database.service import CommonParameters, search_filter_sort_paginate
from src.utils import save_to_pastebin from src.utils import save_to_pastebin
@ -32,7 +32,7 @@ from src.aeros_equipment.schema import EquipmentWithCustomParameters
from .schema import SimulationInput, SimulationPlotResult, SimulationRankingParameters from .schema import SimulationInput, SimulationPlotResult, SimulationRankingParameters
from .utils import calculate_eaf, stream_large_array from .utils import calculate_eaf, stream_large_array
client = httpx.AsyncClient(timeout=300.0) # client = httpx.AsyncClient(timeout=300.0) # Managed in src.aeros_utils
active_simulations = {} active_simulations = {}
@ -399,8 +399,8 @@ async def execute_simulation(*, db_session: DbSession, simulation_id: Optional[U
try: try:
if not is_saved: if not is_saved:
response = await client.post( response = await aeros_post(
f"{AEROS_BASE_URL}/api/Simulation/RunSimulation", "/api/Simulation/RunSimulation",
json=sim_data, json=sim_data,
headers={"Content-Type": "application/json"}, headers={"Content-Type": "application/json"},
) )
@ -420,17 +420,15 @@ async def execute_simulation(*, db_session: DbSession, simulation_id: Optional[U
print("Simulation started with id: %s", simulation.id) print("Simulation started with id: %s", simulation.id)
# if not os.path.exists(tmpfile): # if not os.path.exists(tmpfile):
response = requests.post(f"{AEROS_BASE_URL}/api/Simulation/RunSimulation", stream=True, json=sim_data) # Using aeros_post wrapper which uses LicensedSession
response = await aeros_post(
"/api/Simulation/RunSimulation",
stream=True,
json=sim_data
)
file_obj = response.raw file_obj = response.raw
# response = await client.post(
# f"{AEROS_BASE_URL}/api/Simulation/RunSimulation",
# json=sim_data,
# headers={"Content-Type": "application/json"},
# )
# response.raise_for_status()
# result = response.json()
await save_simulation_result( await save_simulation_result(
db_session=db_session, simulation_id=simulation.id, schematic_name=sim_data["SchematicName"], eq_update=eq_update, file_path=file_obj db_session=db_session, simulation_id=simulation.id, schematic_name=sim_data["SchematicName"], eq_update=eq_update, file_path=file_obj

@ -17,7 +17,7 @@ from fastapi import HTTPException, status
from src.aeros_simulation.model import AerosSimulationCalcResult, AerosSimulationPlotResult from src.aeros_simulation.model import AerosSimulationCalcResult, AerosSimulationPlotResult
from src.aeros_simulation.service import get_all_aeros_node, get_or_save_node, get_plant_calc_result, get_simulation_by_id, get_simulation_with_plot_result from src.aeros_simulation.service import get_all_aeros_node, get_or_save_node, get_plant_calc_result, get_simulation_by_id, get_simulation_with_plot_result
from src.aeros_simulation.utils import calculate_eaf, calculate_eaf_konkin from src.aeros_simulation.utils import calculate_eaf, calculate_eaf_konkin
from src.config import AEROS_BASE_URL from src.aeros_utils import aeros_post
from src.database.core import DbSession from src.database.core import DbSession
@ -32,16 +32,15 @@ async def execute_simulation(
tmpfile = os.path.join(tempfile.gettempdir(), f"simulation_{simulation_id}.json") tmpfile = os.path.join(tempfile.gettempdir(), f"simulation_{simulation_id}.json")
try: try:
async with httpx.AsyncClient(timeout=None) as client: response = await aeros_post(
async with client.stream( "/api/Simulation/RunSimulation",
"POST",
f"{AEROS_BASE_URL}/api/Simulation/RunSimulation",
json=sim_data, json=sim_data,
headers={"Content-Type": "application/json"}, headers={"Content-Type": "application/json"},
) as response: stream=True
)
response.raise_for_status() response.raise_for_status()
with open(tmpfile, "wb") as f: with open(tmpfile, "wb") as f:
async for chunk in response.aiter_bytes(): for chunk in response.iter_content(chunk_size=8192):
f.write(chunk) f.write(chunk)
if not is_saved: if not is_saved:

@ -0,0 +1,32 @@
import anyio
from licaeros import LicensedSession, device_fingerprint_hex
from src.config import AEROS_BASE_URL, AEROS_LICENSE_ID, AEROS_LICENSE_SECRET
import logging
log = logging.getLogger(__name__)
# Initialize a global session if possible, or create on demand
_aeros_session = None
def get_aeros_session():
global _aeros_session
if _aeros_session is None:
log.info(f"Initializing LicensedSession with base URL: {AEROS_BASE_URL}")
log.info(f"Encrypted Device ID: {device_fingerprint_hex()}")
_aeros_session = LicensedSession(
api_base=AEROS_BASE_URL,
license_id=AEROS_LICENSE_ID,
license_secret=AEROS_LICENSE_SECRET,
)
return _aeros_session
async def aeros_post(path: str, json: dict = None, **kwargs):
"""
Asynchronous wrapper for LicensedSession.post
"""
session = get_aeros_session()
# LicensedSession might not be async-compatible, so we run it in a thread
response = await anyio.to_thread.run_sync(
lambda: session.post(path, json)
)
return response

@ -97,3 +97,6 @@ RELIABILITY_SERVICE_API = config("RELIABILITY_SERVICE_API", default="http://192.
CLAMAV_HOST = config("CLAMAV_HOST", default="192.168.1.82") CLAMAV_HOST = config("CLAMAV_HOST", default="192.168.1.82")
CLAMAV_PORT = config("CLAMAV_PORT", cast=int, default=3310) CLAMAV_PORT = config("CLAMAV_PORT", cast=int, default=3310)
AEROS_LICENSE_ID = config("AEROS_LICENSE_ID", default="")
AEROS_LICENSE_SECRET = config("AEROS_LICENSE_SECRET", default="")
Loading…
Cancel
Save