From 56f93165ba2089b9d595f52ffa601f13c698b8ee Mon Sep 17 00:00:00 2001 From: BryantHe Date: Thu, 10 Aug 2023 12:27:18 +0800 Subject: [PATCH] init commit --- .apiflaskenv | 5 + .dockerignore | 1 + .gitignore | 162 +++++++++++++++++++++++++++++++ Dockerfile | 6 ++ README.md | 4 + app/__init__.py | 44 +++++++++ app/api/__init__.py | 0 app/api/v1/__init__.py | 16 +++ app/api/v1/api.py | 80 +++++++++++++++ app/api/v1/exception/__init__.py | 0 app/api/v1/schema/__init__.py | 0 app/api/v1/schema/api.py | 51 ++++++++++ app/config/__init__.py | 0 app/config/config.py | 11 +++ app/util/__init__.py | 0 app/util/common.py | 15 +++ docker-compose.yml | 23 +++++ docker-deploy.sh | 1 + gunicorn.conf.py | 22 +++++ requirements.txt | 2 + starter.py | 14 +++ 21 files changed, 457 insertions(+) create mode 100644 .apiflaskenv create mode 100644 .dockerignore create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 README.md create mode 100644 app/__init__.py create mode 100644 app/api/__init__.py create mode 100644 app/api/v1/__init__.py create mode 100644 app/api/v1/api.py create mode 100644 app/api/v1/exception/__init__.py create mode 100644 app/api/v1/schema/__init__.py create mode 100644 app/api/v1/schema/api.py create mode 100644 app/config/__init__.py create mode 100644 app/config/config.py create mode 100644 app/util/__init__.py create mode 100644 app/util/common.py create mode 100644 docker-compose.yml create mode 100644 docker-deploy.sh create mode 100644 gunicorn.conf.py create mode 100644 requirements.txt create mode 100644 starter.py diff --git a/.apiflaskenv b/.apiflaskenv new file mode 100644 index 0000000..8794abb --- /dev/null +++ b/.apiflaskenv @@ -0,0 +1,5 @@ +FLASK_APP=starter:app +FLASK_RUN_HOST="127.0.0.1" +FLASK_RUN_PORT=5000 +# production or development etc. +FLASK_DEBUG=production diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..1d17dae --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +.venv diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f626f23 --- /dev/null +++ b/.gitignore @@ -0,0 +1,162 @@ +# ---> Python +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +*.env +*.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +.idea/ + diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..2769b81 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,6 @@ +FROM python:3.11 +RUN python3 -m pip uninstall -y chassis +# 拷贝依赖 +COPY requirements.txt . +# 安装依赖 +RUN python3 -m pip install -i https://mirrors.cloud.tencent.com/pypi/simple --trusted-host=mirrors.cloud.tencent.com -r requirements.txt \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..1952dda --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +# pzx-web-api + +pzx 专属的 web api 服务 + diff --git a/app/__init__.py b/app/__init__.py new file mode 100644 index 0000000..1370f1e --- /dev/null +++ b/app/__init__.py @@ -0,0 +1,44 @@ +import os + +# from dotenv import load_dotenv +from apiflask import APIFlask +from chassis.flask_nameko import FlaskPooledClusterRpcProxy + +from app.config.config import Config +from app.util.common import basedir + + +rpc = FlaskPooledClusterRpcProxy() + + +def register_blueprints(apiflask_app): + from app.api.v1 import create_v1 + + apiflask_app.register_blueprint(create_v1(), url_prefix='/v1') + + +def load_app_config(app): + """ + 加载环境变量和配置类到app config + """ + # 读取 .env + # load_dotenv(os.path.join(basedir, '.apiflask.env')) + # 读取配置类 + app.config.from_object('app.config.config.Config') + + +def load_rpc_client(apiflask_app): + apiflask_app.config.update(dict( + NAMEKO_AMQP_URI=str(Config.RABBITMQ_URI) + )) + rpc.init_app(apiflask_app) + + +def create_app(): + # http wsgi server 托管启动需指定读取环境配置 + # load_dotenv(os.path.join(basedir, '.apiflaskenv')) + app = APIFlask(__name__) + load_app_config(app) + register_blueprints(app) + # load_rpc_client(app) + return app \ No newline at end of file diff --git a/app/api/__init__.py b/app/api/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/api/v1/__init__.py b/app/api/v1/__init__.py new file mode 100644 index 0000000..bd4b794 --- /dev/null +++ b/app/api/v1/__init__.py @@ -0,0 +1,16 @@ +from apiflask import APIBlueprint + +from app.api.v1.api import api + + +def create_v1(): + bp_v1 = APIBlueprint('v1', __name__) + bp_v1.register_blueprint(api, url_prefix='/api') + return bp_v1 + + + + + + + diff --git a/app/api/v1/api.py b/app/api/v1/api.py new file mode 100644 index 0000000..70bbd2e --- /dev/null +++ b/app/api/v1/api.py @@ -0,0 +1,80 @@ +import socket +import platform +import psutil + +from apiflask import APIBlueprint + +api = APIBlueprint('api', __name__) + + +@api.get('/hello') +def hello(): + result_one = f'我是您的专属接口提供服务器: {socket.gethostname()}' + result_two = f'我的机器参数如下' + result_three = f'操作系统:{platform.system()},CPU 核数:{psutil.cpu_count()},目前 CPU 占用率: {psutil.cpu_percent()}' + text = """ + +
+

