sde_types_market & rework infra

This commit is contained in:
Tom Villette
2023-10-03 18:03:41 +02:00
parent b90e7028b7
commit d8aa735a55
10 changed files with 251 additions and 126 deletions

View File

@@ -1,12 +1,13 @@
import os
from sqlmodel import create_engine, Session
from eveal import models_sde
sqlite_sde_file_name = "sde.db"
sde_engine = create_engine(f"sqlite:///{sqlite_sde_file_name}", echo=True, future=True, connect_args={"check_same_thread": False})
sqlite_file_name = os.getenv("SQLITE_DB_PATH", "eveal.db")
engine = create_engine(f"sqlite:///{sqlite_file_name}", echo=True, future=True, connect_args={"check_same_thread": False})
def get_sde_session():
db = Session(sde_engine)
def get_session():
db = Session(engine)
try:
yield db
finally:

32
eveal/esi.py Normal file
View File

@@ -0,0 +1,32 @@
import datetime
import os
import redis
import pickle
from esy.client import ESIClient
from esy.auth import ESIAuthenticator
class ESICache(object):
def __init__(self, redis_url: str, redis_port: int, db: str):
self._r = redis.Redis(host=redis_url, port=redis_port, db=db)
# self._r = redis.StrictRedis(host=redis_url, port=redis_port, db=db)
def get(self, key):
# return pickle.loads(self._r[key])
return pickle.loads(self._r.get(key))
def set(self, key, data, cached_until: datetime.datetime):
self._r.set(key, pickle.dumps(data), ex=cached_until - datetime.datetime.now(datetime.timezone.utc))
def __contains__(self, item):
# return item in self._r
return self._r.exists(item)
esi_client_id = os.getenv('ESI_CLIENT_ID')
esi_secret_key = os.getenv('ESI_SECRET_KEY')
esi_cache = ESICache(redis_url=os.getenv("REDIS_URL"), redis_port=int(os.getenv("REDIS_PORT")), db="0")
esi_client = ESIClient.get_client(user_agent=os.getenv('ESI_USER_AGENT'), cache=esi_cache)
esi_auth = ESIAuthenticator()

View File

