All checks were successful
Deploy WiFi-ETL Prod / deploy (push) Successful in 47s
- Substitui uso da Wifeed pela Wifere como fonde de dados de coleta dos usuarios - Correção de cron - Melhoria de logging
118 lines
4.2 KiB
Python
118 lines
4.2 KiB
Python
import requests
|
|
import logging
|
|
from typing import Tuple, Optional
|
|
from datetime import datetime, timezone
|
|
|
|
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()
|
|
data = resp.json()
|
|
token = data.get("accessToken") or data.get("data", {}).get("access_token")
|
|
if not token:
|
|
raise ValueError(f"Token não retornado: {data}")
|
|
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
|
|
|
|
times = [r.get('onlineTime', 0) for r in records if r.get('onlineTime')]
|
|
if times:
|
|
t_min = datetime.fromtimestamp(min(times) / 1000, tz=timezone.utc).strftime('%Y-%m-%d %H:%M')
|
|
t_max = datetime.fromtimestamp(max(times) / 1000, tz=timezone.utc).strftime('%Y-%m-%d %H:%M')
|
|
logger.info(f"Ruijie: página {page} → {len(records)} registros | range {t_min} → {t_max} UTC | coletados={len(all_records)}")
|
|
else:
|
|
logger.info(f"Ruijie: página {page} → {len(records)} registros (sem onlineTime)")
|
|
|
|
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
|