8 Commits
v0.2.0 ... dev

5 changed files with 26 additions and 7 deletions

View File

@@ -58,7 +58,7 @@ jobs:
fetch-tags: true # Fetch all tags (refs/tags)
- name: Install uv
uses: astral-sh/setup-uv@v5
uses: astral-sh/setup-uv@v7
- name: Set up Python
run: uv python install
with:

View File

@@ -16,7 +16,7 @@ jobs:
uses: docker/setup-buildx-action@v2
- name: Install uv
uses: astral-sh/setup-uv@v5
uses: astral-sh/setup-uv@v7
- name: (optional) Prepare dependencies
run: |

13
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,13 @@
{
"cSpell.words": [
"buildx",
"Buildx",
"elif",
"gitea",
"Gitea",
"github",
"linux",
"pyproject",
"semapform"
]
}

View File

@@ -4,17 +4,19 @@ This can run independently to support the PHP application.
"""
from __future__ import annotations
import asyncio
from contextlib import asynccontextmanager
import json
import logging
import os
import re
import time
from typing import Any, TYPE_CHECKING
import urllib.parse
from contextlib import asynccontextmanager
from typing import TYPE_CHECKING, Any
if TYPE_CHECKING:
from collections.abc import AsyncIterator, Callable, Awaitable
from collections.abc import AsyncIterator, Awaitable, Callable
# Avoid importing heavy modules at top-level to keep `import api_service` lightweight
from fastapi import FastAPI, Query, Request, Response
@@ -29,7 +31,7 @@ redis_client = None
@asynccontextmanager
async def _lifespan(_app: FastAPI) -> AsyncIterator[None]:
"""Lifespan handler: connect to Redis on startup and close on shutdown."""
global redis_client
global redis_client # type: ignore[PLW0603]
if REDIS_URL:
try:
import redis.asyncio as aioredis
@@ -159,6 +161,10 @@ async def _cache_set(key: str, value: CacheValue, ttl: int = CACHE_TTL_SECONDS)
async def validate_signature(signature: str = Query(...)) -> JSONResponse:
"""Validate a book signature and return total pages."""
# check cache first
# ensure signature is stripped of leading/trailing whitespace
signature = signature.strip()
# enforce url quotes
signature = urllib.parse.quote(signature)
cache_key = f"signature:{signature}"
cached = await _cache_get(cache_key)
if cached is not None:

View File

@@ -1,6 +1,6 @@
[project]
name = "semapform-api"
version = "0.1.3"
version = "0.2.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.13"