From 1b2721e2b7e9191028de48140e814c00c55bea00 Mon Sep 17 00:00:00 2001 From: Mikhail Date: Sun, 17 May 2026 22:57:02 +0300 Subject: [PATCH] Extract agent protocol models --- .../api-server/src/api_server/agent_models.py | 144 ++++++++++++++++ services/api-server/src/api_server/main.py | 155 ++---------------- 2 files changed, 161 insertions(+), 138 deletions(-) create mode 100644 services/api-server/src/api_server/agent_models.py diff --git a/services/api-server/src/api_server/agent_models.py b/services/api-server/src/api_server/agent_models.py new file mode 100644 index 0000000..16d6013 --- /dev/null +++ b/services/api-server/src/api_server/agent_models.py @@ -0,0 +1,144 @@ +from __future__ import annotations + +from enum import Enum + +from pydantic import BaseModel, Field + +from api_server.import_source_models import ImportMode, ImportSourceKind + + +class AgentImportJobStatus(str, Enum): + QUEUED = "QUEUED" + RUNNING = "RUNNING" + SUCCEEDED = "SUCCEEDED" + FAILED = "FAILED" + CANCELLED = "CANCELLED" + + +class AgentImportJobRequest(BaseModel): + agent_id: str + source: ImportSourceKind + local_path: str | None = None + bin_path: str | None = None + infobase: str | None = None + credentials_ref: str | None = None + mode: ImportMode = ImportMode.FULL_REPLACE + metadata: dict = Field(default_factory=dict) + + +class AgentImportJob(BaseModel): + job_id: str + project_id: str + agent_id: str + source: ImportSourceKind + mode: ImportMode = ImportMode.FULL_REPLACE + status: AgentImportJobStatus = AgentImportJobStatus.QUEUED + local_path: str | None = None + bin_path: str | None = None + infobase: str | None = None + credentials_ref: str | None = None + metadata: dict = Field(default_factory=dict) + created_at: str + updated_at: str + claimed_at: str | None = None + completed_at: str | None = None + server_path: str | None = None + logs: list[str] = Field(default_factory=list) + error: str | None = None + import_summary: dict | None = None + + +class AgentImportJobResult(BaseModel): + status: AgentImportJobStatus = AgentImportJobStatus.SUCCEEDED + server_path: str | None = None + logs: list[str] = Field(default_factory=list) + error: str | None = None + metadata: dict = Field(default_factory=dict) + + +class AgentImportJobLogRequest(BaseModel): + logs: list[str] = Field(default_factory=list) + status: AgentImportJobStatus | None = None + + +class AgentBrowseRequestStatus(str, Enum): + QUEUED = "QUEUED" + RUNNING = "RUNNING" + SUCCEEDED = "SUCCEEDED" + FAILED = "FAILED" + + +class AgentBrowseRequestCreate(BaseModel): + agent_id: str + path: str | None = None + + +class AgentFolderEntry(BaseModel): + name: str + path: str + is_directory: bool = True + + +class AgentBrowseRequest(BaseModel): + request_id: str + agent_id: str + path: str | None = None + status: AgentBrowseRequestStatus = AgentBrowseRequestStatus.QUEUED + created_at: str + updated_at: str + claimed_at: str | None = None + completed_at: str | None = None + entries: list[AgentFolderEntry] = Field(default_factory=list) + parent_path: str | None = None + error: str | None = None + + +class AgentBrowseResult(BaseModel): + status: AgentBrowseRequestStatus = AgentBrowseRequestStatus.SUCCEEDED + entries: list[AgentFolderEntry] = Field(default_factory=list) + parent_path: str | None = None + error: str | None = None + + +class AgentHeartbeatRequest(BaseModel): + agent_id: str + host: str | None = None + user: str | None = None + version: str | None = None + started_at: str | None = None + network_roots: list[str] = Field(default_factory=list) + platform_bins: list[str] = Field(default_factory=list) + + +class AgentStatus(BaseModel): + agent_id: str + status: str = "offline" + last_seen_at: str | None = None + host: str | None = None + user: str | None = None + version: str | None = None + started_at: str | None = None + network_roots: list[str] = Field(default_factory=list) + platform_bins: list[str] = Field(default_factory=list) + + +class AgentProjectConfig(BaseModel): + project_id: str + project_name: str + one_c_bin: str | None = None + edt_path: str | None = None + default_local_path: str | None = None + network_roots: list[str] = Field(default_factory=list) + + +class AgentConfigResponse(BaseModel): + agent_id: str + poll_seconds: int = 5 + projects: list[AgentProjectConfig] = Field(default_factory=list) + + +class ServerBrowseResponse(BaseModel): + path: str + parent_path: str | None = None + entries: list[AgentFolderEntry] = Field(default_factory=list) + error: str | None = None diff --git a/services/api-server/src/api_server/main.py b/services/api-server/src/api_server/main.py index 4a747ea..b13e1d0 100644 --- a/services/api-server/src/api_server/main.py +++ b/services/api-server/src/api_server/main.py @@ -15,7 +15,6 @@ import zipfile import xml.etree.ElementTree as ET from collections import Counter from difflib import SequenceMatcher -from enum import Enum from pathlib import Path from typing import Any, Callable from urllib.parse import quote, urljoin, urlsplit, urlunsplit @@ -36,6 +35,23 @@ from fastapi.responses import PlainTextResponse, Response, StreamingResponse from neo4j import AsyncGraphDatabase from pydantic import BaseModel, Field +from api_server.agent_models import ( + AgentBrowseRequest, + AgentBrowseRequestCreate, + AgentBrowseRequestStatus, + AgentBrowseResult, + AgentConfigResponse, + AgentFolderEntry, + AgentHeartbeatRequest, + AgentImportJob, + AgentImportJobLogRequest, + AgentImportJobRequest, + AgentImportJobResult, + AgentImportJobStatus, + AgentProjectConfig, + AgentStatus, + ServerBrowseResponse, +) from api_server.html5_forms import ( html5_form_data as _html5_form_data, ) @@ -324,143 +340,6 @@ _MODULE_OWNER_NODE_KINDS = { if _EVENT_SUBSCRIPTION_KIND is not None: _MODULE_OWNER_NODE_KINDS.add(_EVENT_SUBSCRIPTION_KIND) -class AgentImportJobStatus(str, Enum): - QUEUED = "QUEUED" - RUNNING = "RUNNING" - SUCCEEDED = "SUCCEEDED" - FAILED = "FAILED" - CANCELLED = "CANCELLED" - - -class AgentImportJobRequest(BaseModel): - agent_id: str - source: ImportSourceKind - local_path: str | None = None - bin_path: str | None = None - infobase: str | None = None - credentials_ref: str | None = None - mode: ImportMode = ImportMode.FULL_REPLACE - metadata: dict = Field(default_factory=dict) - - -class AgentImportJob(BaseModel): - job_id: str - project_id: str - agent_id: str - source: ImportSourceKind - mode: ImportMode = ImportMode.FULL_REPLACE - status: AgentImportJobStatus = AgentImportJobStatus.QUEUED - local_path: str | None = None - bin_path: str | None = None - infobase: str | None = None - credentials_ref: str | None = None - metadata: dict = Field(default_factory=dict) - created_at: str - updated_at: str - claimed_at: str | None = None - completed_at: str | None = None - server_path: str | None = None - logs: list[str] = Field(default_factory=list) - error: str | None = None - import_summary: dict | None = None - - -class AgentImportJobResult(BaseModel): - status: AgentImportJobStatus = AgentImportJobStatus.SUCCEEDED - server_path: str | None = None - logs: list[str] = Field(default_factory=list) - error: str | None = None - metadata: dict = Field(default_factory=dict) - - -class AgentImportJobLogRequest(BaseModel): - logs: list[str] = Field(default_factory=list) - status: AgentImportJobStatus | None = None - - -class AgentBrowseRequestStatus(str, Enum): - QUEUED = "QUEUED" - RUNNING = "RUNNING" - SUCCEEDED = "SUCCEEDED" - FAILED = "FAILED" - - -class AgentBrowseRequestCreate(BaseModel): - agent_id: str - path: str | None = None - - -class AgentFolderEntry(BaseModel): - name: str - path: str - is_directory: bool = True - - -class AgentBrowseRequest(BaseModel): - request_id: str - agent_id: str - path: str | None = None - status: AgentBrowseRequestStatus = AgentBrowseRequestStatus.QUEUED - created_at: str - updated_at: str - claimed_at: str | None = None - completed_at: str | None = None - entries: list[AgentFolderEntry] = Field(default_factory=list) - parent_path: str | None = None - error: str | None = None - - -class AgentBrowseResult(BaseModel): - status: AgentBrowseRequestStatus = AgentBrowseRequestStatus.SUCCEEDED - entries: list[AgentFolderEntry] = Field(default_factory=list) - parent_path: str | None = None - error: str | None = None - - -class AgentHeartbeatRequest(BaseModel): - agent_id: str - host: str | None = None - user: str | None = None - version: str | None = None - started_at: str | None = None - network_roots: list[str] = Field(default_factory=list) - platform_bins: list[str] = Field(default_factory=list) - - -class AgentStatus(BaseModel): - agent_id: str - status: str = "offline" - last_seen_at: str | None = None - host: str | None = None - user: str | None = None - version: str | None = None - started_at: str | None = None - network_roots: list[str] = Field(default_factory=list) - platform_bins: list[str] = Field(default_factory=list) - - -class AgentProjectConfig(BaseModel): - project_id: str - project_name: str - one_c_bin: str | None = None - edt_path: str | None = None - default_local_path: str | None = None - network_roots: list[str] = Field(default_factory=list) - - -class AgentConfigResponse(BaseModel): - agent_id: str - poll_seconds: int = 5 - projects: list[AgentProjectConfig] = Field(default_factory=list) - - -class ServerBrowseResponse(BaseModel): - path: str - parent_path: str | None = None - entries: list[AgentFolderEntry] = Field(default_factory=list) - error: str | None = None - - class ServerSmbBrowseRequest(BaseModel): path: str username: str | None = None