Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,18 @@ DB_USER=example_db_user
DB_PASSWORD=example_db_password
DB_NAME=example_db_name

# Suppressor vector PostgreSQL container
PGVECTOR_DB_HOST=vector-db
PGVECTOR_DB_PORT=5432
PGVECTOR_DB_PUBLISHED_PORT=5433
PGVECTOR_DB_USER=vector_db_user
PGVECTOR_DB_PASSWORD=vector_db_password
PGVECTOR_DB_NAME=vector_db
PGVECTOR_TABLE=public.es3_vector
EMBEDDING_DIM=1024
PGVECTOR_MATCH_THRESHOLD=0
PGVECTOR_MATCH_COUNT=10

# Nexus container
NEXUS_BASE_URL=http://nexus:8081
NEXUS_PUBLISHED_PORT=8081
Expand All @@ -35,4 +47,4 @@ LLM_TIMEOUT=300
LLM_TEMPERATURE=0.1
SLACK_WEBHOOK_URL=
DASHBOARD_BASE_URL=http://localhost:8000
OLLAMA_KEEP_ALIVE=5m
OLLAMA_KEEP_ALIVE=5m
105 changes: 101 additions & 4 deletions backend/nexus/nexus_repo.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import asyncio
import os
import time
from pathlib import PurePosixPath
from urllib.parse import quote

import httpx
import requests
from fastapi import APIRouter, Depends, HTTPException, Request
from fastapi.responses import StreamingResponse
from requests.auth import HTTPBasicAuth
from starlette.concurrency import run_in_threadpool

from backend.auth.security import require_permission

Expand All @@ -21,6 +22,7 @@
NEXUS_DASHBOARD_CACHE_TTL_SECONDS = int(os.getenv("NEXUS_DASHBOARD_CACHE_TTL_SECONDS", "30"))

nexus_auth = HTTPBasicAuth(NEXUS_USERNAME, NEXUS_PASSWORD)
httpx_nexus_auth = httpx.BasicAuth(NEXUS_USERNAME or "", NEXUS_PASSWORD or "")
_dashboard_cache = {"expires_at": 0.0, "payload": None}


Expand Down Expand Up @@ -65,6 +67,35 @@ def fetch_nexus_assets():
return all_assets


async def fetch_nexus_assets_async(client):
nexus_url = f"{NEXUS_BASE_URL}/service/rest/v1/assets"
all_assets = []
continuation_token = None

while True:
params = {"repository": NEXUS_REPOSITORY}
if continuation_token:
params["continuationToken"] = continuation_token

response = await client.get(nexus_url, params=params)

if response.status_code != 200:
print(f"Nexus API Error: {response.status_code} - {response.text}")
break

data = response.json()
for item in data.get("items", []):
if item.get("path"):
item["path"] = item["path"].lstrip("/")
all_assets.append(item)
continuation_token = data.get("continuationToken")

if not continuation_token:
break

return all_assets


def fetch_nexus_assets_by_name(names):
nexus_url = f"{NEXUS_BASE_URL}/service/rest/v1/search/assets"
matches = []
Expand Down Expand Up @@ -98,6 +129,39 @@ def fetch_nexus_assets_by_name(names):
return matches


async def fetch_nexus_assets_by_name_async(client, names):
nexus_url = f"{NEXUS_BASE_URL}/service/rest/v1/search/assets"

async def fetch_one(name):
if not name:
return []

matches = []
continuation_token = None
while True:
params = {"repository": NEXUS_REPOSITORY, "name": name}
if continuation_token:
params["continuationToken"] = continuation_token

response = await client.get(nexus_url, params=params)
if response.status_code != 200:
print(f"Nexus Search API Error: {response.status_code} - {response.text}")
break

data = response.json()
for item in data.get("items", []):
if item.get("path"):
item["path"] = item["path"].lstrip("/")
matches.append(item)
continuation_token = data.get("continuationToken")
if not continuation_token:
break
return matches

results = await asyncio.gather(*(fetch_one(name) for name in names))
return [item for group in results for item in group]


def fetch_nexus_blobstores():
nexus_url = f"{NEXUS_BASE_URL}/service/rest/v1/blobstores"
response = requests.get(
Expand All @@ -113,6 +177,17 @@ def fetch_nexus_blobstores():
return response.json()


async def fetch_nexus_blobstores_async(client):
nexus_url = f"{NEXUS_BASE_URL}/service/rest/v1/blobstores"
response = await client.get(nexus_url)

if response.status_code != 200:
print(f"Nexus Blob Store API Error: {response.status_code} - {response.text}")
return []

return response.json()


def get_safe_item_name(item):
path = item.get("path") or ""
parts = path.split("/")
Expand Down Expand Up @@ -184,10 +259,30 @@ def fetch_dashboard_payload():
return payload


async def fetch_dashboard_payload_async(client):
now = time.monotonic()
cached_payload = _dashboard_cache["payload"]
if cached_payload is not None and _dashboard_cache["expires_at"] > now:
return cached_payload

assets, blobstores = await asyncio.gather(
fetch_nexus_assets_async(client),
fetch_nexus_blobstores_async(client),
)
payload = {
"items": assets,
"summary": build_dashboard_summary(assets, blobstores),
}
_dashboard_cache["payload"] = payload
_dashboard_cache["expires_at"] = now + NEXUS_DASHBOARD_CACHE_TTL_SECONDS
return payload


@router.post("/api/nexus/list")
async def nexus_list(_user: dict = Depends(require_permission("install_extension"))):
try:
all_assets = await run_in_threadpool(fetch_nexus_assets)
async with httpx.AsyncClient(auth=httpx_nexus_auth, timeout=10) as client:
all_assets = await fetch_nexus_assets_async(client)
print(f"총 {len(all_assets)}개의 자산을 Nexus에서 성공적으로 불러왔습니다.")
return all_assets
except Exception as e:
Expand All @@ -212,7 +307,8 @@ async def nexus_exists(
candidate_names.append(f"{ext_id}-{version}.vsix")

try:
matches = await run_in_threadpool(fetch_nexus_assets_by_name, candidate_names)
async with httpx.AsyncClient(auth=httpx_nexus_auth, timeout=10) as client:
matches = await fetch_nexus_assets_by_name_async(client, candidate_names)
except Exception as e:
print(f"Nexus exists lookup error: {e}")
matches = []
Expand Down Expand Up @@ -277,7 +373,8 @@ def iterfile():
@router.get("/api/nexus/dashboard")
async def nexus_dashboard():
try:
return await run_in_threadpool(fetch_dashboard_payload)
async with httpx.AsyncClient(auth=httpx_nexus_auth, timeout=10) as client:
return await fetch_dashboard_payload_async(client)
except Exception as e:
print(f"Nexus dashboard summary error: {e}")
return {
Expand Down
Loading
Loading