feat: 添加CORS支持,优化API响应,重构工作流管理逻辑,支持本地存储设置
This commit is contained in:
153
__init__.py
153
__init__.py
@@ -13,7 +13,6 @@ CONFIG_FILE = os.path.join(NODE_DIR, "config.json")
|
||||
|
||||
# 默认配置
|
||||
DEFAULT_CONFIG = {
|
||||
"api_url": "",
|
||||
"host": ""
|
||||
}
|
||||
|
||||
@@ -75,7 +74,11 @@ class WorkflowPublisherNode:
|
||||
async def get_publisher_settings(request):
|
||||
"""获取发布器设置"""
|
||||
config = load_config()
|
||||
return web.json_response(config)
|
||||
response = web.json_response(config)
|
||||
response.headers['Access-Control-Allow-Origin'] = '*'
|
||||
response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS'
|
||||
response.headers['Access-Control-Allow-Headers'] = 'Content-Type, Authorization'
|
||||
return response
|
||||
|
||||
|
||||
@PromptServer.instance.routes.post("/publisher/settings")
|
||||
@@ -83,15 +86,21 @@ async def save_publisher_settings(request):
|
||||
"""保存发布器设置"""
|
||||
try:
|
||||
data = await request.json()
|
||||
api_url = data.get("api_url", "")
|
||||
host = data.get("host", "")
|
||||
config = load_config()
|
||||
config["api_url"] = api_url
|
||||
config["host"] = host
|
||||
save_config(config)
|
||||
return web.json_response({"status": "success", "message": "Settings saved"})
|
||||
response = web.json_response({"status": "success", "message": "Settings saved"})
|
||||
response.headers['Access-Control-Allow-Origin'] = '*'
|
||||
response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS'
|
||||
response.headers['Access-Control-Allow-Headers'] = 'Content-Type, Authorization'
|
||||
return response
|
||||
except Exception as e:
|
||||
return web.json_response({"status": "error", "message": str(e)}, status=500)
|
||||
response = web.json_response({"status": "error", "message": str(e)}, status=500)
|
||||
response.headers['Access-Control-Allow-Origin'] = '*'
|
||||
response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS'
|
||||
response.headers['Access-Control-Allow-Headers'] = 'Content-Type, Authorization'
|
||||
return response
|
||||
|
||||
|
||||
@PromptServer.instance.routes.post("/publisher/publish")
|
||||
@@ -103,22 +112,24 @@ async def publish_workflow_handler(request):
|
||||
workflow_name = data.get("name")
|
||||
|
||||
if not workflow or not workflow_name:
|
||||
return web.json_response({"status": "error", "message": "Missing workflow data or name"}, status=400)
|
||||
response = web.json_response({"status": "error", "message": "Missing workflow data or name"}, status=400)
|
||||
response.headers['Access-Control-Allow-Origin'] = '*'
|
||||
response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS'
|
||||
response.headers['Access-Control-Allow-Headers'] = 'Content-Type, Authorization'
|
||||
return response
|
||||
|
||||
config = load_config()
|
||||
target_api_url = config.get("api_url")
|
||||
host = config.get("host", "")
|
||||
|
||||
if not target_api_url:
|
||||
return web.json_response({"status": "error", "message": "API URL not configured"}, status=400)
|
||||
if not host:
|
||||
response = web.json_response({"status": "error", "message": "Host not configured"}, status=400)
|
||||
response.headers['Access-Control-Allow-Origin'] = '*'
|
||||
response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS'
|
||||
response.headers['Access-Control-Allow-Headers'] = 'Content-Type, Authorization'
|
||||
return response
|
||||
|
||||
# 构建完整的URL
|
||||
if host and not target_api_url.startswith(('http://', 'https://')):
|
||||
# 如果提供了host且api_url不是完整URL,则组合它们
|
||||
full_url = host.rstrip('/') + '/' + target_api_url.lstrip('/')
|
||||
else:
|
||||
# 否则直接使用api_url
|
||||
full_url = target_api_url
|
||||
# 构建完整的URL - 直接使用 host + /api/workflow
|
||||
full_url = host.rstrip('/') + '/api/workflow'
|
||||
|
||||
# 准备要发送到目标API的数据
|
||||
payload = {
|
||||
@@ -133,19 +144,31 @@ async def publish_workflow_handler(request):
|
||||
async with session.post(full_url, json=payload, headers=headers) as response:
|
||||
response_text = await response.text()
|
||||
if response.status == 200 or response.status == 201:
|
||||
return web.json_response(
|
||||
result_response = web.json_response(
|
||||
{"status": "success", "message": "Workflow published successfully!", "details": response_text})
|
||||
result_response.headers['Access-Control-Allow-Origin'] = '*'
|
||||
result_response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS'
|
||||
result_response.headers['Access-Control-Allow-Headers'] = 'Content-Type, Authorization'
|
||||
return result_response
|
||||
else:
|
||||
return web.json_response({
|
||||
result_response = web.json_response({
|
||||
"status": "error",
|
||||
"message": f"Failed to publish workflow. Target API returned status {response.status}",
|
||||
"details": response_text
|
||||
}, status=500)
|
||||
result_response.headers['Access-Control-Allow-Origin'] = '*'
|
||||
result_response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS'
|
||||
result_response.headers['Access-Control-Allow-Headers'] = 'Content-Type, Authorization'
|
||||
return result_response
|
||||
|
||||
except Exception as e:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return web.json_response({"status": "error", "message": str(e)}, status=500)
|
||||
result_response = web.json_response({"status": "error", "message": str(e)}, status=500)
|
||||
result_response.headers['Access-Control-Allow-Origin'] = '*'
|
||||
result_response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS'
|
||||
result_response.headers['Access-Control-Allow-Headers'] = 'Content-Type, Authorization'
|
||||
return result_response
|
||||
|
||||
|
||||
@PromptServer.instance.routes.get("/publisher/workflows")
|
||||
@@ -153,29 +176,31 @@ async def get_workflows_from_server(request):
|
||||
"""从目标服务器获取工作流列表,并按基础名称进行分组"""
|
||||
try:
|
||||
config = load_config()
|
||||
target_api_url = config.get("api_url")
|
||||
host = config.get("host", "")
|
||||
|
||||
if not target_api_url:
|
||||
return web.json_response({"status": "error", "message": "API URL not configured"}, status=400)
|
||||
if not host:
|
||||
response = web.json_response({"status": "error", "message": "Host not configured"}, status=400)
|
||||
response.headers['Access-Control-Allow-Origin'] = '*'
|
||||
response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS'
|
||||
response.headers['Access-Control-Allow-Headers'] = 'Content-Type, Authorization'
|
||||
return response
|
||||
|
||||
# 构建完整的URL
|
||||
if host and not target_api_url.startswith(('http://', 'https://')):
|
||||
# 如果提供了host且api_url不是完整URL,则组合它们
|
||||
full_url = host.rstrip('/') + '/' + target_api_url.lstrip('/')
|
||||
else:
|
||||
# 否则直接使用api_url
|
||||
full_url = target_api_url
|
||||
# 构建完整的URL - 直接使用 host + /api/workflow
|
||||
full_url = host.rstrip('/') + '/api/workflow'
|
||||
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(full_url) as response:
|
||||
if response.status != 200:
|
||||
response_text = await response.text()
|
||||
return web.json_response({
|
||||
result_response = web.json_response({
|
||||
"status": "error",
|
||||
"message": f"Failed to fetch workflows. Target API returned status {response.status}",
|
||||
"details": response_text
|
||||
}, status=500)
|
||||
result_response.headers['Access-Control-Allow-Origin'] = '*'
|
||||
result_response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS'
|
||||
result_response.headers['Access-Control-Allow-Headers'] = 'Content-Type, Authorization'
|
||||
return result_response
|
||||
|
||||
workflows = await response.json()
|
||||
|
||||
@@ -206,12 +231,20 @@ async def get_workflows_from_server(request):
|
||||
for base_name in grouped_workflows:
|
||||
grouped_workflows[base_name].sort(key=lambda x: x['version'], reverse=True)
|
||||
|
||||
return web.json_response(grouped_workflows)
|
||||
result_response = web.json_response(grouped_workflows)
|
||||
result_response.headers['Access-Control-Allow-Origin'] = '*'
|
||||
result_response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS'
|
||||
result_response.headers['Access-Control-Allow-Headers'] = 'Content-Type, Authorization'
|
||||
return result_response
|
||||
|
||||
except Exception as e:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return web.json_response({"status": "error", "message": str(e)}, status=500)
|
||||
result_response = web.json_response({"status": "error", "message": str(e)}, status=500)
|
||||
result_response.headers['Access-Control-Allow-Origin'] = '*'
|
||||
result_response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS'
|
||||
result_response.headers['Access-Control-Allow-Headers'] = 'Content-Type, Authorization'
|
||||
return result_response
|
||||
|
||||
|
||||
@PromptServer.instance.routes.post("/publisher/workflow/delete")
|
||||
@@ -221,22 +254,24 @@ async def delete_workflow_version(request):
|
||||
data = await request.json()
|
||||
workflow_name = data.get("name")
|
||||
if not workflow_name:
|
||||
return web.json_response({"status": "error", "message": "Missing workflow name"}, status=400)
|
||||
response = web.json_response({"status": "error", "message": "Missing workflow name"}, status=400)
|
||||
response.headers['Access-Control-Allow-Origin'] = '*'
|
||||
response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS'
|
||||
response.headers['Access-Control-Allow-Headers'] = 'Content-Type, Authorization'
|
||||
return response
|
||||
|
||||
config = load_config()
|
||||
target_api_url = config.get("api_url")
|
||||
host = config.get("host", "")
|
||||
|
||||
if not target_api_url:
|
||||
return web.json_response({"status": "error", "message": "API URL not configured"}, status=400)
|
||||
if not host:
|
||||
response = web.json_response({"status": "error", "message": "Host not configured"}, status=400)
|
||||
response.headers['Access-Control-Allow-Origin'] = '*'
|
||||
response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS'
|
||||
response.headers['Access-Control-Allow-Headers'] = 'Content-Type, Authorization'
|
||||
return response
|
||||
|
||||
# 构建完整的URL
|
||||
if host and not target_api_url.startswith(('http://', 'https://')):
|
||||
# 如果提供了host且api_url不是完整URL,则组合它们
|
||||
base_url = host.rstrip('/') + '/' + target_api_url.lstrip('/')
|
||||
else:
|
||||
# 否则直接使用api_url
|
||||
base_url = target_api_url
|
||||
# 构建完整的URL - 直接使用 host + /api/workflow
|
||||
base_url = host.rstrip('/') + '/api/workflow'
|
||||
|
||||
# 构建目标URL,需要对工作流名称进行URL编码
|
||||
delete_url = f"{base_url}/{urllib.parse.quote(workflow_name)}"
|
||||
@@ -244,16 +279,40 @@ async def delete_workflow_version(request):
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.delete(delete_url) as response:
|
||||
if response.status == 200:
|
||||
return web.json_response({"status": "success", "message": "Workflow version deleted"})
|
||||
result_response = web.json_response({"status": "success", "message": "Workflow version deleted"})
|
||||
result_response.headers['Access-Control-Allow-Origin'] = '*'
|
||||
result_response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS'
|
||||
result_response.headers['Access-Control-Allow-Headers'] = 'Content-Type, Authorization'
|
||||
return result_response
|
||||
else:
|
||||
details = await response.text()
|
||||
return web.json_response({
|
||||
result_response = web.json_response({
|
||||
"status": "error",
|
||||
"message": f"Target API failed to delete. Status: {response.status}",
|
||||
"details": details
|
||||
}, status=response.status)
|
||||
result_response.headers['Access-Control-Allow-Origin'] = '*'
|
||||
result_response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS'
|
||||
result_response.headers['Access-Control-Allow-Headers'] = 'Content-Type, Authorization'
|
||||
return result_response
|
||||
except Exception as e:
|
||||
return web.json_response({"status": "error", "message": str(e)}, status=500)
|
||||
result_response = web.json_response({"status": "error", "message": str(e)}, status=500)
|
||||
result_response.headers['Access-Control-Allow-Origin'] = '*'
|
||||
result_response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS'
|
||||
result_response.headers['Access-Control-Allow-Headers'] = 'Content-Type, Authorization'
|
||||
return result_response
|
||||
|
||||
|
||||
# 添加OPTIONS请求处理,用于CORS预检请求
|
||||
@PromptServer.instance.routes.options("/publisher/{path:.*}")
|
||||
async def handle_options(request):
|
||||
"""处理CORS预检请求"""
|
||||
response = web.Response()
|
||||
response.headers['Access-Control-Allow-Origin'] = '*'
|
||||
response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS'
|
||||
response.headers['Access-Control-Allow-Headers'] = 'Content-Type, Authorization'
|
||||
response.headers['Access-Control-Max-Age'] = '86400' # 24小时
|
||||
return response
|
||||
|
||||
# -----------------
|
||||
# ComfyUI 注册
|
||||
|
||||
Reference in New Issue
Block a user