Spaces:
Running
Running
Upload 8 files
Browse files- app.py +4 -1
- owned_thread.py +25 -1
- resource_work.py +45 -0
- router_items.py +6 -5
- router_wallet.py +0 -0
app.py
CHANGED
|
@@ -70,7 +70,7 @@ from router_users_social import router as users_social_router
|
|
| 70 |
from router_items import (router as items_router, start_resource_reads, stop_resource_reads, close_resource_reads) # 📦 内容管理(工具/Skill/应用/推荐)
|
| 71 |
from router_comments import (router as comments_router, start_comment_writes, stop_comment_writes, close_comment_writes) # 💬 评论系统
|
| 72 |
from router_messages import (router as messages_router, start_message_io, stop_message_io, close_message_io) # ✉️ 私信系统
|
| 73 |
-
from router_wallet import router as wallet_router # 💰 钱包/提现
|
| 74 |
from router_proxy import router as proxy_router # 🔗 代理下载
|
| 75 |
from router_posts import (router as posts_router, start_posts_io, stop_posts_io, close_posts_io) # 💬 讨论区
|
| 76 |
from router_prompts import (router as prompts_router, start_prompts_io, stop_prompts_io, close_prompts_io) # ✨ 提示词市场
|
|
@@ -294,6 +294,7 @@ async def on_startup():
|
|
| 294 |
start_identity_io()
|
| 295 |
start_shared_work()
|
| 296 |
start_open_sql()
|
|
|
|
| 297 |
start_resource_work()
|
| 298 |
start_resource_reads()
|
| 299 |
start_comment_writes()
|
|
@@ -358,6 +359,7 @@ async def _shutdown_resources():
|
|
| 358 |
failures.call('log_start', logger.info, "🛑 ComfyUI-Ranking API 正在关闭...")
|
| 359 |
failures.call('stop_warmup', stop_startup_warmup, app.state)
|
| 360 |
for stage, stop in (
|
|
|
|
| 361 |
('stop_resource_reads', stop_resource_reads), ('stop_comment_writes', stop_comment_writes),
|
| 362 |
('stop_posts', stop_posts_io), ('stop_prompts', stop_prompts_io),
|
| 363 |
('stop_messages', stop_message_io), ('stop_resources', stop_resource_work), ('stop_open_sql', stop_open_sql), ('stop_shared', stop_shared_work),
|
|
@@ -374,6 +376,7 @@ async def _shutdown_resources():
|
|
| 374 |
failures.call('stop_' + name, request_periodic_stop, app.state, (name,))
|
| 375 |
for stage, close, args in (
|
| 376 |
('wait_warmup', wait_startup_warmup, (app.state,)),
|
|
|
|
| 377 |
('close_resource_reads', close_resource_reads, ()), ('close_comment_writes', close_comment_writes, ()),
|
| 378 |
('close_posts', close_posts_io, ()), ('close_prompts', close_prompts_io, ()),
|
| 379 |
('close_messages', close_message_io, ()), ('close_resources', close_resource_work, ()), ('close_open_sql', close_open_sql, ()), ('close_shared', close_shared_work, ()),
|
|
|
|
| 70 |
from router_items import (router as items_router, start_resource_reads, stop_resource_reads, close_resource_reads) # 📦 内容管理(工具/Skill/应用/推荐)
|
| 71 |
from router_comments import (router as comments_router, start_comment_writes, stop_comment_writes, close_comment_writes) # 💬 评论系统
|
| 72 |
from router_messages import (router as messages_router, start_message_io, stop_message_io, close_message_io) # ✉️ 私信系统
|
| 73 |
+
from router_wallet import (router as wallet_router, start_wallet_sql, stop_wallet_sql, close_wallet_sql) # 💰 钱包/提现
|
| 74 |
from router_proxy import router as proxy_router # 🔗 代理下载
|
| 75 |
from router_posts import (router as posts_router, start_posts_io, stop_posts_io, close_posts_io) # 💬 讨论区
|
| 76 |
from router_prompts import (router as prompts_router, start_prompts_io, stop_prompts_io, close_prompts_io) # ✨ 提示词市场
|
|
|
|
| 294 |
start_identity_io()
|
| 295 |
start_shared_work()
|
| 296 |
start_open_sql()
|
| 297 |
+
start_wallet_sql()
|
| 298 |
start_resource_work()
|
| 299 |
start_resource_reads()
|
| 300 |
start_comment_writes()
|
|
|
|
| 359 |
failures.call('log_start', logger.info, "🛑 ComfyUI-Ranking API 正在关闭...")
|
| 360 |
failures.call('stop_warmup', stop_startup_warmup, app.state)
|
| 361 |
for stage, stop in (
|
| 362 |
+
('stop_wallet_sql', stop_wallet_sql),
|
| 363 |
('stop_resource_reads', stop_resource_reads), ('stop_comment_writes', stop_comment_writes),
|
| 364 |
('stop_posts', stop_posts_io), ('stop_prompts', stop_prompts_io),
|
| 365 |
('stop_messages', stop_message_io), ('stop_resources', stop_resource_work), ('stop_open_sql', stop_open_sql), ('stop_shared', stop_shared_work),
|
|
|
|
| 376 |
failures.call('stop_' + name, request_periodic_stop, app.state, (name,))
|
| 377 |
for stage, close, args in (
|
| 378 |
('wait_warmup', wait_startup_warmup, (app.state,)),
|
| 379 |
+
('close_wallet_sql', close_wallet_sql, ()),
|
| 380 |
('close_resource_reads', close_resource_reads, ()), ('close_comment_writes', close_comment_writes, ()),
|
| 381 |
('close_posts', close_posts_io, ()), ('close_prompts', close_prompts_io, ()),
|
| 382 |
('close_messages', close_message_io, ()), ('close_resources', close_resource_work, ()), ('close_open_sql', close_open_sql, ()), ('close_shared', close_shared_work, ()),
|
owned_thread.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
"""等待所属同步工作真实终态;内部取消也不能遗留仍读写资源的线程。"""
|
| 2 |
import asyncio
|
| 3 |
from functools import wraps
|
| 4 |
-
from inspect import iscoroutinefunction, isasyncgenfunction, isgeneratorfunction
|
| 5 |
import threading
|
| 6 |
|
| 7 |
|
|
@@ -142,3 +142,27 @@ def owned_sync_endpoint(group):
|
|
| 142 |
return await group.run(endpoint, *args, **kwargs)
|
| 143 |
return invoke
|
| 144 |
return decorate
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
"""等待所属同步工作真实终态;内部取消也不能遗留仍读写资源的线程。"""
|
| 2 |
import asyncio
|
| 3 |
from functools import wraps
|
| 4 |
+
from inspect import Parameter, signature, iscoroutinefunction, isasyncgenfunction, isgeneratorfunction
|
| 5 |
import threading
|
| 6 |
|
| 7 |
|
|
|
|
| 142 |
return await group.run(endpoint, *args, **kwargs)
|
| 143 |
return invoke
|
| 144 |
return decorate
|
| 145 |
+
|
| 146 |
+
|
| 147 |
+
def owned_session_endpoint(group, session_factory, session_parameter):
|
| 148 |
+
def decorate(endpoint):
|
| 149 |
+
if iscoroutinefunction(endpoint) or isasyncgenfunction(endpoint) or isgeneratorfunction(endpoint):
|
| 150 |
+
raise TypeError('owned session endpoint must be a synchronous function')
|
| 151 |
+
original = signature(endpoint)
|
| 152 |
+
if session_parameter not in original.parameters:
|
| 153 |
+
raise ValueError('missing owned session parameter')
|
| 154 |
+
if any(parameter.kind not in (Parameter.POSITIONAL_OR_KEYWORD, Parameter.KEYWORD_ONLY)
|
| 155 |
+
for parameter in original.parameters.values()):
|
| 156 |
+
raise TypeError('owned session endpoint requires named parameters')
|
| 157 |
+
public = original.replace(parameters=[parameter for name, parameter in original.parameters.items()
|
| 158 |
+
if name != session_parameter])
|
| 159 |
+
@wraps(endpoint)
|
| 160 |
+
async def invoke(*args, **kwargs):
|
| 161 |
+
arguments = public.bind(*args, **kwargs).arguments
|
| 162 |
+
def execute():
|
| 163 |
+
with session_factory() as session:
|
| 164 |
+
return endpoint(**arguments, **{session_parameter: session})
|
| 165 |
+
return await group.run(execute)
|
| 166 |
+
invoke.__signature__ = public
|
| 167 |
+
return invoke
|
| 168 |
+
return decorate
|
resource_work.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
| 1 |
"""资源写入与可选预缓存的准入和关闭归属。"""
|
| 2 |
import asyncio
|
| 3 |
import logging
|
|
|
|
| 4 |
|
| 5 |
from fastapi import HTTPException
|
| 6 |
from owned_thread import OwnedThreadGroup, owned_sync_endpoint
|
|
@@ -34,6 +35,49 @@ class ResourceWork:
|
|
| 34 |
async def run(self, function, *args, **kwargs):
|
| 35 |
return await self.writes.run(function, *args, **kwargs)
|
| 36 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 37 |
def background(self, factory):
|
| 38 |
if not self._accepting or len(self._tasks) >= self.background_capacity:
|
| 39 |
return False
|
|
@@ -83,6 +127,7 @@ class ResourceWork:
|
|
| 83 |
_resource_work = ResourceWork()
|
| 84 |
run_resource_write = _resource_work.run
|
| 85 |
resource_write_endpoint = owned_sync_endpoint(_resource_work)
|
|
|
|
| 86 |
start_resource_background = _resource_work.background
|
| 87 |
start_resource_work = _resource_work.start
|
| 88 |
stop_resource_work = _resource_work.stop
|
|
|
|
| 1 |
"""资源写入与可选预缓存的准入和关闭归属。"""
|
| 2 |
import asyncio
|
| 3 |
import logging
|
| 4 |
+
from functools import wraps
|
| 5 |
|
| 6 |
from fastapi import HTTPException
|
| 7 |
from owned_thread import OwnedThreadGroup, owned_sync_endpoint
|
|
|
|
| 35 |
async def run(self, function, *args, **kwargs):
|
| 36 |
return await self.writes.run(function, *args, **kwargs)
|
| 37 |
|
| 38 |
+
def endpoint(self, function):
|
| 39 |
+
@wraps(function)
|
| 40 |
+
async def invoke(*args, **kwargs):
|
| 41 |
+
return await self.operation(function, *args, **kwargs)
|
| 42 |
+
return invoke
|
| 43 |
+
|
| 44 |
+
async def operation(self, function, *args, **kwargs):
|
| 45 |
+
if not self._accepting or len(self._tasks) >= self.background_capacity:
|
| 46 |
+
raise HTTPException(status_code=503, detail='资源处理繁忙,请稍后重试')
|
| 47 |
+
|
| 48 |
+
async def execute():
|
| 49 |
+
try:
|
| 50 |
+
return True, await function(*args, **kwargs)
|
| 51 |
+
except BaseException as error:
|
| 52 |
+
return False, error
|
| 53 |
+
|
| 54 |
+
coroutine = execute()
|
| 55 |
+
try:
|
| 56 |
+
task = asyncio.create_task(coroutine)
|
| 57 |
+
except BaseException:
|
| 58 |
+
coroutine.close()
|
| 59 |
+
raise
|
| 60 |
+
self._tasks.add(task)
|
| 61 |
+
cancelled = None
|
| 62 |
+
try:
|
| 63 |
+
while not task.done():
|
| 64 |
+
try:
|
| 65 |
+
await asyncio.shield(task)
|
| 66 |
+
except asyncio.CancelledError as error:
|
| 67 |
+
if cancelled is None:
|
| 68 |
+
cancelled = error
|
| 69 |
+
task.cancel()
|
| 70 |
+
if task.cancelled():
|
| 71 |
+
raise cancelled or asyncio.CancelledError()
|
| 72 |
+
succeeded, result = task.result()
|
| 73 |
+
if cancelled is not None:
|
| 74 |
+
raise cancelled
|
| 75 |
+
if not succeeded:
|
| 76 |
+
raise result
|
| 77 |
+
return result
|
| 78 |
+
finally:
|
| 79 |
+
self._tasks.discard(task)
|
| 80 |
+
|
| 81 |
def background(self, factory):
|
| 82 |
if not self._accepting or len(self._tasks) >= self.background_capacity:
|
| 83 |
return False
|
|
|
|
| 127 |
_resource_work = ResourceWork()
|
| 128 |
run_resource_write = _resource_work.run
|
| 129 |
resource_write_endpoint = owned_sync_endpoint(_resource_work)
|
| 130 |
+
resource_operation_endpoint = _resource_work.endpoint
|
| 131 |
start_resource_background = _resource_work.background
|
| 132 |
start_resource_work = _resource_work.start
|
| 133 |
stop_resource_work = _resource_work.stop
|
router_items.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
-
from resource_work import run_resource_write, start_resource_background, resource_write_endpoint
|
| 2 |
-
from owned_thread import OwnedThreadGroup, owned_sync_endpoint
|
| 3 |
# router_items.py
|
| 4 |
from fastapi import APIRouter, HTTPException, Depends, Request
|
| 5 |
from rate_limit import shared_limit
|
|
@@ -11,7 +11,6 @@ import re
|
|
| 11 |
import urllib.request
|
| 12 |
import urllib.error
|
| 13 |
import json
|
| 14 |
-
import asyncio
|
| 15 |
import 数据库连接 as db
|
| 16 |
from models import ItemCreate, ItemUpdate, RatingRequest
|
| 17 |
from 安全认证 import require_auth, check_ownership, is_admin
|
|
@@ -496,13 +495,14 @@ async def update_item(request: Request, item_id: str, update_data: ItemUpdate, c
|
|
| 496 |
# ==========================================
|
| 497 |
@router.post("/api/check_updates")
|
| 498 |
@shared_limit(30)
|
|
|
|
| 499 |
async def check_github_updates(request: Request, current_user: str = Depends(require_auth)):
|
| 500 |
"""
|
| 501 |
遍历所有 GitHub 类型的工具,获取最新 commit hash,存入 versions.json
|
| 502 |
"""
|
| 503 |
if not is_admin(current_user):
|
| 504 |
raise HTTPException(status_code=403, detail="无权限")
|
| 505 |
-
items_db = await
|
| 506 |
updated_count = 0
|
| 507 |
for item in items_db:
|
| 508 |
if not item.get('link', '').startswith('https://github.com/'):
|
|
@@ -788,9 +788,10 @@ def toggle_item_favorite(request: Request, item_id: str, current_user: str = Dep
|
|
| 788 |
# ==========================================
|
| 789 |
@router.post("/api/items/{item_id}/refresh_cache")
|
| 790 |
@shared_limit(3)
|
|
|
|
| 791 |
async def refresh_item_cache(request: Request, item_id: str, current_user: str = Depends(require_auth)):
|
| 792 |
"""手动触发指定资源的 ZIP 预缓存刷新,仅限作者调用"""
|
| 793 |
-
items_db = db.load_data
|
| 794 |
|
| 795 |
# 查找目标 item
|
| 796 |
target_item = None
|
|
|
|
| 1 |
+
from resource_work import run_resource_write, start_resource_background, resource_write_endpoint, resource_operation_endpoint
|
| 2 |
+
from owned_thread import OwnedThreadGroup, owned_sync_endpoint, run_owned_thread
|
| 3 |
# router_items.py
|
| 4 |
from fastapi import APIRouter, HTTPException, Depends, Request
|
| 5 |
from rate_limit import shared_limit
|
|
|
|
| 11 |
import urllib.request
|
| 12 |
import urllib.error
|
| 13 |
import json
|
|
|
|
| 14 |
import 数据库连接 as db
|
| 15 |
from models import ItemCreate, ItemUpdate, RatingRequest
|
| 16 |
from 安全认证 import require_auth, check_ownership, is_admin
|
|
|
|
| 495 |
# ==========================================
|
| 496 |
@router.post("/api/check_updates")
|
| 497 |
@shared_limit(30)
|
| 498 |
+
@resource_operation_endpoint
|
| 499 |
async def check_github_updates(request: Request, current_user: str = Depends(require_auth)):
|
| 500 |
"""
|
| 501 |
遍历所有 GitHub 类型的工具,获取最新 commit hash,存入 versions.json
|
| 502 |
"""
|
| 503 |
if not is_admin(current_user):
|
| 504 |
raise HTTPException(status_code=403, detail="无权限")
|
| 505 |
+
items_db = await run_owned_thread(db.load_data, "items.json", default_data=[], strict=True, skip_cache=True)
|
| 506 |
updated_count = 0
|
| 507 |
for item in items_db:
|
| 508 |
if not item.get('link', '').startswith('https://github.com/'):
|
|
|
|
| 788 |
# ==========================================
|
| 789 |
@router.post("/api/items/{item_id}/refresh_cache")
|
| 790 |
@shared_limit(3)
|
| 791 |
+
@resource_operation_endpoint
|
| 792 |
async def refresh_item_cache(request: Request, item_id: str, current_user: str = Depends(require_auth)):
|
| 793 |
"""手动触发指定资源的 ZIP 预缓存刷新,仅限作者调用"""
|
| 794 |
+
items_db = await run_owned_thread(db.load_data, "items.json", default_data=[])
|
| 795 |
|
| 796 |
# 查找目标 item
|
| 797 |
target_item = None
|
router_wallet.py
CHANGED
|
The diff for this file is too large to render.
See raw diff
|
|
|