|
@@ -31,7 +31,8 @@ from services.workflow_service import WorkflowService
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
IMPORT_INFO_REDIS_KEY_PREFIX = "app_import_info:"
|
|
|
-IMPORT_INFO_REDIS_EXPIRY = 2 * 60 * 60 # 2 hours
|
|
|
+CHECK_DEPENDENCIES_REDIS_KEY_PREFIX = "app_check_dependencies:"
|
|
|
+IMPORT_INFO_REDIS_EXPIRY = 10 * 60 # 10 minutes
|
|
|
CURRENT_DSL_VERSION = "0.1.4"
|
|
|
DSL_MAX_SIZE = 10 * 1024 * 1024 # 10MB
|
|
|
|
|
@@ -54,10 +55,13 @@ class Import(BaseModel):
|
|
|
app_id: Optional[str] = None
|
|
|
current_dsl_version: str = CURRENT_DSL_VERSION
|
|
|
imported_dsl_version: str = ""
|
|
|
- leaked_dependencies: list[PluginDependency] = Field(default_factory=list)
|
|
|
error: str = ""
|
|
|
|
|
|
|
|
|
+class CheckDependenciesResult(BaseModel):
|
|
|
+ leaked_dependencies: list[PluginDependency] = Field(default_factory=list)
|
|
|
+
|
|
|
+
|
|
|
def _check_version_compatibility(imported_version: str) -> ImportStatus:
|
|
|
"""Determine import status based on version comparison"""
|
|
|
try:
|
|
@@ -87,6 +91,11 @@ class PendingData(BaseModel):
|
|
|
app_id: str | None
|
|
|
|
|
|
|
|
|
+class CheckDependenciesPendingData(BaseModel):
|
|
|
+ dependencies: list[PluginDependency]
|
|
|
+ app_id: str | None
|
|
|
+
|
|
|
+
|
|
|
class AppDslService:
|
|
|
def __init__(self, session: Session):
|
|
|
self._session = session
|
|
@@ -243,23 +252,11 @@ class AppDslService:
|
|
|
imported_dsl_version=imported_version,
|
|
|
)
|
|
|
|
|
|
- try:
|
|
|
- dependencies = self.get_leaked_dependencies(account.current_tenant_id, data.get("dependencies", []))
|
|
|
- except Exception as e:
|
|
|
- return Import(
|
|
|
- id=import_id,
|
|
|
- status=ImportStatus.FAILED,
|
|
|
- error=str(e),
|
|
|
- )
|
|
|
-
|
|
|
- if len(dependencies) > 0:
|
|
|
- return Import(
|
|
|
- id=import_id,
|
|
|
- status=ImportStatus.PENDING,
|
|
|
- app_id=app_id,
|
|
|
- imported_dsl_version=imported_version,
|
|
|
- leaked_dependencies=dependencies,
|
|
|
- )
|
|
|
+ # Extract dependencies
|
|
|
+ dependencies = data.get("dependencies", [])
|
|
|
+ check_dependencies_pending_data = None
|
|
|
+ if dependencies:
|
|
|
+ check_dependencies_pending_data = [PluginDependency.model_validate(d) for d in dependencies]
|
|
|
|
|
|
# Create or update app
|
|
|
app = self._create_or_update_app(
|
|
@@ -271,6 +268,7 @@ class AppDslService:
|
|
|
icon_type=icon_type,
|
|
|
icon=icon,
|
|
|
icon_background=icon_background,
|
|
|
+ dependencies=check_dependencies_pending_data,
|
|
|
)
|
|
|
|
|
|
return Import(
|
|
@@ -355,6 +353,29 @@ class AppDslService:
|
|
|
error=str(e),
|
|
|
)
|
|
|
|
|
|
+ def check_dependencies(
|
|
|
+ self,
|
|
|
+ *,
|
|
|
+ app_model: App,
|
|
|
+ ) -> CheckDependenciesResult:
|
|
|
+ """Check dependencies"""
|
|
|
+ # Get dependencies from Redis
|
|
|
+ redis_key = f"{CHECK_DEPENDENCIES_REDIS_KEY_PREFIX}{app_model.id}"
|
|
|
+ dependencies = redis_client.get(redis_key)
|
|
|
+ if not dependencies:
|
|
|
+ return CheckDependenciesResult()
|
|
|
+
|
|
|
+ # Extract dependencies
|
|
|
+ dependencies = CheckDependenciesPendingData.model_validate_json(dependencies)
|
|
|
+
|
|
|
+ # Get leaked dependencies
|
|
|
+ leaked_dependencies = DependenciesAnalysisService.get_leaked_dependencies(
|
|
|
+ tenant_id=app_model.tenant_id, dependencies=dependencies.dependencies
|
|
|
+ )
|
|
|
+ return CheckDependenciesResult(
|
|
|
+ leaked_dependencies=leaked_dependencies,
|
|
|
+ )
|
|
|
+
|
|
|
def _create_or_update_app(
|
|
|
self,
|
|
|
*,
|
|
@@ -366,6 +387,7 @@ class AppDslService:
|
|
|
icon_type: Optional[str] = None,
|
|
|
icon: Optional[str] = None,
|
|
|
icon_background: Optional[str] = None,
|
|
|
+ dependencies: Optional[list[PluginDependency]] = None,
|
|
|
) -> App:
|
|
|
"""Create a new app or update an existing one."""
|
|
|
app_data = data.get("app", {})
|
|
@@ -408,6 +430,14 @@ class AppDslService:
|
|
|
self._session.commit()
|
|
|
app_was_created.send(app, account=account)
|
|
|
|
|
|
+ # save dependencies
|
|
|
+ if dependencies:
|
|
|
+ redis_client.setex(
|
|
|
+ f"{CHECK_DEPENDENCIES_REDIS_KEY_PREFIX}{app.id}",
|
|
|
+ IMPORT_INFO_REDIS_EXPIRY,
|
|
|
+ CheckDependenciesPendingData(app_id=app.id, dependencies=dependencies).model_dump_json(),
|
|
|
+ )
|
|
|
+
|
|
|
# Initialize app based on mode
|
|
|
if app_mode in {AppMode.ADVANCED_CHAT, AppMode.WORKFLOW}:
|
|
|
workflow_data = data.get("workflow")
|