From 341a311eabaeb559a7821ffb95c569053f4de309 Mon Sep 17 00:00:00 2001 From: ScuroNeko Date: Sat, 18 Nov 2023 15:40:34 +0300 Subject: [PATCH] added caching --- .gitignore | 2 ++ main.py | 29 +++++++++----------------- requirements.txt | 6 +++++- src/constants.py | 2 +- src/routes/__init__.py | 21 +++++++++++++++++++ src/routes/api.py | 11 +++++----- src/utils.py | 47 ++++++++++++++++++++++++++++++++++++++---- 7 files changed, 87 insertions(+), 31 deletions(-) create mode 100644 src/routes/__init__.py diff --git a/.gitignore b/.gitignore index 0f4f714..32fd6c3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +.env + .idea/ .vscode/ .idea/**/workspace.xml diff --git a/main.py b/main.py index 793f819..f976f4b 100644 --- a/main.py +++ b/main.py @@ -2,29 +2,12 @@ from json import loads from fastapi import FastAPI from fastapi.openapi.utils import get_openapi +from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import JSONResponse from pydantic import ValidationError from src.errors import Response, NOT_FOUND -from src.routes.achievements import achievements -from src.routes.adventureranks import adventure_ranks -from src.routes.animals import animals -from src.routes.artifacts import artifacts -from src.routes.characters import characters -from src.routes.crafts import crafts -from src.routes.domains import domains -from src.routes.elements import elements -from src.routes.enemies import enemies -from src.routes.foods import foods -from src.routes.geographies import geographies -from src.routes.glider import gliders -from src.routes.materials import materials -from src.routes.namecards import namecards -from src.routes.outfits import outfits -from src.routes.talentmaterialtypes import talent_material_types -from src.routes.tcg import tcg -from src.routes.weaponmaterialtypes import weapon_material_types -from src.routes.weapons import weapons +from src.routes import * from src.routes.api import api @@ -74,3 +57,11 @@ def custom_openapi(): app.openapi = custom_openapi + +app.add_middleware( + CORSMiddleware, + allow_origins=['*'], + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) diff --git a/requirements.txt b/requirements.txt index f0615cf..eaee398 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,6 @@ fastapi -uvicorn \ No newline at end of file +uvicorn +pydantic + +python-memcached +python-dotenv \ No newline at end of file diff --git a/src/constants.py b/src/constants.py index 0b91f83..9d76c55 100644 --- a/src/constants.py +++ b/src/constants.py @@ -1,4 +1,4 @@ -SERVER_VERSION = '1.0' +SERVER_VERSION = '1.1' GAME_VERSION = '4.2.0' DEFAULT_QUERY = ['English', 'Russian'] diff --git a/src/routes/__init__.py b/src/routes/__init__.py new file mode 100644 index 0000000..b1da663 --- /dev/null +++ b/src/routes/__init__.py @@ -0,0 +1,21 @@ +from .api import api + +from .achievements import achievements +from .adventureranks import adventure_ranks +from .animals import animals +from .artifacts import artifacts +from .characters import characters +from .crafts import crafts +from .domains import domains +from .elements import elements +from .enemies import enemies +from .foods import foods +from .geographies import geographies +from .glider import gliders +from .materials import materials +from .namecards import namecards +from .outfits import outfits +from .talentmaterialtypes import talent_material_types +from .tcg import tcg +from .weaponmaterialtypes import weapon_material_types +from .weapons import weapons diff --git a/src/routes/api.py b/src/routes/api.py index ac10e34..7c9d4b3 100644 --- a/src/routes/api.py +++ b/src/routes/api.py @@ -4,7 +4,6 @@ from subprocess import check_output from src.constants import GAME_VERSION, SERVER_VERSION, LANGUAGES from src.errors import Response - api = APIRouter(prefix='/api', tags=['Service']) @@ -13,12 +12,12 @@ async def get_versions(): git_server = git_info('.') git_data = git_info('./data') - reponse = {'server_version': SERVER_VERSION, - 'game_version': GAME_VERSION, - 'git_server': git_server, - 'git_data': git_data} + response = {'server_version': SERVER_VERSION, + 'game_version': GAME_VERSION, + 'git_server': git_server, + 'git_data': git_data} - return Response(response=reponse) + return Response(response=response) @api.get('/languages') diff --git a/src/utils.py b/src/utils.py index 013d2d0..a9eeed8 100644 --- a/src/utils.py +++ b/src/utils.py @@ -1,24 +1,63 @@ -from json import load +from json import load, loads, dumps +from os import environ from os.path import join +from dotenv import load_dotenv from fastapi import HTTPException +from memcache import Client from src.constants import LANGUAGES, DEFAULT_RESULT, DEFAULT_QUERY, DATA_FOLDER +load_dotenv() +memcache_ip = environ.get('MEMCACHE_IP') +memcache_port = environ.get('MEMCACHE_PORT') or 11211 +mc = Client([f'{memcache_ip}:{memcache_port}'], debug=1) + + +def load_cached(key): + value = mc.get(key) + if not value: + return None + print(f'loaded {key} from cache') + return loads(value) + + +def save_cache(key, value: str | dict): + if type(value) is dict: + mc.set(key, dumps(value), 86400) + else: + mc.set(key, value, 86400) + + def load_index(language: str, category: str): + cache_key = join('index', language, category) + if cache := load_cached(cache_key): + return cache with open(join(DATA_FOLDER, 'index', language, f'{category}.json'), 'r', encoding='utf-8') as f: - return load(f) + json = f.read() + save_cache(cache_key, json) + return loads(json) def load_category(lang: str, category: str, name: str) -> dict: + cache_key = join(lang, category, name) + if cache := load_cached(cache_key): + return cache with open(join(DATA_FOLDER, lang, category, f'{name}.json'), 'r', encoding='utf-8') as f: - return load(f) + json = f.read() + save_cache(cache_key, json) + return loads(json) def load_file(folder: str, name: str) -> dict: + cache_key = join(folder, name) + if cache := load_cached(cache_key): + return cache with open(join(DATA_FOLDER, folder, f'{name}.json'), 'r', encoding='utf-8') as f: - return load(f) + json = f.read() + save_cache(cache_key, json) + return loads(json) def get_file_name(query, category, langs) -> str: