This commit is contained in:
@@ -11,7 +11,8 @@ from fastapi.responses import FileResponse, JSONResponse, Response
|
||||
from sqlalchemy import select, func, text
|
||||
from starlette.concurrency import run_in_threadpool
|
||||
from .config import settings
|
||||
from .db import Job, sessions
|
||||
from .expiry import expiration
|
||||
from .db import Job, sessions, active_jobs
|
||||
from .storage import storage
|
||||
from .uploads import read_pcb
|
||||
from .models.pcb import PCBData, PCBStatus, PCBUploadResponse, PCBComparisonStatus, PCBComparisonUploadResponse
|
||||
@@ -34,18 +35,17 @@ def register_pcb_routes(app, *, authorize, require_api, error):
|
||||
return result
|
||||
|
||||
async def create(files, access, expires_in, comparison):
|
||||
ttl = expires_in or settings().link_ttl
|
||||
if ttl > settings().link_ttl: error('invalid_expiry','expires_in exceeds configured link lifetime',422)
|
||||
now=time.time();expires_at=expiration(expires_in,now)
|
||||
sources = {}
|
||||
try:
|
||||
for field, file in files.items(): sources[field] = await read_pcb(file)
|
||||
finally:
|
||||
for file in files.values(): await file.close()
|
||||
identifier = secrets.token_hex(24); token = secrets.token_urlsafe(32); now = time.time()
|
||||
identifier = secrets.token_hex(24); token = secrets.token_urlsafe(32)
|
||||
input_name = 'pcb-comparison.json' if comparison else 'input.PcbDoc'
|
||||
job = Job(id=identifier, filename='PCB comparison' if comparison else sources['file'][0],
|
||||
status='queued', access=access, token_hash=hashlib.sha256(token.encode()).hexdigest(),
|
||||
created_at=now, updated_at=now, expires_at=now+ttl, attempt=0, input_key=f'{identifier}/{input_name}')
|
||||
created_at=now, updated_at=now, expires_at=expires_at, attempt=0, input_key=f'{identifier}/{input_name}')
|
||||
if comparison:
|
||||
bodies = {f'{identifier}/{side}.PcbDoc':sources[side+'_file'][1] for side in ('old','new')}
|
||||
bodies[job.input_key] = json.dumps(dict(schema_version='1.0',document_type='pcb_comparison',
|
||||
@@ -56,7 +56,7 @@ def register_pcb_routes(app, *, authorize, require_api, error):
|
||||
try:
|
||||
with sessions().begin() as db:
|
||||
if db.bind.dialect.name == 'postgresql': db.execute(text('SELECT pg_advisory_xact_lock(84721309)'))
|
||||
pending = db.scalar(select(func.count()).select_from(Job).where(Job.status.in_(['queued','processing']),Job.expires_at>now))
|
||||
pending = db.scalar(select(func.count()).select_from(Job).where(Job.status.in_(['queued','processing']),active_jobs(now)))
|
||||
if pending >= settings().max_pending: error('queue_full','Rendering queue is full; try again later',503)
|
||||
for key, body in bodies.items():
|
||||
# Include the attempted key so a write-then-raise backend is also cleaned up.
|
||||
@@ -78,14 +78,14 @@ def register_pcb_routes(app, *, authorize, require_api, error):
|
||||
|
||||
@app.post('/api/v1/pcbs/render', status_code=202, response_model=PCBUploadResponse, response_model_exclude_none=True, tags=['PCB'])
|
||||
async def render(file:Annotated[UploadFile,File()], access:Annotated[Literal['private','unlisted'],Form()]='private',
|
||||
expires_in:Annotated[int|None,Form(gt=0)]=None, x_api_key:Annotated[str|None,Header()]=None):
|
||||
expires_in:Annotated[int|None,Form(ge=-1, description="-1 for no expiry, or positive seconds")]=None, x_api_key:Annotated[str|None,Header()]=None):
|
||||
require_api(x_api_key)
|
||||
return await create({'file':file},access,expires_in,False)
|
||||
|
||||
@app.post('/api/v1/pcbs/comparisons',status_code=202,response_model=PCBComparisonUploadResponse,response_model_exclude_none=True,tags=['PCB'])
|
||||
async def compare(old_file:Annotated[UploadFile,File()],new_file:Annotated[UploadFile,File()],
|
||||
access:Annotated[Literal['private','unlisted'],Form()]='private',
|
||||
expires_in:Annotated[int|None,Form(gt=0)]=None,x_api_key:Annotated[str|None,Header()]=None):
|
||||
expires_in:Annotated[int|None,Form(ge=-1, description="-1 for no expiry, or positive seconds")]=None,x_api_key:Annotated[str|None,Header()]=None):
|
||||
require_api(x_api_key)
|
||||
return await create({'old_file':old_file,'new_file':new_file},access,expires_in,True)
|
||||
|
||||
|
||||
مرجع در شماره جدید
مسدود کردن کاربر