Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix python lint issue #2

Merged
merged 2 commits into from
Dec 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@
```shell
export PYTHONPATH=<repo_dir>/src
uvicorn gentrade-server.main:app --reload
```
or
python -m gentrade-server.main
```
6 changes: 5 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
fastapi[standard]
uvicorn
uvicorn
pydantic
pydantic-settings
ntplib
python-dateutil
15 changes: 0 additions & 15 deletions src/gentrade-server/main.py

This file was deleted.

8 changes: 0 additions & 8 deletions src/gentrade-server/routers/public.py

This file was deleted.

File renamed without changes.
12 changes: 9 additions & 3 deletions src/gentrade-server/auth.py → src/gentrade_server/auth.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
"""
Authorization module
"""
from fastapi import Security, HTTPException, status
from fastapi.security import APIKeyHeader
from .db import check_api_key, get_user_from_api_key

api_key_header = APIKeyHeader(name="X-API-Key")

def get_user(api_key_header: str = Security(api_key_header)):
if check_api_key(api_key_header):
user = get_user_from_api_key(api_key_header)
def get_user(header: str = Security(api_key_header)):
"""
Get user from the API key
"""
if check_api_key(header):
user = get_user_from_api_key(header)
return user
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
Expand Down
12 changes: 12 additions & 0 deletions src/gentrade_server/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
"""
Configure
"""
from pydantic_settings import BaseSettings

class Settings(BaseSettings):
"""
Settings
"""
ntp_server: str = "ntp.ntsc.ac.cn"

settings = Settings()
9 changes: 9 additions & 0 deletions src/gentrade-server/db.py → src/gentrade_server/db.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
"""
Database
"""
api_keys = {
"e54d4431-5dab-474e-b71a-0db1fcb9e659": "7oDYjo3d9r58EJKYi5x4E8",
"5f0c7127-3be9-4488-b801-c7b6415b45e9": "mUP7PpTHmFAkxcQLWKMY8t"
Expand All @@ -13,7 +16,13 @@
}

def check_api_key(api_key: str):
"""
Check whether API key valid
"""
return api_key in api_keys

def get_user_from_api_key(api_key: str):
"""
Get the user from the given API key
"""
return users[api_keys[api_key]]
49 changes: 49 additions & 0 deletions src/gentrade_server/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
"""
The main entry
"""
import logging
from contextlib import asynccontextmanager

import uvicorn
from fastapi import FastAPI, Depends
from fastapi.middleware.cors import CORSMiddleware

from .routers import secure, public
from .auth import get_user
from .util import sync_ntp_server

logging.basicConfig(level=logging.INFO, format='%(asctime)s %(message)s')
LOG = logging.getLogger(__name__)

@asynccontextmanager
async def lifespan(_:FastAPI):
"""
App lifecycle
"""
LOG.info("Starting Up...")
sync_ntp_server()
yield
LOG.info("Shutting Down...")

app = FastAPI()
app = FastAPI(lifespan=lifespan)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)

app.include_router(
public.router,
prefix="/api/v1/public"
)
app.include_router(
secure.router,
prefix="/api/v1/secure",
dependencies=[Depends(get_user)]
)

if __name__ == '__main__':
uvicorn.run(app, host="0.0.0.0", port=8000)
65 changes: 65 additions & 0 deletions src/gentrade_server/routers/public.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
"""
Public result API interfaces
"""
import logging

import time
import datetime
from dateutil.tz import tzlocal

from fastapi import APIRouter
from pydantic import BaseModel

from ..util import sync_ntp_server
from ..config import settings

LOG = logging.getLogger(__name__)

router = APIRouter()

@router.get("/")
async def get_testroute():
"""
Test public interface
"""
return "OK"

class HealthCheck(BaseModel):
"""
Response model to validate and return when performing a health check.
"""

status: str = "OK"

@router.get("/health")
async def get_health() -> HealthCheck:
"""
Check health
"""
return HealthCheck(status="OK")

@router.get("/settings")
async def get_settings():
"""
Get server settings
"""
return {
'ntp_server': settings.ntp_server
}

@router.get("/server_time")
async def get_server_time():
"""
Get server time
"""
curr_ts = time.time()
now_utc = datetime.datetime.fromtimestamp(curr_ts, datetime.UTC)
tl = tzlocal()
ntp_offset = sync_ntp_server()

return {
'ntp_offset': ntp_offset,
'timezone_name': tl.tzname(now_utc),
'timezone_offset': tl.utcoffset(now_utc).total_seconds(),
'timestamp_server': int(curr_ts)
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
"""
Secure API interface
"""
from fastapi import APIRouter, Depends
from ..auth import get_user

router = APIRouter()

@router.get("/")
async def get_testroute(user: dict = Depends(get_user)):
return user
"""
Test secure interface
"""
return user
32 changes: 32 additions & 0 deletions src/gentrade_server/util.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"""
Utils
"""
import logging
import ntplib

LOG = logging.getLogger(__name__)

def sync_ntp_server() -> float:
"""
Sync with NTP server

:return : offset in seconds
"""
ntp_servers = ['ntp.ntsc.ac.cn', 'ntp.sjtu.edu.cn', 'cn.ntp.org.cn',
'cn.pool.ntp.org', 'ntp.aliyun.com']
retry = len(ntp_servers) - 1
client = ntplib.NTPClient()
while retry > 0:
LOG.info("Try to get time from NTP: %s", ntp_servers[retry])

try:
ret = client.request(ntp_servers[retry], version=3)
offset = (ret.recv_time - ret.orig_time +
ret.dest_time - ret.tx_time) / 2
LOG.info("NTP offset: %.2f", offset)
return offset
except ntplib.NTPException:
LOG.error("Fail to get time, try another")
retry -= 1
continue
return None
Loading