diff --git a/.env.development b/.env.development index 3f332b9..658843f 100644 --- a/.env.development +++ b/.env.development @@ -1,16 +1,18 @@ ENVIRONMENT=development +# JWT -# jwt -SECRET_KEY=JwrddNQ1jbhdgEqEXhIVqUU1PineCLVW4evEKly2Zdc +# 错误日志收集 +SENTRY_DSN=https://cf047260c50340fa8a96f4f198cefa12@o959813.ingest.sentry.io/6128331 # 数据库 -MYSQL_SERVER=localhost:3306 +MYSQL_ADDRESS=127.0.0.1:3306 MYSQL_USER=root MYSQL_PASSWORD=123456 MYSQL_DB=mall # redis -REDIS_SERVER=localhost:6379 +REDIS_ADDRESS=localhost:6379 #rabbitMQ +RABBITMQ_ADDRESS=localhost:5672 diff --git a/core/config.py b/core/config.py index 27f5e75..e359d9f 100644 --- a/core/config.py +++ b/core/config.py @@ -1,8 +1,17 @@ -from pydantic import BaseSettings +import secrets +from typing import Optional + +from pydantic import BaseSettings, HttpUrl class Settings(BaseSettings): - SECRET_KEY: str + # JWT + SECRET_KEY: str = secrets.token_urlsafe(32) + ALGORITHM: str = 'HS256' + ACCESS_TOKEN_EXPIRE_MINUTES: int = 60 * 24 * 3 + + # Sentry + SENTRY_DSN: Optional[HttpUrl] # 数据库 MYSQL_ADDRESS: str @@ -11,11 +20,10 @@ class Settings(BaseSettings): MYSQL_DB: str # redis, ip + 端口 - REDIS_SERVER: str - + REDIS_ADDRESS: str # rabbitMQ RABBITMQ_ADDRESS: str - + ... # 短信服务 # 邮件服务 @@ -24,6 +32,6 @@ class Settings(BaseSettings): # 存储服务信息 - # pip freeze > requirements.txt -# settings = Settings(_env_file='prod.env', _env_file_encoding='utf-8') \ No newline at end of file +# settings = Settings(_env_file='../.env.development', _env_file_encoding='utf-8') +settings = Settings(_env_file='.env.development', _env_file_encoding='utf-8') \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..24dd821 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,23 @@ +version: "3.9" +services: + mysql: + image: "mysql:8.0.27" + restart: always + environment: + MYSQL_ROOT_PASSWORD: "123456" + TZ: Asia/Shanghai # 指定时区 + ports: + - "3306:3306" + + redis: + image: "redis:6.2.6-alpine3.15" + restart: always + ports: + - "6379:6379" + + rabbitmq: + image: "rabbitmq:3.9.11-management-alpine" + restart: always + ports: + - "15672:15672" + - "5672:5672" \ No newline at end of file diff --git a/main.py b/main.py index 5ff382a..ba3f607 100644 --- a/main.py +++ b/main.py @@ -1,6 +1,8 @@ from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware +from utils import register_orm, register_redis +from utils import register_middleware app = FastAPI() @@ -11,3 +13,12 @@ app.add_middleware( allow_methods=["*"], allow_headers=["*"], ) + +register_middleware(app) +register_orm(app) +register_redis(app) + + +if __name__ == '__main__': + import uvicorn + uvicorn.run("main:app", reload=True) diff --git a/migrations/models/0_20211230145350_init.sql b/migrations/models/0_20211230145350_init.sql new file mode 100644 index 0000000..0cdf7d0 --- /dev/null +++ b/migrations/models/0_20211230145350_init.sql @@ -0,0 +1,11 @@ +-- upgrade -- +CREATE TABLE IF NOT EXISTS `user` ( + `id` INT NOT NULL PRIMARY KEY AUTO_INCREMENT, + `username` VARCHAR(32) NOT NULL COMMENT '和用户名' +) CHARACTER SET utf8mb4; +CREATE TABLE IF NOT EXISTS `aerich` ( + `id` INT NOT NULL PRIMARY KEY AUTO_INCREMENT, + `version` VARCHAR(255) NOT NULL, + `app` VARCHAR(20) NOT NULL, + `content` JSON NOT NULL +) CHARACTER SET utf8mb4; diff --git a/models/__init__.py b/models/__init__.py index e69de29..ee4c00b 100644 --- a/models/__init__.py +++ b/models/__init__.py @@ -0,0 +1 @@ +from .user import User diff --git a/models/user.py b/models/user.py index e69de29..217f538 100644 --- a/models/user.py +++ b/models/user.py @@ -0,0 +1,6 @@ +from tortoise import models +from tortoise import fields + + +class User(models.Model): + username = fields.CharField(max_length=32, description='和用户名') \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..a1e951f --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,4 @@ +[tool.aerich] +tortoise_orm = "utils.TORTOISE_ORM" +location = "./migrations" +src_folder = "./." diff --git a/requirements.txt b/requirements.txt index 01ef3a5..7a4b998 100644 Binary files a/requirements.txt and b/requirements.txt differ diff --git a/utils.py b/utils.py index e69de29..8bdac23 100644 --- a/utils.py +++ b/utils.py @@ -0,0 +1,84 @@ +from typing import Dict +from typing import List +from typing import NoReturn +from typing import Optional + +import sentry_sdk +from sentry_sdk.integrations.asgi import SentryAsgiMiddleware +from aioredis import Redis +from aioredis import from_url +from fastapi import FastAPI +from starlette.requests import Request +from tortoise.contrib.fastapi import register_tortoise + +from core.config import settings + +sentry_sdk.init(settings.SENTRY_DSN) + + +def mysql_cdn(): + """mysql cdn 完整地址""" + return f'mysql://{settings.MYSQL_USER}:{settings.MYSQL_PASSWORD}@{settings.MYSQL_ADDRESS}/{settings.MYSQL_DB}' + + +def redis_cdn(): + """redis cdn""" + return f'redis://{settings.REDIS_ADDRESS}' + + +def register_middleware(app: FastAPI): + """注册 日志错误收集 中间件""" + app.add_middleware(SentryAsgiMiddleware) + + +def register_orm(app: FastAPI, modules: Optional[Dict[str, List[str]]] = None) -> NoReturn: + """注册orm""" + if modules is None: + modules = {"models": ["models"]} + register_tortoise( + app, + db_url=mysql_cdn(), + modules=modules + ) + + +def redis_pool() -> Dict[int, Redis]: + """redis 16个db 每个创建池""" + return {db: from_url(redis_cdn(), db=db, max_connections=10, encoding="utf-8", decode_responses=True) + for db in range(16) + } + + +def close_redis_pool(pool: Dict[int, Redis]): + for v in pool.values(): + v.close() + + +def get_redis_db(request: Request, db: int = 0) -> Redis: + """获取到FastAPI中的缓存redis 字典获取 指定 db""" + return request.app.state.redis_pool.get(db) + + +def register_redis(app: FastAPI): + """redis 注册""" + + @app.on_event("startup") + async def create_redis(): + app.state.redis_pool = redis_pool() + + @app.on_event("shutdown") + async def close_redis(): + close_redis_pool(app.state.redis_pool) + + +# orm 迁移生成表 +# https://tortoise.github.io/migration.html +TORTOISE_ORM = { + "connections": {"default": mysql_cdn()}, + "apps": { + "models": { + "models": ["models", "aerich.models"], + "default_connection": "default", + }, + } +}