重写&重构项目, 优化项目结构

This commit is contained in:
MarkusJoe
2022-03-26 08:02:25 +08:00
parent 8b07e25b88
commit bf35508e95
33 files changed
+344 -966

No files matched your search

+1 -1
View File
@@ -1 +1 @@
web: gunicorn app:app web: gunicorn manage:app
+4 -6
View File
@@ -34,12 +34,11 @@
### 部署到Heroku ### 部署到Heroku
1. `fork` 本项目到你的仓库 1. `fork` 本项目到你的仓库
2. 此步骤为 `非必要` 你可以在 `fork` 本仓库到你的仓库时, 修改 `./bin/conf/config.yml` 内的配置文件来修改配置 (前提时你的仓库为私人仓库, 否则可能泄露一些私人信息) 2. 在[Heroku](https://www.heroku.com/) 注册账号
3. 在[Heroku](https://www.heroku.com/) 注册账号 3. 在[Dashboard](https://dashboard.heroku.com/apps) 新建App
4. 在[Dashboard](https://dashboard.heroku.com/apps) 新建App 4. 流程: 进入网址 -> 点击右上角`New` -> 点击 `Create new app` -> 输入App名称 -> `Create app` -> 选择`Github` (登陆完成后) -> 点击`Search` ->
5. 流程: 进入网址 -> 点击右上角`New` -> 点击 `Create new app` -> 输入App名称 -> `Create app` -> 选择`Github` (登陆完成后) -> 点击`Search` ->
选择你fork的项目并点击`Connect` -> 滑到末尾点击`Deploy branch`(如果你想在仓库更新时自动部署的话可以把`Enable Automatic Deploy`勾选) -> 等待完成 选择你fork的项目并点击`Connect` -> 滑到末尾点击`Deploy branch`(如果你想在仓库更新时自动部署的话可以把`Enable Automatic Deploy`勾选) -> 等待完成
6. App的地址就是 `App名称` + `.herokuapp.com` 5. App的地址就是 `App名称` + `.herokuapp.com`
### 部署到本地服务器 ### 部署到本地服务器
@@ -56,7 +55,6 @@ $ python3 app.py
- 最大可以计数`10`位数, 超过则重置 - 最大可以计数`10`位数, 超过则重置
- 可以自定义显示位数默认`7`位数最大`10` - 可以自定义显示位数默认`7`位数最大`10`
- 可以自己选择更多的主题只需要加上请求参数: `theme` 再加上想要的主题即可 - 可以自己选择更多的主题只需要加上请求参数: `theme` 再加上想要的主题即可
-`theme`请求参数中写入`ls`可以获取所有可选的主题 (来自于`./bin/assets/theme.db`)
# 一些信息 # 一些信息
-90
View File
@@ -1,90 +0,0 @@
#!/usr/bin/env python3
# -- coding:utf-8 --
# @Author: markushammered@gmail.com
# @Development Tool: PyCharm
# @Create Time: 2022/2/3
# @File Name: app.py
from gevent import pywsgi
from flask import Flask
from flask import Response
from flask import request
from flask import make_response
from flask import render_template
from bin.utils.logger import logger
from bin.utils.features import Features
from bin.utils.settings import Settings
from bin.utils.error import ErrorProcess
from bin.utils.view import view_template
conf = Settings()
if conf.type.lower() == 'mysql':
from bin.db.db import MySQL as db
else:
from bin.db.db import SQLite as db
app = Flask(__name__, static_url_path='')
app.config['JSON_SORT_KEYS'] = False # 设置JSON消息不根据字母顺序重新排序
app.config['JSON_AS_ASCII'] = False # 设置JSON消息显示中文
@app.before_request
def requests_log() -> None:
"""
向日志文件内请求记录
:return:
"""
if request.path != '/favicon.ico': # 不记录favicon.ico的请求记录
logger.info(f'{request.remote_addr} {request.method} {request.base_url}')
@app.route('/count/<string:name>', methods=['GET', 'POST']) # 允许 GET 和 POST 方法
def main(name: str) -> Response or str:
"""
API 页面函数
:return:
"""
args = request.args
theme = args.get('theme', type=str)
length = args.get('length', type=int)
if not bool(theme): # 判断主题是否存在查询参数内如果不存在则使用配置文件内的默认主题
theme = conf.default_style
elif theme == 'ls':
return Features(db).theme_list()
if not bool(length):
length = 7
if not db().exists_name(name):
db().insert(name)
count = db().fetch(name)
if not db().exists_table(theme):
return ErrorProcess(db).theme_error(theme)
if 7 <= int(length) <= 10: # 限定自定义长度阈值
view_number = '0' * (int(length) - len(str(count[1]))) + str(count[1])
response = make_response(view_template(theme, int(length), name, view_number, db)) # 设置响应体 和 响应头
response.headers['Content-Type'] = 'image/svg+xml; charset=utf-8'
response.headers['cache-control'] = 'max-age=0, no-cache, no-store, must-revalidate'
return response
else:
return ErrorProcess(db).length_error(length)
@app.route('/', methods=['GET', 'POST'])
def home() -> str:
"""
主页面
:return:
"""
return render_template('index.html', remote_address=request.remote_addr)
if __name__ == '__main__':
logger.info(f'服务器已在 http://127.0.0.1:{conf.port} 运行')
try:
server = pywsgi.WSGIServer((conf.host, conf.port), app, log=None) # log=None 关闭日志输出, 使用自写的日志器记录
server.serve_forever()
except OSError:
logger.critical(f'{conf.port} 端口被占用 已退出')
except KeyboardInterrupt:
logger.info('程序已退出')
+26
View File
@@ -0,0 +1,26 @@
#!/usr/bin/env python3
# -- coding:utf-8 --
# @Author: markushammered@gmail.com
# @Development Tool: PyCharm
# @Create Time: 2022/3/25
# @File Name: __init__.py
from flask import Flask
from .main import main
from .db.db import SQLite
class Config:
"""基类配置"""
JSON_SORT_KEYS = False
JSON_AS_ASCII = False
def create_app():
"""创建主app"""
app = Flask(__name__)
app.register_blueprint(main)
app.config.from_object(Config)
return app
+1 -7
View File
@@ -2,11 +2,5 @@
# -- coding:utf-8 -- # -- coding:utf-8 --
# @Author: markushammered@gmail.com # @Author: markushammered@gmail.com
# @Development Tool: PyCharm # @Development Tool: PyCharm
# @Create Time: 2022/2/3 # @Create Time: 2022/3/25
# @File Name: __init__.py.py # @File Name: __init__.py.py
import sys
sys.stdout.write('禁止调用')
sys.exit(-1)
+138
View File
@@ -0,0 +1,138 @@
#!/usr/bin/env python3
# -- coding:utf-8 --
# @Author: markushammered@gmail.com
# @Development Tool: PyCharm
# @Create Time: 2022/3/25
# @File Name: db.py
import sqlite3
from typing import List
class SQLite:
"""操作SQLite数据库"""
def __init__(self) -> None:
"""
初始化SQLite对象
完成后会自动提交, 自动关闭
"""
self.__path = './app/db/data.db'
self.__conn = sqlite3.connect(self.__path)
self.__cursor = self.__conn.cursor()
def __del__(self) -> None:
"""
自动提交
自动关闭连接
:return:
"""
self.__conn.commit()
self.__cursor.close()
self.__conn.close()
@property
def show_tables(self) -> list:
"""
列出所有在数据库内的表
:return:
"""
self.__cursor.execute('select * from sqlite_master where type="table"')
tables = self.__cursor.fetchall()
lst = []
for table in tables:
lst.append(table[1])
del tables
return lst
def exists_name(self, name: str) -> bool:
"""
判断当前名称是否在数据库内
调用self.fetch()方法
:param name:
:return:
"""
status = self.fetch(name, True)
if status == ():
return False
else:
return True
def exists_table(self, table: str) -> bool:
"""
判断表是否在数据库内
调用self.fetching_table()方法
:param table:
:return:
"""
tables = self.show_tables
if table in tables:
return True
else:
return False
def insert(self, name: str, times: int = 0) -> bool:
"""
插入数据
:param name:
:param times:
:return:
"""
self.__cursor.execute(
'insert into reqcount (name, times) values("%(name)s", %(times)s)' % {'name': name, 'times': times})
return True
def delete(self, name: str) -> bool:
"""
删除数据
暂时不会用到此接口
:param name:
:return:
"""
self.__cursor.execute('delete from reqcount where name="%(name)s"' % {'name': name})
return True
def fetch(self, name: str, is_check: bool = False) -> tuple:
"""
抓取数据
:param name:
:param is_check:
:return:
"""
self.__cursor.execute('select * from reqcount where name="%(name)s"' % {'name': name})
data = self.__cursor.fetchall()[0]
if not is_check:
self.update(name, data[-1])
return data
def update(self, name: str, times: int) -> bool:
"""
更新数据
:param name:
:param times:
:return:
"""
self.__cursor.execute(
'update reqcount set times=%(times)s where name="%(name)s"' % {'times': times + 1, 'name': name})
return True
def fetching_table(self, table: str) -> List[dict]:
"""
抓取主题表的数据
:param table:
:return:
"""
status = self.exists_table(table)
if status:
tables = self.__cursor.execute('select * from %(table)s' % {'table': table})
lst = []
for data in tables:
lst.append({'index': data[0],
'base64': data[1],
'width': data[2],
'height': data[3]})
del tables
return lst
else:
return []
+13
View File
@@ -0,0 +1,13 @@
#!/usr/bin/env python3
# -- coding:utf-8 --
# @Author: markushammered@gmail.com
# @Development Tool: PyCharm
# @Create Time: 2022/3/25
# @File Name: __init__.py.py
from flask import Blueprint
main = Blueprint('main', __name__)
from . import views, errors
+29
View File
@@ -0,0 +1,29 @@
#!/usr/bin/env python3
# -- coding:utf-8 --
# @Author: markushammered@gmail.com
# @Development Tool: PyCharm
# @Create Time: 2022/3/25
# @File Name: errors.py
from . import main
@main.app_errorhandler(404)
def page_not_found(e):
"""
404页面未找到
:param e:
:return:
"""
return {'code': 404, 'msg': '页面未找到', 'data': []}, 404
@main.app_errorhandler(500)
def internal_server_error(e):
"""
500服务器内部错误
:param e:
:return:
"""
return {'code': 500, 'msg': '服务器内部错误', 'data': []}, 500
+62
View File
@@ -0,0 +1,62 @@
#!/usr/bin/env python3
# -- coding:utf-8 --
# @Author: markushammered@gmail.com
# @Development Tool: PyCharm
# @Create Time: 2022/3/25
# @File Name: views.py
from flask import abort
from flask import jsonify
from flask import request
from flask import Response
from flask import make_response
from flask import render_template
from . import main
from ..db.db import SQLite as db
from ..utils.view import view
@main.route('/', methods=['GET', 'POST'])
def index():
"""
主页
:return:
"""
return render_template('index.html', remote_address=request.remote_addr)
@main.route('/api/v1/<string:name>', methods=['GET', 'POST'])
@main.route('/count/<string:name>', methods=['GET', 'POST'])
def api_v1(name: str):
length = request.args.get('length', type=int)
theme = request.args.get('theme', type=str)
if not bool(length):
length = 7
if not bool(theme):
theme = 'lewd'
if not db().exists_name(name):
db().insert(name)
if not db().exists_table(theme):
abort(500)
if 7 <= length <= 10:
data = db().fetch(name)
number = '0' * (length - len(str(data[-1]))) + str(data[-1])
# 将设置的长度减去数据库内已有的数据库字符串长度剩下的结果为[0]的个数
# 再将这个字符串后拼接上数据库内已有次数的字符串, 就可以得到最终的结果
response = make_response(view(theme, int(length), name, number))
response.headers['Content-Type'] = 'image/svg+xml; charset=utf-8'
response.headers['cache-control'] = 'max-age=0, no-cache, no-store, must-revalidate'
return response
return abort(500)
@main.route('/exists-table', methods=['GET', 'POST'])
@main.route('/exists', methods=['GET', 'POST'])
def show_tables() -> Response:
"""
返回已有表
:return:
"""
tables = db().show_tables
return jsonify({'code': 200, 'msg': '已有表', 'data': [tables]})
File renamed without changes.
@@ -24,7 +24,7 @@
<br> <br>
<i>服务端使用Flask开发没有使用异步编程</i> <i>服务端使用Flask开发没有使用异步编程</i>
<br> <br>
<i><a href="http://127.0.0.1:5000/countRequestCounter">点击查看本地部署示例</a></i> <i><a href="http://127.0.0.1:5000/api/v1/main">点击查看本地部署示例</a></i>
<br> <br>
<i><a href="https://requestcounter.herokuapp.com/count/RequestCounter">点击查看已部署好的调用示例</a></i> <i><a href="https://requestcounter.herokuapp.com/count/RequestCounter">点击查看已部署好的调用示例</a></i>
<br> <br>
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<svg width="{{ general_width }}" height="{{ general_height }}" version="1.1" xmlns="http://www.w3.org/2000/svg" <svg width="{{ general_width }}" height="{{ general_height }}" version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"> xmlns:xlink="http://www.w3.org/1999/xlink">
<title>{{ title }}</title> <title>{{ title }} | {{ address }}</title>
<g> <g>
{% for value in context %} {% for value in context %}
<image x="{{ value.position }}" y="0" width="{{ value.width }}" height="{{ value.height }}" <image x="{{ value.position }}" y="0" width="{{ value.width }}" height="{{ value.height }}"
+6
View File
@@ -0,0 +1,6 @@
#!/usr/bin/env python3
# -- coding:utf-8 --
# @Author: markushammered@gmail.com
# @Development Tool: PyCharm
# @Create Time: 2022/3/26
# @File Name: __init__.py.py
+23
View File
@@ -0,0 +1,23 @@
#!/usr/bin/env python3
# -- coding:utf-8 --
# @Author: markushammered@gmail.com
# @Development Tool: PyCharm
# @Create Time: 2022/3/25
# @File Name: __init__.py.py
import os
import requests
def download():
res = requests.get('http://resource-base.herokuapp.com/download/data.db')
with open('./app/db/data.db', 'wb') as fp:
fp.write(res.content)
if __name__ == '__main__':
if not os.path.exists('./app/db/data.db'):
print('数据库文件未找到, 正在下载中')
download()
print('下载完成')
+10 -5
View File
@@ -2,24 +2,29 @@
# -- coding:utf-8 -- # -- coding:utf-8 --
# @Author: markushammered@gmail.com # @Author: markushammered@gmail.com
# @Development Tool: PyCharm # @Development Tool: PyCharm
# @Create Time: 2022/2/18 # @Create Time: 2022/3/25
# @File Name: view.py # @File Name: view.py
from ..db.db import SQLite as db
from flask import render_template from flask import render_template
from typing import Tuple
def view_template(style: str, length: int, name: str, count: str, DB) -> str or tuple[bool, str]: def view(theme: str,
length: int,
name: str,
count: str
) -> str or Tuple[bool, str]:
""" """
渲染模板 渲染模板
:param style: :param theme:
:param length: :param length:
:param name: :param name:
:param count: :param count:
:param DB:
:return: :return:
""" """
datas = DB().fetching_table(style) datas = db().fetching_table(theme)
context = [] context = []
for i in count: for i in count:
if i == '0': if i == '0':
-45
View File
@@ -1,45 +0,0 @@
#!/usr/bin/env python3
# -- coding:utf-8 --
# @Author: markushammered@gmail.com
# @Development Tool: PyCharm
# @Create Time: 2022/2/17
# @File Name: __init__.py
import os
import time
import requests
from bin.utils.logger import logger
def cost(func):
def wrapper(*args, **kwargs):
logger.info('开始下载')
s = time.time()
execute = func(*args, **kwargs)
e = time.time()
logger.info(f'下载结束, 用时: {round(e - s, 2)} s')
return execute
return wrapper
@cost
def download(url: str) -> None:
"""
单线程下载资源
:param url:
:return:
"""
content = requests.get(url, timeout=10, stream=True).content
with open('./bin/db/data.db', 'wb') as fp:
fp.write(content)
if __name__ != '__main__':
if not os.path.exists('./bin/db/data.db'):
logger.warning('数据库文件不存在, 即将开始下载')
try:
download('https://resource-base.herokuapp.com/download/data.db')
except requests.Timeout:
logger.critical('连接超时')
-34
View File
@@ -1,34 +0,0 @@
servers:
# 服务器建立的地址
host: "0.0.0.0"
# 服务器监听的端口
port: 5000
view:
# 默认显示主题
style: "lewd"
database:
# 数据库类型
# 可选 'SQLite' 'MySQL'
type: "SQLite"
SQLite:
path: "./bin/db/data.db"
MySQL:
# 数据库地址
host: "127.0.0.1"
# 数据库端口
port: 3306
# 数据库用户
user: ""
# 数据库密码
password: ""
# 数据库名称
# 如果该数据库不存在则自动创建
db: ""
-19
View File
@@ -1,19 +0,0 @@
#!/usr/bin/env python3
# -- coding:utf-8 --
# @Author: markushammered@gmail.com
# @Development Tool: PyCharm
# @Create Time: 2022/2/4
# @File Name: __init__.py.py
import os
from bin.utils.logger import logger
from bin.utils.settings import Settings
if __name__ != '__main__':
if Settings().type.lower() == 'mysql' and not os.path.exists('./static/origin.sql'):
logger.warning('当前使用的数据库为MySQL请前往 https://filebase.vercel.app/db.sql 下载sql文件')
logger.warning('并使用 source 命令来导入MySQL数据库')
logger.warning('此消息只显示一次, 下次启动不显示')
open('./static/origin.sql', 'w').close()
__all__ = ['db']
-290
View File
@@ -1,290 +0,0 @@
#!/usr/bin/env python3
# -- coding:utf-8 --
# @Author: markushammered@gmail.com
# @Development Tool: PyCharm
# @Create Time: 2022/2/24
# @File Name: db.py
import sqlite3
import pymysql
from bin.utils.settings import Settings
conf = Settings()
class SQLite:
"""操作SQLite数据库"""
def __init__(self, **kwargs) -> None:
"""
初始化SQLite对象
完成后会自动提交, 自动关闭
:param path: 数据库路径
"""
self.__path = './bin/db/data.db'
self.__conn = sqlite3.connect(self.__path)
self.__cursor = self.__conn.cursor()
def __del__(self) -> None:
"""
自动提交
自动关闭连接
:return:
"""
self.__conn.commit()
self.__cursor.close()
self.__conn.close()
@property
def show_tables(self) -> list:
"""
列出所有在数据库内的表
:return:
"""
self.__cursor.execute('select * from sqlite_master where type="table"')
tables = self.__cursor.fetchall()
lst = []
for table in tables:
lst.append(table[1])
del tables
return lst
def exists_name(self, name: str) -> bool:
"""
判断当前名称是否在数据库内
调用self.fetch()方法
:param name:
:return:
"""
status = self.fetch(name, True)
if status == ():
return False
else:
return True
def exists_table(self, table: str) -> bool:
"""
判断表是否在数据库内
调用self.fetching_table()方法
:param table:
:return:
"""
tables = self.show_tables
if table in tables:
return True
else:
return False
def insert(self, name: str, times: int = 0) -> bool:
"""
插入数据
:param name:
:param times:
:return:
"""
self.__cursor.execute(
'insert into reqcount (name, times) values("%(name)s", %(times)s)' % {'name': name, 'times': times})
return True
def delete(self, name: str) -> bool:
"""
删除数据
暂时不会用到此接口
:param name:
:return:
"""
self.__cursor.execute('delete from reqcount where name="%(name)s"' % {'name': name})
return True
def fetch(self, name: str, is_check: bool = False) -> tuple:
"""
抓取数据
:param name:
:param is_check:
:return:
"""
self.__cursor.execute('select * from reqcount where name="%(name)s"' % {'name': name})
data = self.__cursor.fetchall()
if not is_check:
self.update(name, data[0][1])
if len(data):
return data[0]
else:
return tuple(data)
def update(self, name: str, times: int) -> bool:
"""
更新数据
:param name:
:param times:
:return:
"""
self.__cursor.execute(
'update reqcount set times=%(times)s where name="%(name)s"' % {'times': times + 1, 'name': name})
return True
def fetching_table(self, table: str) -> list[dict]:
"""
抓取主题表的数据
:param table:
:return:
"""
status = self.exists_table(table)
if status:
tables = self.__cursor.execute('select * from %(table)s' % {'table': table})
lst = []
for data in tables:
lst.append({'index': data[0],
'base64': data[1],
'width': data[2],
'height': data[3]})
del tables
return lst
else:
return []
class MySQL:
"""操作MySQL数据库"""
def __init__(self, **kwargs) -> None:
"""
初始化MySQL对象并创建一个连接
创建的连接会在执行完毕后自动提交以及自动关闭
:param host: 数据库地址
:param user: 数据库用户名
:param pwd: 数据库密码
:param database: 数据库名
"""
self.__host = conf.m_host
self.__user = conf.m_user
self.__password = conf.m_pwd
self.__database = conf.m_db
self.__conn = pymysql.connect(user=self.__user,
password=self.__password,
host=self.__host,
database=self.__database) # 创建连接
self.__cursor = self.__conn.cursor()
def __del__(self):
"""
自动提交
自动关闭连接
:return:
"""
self.__conn.commit()
self.__cursor.close()
self.__conn.close()
@property
def show_tables(self) -> list:
"""
查询已有的表
:return:
"""
self.__cursor.execute('show tables;') # 列出所有的表名
tuple_tables = self.__cursor.fetchall()
# 将元组类型转换为列表
tables = []
for origin in tuple_tables:
tables.append(origin[0])
del tuple_tables
return tables
def exists_name(self, name: str):
"""
判断是否存在于数据库内
:param name:
:return:
"""
status = self.fetch(name, True)
if status == ():
return False
else:
return True
def exists_table(self, table: str) -> bool:
"""
判断表是否在数据库内
:param table:
:return:
"""
tables = self.show_tables
if table in tables:
return True
else:
return False
def insert(self, name: str, times: int = 0) -> bool:
"""
插入数据
:param name:
:param times:
:return:
"""
try:
self.__cursor.execute(
'insert into reqcount(name, times) values("%(name)s", %(times)s);' % {'name': name, 'times': times})
return True
except pymysql.err.IntegrityError:
return False
def delete(self, name: str) -> bool:
"""
删除数据
暂时不会用到此接口
:param name:
:return:
"""
self.__cursor.execute('delete from reqcount where name="%(name)s";' % {'name': name})
return True
def fetch(self, name: str, is_check: bool = False) -> tuple:
"""
抓取数据
:param name:
:param is_check:
:return:
"""
self.__cursor.execute('select * from reqcount where name="%(name)s";' % {'name': name})
data = self.__cursor.fetchall()
if not is_check: # 条件适用于使用self.exists_name检查时不将数据库的计数加一
self.update(name, data[0][1])
if data == ():
return ()
else:
return data[0]
def update(self, name: str, times: int) -> bool:
"""
更改数据
:param name:
:param times:
:return:
"""
self.__cursor.execute(
'update reqcount set times=%(times)s where name="%(name)s";' % {'times': times + 1, 'name': name})
return True
def fetching_table(self, table: str) -> list:
"""
抓取主题表内的数据
:param table:
:return:
"""
self.__cursor.execute('select * from %(table)s' % {'table': table})
datas = self.__cursor.fetchall()
lst = []
for i in datas:
lst.append({'index': i[0],
'base64': i[1],
'width': i[2],
'height': i[3]}
) # 向空列表内添加抓取到的数据 -> 将元组数据转换为列表
del datas
return lst
__all__ = ['SQLite', 'MySQL']
View File
Whitespace-only changes.
-101
View File
@@ -1,101 +0,0 @@
#!/usr/bin/env python3
# -- coding:utf-8 --
# @Author: markushammered@gmail.com
# @Development Tool: PyCharm
# @Create Time: 2022/3/4
# @File Name: down.py
import sys
import time
import requests
import threading
class Downloader(threading.Thread):
"""继承threading实现多线程"""
def __init__(self, start_: int, end_: int, t_id: int, url: str, name: str):
"""
初始化类
:param start_: seek开始点
:param end_: seek结束点
:param t_id: 线程id
:param url: 资源地址
:param name: 文件名
"""
super(Downloader, self).__init__()
self.start_ = start_
self.end_ = end_
self.t_id = t_id
self.url = url
self.name = name
def download(self):
"""
开始下载
:return:
"""
print(f'{self.t_id} 开始下载')
res = requests.get(self.url, headers={'Range': f'Bytes={self.start_}-{self.end_}'}).content
with open(self.name, 'r+b') as fp:
fp.seek(self.start_)
fp.write(res)
print(f'{self.t_id} 结束下载')
def run(self):
"""
开始运行
:return:
"""
self.download()
def cost(func):
def wrapper(*args, **kwargs):
print('文件开始开始下载')
s = time.time()
execute = func(*args, **kwargs)
e = time.time()
print(f'下载结束, 用时: {round(e - s, 2)} s')
return execute
return wrapper
@cost
def main(url: str, threads: int = 4):
"""
处理各种数据
:param url: 资源地址
:param threads: 线程数
:return:
"""
try:
res = requests.get(url)
except requests.exceptions.ConnectionError:
print('资源连接错误')
sys.exit(-1)
if res.status_code == 302:
url = res.headers['Location']
print(f'资源已重定向到: {url}')
file_name = url.split('/')[-1]
open(file_name, 'w').close()
file_size = int(res.headers['Content-Length'])
offset = file_size // threads
start = 0
for i in range(threads):
if i == 0:
end = offset
elif i == threads - 1:
end = file_size
else:
end = i * offset
t = Downloader(start, end, i, url, file_name)
t.start()
t.join()
start = end
if __name__ == '__main__':
main('https://i0.hdslb.com/bfs/archive/ef0945f7d54a505953272022063a6335a9d3becf.jpg')
-55
View File
@@ -1,55 +0,0 @@
#!/usr/bin/env python3
# -- coding:utf-8 --
# @Author: markushammered@gmail.com
# @Development Tool: PyCharm
# @Create Time: 2022/3/2
# @File Name: downloader.py
import requests
import threading
class Threaded(threading.Thread):
def __init__(self, s, e, fp, id_, url):
super().__init__()
self.start_ = s
self.end_ = e
self.fp = fp
self.id = id_
self.url = url
def download(self):
print(f'线程: {self.id} 开始下载')
res = requests.get(self.url, headers={'Range': f'Bytes={self.start_}-{self.end_}'}).content
self.fp.seek(self.start_)
self.fp.write(res)
print(f'线程: {self.id} 结束下载')
def run(self):
self.download()
def main(url: str, path: str = '.', workers: int = 8):
print(f'本次下载使用线程数: {workers}')
file_name = url.split('/')[-1]
file_size = int(requests.get(url).headers['Content-Length'])
if requests.get(url).status_code == '302':
url = requests.get(url).headers['Location']
offset = int(file_size / workers)
start = 0
open(path + file_name, 'wb').close()
fp = open(path + file_name, 'r+b')
for i in range(workers):
if i == workers - 1:
end = file_size
elif i != 0:
end = i * offset
else:
end = offset
Threaded(start, end, fp, i, url).start()
start = end + 1
if __name__ == '__main__':
main('https://i0.hdslb.com/bfs/archive/cc013c0a726082e07772ec77d5c0444ac7d40a6f.jpg')
-12
View File
@@ -1,12 +0,0 @@
#!/usr/bin/env python3
# -- coding:utf-8 --
# @Author: markushammered@gmail.com
# @Development Tool: PyCharm
# @Create Time: 2022/3/13
# @File Name: length_down.py
import requests
print(requests.get('http://127.0.0.1:8000/data.db').headers)
-18
View File
@@ -1,18 +0,0 @@
#!/usr/bin/env python3
# -- coding:utf-8 --
# @Author: markushammered@gmail.com
# @Development Tool: PyCharm
# @Create Time: 2022/2/7
# @File Name: stress_test.py
import requests
import threading
def thread_():
print(requests.get('http://127.0.0.1:5000/get?name=MarkusJoe&theme=lewd').elapsed.microseconds)
for i in range(100):
threading.Thread(target=thread_).start()
-4
View File
@@ -1,4 +0,0 @@
# ²âÊÔhttpÇëÇó
GET http://localhost:5000/get?name=HTTPtest
Accept: application/json
-9
View File
@@ -1,9 +0,0 @@
#!/usr/bin/env python3
# -- coding:utf-8 --
# @Author: markushammered@gmail.com
# @Development Tool: PyCharm
# @Create Time: 2022/2/12
# @File Name: __init__.py
__all__ = ['error', 'logger', 'features', 'settings', 'view']
-62
View File
@@ -1,62 +0,0 @@
#!/usr/bin/env python3
# -- coding:utf-8 --
# @Author: markushammered@gmail.com
# @Development Tool: PyCharm
# @Create Time: 2022/2/9
# @File Name: error.py
from typing import Optional
from flask import jsonify
from flask import Response
from bin.utils.logger import logger
class ErrorProcess:
"""处理错误的页面"""
def __init__(self, db) -> None:
"""
初始化
:param db:
"""
self.db = db # 数据库对象
self.response = {'code': Optional[int],
'msg': Optional[str],
'data': Optional[list]}
def theme_error(self, theme: str) -> Response:
"""
错误的主题
:param theme:
:return:
"""
logger.debug('错误的主题')
table_list = self.db().show_tables
self.response['code'] = -2
self.response['msg'] = f'错误的主题: {theme}. 以下是已保存的主题'
self.response['data'] = table_list
return jsonify(self.response)
def length_error(self, length: int or str) -> Response:
"""
数值太长显示此页面
:param length:
:return:
"""
self.response['code'] = -2
self.response['msg'] = f'错误的长度: {length}'
self.response['data'] = []
return jsonify(self.response)
def count_error(self, name: str) -> Response:
"""
数据过长重置数据
:param name:
:return:
"""
self.db().update(name, 0)
self.response['code'] = 200
self.response['msg'] = '当前长度已超过最大可计数范围. 已将此名称的计数器重置为零'
self.response['data'] = []
return jsonify(self.response)
-36
View File
@@ -1,36 +0,0 @@
#!/usr/bin/env python3
# -- coding:utf-8 --
# @Author: markushammered@gmail.com
# @Development Tool: PyCharm
# @Create Time: 2022/2/28
# @File Name: features.py
from typing import Optional
from flask import jsonify
from flask import Response
class Features:
"""特殊操作"""
def __init__(self, db) -> None:
"""
初始化
:param db:
"""
self.db = db
self.response = {'code': Optional[int],
'msg': Optional[str],
'data': Optional[list]}
def theme_list(self) -> Response:
"""
读取已有数据库并返回一个列表
:return:
"""
table_list = self.db().show_tables
self.response['code'] = 200
self.response['msg'] = '当前已保存到数据库的主题如下'
self.response['data'] = table_list
return jsonify(self.response)
-55
View File
@@ -1,55 +0,0 @@
#!/usr/bin/env python3
# -- coding:utf-8 --
# @Author: markushammered@gmail.com
# @Development Tool: PyCharm
# @Create Time: 2021/12/15
# @File Name: logger.py
import time
import logging.handlers
from logging import Logger
from colorlog import ColoredFormatter
class MakeLogger:
def __init__(self) -> None:
self.date_format = '%H:%M:%S'
self.format_console = '%(log_color)s[%(asctime)s] |%(filename)s[%(lineno)-3s] |%(levelname)-8s |%(message)s'
self.format_file = '[%(asctime)s] |%(filename)s[%(funcName)sline:%(lineno)d] |%(levelname)-8s |%(message)s'
def setup_logger(self) -> Logger:
"""
建立日志器
:return:
"""
formatter = ColoredFormatter(fmt=self.format_console,
datefmt=self.date_format,
reset=True,
log_colors={
'DEBUG': 'light_purple',
'INFO': 'light_cyan',
'WARNING': 'yellow',
'ERROR': 'red',
'CRITICAL': 'red,bold_red'}) # 定义终端输出颜色
formatter_file = logging.Formatter(fmt=self.format_file,
datefmt=self.date_format) # 文件输入不使用颜色
_logger = logging.getLogger('RequestCounter') # 设置日志器名称
_logger.setLevel(logging.INFO) # 设置等级
console_logger = logging.StreamHandler() # 输出到终端
console_logger.setFormatter(formatter) # 设置输出格式化
log_name = time.strftime('%Y-%m-%d %H') # 一小时内使用的日志文件都是同一个
file_logger = logging.handlers.RotatingFileHandler(filename=f'./bin/log/{log_name}.log',
maxBytes=102400,
backupCount=5,
encoding='utf-8') # 每个日志文件最大102400字节(100Kb)
file_logger.setFormatter(formatter_file)
_logger.addHandler(console_logger)
_logger.addHandler(file_logger)
return _logger
if __name__ != '__main__':
logger = MakeLogger().setup_logger()
-100
View File
@@ -1,100 +0,0 @@
#!/usr/bin/env python3
# -- coding:utf-8 --
# @Author: markushammered@gmail.com
# @Development Tool: PyCharm
# @Create Time: 2022/2/23
# @File Name: settings.py
import yaml
from typing import Dict
class Settings:
def __init__(self):
self.__setting_file = './bin/conf/config.yml'
with open(self.__setting_file, encoding='utf-8') as fp:
self.data = yaml.load(fp.read(), Loader=yaml.Loader)
self.__servers = self.data['servers']
self.__database = self.data['database']
self.__view = self.data['view']
def all_data(self) -> Dict:
"""
获取原始配置文件
:return:
"""
return self.data
@property
def default_style(self) -> str:
"""
默认显示主题
:return:
"""
return self.__view['style']
@property
def host(self) -> str:
"""
应用地址
:return:
"""
return self.__servers['host']
@property
def port(self) -> str:
"""
应用端口
:return:
"""
return self.__servers['port']
@property
def type(self) -> str:
"""
数据库类型
:return:
"""
return self.__database['type']
@property
def m_host(self) -> str:
"""
mysql数据库的地址
:return:
"""
return self.__database['MySQL']['host']
@property
def m_port(self) -> int:
"""
mysql数据库的端口
默认3306
:return:
"""
return self.__database['MySQL']['port']
@property
def m_user(self) -> str:
"""
mysql数据库的用户名
:return:
"""
return self.__database['MySQL']['user']
@property
def m_pwd(self) -> str:
"""
mysql数据库的密码
:return:
"""
return self.__database['MySQL']['password']
@property
def m_db(self) -> str:
"""
保存数据库数据库名
:return:
"""
return self.__database['MySQL']['db']
+3 -3
View File
@@ -22,14 +22,14 @@
# 基本信息 # 基本信息
- Python版本: `3.10.x` - Python版本: `3.10.x`
- 请求方法: `GET` `POST` - 请求方法: `GET` `POST`
- 请求地址: `/count/<string:name>` - 请求地址: `/count/<string:name>` or `/api/v1/<string:name>`
- 你需要在 `/count/` 后加入你需要使用的名称来进行 - 你需要在 请求地址末尾加入你需要使用的名称来进行计
- 可选参数: `theme` `length` - 可选参数: `theme` `length`
## 获取主题数据库文件 ## 获取主题数据库文件
* 此接口没有在本项目中, 该仓库为私人仓库暂不开源 * 此接口没有在本项目中, 该仓库为私人仓库暂不开源
* 访问 `https://themedatabase.vercel.app/assets` 获取 * 访问 `http://resource-base.herokuapp.com/` or `https://filebase.vercel.app/download/data.db` 获取数据库文件
* 由于速度较慢建议使用多线程进行下载 * 由于速度较慢建议使用多线程进行下载
* 项目中自动下载主题数据库的文件也是来自此处 * 项目中自动下载主题数据库的文件也是来自此处
+17
View File
@@ -0,0 +1,17 @@
#!/usr/bin/env python3
# -- coding:utf-8 --
# @Author: markushammered@gmail.com
# @Development Tool: PyCharm
# @Create Time: 2022/3/25
# @File Name: manage.py
from gevent import pywsgi
from app import create_app
app = create_app()
if __name__ == '__main__':
server = pywsgi.WSGIServer(('0.0.0.0', 5000), app, log=None)
server.serve_forever()
-3
View File
@@ -2,8 +2,5 @@ flask~=2.0.3
requests~=2.27.1 requests~=2.27.1
gevent~=21.12.0 gevent~=21.12.0
gunicorn~=20.1.0 gunicorn~=20.1.0
colorlog~=6.6.0
PyMySQL~=1.0.2
PyYAML~=6.0
Werkzeug~=2.0.3 Werkzeug~=2.0.3
itsdangerous~=2.1.0 itsdangerous~=2.1.0