From 55b57b90531f33558ac4683f9093c09cdb4e7c0a Mon Sep 17 00:00:00 2001 From: pengtao Date: Fri, 19 Nov 2021 17:33:35 +0800 Subject: [PATCH] init --- README.MD | 25 +++++++++++ __init__.py | 0 config/__init__.py | 0 config/config.py | 35 +++++++++++++++ dependencies.py | 22 ++++++++++ jobs.sqlite | Bin 0 -> 16384 bytes main.py | 86 +++++++++++++++++++++++++++++++++++++ ops/__init__.py | 0 ops/imgsmall/__init__.py | 0 ops/imgsmall/route.py | 42 ++++++++++++++++++ requests.txt | 7 +++ scripts/__init__.py | 0 scripts/common/__init__.py | 26 +++++++++++ scripts/common/get_img.py | 9 ++++ scripts/common/redis.py | 14 ++++++ scripts/logger.py | 20 +++++++++ test.py | 30 +++++++++++++ 17 files changed, 316 insertions(+) create mode 100644 README.MD create mode 100644 __init__.py create mode 100644 config/__init__.py create mode 100644 config/config.py create mode 100644 dependencies.py create mode 100644 jobs.sqlite create mode 100644 main.py create mode 100644 ops/__init__.py create mode 100644 ops/imgsmall/__init__.py create mode 100644 ops/imgsmall/route.py create mode 100644 requests.txt create mode 100644 scripts/__init__.py create mode 100644 scripts/common/__init__.py create mode 100644 scripts/common/get_img.py create mode 100644 scripts/common/redis.py create mode 100644 scripts/logger.py create mode 100644 test.py diff --git a/README.MD b/README.MD new file mode 100644 index 0000000..8137695 --- /dev/null +++ b/README.MD @@ -0,0 +1,25 @@ +### 项目简介: + +new project with fastapi + +https://fastapi.tiangolo.com/zh/tutorial/bigger-applications/ + +采用异步方式实现,考虑并发性能 + +### 功能 + +1. 实现认证功能 + +2. 实现接口 + +3. 后端采用redis,mysql + + +#### route分类 +> common + mail -clearn +> deploy + aliyun cdn + +> ops +> data_collect \ No newline at end of file diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/config/__init__.py b/config/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/config/config.py b/config/config.py new file mode 100644 index 0000000..75dce58 --- /dev/null +++ b/config/config.py @@ -0,0 +1,35 @@ +from pydantic import BaseSettings +from typing import Optional +import os + +from pydantic.fields import T + + +class Settings(BaseSettings): + app_name: str = "Kingsome API" + admin_email: str = "pengtao@kingsome.cn" + items_per_user: int = 50 + is_debug: bool = True + + redis_host: str = "192.168.100.30" # reids 服务器IP + redis_port: int = 6379 # redis 端口 + redis_db: int = 2 # redis db + + mail_server: str = "smtp.exmail.qq.com" # 邮箱server + mail_user: str = "ops@kingsome.cn" # 邮箱用户名 + mail_pswd: Optional[str] = os.getenv('mail_pswd') # 邮箱密码 + + x_token: str = "abc" + + root_path_in_servers: Optional[bool] = False + root_path: str = '/api/v1' + + origins: list = [ + "http://*.kingsome.cn", + "https://*.kingsome.cn", + "http://localhost", + "http://localhost:8080", + ] + + +settings = Settings() diff --git a/dependencies.py b/dependencies.py new file mode 100644 index 0000000..7dec374 --- /dev/null +++ b/dependencies.py @@ -0,0 +1,22 @@ +from fastapi import Header, HTTPException +from pydantic.fields import T +from starlette.requests import Request +import pdb +from config.config import settings + + +async def get_token_header(request: Request, x_token: str = Header(...)): + client = request.app.state.redis + dd = await client.get('x_token') + # pdb.set_trace() + #print(dd, settings.x_token, x_token) + if x_token == settings.x_token or x_token == dd: + return True + else: + raise HTTPException(status_code=400, detail="X-Token header invalid") + + +async def get_query_token(token: str): + if token != "jessica": + raise HTTPException( + status_code=400, detail="No Jessica token provided") diff --git a/jobs.sqlite b/jobs.sqlite new file mode 100644 index 0000000000000000000000000000000000000000..b369870f5723090fc577bb494091ce879a2f2701 GIT binary patch literal 16384 zcmeI&&2Jk;6aeu3s=c;jZ&DFVgd+BWWJ|zTMsa zwBj>r?{&j{!tATcqN1wGN4BjfN(N>F=INxt%Ivl}J#fx4qZDdiq^;+Qo{1DIW_=F} zoKOG-Pyhu`00mG01yBG5Pyhw~9|DJqdOTZOQx6?KXwiW`a7iy}dbHK=(9pfz-HqIU z4wxJE1DE;xbpEKZQ7;u6C3~}at#s4A@N~OYwdXHk=T6j+KP;&6?An_8mBq+z=TwdJ zr)!fIG>Yq$(is;|Cj6Ftqgda#UaaSw_no|5tu^fGXO+r3b~16IYWw3#t=N#eq2q4E z2qfd{mD>7=Gd`(rZWZgd>~iUro%37yWd1`fmfc=cm62d{(19G@C4JT%ZJ+jZ=6j&S zP&4IlOT(-!43*5ig<;BfbLq>W%m(hqhJ3pna zKQO-aC!f*26geKhOT)_Un}qC0}e zS?IUhG!%Sg=2^cm*&7vFkXQ(wx(18Jq~wvv9}1|}Q=vLjW?SPzrd-IxOYj$~M`9xx z|1Fli{JNBY*7WYN`+{q3PaHwZ)5XXqSGGM8v_0aBtp~lb!u5^qhG3#DzJ|HK%S}3< zO-NFpk?|JYBmEA83z4w>@Ibq?WIVd*I6FVre*u(V&qL81=U8KTMq_IAE*yTrv3e$l zA21r;B^|-7&B^K+EE+eZ!~Jdm78msRj|17`%GS8YJPD~>$o_%o%7VU}e)|XESvha< z3^z~ZV<>>XuoDXQLHD{GwT^_;DiDwfC4Ch0w{n2D1ZVe zfC4Ch0x0lG31p_Pavb@&KTUcueMxm3Ev2u*i^cJ4mvR38RI#30Pp#iysqSH8Q2+%{ p00mG01yBG5Pyhu`00mG01?B}3@_!@U)D2bsW241&BO!me_zO#NWT*fD literal 0 HcmV?d00001 diff --git a/main.py b/main.py new file mode 100644 index 0000000..8c2082c --- /dev/null +++ b/main.py @@ -0,0 +1,86 @@ +# uvicorn main:app --host=127.0.0.1 --port=8000 --reload +from config.config import settings +from fastapi import Depends, FastAPI, BackgroundTasks, Request +from dependencies import get_token_header +from ops.imgsmall import route as img_route + +from typing import Optional +from scripts.common.redis import get_redis_pool +import pdb +from scripts.logger import logger +from fastapi.middleware.cors import CORSMiddleware + +# from apscheduler.events import EVENT_JOB_EXECUTED +# from jobs.jobs import Schedule, job_execute +tags_metadata = [ + # { + # "name": "common", + # "description": "Operations with users. The **login** logic is also here.", + # }, + { + "name": "common", + "description": "Manage items. So _fancy_ they have their own docs.", + "externalDocs": { + "description": "Items external docs", + "url": "https://fastapi.tiangolo.com/", + }, + }, +] + + +def create_app(): + application = FastAPI(dependencies=[Depends(get_token_header)], + openapi_tags=tags_metadata) + application.include_router(img_route.router, prefix="/img") + return application + + +app = create_app() +app.add_middleware( + CORSMiddleware, + allow_origins=settings.origins, + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) + + +@app.on_event("startup") +async def startup_event(): + app.state.redis = await get_redis_pool() + # Schedule.start() + # Schedule.add_listener(job_execute, EVENT_JOB_EXECUTED) + + +@app.on_event("shutdown") +async def shutdown_event(): + app.state.redis.close() + await app.state.redis.wait_close() + + +@app.get("/") +async def root(request: Request): + redis_client = request.app.state.redis + keys = await redis_client.get("online_devices") + logger.info("get keys was {0} with {1}".format(keys, request.url)) + if keys: + return {"message": "Hello Bigger Applications! {}".format(keys)} + else: + return {"message": "kajsk"} + + + +# @app.post("/send-notification/{email}") +# async def send_notification(request: Request, email: str, background_tasks: BackgroundTasks, q: str = Depends(get_query)): +# redis_client = request.app.state.redis +# keys = await redis_client.get("online_devices") +# logger.info("get keys = {}".format(keys)) +# message = f"message to {email} \n" +# background_tasks.add_task(write_log, message) +# return {"message": "Message sent"} + + +if __name__ == '__main__': + import uvicorn + uvicorn.run(app='main:app', host="127.0.0.1", + port=8010, reload=True, debug=True) diff --git a/ops/__init__.py b/ops/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ops/imgsmall/__init__.py b/ops/imgsmall/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ops/imgsmall/route.py b/ops/imgsmall/route.py new file mode 100644 index 0000000..34a9727 --- /dev/null +++ b/ops/imgsmall/route.py @@ -0,0 +1,42 @@ +from fastapi import APIRouter, BackgroundTasks, UploadFile, File, Form +from typing import List +from pydantic import BaseModel +from starlette.requests import Request +from starlette.responses import JSONResponse +from config.config import settings +router = APIRouter() + +@router.get("/img") +async def get_img(url:string)-> JSONResponse: + + +# class EmailSchema(BaseModel): +# email: List[EmailStr] +# body: str +# subject: str + + +# MAIL_CONF = ConnectionConfig( +# MAIL_USERNAME=settings.mail_user, +# MAIL_PASSWORD=settings.mail_pswd, +# MAIL_FROM=settings.mail_user, +# MAIL_PORT='465', +# MAIL_SERVER=settings.mail_server, +# MAIL_TLS=False, +# MAIL_SSL=True, +# # USE_CREDENTIALS=True +# ) + + +@router.post("/email") +async def simple_send(email: EmailSchema) -> JSONResponse: + message = MessageSchema( + subject=email.dict().get("subject"), + # List of recipients, as many as you can pass + recipients=email.dict().get("email"), + body="{}".format(email.dict().get("body")), + subtype="html" + ) + fm = FastMail(MAIL_CONF) + await fm.send_message(message) + return JSONResponse(status_code=200, content={"message": "email has been sent"}) diff --git a/requests.txt b/requests.txt new file mode 100644 index 0000000..1da20e7 --- /dev/null +++ b/requests.txt @@ -0,0 +1,7 @@ +aioredis==1.3.1 +fastapi==0.65.2 +fastapi-mail==0.3.7 +GitPython==3.1.18 +pydantic==1.8.2 +redis==3.2.1 +uvicorn==0.15.0 diff --git a/scripts/__init__.py b/scripts/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/scripts/common/__init__.py b/scripts/common/__init__.py new file mode 100644 index 0000000..3658478 --- /dev/null +++ b/scripts/common/__init__.py @@ -0,0 +1,26 @@ +import subprocess +from scripts.log import logger + + +@logger.catch +def run_cmd(cmd, shell=True, timeout=120): + ''' + Run command with arguments, wait to complete and return ``True`` on success. + + :param cls: The class as implicit first argument. + :param cmd: Command string to be executed. + :returns : ``True`` on success, otherwise ``None``. + :rtype : ``bool`` + ''' + logger.debug('Execute command: {0}'.format(cmd)) + status = True + try: + out_bytes = subprocess.check_output( + cmd, shell=shell, stderr=subprocess.STDOUT, timeout=timeout) + except subprocess.CalledProcessError as e: + out_bytes = e.output # Output generated before error + code = e.returncode # Return code + logger.error(f"run {cmd} failed,out={out_bytes},code={code}") + status = False + + return out_bytes, status diff --git a/scripts/common/get_img.py b/scripts/common/get_img.py new file mode 100644 index 0000000..0b59dd2 --- /dev/null +++ b/scripts/common/get_img.py @@ -0,0 +1,9 @@ +import shutil +import requests +def get_img(url): + url = 'http://imgsmall.dmzj.com/h/59665/121592/0.jpg' + headers = {'Referer': 'https://www.dmzj.com/'} + response = requests.get(url=url, headers=headers, stream=True) + with open('0.jpg', 'wb') as out_file: + shutil.copyfileobj(response.raw, out_file) + del response diff --git a/scripts/common/redis.py b/scripts/common/redis.py new file mode 100644 index 0000000..69af665 --- /dev/null +++ b/scripts/common/redis.py @@ -0,0 +1,14 @@ +from aioredis import create_redis_pool, Redis +from config.config import settings + +# settings = { +# "redis_host": "192.168.100.30", +# "redis_port": 6379, +# "redis_db": 1, + +# } + + +async def get_redis_pool() -> Redis: + redis = await create_redis_pool("redis://{ip}:{port}/{db}?encoding=utf-8".format(ip=settings.redis_host, port=settings.redis_port, db=settings.redis_db)) + return redis diff --git a/scripts/logger.py b/scripts/logger.py new file mode 100644 index 0000000..4f6ab0c --- /dev/null +++ b/scripts/logger.py @@ -0,0 +1,20 @@ +import os +import time +from loguru import logger + +basedir = os.path.dirname( + os.path.dirname(os.path.abspath(__file__))) + +# print(f"log basedir{basedir}") # /xxx/python_code/FastAdmin/backend/app +# 定位到log日志文件 +log_path = os.path.join(basedir, 'logs') + +if not os.path.exists(log_path): + os.mkdir(log_path) + +log_path_error = os.path.join( + log_path, f'{time.strftime("%Y-%m-%d")}_error.log') + +# 日志简单配置 +# 具体其他配置 可自行参考 https://github.com/Delgan/loguru +logger.add(log_path_error, rotation="12:00", retention="5 days", enqueue=True) diff --git a/test.py b/test.py new file mode 100644 index 0000000..445e376 --- /dev/null +++ b/test.py @@ -0,0 +1,30 @@ +from fastapi.testclient import TestClient +from ops.common.common import EmailSchema +from main import app +import time +import pdb +import json +client = TestClient(app) + + +def test_read_main(): + response = client.get("/") + assert response.status_code == 200 + assert response.json() == {"message": "Hello Bigger Applications!"} + + +def test_post_mail(): + data = {"email": ['pengtao@kingsome.cn'], "body": 'test message!', + "subject": 'ttt {}'.format(time.time())} + response = client.post("/common/email", headers={"X-Token": "fake-super-scret-token", "accept": "application/json", "Content-Type": "application/json"}, + data=json.dumps(data), + ) + # data=EmailSchema(**data).json() + print(response) + # pdb.set_trace() + assert response.status_code == 200 + assert response.json() == {"message": "email has been sent"} + + +if __name__ == "__main__": + test_post_mail()