Skip to content

Commit

Permalink
migrates from jsonpickle to dill binary
Browse files Browse the repository at this point in the history
  • Loading branch information
GabrielBarberini committed Sep 8, 2024
1 parent 21a90a4 commit b17ee6f
Show file tree
Hide file tree
Showing 18 changed files with 298 additions and 92 deletions.
5 changes: 3 additions & 2 deletions lib/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
from fastapi import FastAPI, Request, status
from fastapi.exceptions import RequestValidationError
from fastapi.middleware.cors import CORSMiddleware
from fastapi.middleware.gzip import GZipMiddleware
from fastapi.openapi.utils import get_openapi
from fastapi.responses import RedirectResponse, JSONResponse

Expand All @@ -14,13 +13,15 @@

from lib import logger, parse_error
from lib.routes import flight, environment, motor, rocket
from lib.utils import RocketPyGZipMiddleware

app = FastAPI(
swagger_ui_parameters={
"defaultModelsExpandDepth": 0,
"syntaxHighlight.theme": "obsidian",
}
)

app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
Expand All @@ -37,7 +38,7 @@
RequestsInstrumentor().instrument()

# Compress responses above 1KB
app.add_middleware(GZipMiddleware, minimum_size=1000)
app.add_middleware(RocketPyGZipMiddleware, minimum_size=1000)


def custom_openapi():
Expand Down
18 changes: 7 additions & 11 deletions lib/controllers/environment.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from typing import Union

import jsonpickle
from fastapi import HTTPException, status
from pymongo.errors import PyMongoError

Expand All @@ -13,7 +12,6 @@
EnvCreated,
EnvDeleted,
EnvUpdated,
EnvPickle,
)


Expand Down Expand Up @@ -122,18 +120,18 @@ async def get_env_by_id(env_id: str) -> Union[Env, HTTPException]:
)

@classmethod
async def get_rocketpy_env_as_jsonpickle(
async def get_rocketpy_env_binary(
cls,
env_id: str,
) -> Union[EnvPickle, HTTPException]:
) -> Union[bytes, HTTPException]:
"""
Get rocketpy.Environmnet as jsonpickle string.
Get rocketpy.Environmnet dill binary.
Args:
env_id: str
Returns:
views.EnvPickle
bytes
Raises:
HTTP 404 Not Found: If the env is not found in the database.
Expand All @@ -146,19 +144,17 @@ async def get_rocketpy_env_as_jsonpickle(
except Exception as e:
exc_str = parse_error(e)
logger.error(
f"controllers.environment.get_rocketpy_env_as_jsonpickle: {exc_str}"
f"controllers.environment.get_rocketpy_env_as_binary: {exc_str}"
)
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Failed to read environment: {exc_str}",
) from e
else:
return EnvPickle(
jsonpickle_rocketpy_env=jsonpickle.encode(rocketpy_env)
)
return rocketpy_env.get_env_binary()
finally:
logger.info(
f"Call to controllers.environment.get_rocketpy_env_as_jsonpickle completed for Env {env_id}"
f"Call to controllers.environment.get_rocketpy_env_binary completed for Env {env_id}"
)

async def update_env_by_id(
Expand Down
19 changes: 7 additions & 12 deletions lib/controllers/flight.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
from pymongo.errors import PyMongoError


import jsonpickle

from lib import logger, parse_error
from lib.models.environment import Env
from lib.models.rocket import Rocket
Expand All @@ -16,7 +14,6 @@
FlightCreated,
FlightUpdated,
FlightDeleted,
FlightPickle,
FlightView,
)
from lib.repositories.flight import FlightRepository
Expand Down Expand Up @@ -150,18 +147,18 @@ async def get_flight_by_id(
)

@classmethod
async def get_rocketpy_flight_as_jsonpickle(
async def get_rocketpy_flight_binary(
cls,
flight_id: str,
) -> Union[FlightPickle, HTTPException]:
) -> Union[bytes, HTTPException]:
"""
Get rocketpy.flight as jsonpickle string.
Get rocketpy.flight as dill binary.
Args:
flight_id: str
Returns:
views.FlightPickle
bytes
Raises:
HTTP 404 Not Found: If the flight is not found in the database.
Expand All @@ -174,19 +171,17 @@ async def get_rocketpy_flight_as_jsonpickle(
except Exception as e:
exc_str = parse_error(e)
logger.error(
f"controllers.flight.get_rocketpy_flight_as_jsonpickle: {exc_str}"
f"controllers.flight.get_rocketpy_flight_binary: {exc_str}"
)
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Failed to read flight: {exc_str}",
) from e
else:
return FlightPickle(
jsonpickle_rocketpy_flight=jsonpickle.encode(rocketpy_flight)
)
return rocketpy_flight.get_flight_binary()
finally:
logger.info(
f"Call to controllers.flight.get_rocketpy_flight_as_jsonpickle completed for Flight {flight_id}"
f"Call to controllers.flight.get_rocketpy_flight_binary completed for Flight {flight_id}"
)

