Initial commit: iOS Build Server

- FastAPI backend with build queue, WebSocket logs, task management
- Vue 3 frontend with build/config/history views
- Xcode project build automation with IPA export
- Fix: initialize build_dir before try block to ensure cleanup on early failure
This commit is contained in:
shen
2026-06-06 17:42:27 +08:00
commit 6f4f625c56
51 changed files with 9968 additions and 0 deletions
+80
View File
@@ -0,0 +1,80 @@
"""并行打包队列管理"""
import asyncio
from typing import Dict, Callable, Optional
from datetime import datetime
from .log_streamer import log_streamer
class BuildQueue:
"""打包任务队列"""
def __init__(self, max_concurrent: int = 2):
self._max_concurrent = max_concurrent
self._semaphore = asyncio.Semaphore(max_concurrent)
self._queue: asyncio.Queue = asyncio.Queue()
self._running_tasks: Dict[str, asyncio.Task] = {}
self._workers: list = []
self._started = False
async def start(self):
"""启动工作线程"""
if self._started:
return
self._started = True
for i in range(self._max_concurrent):
worker = asyncio.create_task(self._worker(f"worker-{i}"))
self._workers.append(worker)
async def _worker(self, name: str):
"""工作协程"""
while True:
task_id, build_func = await self._queue.get()
try:
await self._semaphore.acquire()
try:
self._running_tasks[task_id] = asyncio.current_task()
await build_func(task_id)
finally:
self._running_tasks.pop(task_id, None)
self._semaphore.release()
except Exception as e:
await log_streamer.emit_error(task_id, f"任务异常: {str(e)}")
finally:
self._queue.task_done()
async def submit(self, task_id: str, build_func: Optional[Callable] = None):
"""提交打包任务"""
if not self._started:
await self.start()
if build_func is None:
from .build_service import run_build_task
build_func = run_build_task
await self._queue.put((task_id, build_func))
await log_streamer.emit(task_id, "任务已加入队列,等待执行...")
def cancel(self, task_id: str):
"""取消任务"""
task = self._running_tasks.get(task_id)
if task and not task.done():
task.cancel()
def update_max_concurrent(self, new_max: int):
"""更新最大并发数"""
self._max_concurrent = new_max
# 注意:运行时修改需要重建 semaphore,这里简化处理
# 实际使用时建议重启服务生效
@property
def queue_size(self) -> int:
return self._queue.qsize()
@property
def running_count(self) -> int:
return len(self._running_tasks)
# 全局单例
build_queue = BuildQueue()