+ 您好,PZX 大人! +
+ + """ + result_one + """ + +
+ + """ + result_two + """ + +
+ + """ + result_three + """ +
+ """ + result_three + """ +
+ """ + f'总内存 {psutil.virtual_memory().total / 1024 / 1024},使用中内存:{round(psutil.virtual_memory().used / 1024 / 1024, 2)}' + """ +
+ """ + f'磁盘总空间 {round(psutil.disk_usage("/").total / 1024 / 1024 / 1024, 2)},磁盘使用情况:{round(psutil.disk_usage("/").used / 1024 / 1024 / 1024, 2)}' + """ +
+

+
+ """ + return text + diff --git a/app/api/v1/exception/__init__.py b/app/api/v1/exception/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/api/v1/schema/__init__.py b/app/api/v1/schema/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/api/v1/schema/api.py b/app/api/v1/schema/api.py new file mode 100644 index 0000000..f9cc113 --- /dev/null +++ b/app/api/v1/schema/api.py @@ -0,0 +1,51 @@ +from apiflask import Schema +from apiflask.fields import Integer, String, Boolean, Nested, List + + +class LoginIn(Schema): + username = String(required=True) + password = String(required=True) + tenantId = String(required=True) + uuid = String() + code = String() + + +class LoginNestedOut(Schema): + token = String() + + +class LoginOut(Schema): + code = Integer() + msg = String() + data = Nested(LoginNestedOut) + + +class CaptchaImageNestedOut(Schema): + captchaEnabled = Boolean() + img = String() + uuid = String() + + +class CaptchaImageOut(Schema): + code = Integer() + msg = String() + data = Nested(CaptchaImageNestedOut) + + +class TenantOut(Schema): + companyName = String() + domain = String() + tenantId = String() + + +class TenantsNestedOut(Schema): + tenantEnabled = Boolean() + voList = List(Nested(TenantOut)) + + +class TenantsOut(Schema): + code = Integer() + msg = String() + data = Nested(TenantsNestedOut) + + diff --git a/app/config/__init__.py b/app/config/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/config/config.py b/app/config/config.py new file mode 100644 index 0000000..62f8f4e --- /dev/null +++ b/app/config/config.py @@ -0,0 +1,11 @@ +import os + +from chassis.config import Config as _Config + + +class Config(_Config): + """ + 配置 + """ + RABBITMQ_URI = os.getenv('RABBITMQ_URI') + diff --git a/app/util/__init__.py b/app/util/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/util/common.py b/app/util/common.py new file mode 100644 index 0000000..f24e78f --- /dev/null +++ b/app/util/common.py @@ -0,0 +1,15 @@ +import os +from itertools import groupby +from operator import itemgetter + + +def split_group(dict_list, key): + dict_list.sort(key=itemgetter(key)) + tmps = groupby(dict_list, itemgetter(key)) + result = [] + for key, group in tmps: + result.append({key: list(group)}) + return result + + +basedir = os.getcwd() diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..bb32ad8 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,23 @@ +version: "3" + +services: + pzx-web-api: + build: + context: . + dockerfile: ./Dockerfile + container_name: pzx-web-api + hostname: pzx-web-api + ports: + - "5010:5000" + volumes: + - .:/app + environment: + TZ: "Asia/Shanghai" + LOG_LEVEL: "DEBUG" + env_file: + - .apiflaskenv + - .apiflask.env + working_dir: /app + tty: true + restart: always + command: ["sh", "docker-deploy.sh"] diff --git a/docker-deploy.sh b/docker-deploy.sh new file mode 100644 index 0000000..c7f7f97 --- /dev/null +++ b/docker-deploy.sh @@ -0,0 +1 @@ +gunicorn -c gunicorn.conf.py starter:app \ No newline at end of file diff --git a/gunicorn.conf.py b/gunicorn.conf.py new file mode 100644 index 0000000..ff2dc1d --- /dev/null +++ b/gunicorn.conf.py @@ -0,0 +1,22 @@ +import multiprocessing + +from gevent import monkey + +monkey.patch_all() + + +bind = "0.0.0.0:5000" +worker_class = 'gevent' +# 设置最大并发量 +daemon = False +debug = False +worker_connections = 2000 +workers = multiprocessing.cpu_count() * 2 + 1 +# 指定每个工作者的线程数 +threads = 10 + +# pidfile = "/var/run/gunicorn.pid" +# accesslog = '/var/log/gunicorn_access.log' +# errorlog = '/var/log/gunicorn_error.log' +# 设置日志记录水平 +loglevel = 'warning' \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..cd6923f --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +git+https://gitea.bearcatlog.com/BryantStudio/chassis.git@main#egg=chassis[apiflask,nameko] +psutil \ No newline at end of file diff --git a/starter.py b/starter.py new file mode 100644 index 0000000..a3ac72e --- /dev/null +++ b/starter.py @@ -0,0 +1,14 @@ +from app import create_app + +app = create_app() + + +if __name__ == "__main__": + app.logger.warning( + """ + ---------------------------- + | app.run() => apiflask run | + ---------------------------- + """ + ) + app.run()