async def update_flight_by_id(
Expand Down
18 changes: 7 additions & 11 deletions lib/controllers/motor.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from typing import Union
from fastapi import HTTPException, status
from pymongo.errors import PyMongoError
import jsonpickle

from lib import logger, parse_error
from lib.models.motor import Motor, MotorKinds
Expand All @@ -12,7 +11,6 @@
MotorCreated,
MotorUpdated,
MotorDeleted,
MotorPickle,
MotorView,
)

Expand Down Expand Up @@ -132,18 +130,18 @@ async def get_motor_by_id(
)

@classmethod
async def get_rocketpy_motor_as_jsonpickle(
async def get_rocketpy_motor_binary(
cls,
motor_id: str,
) -> Union[MotorPickle, HTTPException]:
) -> Union[bytes, HTTPException]:
"""
Get a rocketpy.Motor object as a jsonpickle string.
Get a rocketpy.Motor object as a dill binary.
Args:
motor_id: str
Returns:
views.MotorPickle
bytes
Raises:
HTTP 404 Not Found: If the motor is not found in the database.
Expand All @@ -156,19 +154,17 @@ async def get_rocketpy_motor_as_jsonpickle(
except Exception as e:
exc_str = parse_error(e)
logger.error(
f"controllers.motor.get_rocketpy_motor_as_jsonpickle: {exc_str}"
f"controllers.motor.get_rocketpy_motor_binary: {exc_str}"
)
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Failed to read motor: {exc_str}",
) from e
else:
return MotorPickle(
jsonpickle_rocketpy_motor=jsonpickle.encode(rocketpy_motor)
)
return rocketpy_motor.get_motor_binary()
finally:
logger.info(
f"Call to controllers.motor.get_rocketpy_motor_as_jsonpickle completed for Motor {motor_id}"
f"Call to controllers.motor.get_rocketpy_motor_binary completed for Motor {motor_id}"
)

async def update_motor_by_id(
Expand Down
18 changes: 7 additions & 11 deletions lib/controllers/rocket.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from typing import Union
import jsonpickle

from fastapi import HTTPException, status
from pymongo.errors import PyMongoError
Expand All @@ -14,7 +13,6 @@
RocketCreated,
RocketUpdated,
RocketDeleted,
RocketPickle,
RocketView,
)

Expand Down Expand Up @@ -136,17 +134,17 @@ async def get_rocket_by_id(
)

@classmethod
async def get_rocketpy_rocket_as_jsonpickle(
async def get_rocketpy_rocket_binary(
cls, rocket_id: str
) -> Union[RocketPickle, HTTPException]:
) -> Union[bytes, HTTPException]:
"""
Get a rocketpy.Rocket object as jsonpickle string.
Get a rocketpy.Rocket object as dill binary.
Args:
rocket_id: str
Returns:
views.RocketPickle
bytes
Raises:
HTTP 404 Not Found: If the rocket is not found in the database.
Expand All @@ -159,19 +157,17 @@ async def get_rocketpy_rocket_as_jsonpickle(
except Exception as e:
exc_str = parse_error(e)
logger.error(
f"controllers.rocket.get_rocketpy_rocket_as_jsonpickle: {exc_str}"
f"controllers.rocket.get_rocketpy_rocket_binary: {exc_str}"
)
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Failed to read rocket: {exc_str}",
) from e
else:
return RocketPickle(
jsonpickle_rocketpy_rocket=jsonpickle.encode(rocketpy_rocket)
)
return rocketpy_rocket.get_rocket_binary()
finally:
logger.info(
f"Call to controllers.rocket.get_rocketpy_rocket_as_jsonpickle completed for Rocket {rocket_id}"
f"Call to controllers.rocket.get_rocketpy_rocket_binary completed for Rocket {rocket_id}"
)

