Files
RiceRound d62754850e fix bug
Added serial number validity period and days feature.
Fixed the bug where the serial number could only be used for 7 days.
Code optimization.
2025-01-19 07:26:32 +08:00

244 lines
8.7 KiB
Python

import json
import os
import requests
from .url_config import CatUrlConfig, download_crypto_workflow, user_upload_workflow
from .utils import combine_files, get_machine_id, get_local_app_setting_path
from .auth_unit import AuthUnit
from server import PromptServer
from aiohttp import web
import time
class Cancelled(Exception):
pass
class MessageHolder:
stash = {}
messages = {}
cancelled = False
@classmethod
def addMessage(cls, id, message):
if message == "__cancel__":
cls.messages = {}
cls.cancelled = True
elif message == "__start__":
cls.messages = {}
cls.stash = {}
cls.cancelled = False
else:
cls.messages[str(id)] = message
@classmethod
def waitForMessage(cls, id, period=0.1, timeout=60):
sid = str(id)
cls.messages.clear()
start_time = time.time()
while not sid in cls.messages and not "-1" in cls.messages:
if cls.cancelled:
cls.cancelled = False
raise Cancelled()
if time.time() - start_time > timeout:
raise Cancelled("Operation timed out")
time.sleep(period)
if cls.cancelled:
cls.cancelled = False
raise Cancelled()
message = cls.messages.pop(str(id), None) or cls.messages.pop("-1")
return message.strip()
routes = PromptServer.instance.routes
@routes.post("/cryptocat/message")
async def message_handler(request):
post = await request.post()
MessageHolder.addMessage(post.get("id"), post.get("message"))
return web.json_response({})
class UploadWorkflow:
def __init__(self, user_token):
self.user_token = user_token
def check_workflow(self, template_id):
url = CatUrlConfig().workflow_url
headers = {"Authorization": f"Bearer {self.user_token}"}
response = requests.get(
url, params={"template_id": template_id, "action": "check"}, headers=headers
)
if response.status_code == 200:
response_data = response.json()
error_code = response_data.get("code")
error_msg = response_data.get("message")
return error_code, error_msg
else:
return -1, ""
def upload_workflow(self, template_id, temp_dir):
error_code, error_msg = self.check_workflow(template_id)
if error_code == 1:
auto_overwrite = UserWorkflowSetting().get_auto_overwrite()
if not auto_overwrite:
json_content = {
"title": "已经存在相同template_id的数据,是否覆盖?",
"icon": "info",
"confirmButtonText": "覆盖",
"cancelButtonText": "取消",
"showCancelButton": True,
"timer": 50000,
}
PromptServer.instance.send_sync(
"cryptocat_dialog",
{"json_content": json.dumps(json_content), "id": template_id},
)
msg_result = MessageHolder.waitForMessage(template_id, timeout=60000)
try:
result_code = int(msg_result)
except ValueError:
print("crypto cat upload cancel: Invalid response format")
return False
if result_code != 1:
print("crypto cat upload cancel: User rejected overwrite")
return False
elif error_code != 0:
print(f"crypto cat upload failed: {error_msg}")
PromptServer.instance.send_sync(
"cryptocat_toast", {"content": f"异常情况,{error_msg}", "type": "error"}
)
return False
combine_target_path = os.path.join(temp_dir, f"cryptocat_{template_id}.zip")
combine_file_paths = []
for file in [
f"crypto_{template_id}.json",
f"original_workflow_{template_id}.json",
f"original_prompt_{template_id}.json",
]:
src_path = os.path.join(temp_dir, file)
combine_file_paths.append(src_path)
combine_files(combine_file_paths, template_id, combine_target_path)
for file_path in combine_file_paths:
os.remove(file_path)
success, message = user_upload_workflow(
template_id, combine_target_path, self.user_token
)
if success:
PromptServer.instance.send_sync(
"cryptocat_toast", {"content": "上传成功", "type": "info", "duration": 5000}
)
else:
PromptServer.instance.send_sync(
"cryptocat_toast",
{"content": f"上传失败: {message}", "type": "error", "duration": 5000},
)
return success
def generate_serial_number(
self, template_id, expire_date=None, use_days=None, count=1
):
url = CatUrlConfig().serial_number_url
headers = {"Authorization": f"Bearer {self.user_token}"}
params = {"template_id": template_id, "count": count}
if expire_date is not None:
params["expire_date"] = expire_date
if use_days is not None:
params["use_days"] = use_days
response = requests.get(url, params=params, headers=headers)
if response.status_code == 200:
response_data = response.json()
error_code = response_data.get("code")
error_msg = response_data.get("message", "")
if error_code == 0:
return response_data.get("data", [])
else:
raise ValueError(f"failed to generate serial number: {error_msg}")
else:
raise ValueError(
f"failed to generate serial number: {response.status_code}"
)
class DownloadWorkflow:
_instance = None
_cache = {}
def __new__(cls):
if cls._instance is None:
cls._instance = super(DownloadWorkflow, cls).__new__(cls)
return cls._instance
def __init__(self):
if not hasattr(self, "_initialized"):
self._initialized = True
def download_workflow(self, template_id, serial_number_token, user_token):
if not serial_number_token:
raise ValueError("需要输入序列号")
cache_key = f"{template_id}_{serial_number_token}_{user_token}"
if cache_key in self._cache:
return self._cache[cache_key]
hardware_id = get_machine_id()
success, message = download_crypto_workflow(
template_id, hardware_id, serial_number_token, user_token
)
if success:
self._cache[cache_key] = message
return message
elif message is not None:
if message == "need login" or message == "需要登录":
AuthUnit().login_dialog("运行工作流,请先完成登录")
else:
raise ValueError(message)
else:
raise ValueError("failed to download workflow")
class UserWorkflowSetting:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super(UserWorkflowSetting, cls).__new__(cls)
return cls._instance
def __init__(self):
if not hasattr(self, "initialized"):
local_app_path = get_local_app_setting_path()
local_app_path.mkdir(parents=True, exist_ok=True)
self.config_path = local_app_path / "config.ini"
self.section_name = "Workflow"
self.initialized = True
def get_auto_overwrite(self):
try:
import configparser
config = configparser.ConfigParser()
config.read(self.config_path, encoding="utf-8")
if not config.has_section(self.section_name):
return False
return config.getboolean(
self.section_name, "auto_overwrite", fallback=False
)
except Exception as e:
print(f"Error reading auto_overwrite setting: {str(e)}")
return False
def set_auto_overwrite(self, value):
try:
import configparser
config = configparser.ConfigParser()
config.read(self.config_path, encoding="utf-8")
if not config.has_section(self.section_name):
config.add_section(self.section_name)
config.set(self.section_name, "auto_overwrite", str(value).lower())
with open(self.config_path, "w", encoding="utf-8") as configfile:
config.write(configfile)
return True
except Exception as e:
print(f"Error saving auto_overwrite setting: {str(e)}")
return False