Skip to content

Commit

Permalink
Initial commit devlock api
Browse files Browse the repository at this point in the history
  • Loading branch information
raimannma committed Oct 18, 2024
1 parent 2901dd9 commit 0fc0b54
Show file tree
Hide file tree
Showing 12 changed files with 171 additions and 0 deletions.
44 changes: 44 additions & 0 deletions .github/workflows/docker-image-api.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: docker-image-api

on:
workflow_dispatch:
push:
branches:
- 'main'
paths:
- 'api/**'

env:
IMAGE_TAG_OWNER: opensource-deadlock-tools
IMAGE_TAG_NAME: devlock

permissions:
contents: read
packages: write

concurrency:
cancel-in-progress: true
group: ${{ github.workflow }}-${{ github.ref }}

jobs:
docker:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and Push Compose
uses: docker/build-push-action@v6
with:
push: true
tags: ghcr.io/${{ env.IMAGE_TAG_OWNER }}/${{ env.IMAGE_TAG_NAME }}/api:latest
context: api
12 changes: 12 additions & 0 deletions api/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
FROM python:3.12

WORKDIR /app

COPY requirements.txt requirements.txt

RUN pip install --no-cache-dir uvicorn && \
pip install --no-cache-dir -r requirements.txt

COPY . .

CMD ["uvicorn", "devlock_api.main:app", "--host", "0.0.0.0", "--port", "8080"]
Empty file added api/__init__.py
Empty file.
Empty file added api/devlock_api/__init__.py
Empty file.
12 changes: 12 additions & 0 deletions api/devlock_api/datarepo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import os

import clickhouse_connect

ch_host = os.environ["CLICKHOUSE_HOST"]
ch_port = int(os.environ["CLICKHOUSE_HTTP_PORT"])
ch_user = os.environ["CLICKHOUSE_USER"]
ch_pass = os.environ["CLICKHOUSE_PASSWORD"]

repo = clickhouse_connect.get_client(
host=ch_host, port=ch_port, username=ch_user, password=ch_pass
)
4 changes: 4 additions & 0 deletions api/devlock_api/limiter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from slowapi import Limiter
from slowapi.util import get_remote_address

limiter = Limiter(key_func=get_remote_address, key_style="endpoint")
28 changes: 28 additions & 0 deletions api/devlock_api/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from devlock_api.routes import v1
from fastapi import FastAPI
from prometheus_fastapi_instrumentator import Instrumentator
from starlette.middleware.gzip import GZipMiddleware
from starlette.responses import RedirectResponse

app = FastAPI()
app.add_middleware(GZipMiddleware, minimum_size=1000, compresslevel=5)

Instrumentator().instrument(app).expose(app, include_in_schema=False)

app.include_router(v1.router)


@app.get("/", include_in_schema=False)
def root():
return RedirectResponse(url="/docs")


@app.get("/health", include_in_schema=False)
def health():
return {"status": "ok"}


if __name__ == "__main__":
import uvicorn

uvicorn.run(app, host="0.0.0.0", port=8080)
Empty file.
32 changes: 32 additions & 0 deletions api/devlock_api/routes/v1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from devlock_api.datarepo import repo
from devlock_api.limiter import limiter
from fastapi import APIRouter, Request

router = APIRouter(prefix="/v1", tags=["V1"])


@router.get("/matches")
@limiter.limit("100/minute")
async def match_list(request: Request, skip: int = 0):
query_result = repo.query(
"SELECT * FROM match_info LIMIT 20 OFFSET %(offset)s", {"offset": skip}
)
return query_result.named_results()


@router.get("/matches/{match_id}/meta")
@limiter.limit("100/minute")
async def match_meta(request: Request, match_id: str):
query_result = repo.query(
"SELECT * FROM match_info WHERE match_id = %(match_id)s", {"match_id": match_id}
)
return query_result.first_item


@router.get("/active-matches")
@limiter.limit("100/minute")
async def active_matches(request: Request, skip: int = 0):
query_result = repo.query(
"SELECT * FROM summary_active_matches LIMIT 500 OFFSET %(skip)s", {"skip": skip}
)
return query_result.named_results()
29 changes: 29 additions & 0 deletions api/docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
services:
api:
image: ghcr.io/opensource-deadlock-tools/devlock/api
build: .
restart: always
env_file: ../.env
environment:
VIRTUAL_HOST: api.devlock.net
VIRTUAL_PORT: 8080
LETSENCRYPT_HOST: api.devlock.net
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 10s
retries: 5
ports:
- "8080:8080"
networks:
- webserver
- clickhouse
- monitoring

networks:
clickhouse:
external: true
webserver:
external: true
monitoring:
external: true
7 changes: 7 additions & 0 deletions api/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
fastapi[standard]>=0.115.1
clickhouse-connect>=0.8.3
prometheus-client>=0.21.0
slowapi>=0.1.9
prometheus_fastapi_instrumentator>=7.0.0
starlette>=0.40.0
uvicorn>=0.32.0
3 changes: 3 additions & 0 deletions monitoring/prometheus.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ scrape_configs:
- job_name: node
static_configs:
- targets: ['node-exporter:9100']
- job_name: api
static_configs:
- targets: ['api:8080']
- job_name: Clickhouse
static_configs:
- targets: ['clickhouse:9363']
Expand Down

0 comments on commit 0fc0b54

Please sign in to comment.