Some checks failed
Deploy WiFi-ETL Prod / deploy (push) Failing after 0s
- Adicionado suporte para extração de dados do Ruijie e WiFeed, incluindo autenticação e tratamento de erros. - Adicionado suporte para watermarking em ambas as fontes para extração incremental. - Criado script de transformação para mesclagem de MAC addresses. - Implementado Backfill para WiFeed, permitindo extração histórica com controle de taxa. - Adicionado script de depuração para testes de transformação do WiFeed. - Desenvolvido scripts de implantação e configurações do Docker para setup de produção. - Criado script de inicialização do schema do PostgreSQL em infra/init.sql. - Adicionado teste automatizado para lógica de transformação e carregamento em test_transform_load.py. - Atualizado documentation para implantação e setup de produção.
110 lines
3.7 KiB
Python
110 lines
3.7 KiB
Python
import requests
|
|
import logging
|
|
from typing import Tuple, Optional
|
|
|
|
from app.core.config import (
|
|
RUIJIE_BASE_URL,
|
|
RUIJIE_APPID,
|
|
RUIJIE_SECRET,
|
|
RUIJIE_ACCESS_TOKEN,
|
|
RUIJIE_GROUP_ID,
|
|
)
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
BASE_URL = RUIJIE_BASE_URL
|
|
|
|
|
|
def get_access_token() -> str:
|
|
url = f"{BASE_URL}/service/api/oauth20/client/access_token?token=d63dss0a81e4415a889ac5b78fsc904a"
|
|
payload = {"appid": RUIJIE_APPID, "secret": RUIJIE_SECRET}
|
|
resp = requests.post(url, json=payload, timeout=15)
|
|
resp.raise_for_status()
|
|
token = resp.json().get("data", {}).get("access_token")
|
|
if not token:
|
|
raise ValueError(f"Token não retornado: {resp.json()}")
|
|
return token
|
|
|
|
|
|
def refresh_token(access_token: str) -> str:
|
|
url = f"{BASE_URL}/service/api/token/refresh?appid={RUIJIE_APPID}&secret={RUIJIE_SECRET}&access_token={access_token}"
|
|
resp = requests.get(url, timeout=15)
|
|
resp.raise_for_status()
|
|
token = resp.json().get("accessToken") or resp.json().get("data", {}).get("access_token")
|
|
if not token:
|
|
raise ValueError(f"Refresh falhou: {resp.json()}")
|
|
return token
|
|
|
|
|
|
def get_active_users(access_token: str, page_index: int = 1, page_size: int = 100) -> list[dict]:
|
|
url = f"{BASE_URL}/logbizagent/logbiz/api/sta/sta_users"
|
|
payload = {
|
|
"groupId": int(RUIJIE_GROUP_ID),
|
|
"pageSize": page_size,
|
|
"pageIndex": page_index,
|
|
"staType": "onofflineUserHistory",
|
|
}
|
|
headers = {"Content-Type": "application/json"}
|
|
params = {"access_token": access_token}
|
|
|
|
resp = requests.post(url, json=payload, headers=headers, params=params, timeout=15)
|
|
resp.raise_for_status()
|
|
return resp.json().get("list", [])
|
|
|
|
|
|
def extract_all_users(
|
|
access_token: str,
|
|
watermark_ms: Optional[int] = None,
|
|
page_size: int = 100
|
|
) -> Tuple[list[dict], int]:
|
|
"""
|
|
Extrai sessões Ruijie com suporte a watermark.
|
|
|
|
Args:
|
|
access_token: Token Ruijie
|
|
watermark_ms: onlineTime (epoch ms) da última sessão processada.
|
|
Se fornecido, ignora registros com onlineTime <= watermark.
|
|
page_size: Tamanho da página
|
|
|
|
Returns:
|
|
(lista_de_registros, novo_watermark)
|
|
- novo_watermark = maior onlineTime encontrado (ou watermark anterior se nada novo)
|
|
"""
|
|
all_records = []
|
|
page = 1
|
|
max_online_ms = watermark_ms or 0
|
|
stopped_early = False
|
|
|
|
while True:
|
|
records = get_active_users(access_token, page_index=page, page_size=page_size)
|
|
if not records:
|
|
break
|
|
|
|
# Filtra por watermark (se fornecido) ou adiciona tudo
|
|
if watermark_ms is not None:
|
|
filtered = [r for r in records if r.get('onlineTime', 0) > watermark_ms]
|
|
if len(filtered) < len(records):
|
|
# Parou de voltar no tempo — já viu tudo até o watermark
|
|
stopped_early = True
|
|
all_records.extend(filtered)
|
|
break
|
|
all_records.extend(filtered)
|
|
else:
|
|
# Sem watermark: adiciona todos os registros da página
|
|
all_records.extend(records)
|
|
|
|
# Atualiza max_online_ms
|
|
page_max = max((r.get('onlineTime', 0) for r in records), default=0)
|
|
if page_max > max_online_ms:
|
|
max_online_ms = page_max
|
|
|
|
logger.info(f"Ruijie: página {page} → {len(records)} registros (watermark={watermark_ms})")
|
|
|
|
if len(records) < page_size or stopped_early:
|
|
break
|
|
page += 1
|
|
|
|
new_watermark = max_online_ms if max_online_ms > (watermark_ms or 0) else watermark_ms
|
|
logger.info(f"Ruijie: total extraído = {len(all_records)} registros (novo watermark={new_watermark})")
|
|
return all_records, new_watermark
|