async def update_rocket_by_id(
Expand Down
30 changes: 24 additions & 6 deletions lib/routes/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@
Environment routes
"""

from fastapi import APIRouter
from fastapi import APIRouter, Response
from opentelemetry import trace

from lib.views.environment import (
EnvSummary,
EnvCreated,
EnvUpdated,
EnvPickle,
EnvDeleted,
)
from lib.models.environment import Env
Expand Down Expand Up @@ -67,16 +66,35 @@ async def update_env(env_id: str, env: Env) -> EnvUpdated:
return await EnvController(env).update_env_by_id(env_id)


@router.get("/rocketpy/{env_id}")
async def read_rocketpy_env(env_id: str) -> EnvPickle:
@router.get(
"/rocketpy/{env_id}",
responses={
203: {
"description": "Binary file download",
"content": {"application/octet-stream": {}},
}
},
status_code=203,
response_class=Response,
)
async def read_rocketpy_env(env_id: str):
"""
Loads rocketpy.environment as jsonpickle string
Loads rocketpy.environment as a dill binary
## Args
``` env_id: str ```
"""
with tracer.start_as_current_span("read_rocketpy_env"):
return await EnvController.get_rocketpy_env_as_jsonpickle(env_id)
headers = {
'Content-Disposition': f'attachment; filename="rocketpy_environment_{env_id}.dill"'
}
binary = await EnvController.get_rocketpy_env_binary(env_id)
return Response(
content=binary,
headers=headers,
media_type="application/octet-stream",
status_code=203,
)


@router.get("/{env_id}/summary")
Expand Down
32 changes: 24 additions & 8 deletions lib/routes/flight.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@
Flight routes
"""

from fastapi import APIRouter
from fastapi import APIRouter, Response
from opentelemetry import trace

from lib.views.flight import (
FlightSummary,
FlightCreated,
FlightUpdated,
FlightPickle,
FlightDeleted,
)
from lib.models.environment import Env
Expand Down Expand Up @@ -60,17 +59,34 @@ async def read_flight(flight_id: str) -> FlightView:
return await FlightController.get_flight_by_id(flight_id)


@router.get("/rocketpy/{flight_id}")
async def read_rocketpy_flight(flight_id: str) -> FlightPickle:
@router.get(
"/rocketpy/{flight_id}",
responses={
203: {
"description": "Binary file download",
"content": {"application/octet-stream": {}},
}
},
status_code=203,
response_class=Response,
)
async def read_rocketpy_flight(flight_id: str):
"""
Reads a rocketpy flight object
Loads rocketpy.flight as a dill binary
## Args
``` flight_id: Flight ID ```
``` flight_id: str ```
"""
with tracer.start_as_current_span("read_rocketpy_flight"):
return await FlightController.get_rocketpy_flight_as_jsonpickle(
flight_id
headers = {
'Content-Disposition': f'attachment; filename="rocketpy_flight_{flight_id}.dill"'
}
binary = await FlightController.get_rocketpy_flight_binary(flight_id)
return Response(
content=binary,
headers=headers,
media_type="application/octet-stream",
status_code=203,
)


Expand Down
Loading

0 comments on commit b17ee6f

Please sign in to comment.