Add support for ipv4 prefixes under 16

This commit is contained in:
LilyRose2798 2024-04-23 09:35:02 +10:00
parent 4f10a22ad8
commit 5eee66d071
1 changed files with 32 additions and 14 deletions

View File

@ -23,7 +23,8 @@ parser.add_argument("--log-level", default = "INFO", help = "the log level use f
parser.add_argument("-l", "--limit", default = 3600, type = int, help = "the number of requests per hour to limit usage of the api to (default: %(default)s)") parser.add_argument("-l", "--limit", default = 3600, type = int, help = "the number of requests per hour to limit usage of the api to (default: %(default)s)")
parser.add_argument("-r", "--raws", help = "the path containing raw tile data (default: %(default)s)") parser.add_argument("-r", "--raws", help = "the path containing raw tile data (default: %(default)s)")
parser.add_argument("-t", "--tile-size", default = 256, type = int, help = "the tile size to use (default: %(default)s)") parser.add_argument("-t", "--tile-size", default = 256, type = int, help = "the tile size to use (default: %(default)s)")
parser.add_argument("-c", "--cache-size", default = 4096, type = int, help = "the number of tiles to keep in the cache (default: %(default)s)") parser.add_argument("-c", "--cache-size", default = 4096, type = int, help = "the number of compressed tiles to keep in the cache (default: %(default)s)")
parser.add_argument("-d", "--decomp-cache-size", default = 1024, type = int, help = "the number of decompressed tiles to keep in the cache (default: %(default)s)")
parser.add_argument("-v", "--variants", default = "density,rtt", help = "the variants to return data for (default: %(default)s)") parser.add_argument("-v", "--variants", default = "density,rtt", help = "the variants to return data for (default: %(default)s)")
args = parser.parse_args() args = parser.parse_args()
@ -94,9 +95,15 @@ if args.raws:
data_bytes = 4 data_bytes = 4
@lru_cache(args.cache_size) @lru_cache(args.cache_size)
def get_raw_data(path: Path): def get_raw_data_compressed(path: Path):
print(f"reading file '{path}'...") print(f"reading file '{path}'...")
return decompress(path.read_bytes()) return path.read_bytes()
@lru_cache(args.decomp_cache_size)
def get_raw_data(path: Path):
compressed_data = get_raw_data_compressed(path)
print(f"decompressing file '{path}'...")
return decompress(compressed_data)
@app.get("/api/scandata/:date/:variant/tile/:z/:y/:x") @app.get("/api/scandata/:date/:variant/tile/:z/:y/:x")
def get_info_tile(request: Request): def get_info_tile(request: Request):
@ -106,19 +113,27 @@ if args.raws:
variant = unquote(request.path_params["variant"]) variant = unquote(request.path_params["variant"])
if variant not in variants_set: if variant not in variants_set:
return error_response("Invalid variant provided", 400) return error_response("Invalid variant provided", 400)
try:
z = int(unquote(request.path_params["z"])) z = int(unquote(request.path_params["z"]))
if z < 0: except ValueError:
return error_response("Invalid z value provided", 400) return error_response("Invalid z value provided", 400)
try:
y = int(unquote(request.path_params["y"])) y = int(unquote(request.path_params["y"]))
if y < 0: if y < 0:
raise ValueError()
except ValueError:
return error_response("Invalid y value provided", 400) return error_response("Invalid y value provided", 400)
try:
x = int(unquote(request.path_params["x"])) x = int(unquote(request.path_params["x"]))
if x < 0: if x < 0:
raise ValueError()
except ValueError:
return error_response("Invalid x value provided", 400) return error_response("Invalid x value provided", 400)
y_tile, y_off = divmod(y, tile_size) y_tile, y_off = divmod(y, tile_size)
x_tile, x_off = divmod(x, tile_size) x_tile, x_off = divmod(x, tile_size)
off = y_off * tile_size * data_bytes + x_off * data_bytes
path = raws_path / date / variant / f"{z}" / f"{y_tile}" / f"{x_tile}.bin" path = raws_path / date / variant / f"{z}" / f"{y_tile}" / f"{x_tile}.bin"
img_size = (tile_size >> -z) if z < 0 else tile_size
off = y_off * img_size * data_bytes + x_off * data_bytes
try: try:
value = int.from_bytes(get_raw_data(path)[off : off + data_bytes], "little") value = int.from_bytes(get_raw_data(path)[off : off + data_bytes], "little")
except FileNotFoundError: except FileNotFoundError:
@ -132,10 +147,13 @@ if args.raws:
def get_info_range(request: Request): def get_info_range(request: Request):
try: try:
range = IPv4Network(unquote(request.path_params["range"]), strict = False) range = IPv4Network(unquote(request.path_params["range"]), strict = False)
except: except ValueError:
return error_response("Invalid IPv4 range", 400) return error_response("Invalid IPv4 range", 400)
if range.prefixlen < 16: if range.prefixlen % 2 != 0:
return error_response("Prefix length of IPv4 range must be 16 or above", 400) return error_response("Prefix length of IPv4 range must be even", 400)
if range.prefixlen == 0:
x, y = 0, 0
else:
x, y = HilbertCurve(range.prefixlen // 2, 2).point_from_distance(int(range.network_address) // (1 << (32 - range.prefixlen))) x, y = HilbertCurve(range.prefixlen // 2, 2).point_from_distance(int(range.network_address) // (1 << (32 - range.prefixlen)))
z = (range.prefixlen - 16) // 2 z = (range.prefixlen - 16) // 2
request.path_params["x"] = str(x) request.path_params["x"] = str(x)