Compare commits
13 Commits
v1.0.0
...
9e83da6b1a
Author | SHA1 | Date | |
---|---|---|---|
9e83da6b1a
|
|||
c952bd921f
|
|||
1a4d4997da
|
|||
34d6aa5a36
|
|||
90e9b9bb05
|
|||
44c4f4045f
|
|||
95c6ecf8b4
|
|||
f34cd88de1
|
|||
a999024ddf
|
|||
9ef9c8454b
|
|||
8f2a575010
|
|||
654f2982de
|
|||
f0230bbbc3
|
@ -4,8 +4,9 @@
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"host": "127.0.0.1",
|
"binds": [
|
||||||
"port": 9250,
|
"127.0.0.1:9250"
|
||||||
|
],
|
||||||
"log": "-",
|
"log": "-",
|
||||||
"buffer-size": "4KiB",
|
"buffer-size": "4KiB",
|
||||||
"max-size": "2GB",
|
"max-size": "2GB",
|
||||||
@ -13,6 +14,6 @@
|
|||||||
"TESTKEY"
|
"TESTKEY"
|
||||||
],
|
],
|
||||||
"max-data": "10GB",
|
"max-data": "10GB",
|
||||||
"database": "databse.json"
|
"database": "database.json"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
17
src/main.py
17
src/main.py
@ -4,7 +4,7 @@ import argparse
|
|||||||
import json
|
import json
|
||||||
from os.path import exists
|
from os.path import exists
|
||||||
|
|
||||||
from fastapi import FastAPI, Request, HTTPException
|
from fastapi import FastAPI, Request, HTTPException, Query
|
||||||
from fastapi.responses import StreamingResponse
|
from fastapi.responses import StreamingResponse
|
||||||
from fastapi import status
|
from fastapi import status
|
||||||
from hypercorn.config import Config
|
from hypercorn.config import Config
|
||||||
@ -32,7 +32,7 @@ if not exists(DATABASE):
|
|||||||
save_database(DATABASE, {'data-used': 0})
|
save_database(DATABASE, {'data-used': 0})
|
||||||
|
|
||||||
|
|
||||||
api = FastAPI()
|
api = FastAPI(docs_url=None, redoc_url=None)
|
||||||
|
|
||||||
|
|
||||||
class MaxSizePerRequestError(Exception):
|
class MaxSizePerRequestError(Exception):
|
||||||
@ -44,7 +44,7 @@ class MinSizePerRequestError(Exception):
|
|||||||
|
|
||||||
|
|
||||||
@api.get('/')
|
@api.get('/')
|
||||||
def test_data(api_key: str, size: str, request: Request) -> StreamingResponse:
|
async def test_data(api_key: str, request: Request, size: str) -> StreamingResponse:
|
||||||
try:
|
try:
|
||||||
if api_key not in AUTHORIZED_KEYS:
|
if api_key not in AUTHORIZED_KEYS:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
@ -52,7 +52,13 @@ def test_data(api_key: str, size: str, request: Request) -> StreamingResponse:
|
|||||||
detail='Invalid API Key.'
|
detail='Invalid API Key.'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
size = convert_to_bytes(size)
|
size = convert_to_bytes(size)
|
||||||
|
except ValueError:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_400_BAD_REQUEST,
|
||||||
|
detail='Invalid format format for size.'
|
||||||
|
)
|
||||||
|
|
||||||
if size < 0:
|
if size < 0:
|
||||||
raise MinSizePerRequestError
|
raise MinSizePerRequestError
|
||||||
@ -71,7 +77,8 @@ def test_data(api_key: str, size: str, request: Request) -> StreamingResponse:
|
|||||||
|
|
||||||
return StreamingResponse(
|
return StreamingResponse(
|
||||||
status_code=status.HTTP_200_OK,
|
status_code=status.HTTP_200_OK,
|
||||||
content=generate_data(size, BUFFER_SIZE)
|
content=generate_data(size, BUFFER_SIZE),
|
||||||
|
media_type='application/octet-stream'
|
||||||
)
|
)
|
||||||
|
|
||||||
except MinSizePerRequestError:
|
except MinSizePerRequestError:
|
||||||
@ -90,7 +97,7 @@ def main():
|
|||||||
asyncio.run(serve(
|
asyncio.run(serve(
|
||||||
api,
|
api,
|
||||||
Config().from_mapping(
|
Config().from_mapping(
|
||||||
bind=[f"{CONFIG['host']}:{CONFIG['port']}"],
|
bind=CONFIG['binds'],
|
||||||
accesslog='-'
|
accesslog='-'
|
||||||
)
|
)
|
||||||
))
|
))
|
||||||
|
19
src/utils.py
19
src/utils.py
@ -1,14 +1,15 @@
|
|||||||
import json
|
import json
|
||||||
|
import asyncio
|
||||||
|
|
||||||
def convert_to_bytes(size: int | str) -> int:
|
def convert_to_bytes(size: int | str) -> int:
|
||||||
try:
|
try:
|
||||||
return int(size)
|
return int(size)
|
||||||
except ValueError: # treat as string
|
except ValueError: # treat as string
|
||||||
units = {
|
units = {
|
||||||
'TB': 10 ** 12, 'TiB': 2 ** 40,
|
'TB': 1000 ** 4, 'TiB': 1024 ** 4,
|
||||||
'GB': 10 ** 9, 'GiB': 2 ** 30,
|
'GB': 1000 ** 3, 'GiB': 1024 ** 3,
|
||||||
'MB': 10 ** 6, 'MiB': 2 ** 20,
|
'MB': 1000 ** 2, 'MiB': 1024 ** 2,
|
||||||
'KB': 10 ** 3, 'KiB': 2 ** 10,
|
'KB': 1000, 'KiB': 1024,
|
||||||
'B': 1
|
'B': 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -17,15 +18,25 @@ def convert_to_bytes(size: int | str) -> int:
|
|||||||
return int(float(size.removesuffix(unit)) * units[unit])
|
return int(float(size.removesuffix(unit)) * units[unit])
|
||||||
break
|
break
|
||||||
|
|
||||||
|
raise ValueError
|
||||||
|
|
||||||
|
|
||||||
async def generate_data(size: int, buffer_size: int = 4 * 1024) -> bytes:
|
async def generate_data(size: int, buffer_size: int = 4 * 1024) -> bytes:
|
||||||
size_left = size
|
size_left = size
|
||||||
|
|
||||||
|
# https://github.com/tiangolo/fastapi/issues/5183
|
||||||
|
# https://github.com/encode/starlette/discussions/1776#discussioncomment-3207518
|
||||||
|
|
||||||
|
try:
|
||||||
while size_left > buffer_size:
|
while size_left > buffer_size:
|
||||||
size_left -= buffer_size
|
size_left -= buffer_size
|
||||||
yield b'\0' * buffer_size
|
yield b'\0' * buffer_size
|
||||||
|
await asyncio.sleep(0)
|
||||||
else:
|
else:
|
||||||
yield b'\0' * size_left
|
yield b'\0' * size_left
|
||||||
|
await asyncio.sleep(0)
|
||||||
|
except asyncio.CancelledError:
|
||||||
|
raise GeneratorExit
|
||||||
|
|
||||||
|
|
||||||
def check_policies(ip: str) -> None:
|
def check_policies(ip: str) -> None:
|
||||||
|
Reference in New Issue
Block a user