Compare commits

...

8 Commits

6 changed files with 77 additions and 13 deletions

View File

@ -0,0 +1,17 @@
---
name: Flake8
on: [push]
# XXX need to do stuff with uv
jobs:
build:
runs-on: freebsd
strategy:
matrix:
python-version: ["3.11"]
steps:
- uses: actions/checkout@v4
- name: Analyse code with Flake8
run: |
flake8 $(git ls-files '*.py')

17
.gitea/workflows/mypy.yml Normal file
View File

@ -0,0 +1,17 @@
---
name: Mypy
on: [push]
# XXX need to do stuff with uv
jobs:
build:
runs-on: freebsd
strategy:
matrix:
python-version: ["3.11"]
steps:
- uses: actions/checkout@v4
- name: Analyse code with Mypy
run: |
mypy --install-types --non-interactive $(git ls-files '*.py')

View File

@ -0,0 +1,17 @@
---
name: Pylint
on: [push]
# XXX need to do stuff with uv
jobs:
build:
runs-on: freebsd
strategy:
matrix:
python-version: ["3.11"]
steps:
- uses: actions/checkout@v4
- name: Analyse code with Pylint
run: |
pylint $(git ls-files '*.py')

View File

@ -15,12 +15,14 @@ app = FastAPI()
GEOLITE2_ASN_DB = '/usr/local/share/GeoIP/GeoLite2-ASN.mmdb'
GEOLITE2_CITY_DB = '/usr/local/share/GeoIP/GeoLite2-City.mmdb'
class IPAddressParam(BaseModel):
'''
Payload entry as used in POST
'''
ip: Union[IPv6Address, IPv4Address]
class Locality(BaseModel):
'''
Locality data
@ -30,6 +32,7 @@ class Locality(BaseModel):
continent: Optional[str] = None
is_eu: bool = False
class GeoLocation(BaseModel):
'''
Geolocation data model
@ -40,9 +43,12 @@ class GeoLocation(BaseModel):
network: Optional[Union[IPv6Network, IPv4Network]] = None
locality: Locality = Locality()
@app.post("/")
async def root_post(ipaddresses: Annotated[list[IPAddressParam],
Body(title="The IPAddresses to geolocate")]
async def root_post(ipaddresses: Annotated[
list[IPAddressParam],
Body(title="The IPAddresses to geolocate")],
response: Response
) -> list[GeoLocation]:
'''
Return GeoLocation item(s) for a list of IPAddressParam objects
@ -72,23 +78,28 @@ async def root_post(ipaddresses: Annotated[list[IPAddressParam],
ip=ipaddress.ip
)
)
if geolocations:
response.headers['Cache-Control'] = 'private, max-age=604800'
return geolocations
@app.get("/{ipaddress}")
async def root_get(ipaddress: Annotated[Union[IPv4Address,IPv6Address],
async def root_get(ipaddress: Annotated[
Union[IPv4Address, IPv6Address],
Path(title="The IPAddress to geolocate")],
response: Response
) -> GeoLocation:
'''
Look up geolocation for ip in path parameter
'''
locations = await root_post([IPAddressParam(ip=ipaddress)])
locations = await root_post([IPAddressParam(ip=ipaddress)], response)
if locations:
response.headers['Cache-Control'] = 'private, max-age=604800'
return locations.pop()
response.status_code = status.HTTP_404_NOT_FOUND
return GeoLocation()
@app.get("/")
def root_redirect(req: Request) -> RedirectResponse:
'''

2
requirements.txt Normal file
View File

@ -0,0 +1,2 @@
geoip2==4.7.0
fastapi==0.115.6

View File

@ -8,12 +8,12 @@ WORKERS=3
WORKER_CLASS=uvicorn.workers.UvicornWorker
#VENV=$DIR/.venv/bin/activate
BIND=unix:$DIR/../run/gunicorn.sock
LOG_LEVEL=debug
LOG_LEVEL=error
cd $DIR
# source $VENV
exec gunicorn main:app \
exec /usr/local/bin/gunicorn main:app \
--name $NAME \
--workers $WORKERS \
--worker-class $WORKER_CLASS \