pytrace/server/app/api/endpoints_custom_nodes.py
Boshuang Zhao fb8458011a upload
2026-01-15 21:58:30 +08:00

73 lines
2.7 KiB
Python

from fastapi import APIRouter, HTTPException, Body
from pytrace.core.registry import NodeRegistry, get_type_string
import importlib.util
import sys
from pathlib import Path
import os
router = APIRouter()
# Create a directory to store custom nodes uploaded by clients
CUSTOM_NODES_DIR = Path("custom_nodes")
CUSTOM_NODES_DIR.mkdir(exist_ok=True)
if str(CUSTOM_NODES_DIR.resolve()) not in sys.path:
sys.path.insert(0, str(CUSTOM_NODES_DIR.resolve()))
@router.post("/register")
async def register_custom_node(code: str = Body(..., embed=True)):
"""
Receives Python code for a custom node, saves it, and loads it.
"""
# This is a simplified and dangerous implementation for demonstration.
# A real implementation would need heavy security validation (AST analysis, sandboxing).
try:
# For simplicity, we'll hash the code to create a filename.
import hashlib
code_hash = hashlib.sha256(code.encode()).hexdigest()
file_path = CUSTOM_NODES_DIR / f"node_{code_hash}.py"
if file_path.exists():
# Node is already registered, we can assume.
return {"message": "Node already exists and is registered."}
file_path.write_text(code, encoding="utf-8")
# Dynamically load the module.
# The node's class should have the `@register_node` decorator,
# so importing it will automatically register it.
module_name = file_path.stem
spec = importlib.util.spec_from_file_location(module_name, file_path)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
# Find which node was just registered by looking for a new class
# from the loaded module.
newly_registered_type = None
for node_type, node_class in NodeRegistry._implementations.items():
if node_class.__module__ == module_name:
newly_registered_type = node_type
break
if not newly_registered_type:
# Cleanup the created file if registration fails
os.remove(file_path)
raise HTTPException(status_code=400, detail="Could not find a class with @register_node in the provided code.")
return {
"message": "Node registered successfully.",
"node_type": newly_registered_type,
"spec": NodeRegistry.get_spec(newly_registered_type).dict()
}
except Exception as e:
import traceback
raise HTTPException(
status_code=500,
detail={
"error": str(e),
"traceback": traceback.format_exc()
}
)