@@ -6,10 +6,10 @@ from typing import List, Annotated, Tuple, Literal
from sqlmodel import SQLModel, Session, select
from eveal.schemas import Evepraisal, PriceReprocess
from eveal.database import sde_engine, get_sde_session
from eveal import models_sde
from eveal.database import engine, get_session
from eveal import models_sde, esi
SQLModel.metadata.create_all(sde_engine) # remove? db should be created by import_sde.py
SQLModel.metadata.create_all(engine) # use alembic?
app = FastAPI()
app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"])
@@ -21,13 +21,13 @@ async def root():
@app.post("/reprocess/")
async def reprocess(ep_items: Evepraisal, ep_mat: Evepraisal, efficiency: float = .55, sde: Session = Depends(get_sde_session)) -> List[PriceReprocess]:
async def reprocess(ep_items: Evepraisal, ep_mat: Evepraisal, efficiency: float = .55, db: Session = Depends(get_session)) -> List[PriceReprocess]:
matprices = {item.typeID: {'sell': item.prices.sell.min, 'buy': item.prices.buy.max} for item in ep_mat.items}
item_reprocess: List[PriceReprocess] = []
for rawitem in ep_items.items:
# item = sde.exec(select(models_sde.Type).where(models_sde.Type.id == rawitem.typeID)).one()
item = sde.get(models_sde.Type, rawitem.typeID)
item = db.get(models_sde.SDEType, rawitem.typeID)
buy_reprocess = sell_reprocess = 0.0
for mat in item.materials.all():
buy_reprocess += matprices[mat.type.id]['buy'] * mat.quantity * efficiency
@@ -43,17 +43,29 @@ async def reprocess(ep_items: Evepraisal, ep_mat: Evepraisal, efficiency: float
@app.get("/sde/types/{sde_type}/")
async def sde_types(sde_type: int | str, sde: Session = Depends(get_sde_session)) -> models_sde.Type:
async def sde_types(sde_type: int | str, db: Session = Depends(get_session)) -> models_sde.SDEType:
try:
item = sde.get(models_sde.Type, int(sde_type))
item = db.get(models_sde.SDEType, int(sde_type))
except ValueError:
item = sde.exec(select(models_sde.Type).where(models_sde.Type.name == sde_type)).one()
item = db.exec(select(models_sde.SDEType).where(models_sde.SDEType.name == sde_type)).one()
return item
@app.post("/sde/types/search")
async def sde_types_search(query: List[Tuple[Literal["id", "name"], int | str]], sde: Session = Depends(get_sde_session)) -> List[models_sde.Type]:
async def sde_types_search(query: List[Tuple[Literal["id", "name"], int | str]], db: Session = Depends(get_session)) -> List[models_sde.SDEType]:
items = []
for key, val in query:
items.extend(sde.exec(select(models_sde.Type).where(getattr(models_sde.Type, key) == val)).all())
items.extend(db.exec(select(models_sde.SDEType).where(getattr(models_sde.SDEType, key) == val)).all())
return items
@app.get("/esi/types/{sde_type}/market/{region_id}/")
async def sde_types_market(sde_type: int | str, region_id: int | str, db: Session = Depends(get_session)):
"""Get market orders for a type in a region. example: /esi/types/22291/market/10000002/"""
"""TODO: use ESIMarketOrder"""
return list(esi.esi_client.Market.get_markets_region_id_orders(order_type="all", type_id=sde_type, region_id=region_id))
if __name__ == "__main__":
import uvicorn
uvicorn.run("eveal.main:app", host="0.0.0.0", port=8000, reload=True)

24
eveal/models_esi.py Normal file
View File

@@ -0,0 +1,24 @@
from datetime import datetime
from typing import Optional, List
from sqlmodel import SQLModel, Field, Relationship
class ESIMarketOrder(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
timestamp: datetime = Field(default_factory=datetime.utcnow, nullable=False)
region_id: int
type_id: int # TODO: link to SDE
location_id: int # TODO: link to SDE
volume_total: int
volume_remain: int
min_volume: int
order_id: int # TODO: use this as PK ? (will lose volume_remain history)
price: float
is_buy_order: bool
duration: int
issued: datetime
range: str # TODO: enum?
system_id: int # TODO: link to SDE

View File

@@ -2,107 +2,107 @@ from typing import Optional, List
from sqlmodel import SQLModel, Field, Relationship
class Icon(SQLModel, table=True):
class SDEIcon(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
description: Optional[str] = None
iconFile: str
categories: List['Category'] = Relationship(back_populates="icon")
groups: List['Group'] = Relationship(back_populates="icon")
marketgroups: List['MarketGroup'] = Relationship(back_populates="icon")
types: List['Type'] = Relationship(back_populates="icon")
categories: List['SDECategory'] = Relationship(back_populates="icon")
groups: List['SDEGroup'] = Relationship(back_populates="icon")
marketgroups: List['SDEMarketGroup'] = Relationship(back_populates="icon")
types: List['SDEType'] = Relationship(back_populates="icon")
class Category(SQLModel, table=True):
class SDECategory(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
icon_id: Optional[int] = Field(default=None, foreign_key="icon.id")
icon: Optional[Icon] = Relationship(back_populates="categories")
icon_id: Optional[int] = Field(default=None, foreign_key="sdeicon.id")
icon: Optional[SDEIcon] = Relationship(back_populates="categories")
name: str
published: bool
groups: List['Group'] = Relationship(back_populates="category")
groups: List['SDEGroup'] = Relationship(back_populates="category")
class Group(SQLModel, table=True):
class SDEGroup(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
anchorable: bool
anchored: bool
category_id: Optional[int] = Field(default=None, foreign_key="category.id")
category: Optional[Category] = Relationship(back_populates="groups")
category_id: Optional[int] = Field(default=None, foreign_key="sdecategory.id")
category: Optional[SDECategory] = Relationship(back_populates="groups")
fittableNonSingletion: bool
icon_id: Optional[int] = Field(default=None, foreign_key="icon.id")
icon: Optional[Icon] = Relationship(back_populates="groups")
icon_id: Optional[int] = Field(default=None, foreign_key="sdeicon.id")
icon: Optional[SDEIcon] = Relationship(back_populates="groups")
name: str
published: bool
useBasePrice: bool
types: List['Type'] = Relationship(back_populates="group")
types: List['SDEType'] = Relationship(back_populates="group")
class MarketGroup(SQLModel, table=True):
class SDEMarketGroup(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
description: Optional[str] = None
hasTypes: bool
icon_id: Optional[int] = Field(default=None, foreign_key="icon.id")
icon: Optional[Icon] = Relationship(back_populates="marketgroups")
icon_id: Optional[int] = Field(default=None, foreign_key="sdeicon.id")
icon: Optional[SDEIcon] = Relationship(back_populates="marketgroups")
name: str
parent_marketgroup_id: Optional[int] = Field(default=None, foreign_key="marketgroup.id")
parent_marketgroup: Optional['MarketGroup'] = Relationship(back_populates="children_marketgroups",
sa_relationship_kwargs={"remote_side": 'MarketGroup.id'}) # workaround for self reference: https://github.com/tiangolo/sqlmodel/issues/127#issuecomment-1224135123
children_marketgroups: List['MarketGroup'] = Relationship(back_populates="parent_marketgroup")
parent_marketgroup_id: Optional[int] = Field(default=None, foreign_key="sdemarketgroup.id")
parent_marketgroup: Optional['SDEMarketGroup'] = Relationship(back_populates="children_marketgroups",
sa_relationship_kwargs={"remote_side": 'SDEMarketGroup.id'}) # workaround for self reference: https://github.com/tiangolo/sqlmodel/issues/127#issuecomment-1224135123
children_marketgroups: List['SDEMarketGroup'] = Relationship(back_populates="parent_marketgroup")
types: List['Type'] = Relationship(back_populates="marketgroup")
types: List['SDEType'] = Relationship(back_populates="marketgroup")
class Type(SQLModel, table=True):
class SDEType(SQLModel, table=True):
id: int = Field(primary_key=True)
group_id: Optional[int] = Field(default=None, foreign_key="group.id")
group: Optional[Group] = Relationship(back_populates="types")
group_id: Optional[int] = Field(default=None, foreign_key="sdegroup.id")
group: Optional[SDEGroup] = Relationship(back_populates="types")
marketgroup_id: Optional[int] = Field(default=None, foreign_key="marketgroup.id")
marketgroup: Optional[MarketGroup] = Relationship(back_populates="types")
marketgroup_id: Optional[int] = Field(default=None, foreign_key="sdemarketgroup.id")
marketgroup: Optional[SDEMarketGroup] = Relationship(back_populates="types")
name: str
published: bool = False
description: Optional[str] = None
basePrice: Optional[float] = None
icon_id: Optional[int] = Field(default=None, foreign_key="icon.id")
icon: Optional[Icon] = Relationship(back_populates="types")
icon_id: Optional[int] = Field(default=None, foreign_key="sdeicon.id")
icon: Optional[SDEIcon] = Relationship(back_populates="types")
volume: Optional[float] = None
portionSize: int
materials: List['TypeMaterial'] = Relationship(back_populates="type",
sa_relationship_kwargs={"foreign_keys": '[TypeMaterial.type_id]'}) # https://github.com/tiangolo/sqlmodel/issues/10#issuecomment-1537445078
material_of: List['TypeMaterial'] = Relationship(back_populates="material_type",
sa_relationship_kwargs={"foreign_keys": '[TypeMaterial.material_type_id]'}) # https://github.com/tiangolo/sqlmodel/issues/10#issuecomment-1537445078
materials: List['SDETypeMaterial'] = Relationship(back_populates="type",
sa_relationship_kwargs={"foreign_keys": '[SDETypeMaterial.type_id]'}) # https://github.com/tiangolo/sqlmodel/issues/10#issuecomment-1537445078
material_of: List['SDETypeMaterial'] = Relationship(back_populates="material_type",
sa_relationship_kwargs={"foreign_keys": '[SDETypeMaterial.material_type_id]'}) # https://github.com/tiangolo/sqlmodel/issues/10#issuecomment-1537445078
class TypeMaterial(SQLModel, table=True):
class SDETypeMaterial(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
type_id: Optional[int] = Field(default=None, foreign_key="type.id")
type: Optional[Type] = Relationship(back_populates="materials",
sa_relationship_kwargs={"primaryjoin": 'TypeMaterial.type_id==Type.id',
type_id: Optional[int] = Field(default=None, foreign_key="sdetype.id")
type: Optional[SDEType] = Relationship(back_populates="materials",
sa_relationship_kwargs={"primaryjoin": 'SDETypeMaterial.type_id==SDEType.id',
'lazy': 'joined'}) # workaround: https://github.com/tiangolo/sqlmodel/issues/10#issuecomment-1002835506
material_type_id: Optional[int] = Field(default=None, foreign_key="type.id")
material_type: Optional[Type] = Relationship(back_populates="material_of",
sa_relationship_kwargs={"primaryjoin": 'TypeMaterial.material_type_id==Type.id',
material_type_id: Optional[int] = Field(default=None, foreign_key="sdetype.id")
material_type: Optional[SDEType] = Relationship(back_populates="material_of",
sa_relationship_kwargs={"primaryjoin": 'SDETypeMaterial.material_type_id==SDEType.id',
'lazy': 'joined'}) # workaround: https://github.com/tiangolo/sqlmodel/issues/10#issuecomment-1002835506
quantity: int