mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-12-05 22:26:27 +00:00
Compare commits
4 Commits
1036e9f3f3
...
11c300ecf7
| Author | SHA1 | Date | |
|---|---|---|---|
| 11c300ecf7 | |||
| 1e975ce238 | |||
| b39fa4262d | |||
| d7699389bc |
@@ -38,7 +38,7 @@ PUBLIC_URL=http://localhost:8901
|
||||
# Set `verified` to true if you don't wanna manually verify users.
|
||||
EXTRA_CLAIMS='{"permissions": ["core.read", "core.play"], "verified": false}'
|
||||
# This is the permissions of the first user (aka the first user is admin)
|
||||
FIRST_USER_CLAIMS='{"permissions": ["users.read", "users.write", "apikeys.read", "apikeys.write", "users.delete", "core.read", "core.write", "core.play", "scanner.trigger"], "verified": true}'
|
||||
FIRST_USER_CLAIMS='{"permissions": ["users.read", "users.write", "users.delete", "apikeys.read", "apikeys.write", "core.read", "core.write", "core.play", "scanner.trigger"], "verified": true}'
|
||||
|
||||
# Guest (meaning unlogged in users) can be:
|
||||
# unauthorized (they need to connect before doing anything)
|
||||
|
||||
@@ -211,6 +211,7 @@ func (h *Handler) createApiJwt(apikey string) (string, error) {
|
||||
Time: time.Now().UTC().Add(time.Hour),
|
||||
}
|
||||
jwt := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
|
||||
jwt.Header["kid"] = h.config.JwtKid
|
||||
t, err := jwt.SignedString(h.config.JwtPrivateKey)
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
||||
@@ -20,5 +20,5 @@ create table scanner.requests(
|
||||
status scanner.request_status not null default 'pending',
|
||||
started_at timestamptz,
|
||||
created_at timestamptz not null default now()::timestamptz,
|
||||
constraint unique_kty unique(kind, title, year)
|
||||
constraint unique_kty unique nulls not distinct (kind, title, year)
|
||||
);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from __future__ import annotations
|
||||
from datetime import datetime
|
||||
from typing import Literal
|
||||
|
||||
from pydantic import Field
|
||||
@@ -18,3 +19,16 @@ class Request(Model, extra="allow"):
|
||||
class Video(Model):
|
||||
id: str
|
||||
episodes: list[Guess.Episode]
|
||||
|
||||
|
||||
class RequestRet(Model):
|
||||
id: str
|
||||
kind: Literal["episode", "movie"]
|
||||
title: str
|
||||
year: int | None
|
||||
status: Literal[
|
||||
"pending",
|
||||
"running",
|
||||
"failed",
|
||||
]
|
||||
started_at: datetime | None
|
||||
|
||||
15
scanner/scanner/routers/health.py
Normal file
15
scanner/scanner/routers/health.py
Normal file
@@ -0,0 +1,15 @@
|
||||
from fastapi import APIRouter
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("/health")
|
||||
def get_health():
|
||||
return {"status": "healthy"}
|
||||
|
||||
|
||||
@router.get("/ready")
|
||||
def get_ready():
|
||||
# child spans (`select 1` & db connection reset) was still logged,
|
||||
# since i don't really wanna deal with it, let's just do that.
|
||||
return {"status": "healthy"}
|
||||
@@ -1,9 +1,9 @@
|
||||
from typing import Annotated
|
||||
from typing import Annotated, Literal
|
||||
|
||||
from asyncpg import Connection
|
||||
from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, Security
|
||||
from fastapi import APIRouter, BackgroundTasks, Depends, Security
|
||||
|
||||
from scanner.database import get_db_fapi
|
||||
from scanner.models.request import RequestRet
|
||||
from scanner.status import StatusService
|
||||
|
||||
from ..fsscan import create_scanner
|
||||
from ..jwt import validate_bearer
|
||||
@@ -11,6 +11,19 @@ from ..jwt import validate_bearer
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("/scan")
|
||||
async def get_scan_status(
|
||||
svc: Annotated[StatusService, Depends(StatusService.create)],
|
||||
_: Annotated[None, Security(validate_bearer, scopes=["scanner.trigger"])],
|
||||
status: Literal["pending", "running", "failed"] | None = None,
|
||||
) -> list[RequestRet]:
|
||||
"""
|
||||
Get scan status, know what tasks are running, pending or failed.
|
||||
"""
|
||||
|
||||
return await svc.list_requests(status=status)
|
||||
|
||||
|
||||
@router.put(
|
||||
"/scan",
|
||||
status_code=204,
|
||||
@@ -29,25 +42,3 @@ async def trigger_scan(
|
||||
await scanner.scan()
|
||||
|
||||
tasks.add_task(run)
|
||||
|
||||
|
||||
@router.get("/health")
|
||||
def get_health():
|
||||
return {"status": "healthy"}
|
||||
|
||||
|
||||
@router.get("/ready")
|
||||
def get_ready():
|
||||
# child spans (`select 1` & db connection reset) was still logged,
|
||||
# since i don't really wanna deal with it, let's just do that.
|
||||
return {"status": "healthy"}
|
||||
|
||||
|
||||
# async def get_ready(db: Annotated[Connection, Depends(get_db_fapi)]):
|
||||
# try:
|
||||
# _ = await db.execute("select 1")
|
||||
# return {"status": "healthy", "database": "healthy"}
|
||||
# except Exception as e:
|
||||
# raise HTTPException(
|
||||
# status_code=500, detail={"status": "unhealthy", "database": str(e)}
|
||||
# )
|
||||
|
||||
41
scanner/scanner/status.py
Normal file
41
scanner/scanner/status.py
Normal file
@@ -0,0 +1,41 @@
|
||||
from typing import Literal
|
||||
|
||||
from asyncpg import Connection
|
||||
from pydantic import TypeAdapter
|
||||
|
||||
from scanner.database import get_db
|
||||
|
||||
from .models.request import RequestRet
|
||||
|
||||
|
||||
class StatusService:
|
||||
def __init__(self, database: Connection):
|
||||
self._database = database
|
||||
|
||||
@classmethod
|
||||
async def create(cls):
|
||||
async with get_db() as db:
|
||||
yield StatusService(db)
|
||||
|
||||
async def list_requests(
|
||||
self, *, status: Literal["pending", "running", "failed"] | None = None
|
||||
) -> list[RequestRet]:
|
||||
ret = await self._database.fetch(
|
||||
f"""
|
||||
select
|
||||
pk::text as id,
|
||||
kind,
|
||||
title,
|
||||
year,
|
||||
status,
|
||||
started_at
|
||||
from
|
||||
scanner.requests
|
||||
order by
|
||||
started_at,
|
||||
pk
|
||||
{"where status = $1" if status is not None else ""}
|
||||
""",
|
||||
*([status] if status is not None else []),
|
||||
)
|
||||
return TypeAdapter(list[RequestRet]).validate_python(ret)
|
||||
Reference in New Issue
Block a user