Задача 042: свёртка свободных адресов в раскрывающиеся диапазоны
В списке адресов префикса подряд идущие свободные адреса сворачиваются в строку «начало – конец · Свободно: N» (параметр group_free, группировка на сервере — пагинация по строкам после свёртки); раскрытие — существующим status=free&offset=free_offset порциями по 500. Без group_free ответ API прежний. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
9301069c29
commit
d1a2efd683
7 files changed
+176
-12
No files matched your search
+33
-2
@@ -380,11 +380,13 @@ def _check_device(db: Session, user: User, prefix: Prefix, device_id: int | None
|
||||
|
||||
@router.get("/prefixes/{id}/addresses", response_model=s.AddressPage)
|
||||
def list_addresses(
|
||||
id: int, status: str = "", q: str = "", limit: int = Query(100, ge=1, le=500), offset: int = Query(0, ge=0, le=MAX_OFFSET),
|
||||
id: int, status: str = "", q: str = "", group_free: bool = False, limit: int = Query(100, ge=1, le=500), offset: int = Query(0, ge=0, le=MAX_OFFSET),
|
||||
db: Session = Depends(get_db), user: User = Depends(current_user), # изменение 032
|
||||
):
|
||||
"""status: assigned | reserved | deprecated | free | пусто (все; свободные подмешиваются для малых подсетей).
|
||||
Пагинация — в SQL; страница «свободных» считается арифметически (без перебора адресов подсети)."""
|
||||
Пагинация — в SQL; страница «свободных» считается арифметически (без перебора адресов подсети).
|
||||
group_free (изменение 042): только в смешанном режиме — подряд идущие свободные адреса сворачиваются
|
||||
в строки free_range; без параметра поведение и ответ побайтно прежние (совместимость, тесты)."""
|
||||
p = get_or_404(db, Prefix, id, "Префикс")
|
||||
require_org(user, p.organization_id, "Префикс") # изменение 032
|
||||
cap = capacity(str(p.prefix))
|
||||
@@ -404,6 +406,33 @@ def list_addresses(
|
||||
def free_rows(ips: list[str]) -> list[s.AddressOut]:
|
||||
return [s.AddressOut(id=None, prefix_id=id, address=ip, status="free") for ip in ips]
|
||||
|
||||
def group_free_rows(rows: list[s.AddressOut]) -> list[s.AddressOut]:
|
||||
"""Изменение 042: подряд идущие строки status=free (серия ≥ 2) сворачиваются в одну строку free_range.
|
||||
Свёртка — арифметически по уже отсортированному списку (free-строки идут подряд после сортировки),
|
||||
без повторного перебора подсети. free_offset — число свободных адресов подсети до начала диапазона,
|
||||
совпадает с offset для GET .../addresses?status=free&offset=…&limit=… (free_page считает так же)."""
|
||||
out: list[s.AddressOut] = []
|
||||
free_before, i, n = 0, 0, len(rows)
|
||||
while i < n:
|
||||
if rows[i].status != "free":
|
||||
out.append(rows[i])
|
||||
i += 1
|
||||
continue
|
||||
j = i
|
||||
while j < n and rows[j].status == "free":
|
||||
j += 1
|
||||
run = j - i
|
||||
if run >= 2:
|
||||
out.append(s.AddressOut(
|
||||
id=None, prefix_id=id, address=rows[i].address, status="free_range",
|
||||
range_end=rows[j - 1].address, range_count=run, free_offset=free_before,
|
||||
))
|
||||
else:
|
||||
out.append(rows[i])
|
||||
free_before += run
|
||||
i = j
|
||||
return out
|
||||
|
||||
if status == "free":
|
||||
return s.AddressPage(items=free_rows(free_page(net, occupied(), offset, limit)), total=summary.free, summary=summary)
|
||||
|
||||
@@ -423,6 +452,8 @@ def list_addresses(
|
||||
if mixed:
|
||||
rows = [_addr_out(a, dn, dtn, ds.value if ds else None) for a, dn, dtn, ds in db.execute(stmt.order_by(Address.address)).all()]
|
||||
rows = sorted(rows + free_rows(free_page(net, occupied(), 0, cap)), key=lambda r: ipaddress.ip_address(r.address))
|
||||
if group_free: # изменение 042
|
||||
rows = group_free_rows(rows)
|
||||
return s.AddressPage(items=rows[offset:offset + limit], total=len(rows), summary=summary)
|
||||
total = count(db, select(Address.id).where(*flt))
|
||||
page = db.execute(stmt.order_by(Address.address).limit(limit).offset(offset)).all()
|
||||
|
||||
Reference in new issue
Block a user