From 1662d3f1d8f8d00b34e15852950f1f4ade934b95 Mon Sep 17 00:00:00 2001 From: zhangtao <9480807882@qq.com> Date: Sun, 16 Feb 2025 04:25:08 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../v1/controllers/system/auth_controller.py | 40 --- backend/app/core/tasks.py | 30 --- backend/app/utils/docker_util.py | 44 ---- backend/app/utils/time_format_util.py | 56 ----- backend/app/utils/time_util.py | 228 ++++++++++++++++++ 5 files changed, 228 insertions(+), 170 deletions(-) delete mode 100644 backend/app/core/tasks.py delete mode 100644 backend/app/utils/docker_util.py delete mode 100644 backend/app/utils/time_format_util.py create mode 100644 backend/app/utils/time_util.py diff --git a/backend/app/api/v1/controllers/system/auth_controller.py b/backend/app/api/v1/controllers/system/auth_controller.py index 5ee1f39c..275c8ce3 100644 --- a/backend/app/api/v1/controllers/system/auth_controller.py +++ b/backend/app/api/v1/controllers/system/auth_controller.py @@ -5,8 +5,6 @@ from fastapi import APIRouter, Depends, Request, Query, BackgroundTasks, WebSock from fastapi.responses import JSONResponse from sqlalchemy.ext.asyncio import AsyncSession - - from app.config.setting import settings from app.common.response import ErrorResponse, SuccessResponse, StreamResponse from app.api.v1.services.system.auth_service import ( @@ -26,7 +24,6 @@ from app.core.dependencies import ( from app.core.router_class import OperationLogRoute from app.core.security import CustomOAuth2PasswordRequestForm from app.core.logger import logger -from app.core.tasks import celery_app, background_task router = APIRouter(route_class=OperationLogRoute) @@ -79,40 +76,3 @@ async def logout( logger.info('退出成功') return SuccessResponse(msg='退出成功') return ErrorResponse(msg='退出失败') - -# ws://127.0.0.1:8000/api/v1/system/auth/ws -@router.websocket("/ws", name="websocket") -async def websocket_endpoint(websocket: WebSocket): - await websocket.accept() - while True: - data = await websocket.receive_text() - await websocket.send_text(f"Message text was: {data}") - - -@router.post("/celery-task", summary="模拟celery进行后台任务") -async def process_data(data: str): - # 调用 Celery 任务 - result = background_task.delay(data) - return SuccessResponse(msg=f"任务已提交到 Celery: {result}") - - -@router.get("/celery-task/{task_id}", summary="获取celery任务状态") -async def get_task_status(task_id: str): - task = celery_app.AsyncResult(task_id) - return { - "task_id": task_id, - "status": task.status, - } - -# 模拟流响应 -@router.get("/bg-tsak-stream", summary="模拟fastapi自带后台任务-模拟流式响应") -async def stream_response(data: str,background_tasks: BackgroundTasks): - def log_task(message): - logger.info(message) - - background_tasks.add_task(log_task, "Streaming started") - return StreamResponse( - data = background_task(data=data), - headers={"X-Custom-Header": "Streaming-Response"}, - media_type="text/plain", - ) diff --git a/backend/app/core/tasks.py b/backend/app/core/tasks.py deleted file mode 100644 index d32a7fad..00000000 --- a/backend/app/core/tasks.py +++ /dev/null @@ -1,30 +0,0 @@ -# -*- coding: utf-8 -*- - -from typing import Dict, Any -from celery import Celery -from datetime import datetime - -from pydantic import RedisDsn - -from app.config.setting import settings - -REDIS_URL: RedisDsn = f"redis://:{settings.REDIS_PASSWORD}@{settings.REDIS_HOST}:{settings.REDIS_PORT}/{settings.REDIS_DB_NAME}" -# 创建 Celery 实例 -celery_app = Celery( - "worker", - broker=REDIS_URL, - backend=REDIS_URL, # 使用 Redis 存储任务结果 - include=["tasks"], # 包含任务模块 -) - -# 配置 Celery -celery_app.conf.update( - result_expires=3600, # 任务结果过期时间(秒) - timezone="Asia/Shanghai", # 时区 -) - -# 不可以使用协程:TypeError: object AsyncResult can't be used in 'await' expression -@celery_app.task -def background_task(data): - return f"task_id: {data}" - diff --git a/backend/app/utils/docker_util.py b/backend/app/utils/docker_util.py deleted file mode 100644 index 3d1923c8..00000000 --- a/backend/app/utils/docker_util.py +++ /dev/null @@ -1,44 +0,0 @@ -# -*- coding: utf-8 -*- - -import docker - - -class DockerUtil: - """ - Docker API封装 - """ - def __init__(self): - # 连接当前docker服务 - self.client = docker.from_env() - # 连接远程docker服务 - self.client = docker.Dockerclient("ssh://username@yourip", use_ssh_client=True) - - def get_docker_version(self): - """docker版本信息""" - return self.client.version() - - def get_container_list(self): - """docker容器列表""" - return self.client.containers.list() - - def get_image_list(self): - """docker镜像列表""" - return self.client.images.list() - - -# 创建DockerAPI对象 -docker_api = DockerUtil() - -# 调用封装的方法 -version = docker_api.get_docker_version() -containers = docker_api.get_container_list() -images = docker_api.get_image_list() - -# 打印结果 -print("Docker版本信息:", version) -print("Docker容器列表:") -for container in containers: - print(container.name) -print("Docker镜像列表:") -for image in images: - print(image.tags) diff --git a/backend/app/utils/time_format_util.py b/backend/app/utils/time_format_util.py deleted file mode 100644 index 4943db9e..00000000 --- a/backend/app/utils/time_format_util.py +++ /dev/null @@ -1,56 +0,0 @@ -# -*- coding: utf-8 -*- - -import datetime -from typing import Any, List, Dict - - -class TimeFormatUtil: - """ - 时间格式化工具类 - """ - - DEFAULT_DATETIME_FORMAT = '%Y-%m-%d %H:%M:%S' - - @classmethod - def object_format_datetime(cls, obj: Any) -> Any: - """ - 格式化对象中的datetime类型属性 - - :param obj: 输入对象 - :return: 格式化后的对象 - """ - for attr in dir(obj): - if not attr.startswith('_'): # 跳过私有属性 - value = getattr(obj, attr) - if isinstance(value, datetime.datetime): - setattr(obj, attr, value.strftime(cls.DEFAULT_DATETIME_FORMAT)) - return obj - - @classmethod - def list_format_datetime(cls, lst: List[Any]) -> List[Any]: - """ - 格式化对象列表中所有对象的datetime类型属性 - - :param lst: 对象列表 - :return: 格式化后的对象列表 - """ - return [cls.object_format_datetime(obj) for obj in lst] - - @classmethod - def format_datetime_dict_list(cls, dicts: List[Dict]) -> List[Dict]: - """ - 递归格式化字典列表中的datetime值 - - :param dicts: 字典列表 - :return: 格式化后的字典列表 - """ - def _format_value(value: Any) -> Any: - if isinstance(value, dict): - return {k: _format_value(v) for k, v in value.items()} - elif isinstance(value, list): - return [_format_value(item) for item in value] - elif isinstance(value, datetime.datetime): - return value.strftime(cls.DEFAULT_DATETIME_FORMAT) - return value - - return [_format_value(item) for item in dicts] diff --git a/backend/app/utils/time_util.py b/backend/app/utils/time_util.py new file mode 100644 index 00000000..91309734 --- /dev/null +++ b/backend/app/utils/time_util.py @@ -0,0 +1,228 @@ +# -*- coding: utf-8 -*- + +import re +from datetime import datetime +from typing import Any, List, Dict + +class TimeUtil: + """ + 时间格式化工具类 + """ + + DEFAULT_DATETIME_FORMAT = '%Y-%m-%d %H:%M:%S' + + @classmethod + def object_format_datetime(cls, obj: Any) -> Any: + """ + 格式化对象中的datetime类型属性 + + :param obj: 输入对象 + :return: 格式化后的对象 + """ + for attr in dir(obj): + if not attr.startswith('_'): # 跳过私有属性 + value = getattr(obj, attr) + if isinstance(value, datetime): + setattr(obj, attr, value.strftime(cls.DEFAULT_DATETIME_FORMAT)) + return obj + + @classmethod + def list_format_datetime(cls, lst: List[Any]) -> List[Any]: + """ + 格式化对象列表中所有对象的datetime类型属性 + + :param lst: 对象列表 + :return: 格式化后的对象列表 + """ + return [cls.object_format_datetime(obj) for obj in lst] + + @classmethod + def format_datetime_dict_list(cls, dicts: List[Dict]) -> List[Dict]: + """ + 递归格式化字典列表中的datetime值 + + :param dicts: 字典列表 + :return: 格式化后的字典列表 + """ + def _format_value(value: Any) -> Any: + if isinstance(value, dict): + return {k: _format_value(v) for k, v in value.items()} + elif isinstance(value, list): + return [_format_value(item) for item in value] + elif isinstance(value, datetime): + return value.strftime(cls.DEFAULT_DATETIME_FORMAT) + return value + + return [_format_value(item) for item in dicts] + + @classmethod + def __valid_range(cls, search_str: str, start_range: int, end_range: int): + match = re.match(r'^(\d+)-(\d+)$', search_str) + if match: + start, end = int(match.group(1)), int(match.group(2)) + return start_range <= start < end <= end_range + return False + + @classmethod + def __valid_sum( + cls, search_str: str, start_range_a: int, start_range_b: int, end_range_a: int, end_range_b: int, sum_range: int + ): + match = re.match(r'^(\d+)/(\d+)$', search_str) + if match: + start, end = int(match.group(1)), int(match.group(2)) + return ( + start_range_a <= start <= start_range_b + and end_range_a <= end <= end_range_b + and start + end <= sum_range + ) + return False + + @classmethod + def validate_second_or_minute(cls, second_or_minute: str): + """ + 校验秒或分钟值是否正确 + + :param second_or_minute: 秒或分钟值 + :return: 校验结果 + """ + if ( + second_or_minute == '*' + or ('-' in second_or_minute and cls.__valid_range(second_or_minute, 0, 59)) + or ('/' in second_or_minute and cls.__valid_sum(second_or_minute, 0, 58, 1, 59, 59)) + or re.match(r'^(?:[0-5]?\d|59)(?:,[0-5]?\d|59)*$', second_or_minute) + ): + return True + return False + + @classmethod + def validate_hour(cls, hour: str): + """ + 校验小时值是否正确 + + :param hour: 小时值 + :return: 校验结果 + """ + if ( + hour == '*' + or ('-' in hour and cls.__valid_range(hour, 0, 23)) + or ('/' in hour and cls.__valid_sum(hour, 0, 22, 1, 23, 23)) + or re.match(r'^(?:0|[1-9]|1\d|2[0-3])(?:,(?:0|[1-9]|1\d|2[0-3]))*$', hour) + ): + return True + return False + + @classmethod + def validate_day(cls, day: str): + """ + 校验日值是否正确 + + :param day: 日值 + :return: 校验结果 + """ + if ( + day in ['*', '?', 'L'] + or ('-' in day and cls.__valid_range(day, 1, 31)) + or ('/' in day and cls.__valid_sum(day, 1, 30, 1, 30, 31)) + or ('W' in day and re.match(r'^(?:[1-9]|1\d|2\d|3[01])W$', day)) + or re.match(r'^(?:0|[1-9]|1\d|2[0-9]|3[0-1])(?:,(?:0|[1-9]|1\d|2[0-9]|3[0-1]))*$', day) + ): + return True + return False + + @classmethod + def validate_month(cls, month: str): + """ + 校验月值是否正确 + + :param month: 月值 + :return: 校验结果 + """ + if ( + month == '*' + or ('-' in month and cls.__valid_range(month, 1, 12)) + or ('/' in month and cls.__valid_sum(month, 1, 11, 1, 11, 12)) + or re.match(r'^(?:0|[1-9]|1[0-2])(?:,(?:0|[1-9]|1[0-2]))*$', month) + ): + return True + return False + + @classmethod + def validate_week(cls, week: str): + """ + 校验周值是否正确 + + :param week: 周值 + :return: 校验结果 + """ + if ( + week in ['*', '?'] + or ('-' in week and cls.__valid_range(week, 1, 7)) + or ('#' in week and re.match(r'^[1-7]#[1-4]$', week)) + or ('L' in week and re.match(r'^[1-7]L$', week)) + or re.match(r'^[1-7](?:(,[1-7]))*$', week) + ): + return True + return False + + @classmethod + def validate_year(cls, year: str): + """ + 校验年值是否正确 + + :param year: 年值 + :return: 校验结果 + """ + current_year = int(datetime.now().year) + future_years = [current_year + i for i in range(9)] + if ( + year == '*' + or ('-' in year and cls.__valid_range(year, current_year, 2099)) + or ('/' in year and cls.__valid_sum(year, current_year, 2098, 1, 2099 - current_year, 2099)) + or ('#' in year and re.match(r'^[1-7]#[1-4]$', year)) + or ('L' in year and re.match(r'^[1-7]L$', year)) + or ( + (len(year) == 4 or ',' in year) + and all(int(item) in future_years and current_year <= int(item) <= 2099 for item in year.split(',')) + ) + ): + return True + return False + + @classmethod + def validate_cron_expression(cls, cron_expression: str): + """ + 校验Cron表达式是否正确 + * * * * * * + | | | | | | + | | | | | +--- 星期(0-7,0和7都表示星期日) + | | | | +----- 月份(1-12) + | | | +------- 日期(1-31) + | | +--------- 小时(0-23) + | +----------- 分钟(0-59) + +------------- 秒(0-59),**部分环境不支持秒字段** + + :param cron_expression: Cron表达式 + :return: 校验结果 + """ + values = cron_expression.split() + if len(values) != 6 and len(values) != 7: + return False + second_validation = cls.validate_second_or_minute(values[0]) + minute_validation = cls.validate_second_or_minute(values[1]) + hour_validation = cls.validate_hour(values[2]) + day_validation = cls.validate_day(values[3]) + month_validation = cls.validate_month(values[4]) + week_validation = cls.validate_week(values[5]) + validation = ( + second_validation + and minute_validation + and hour_validation + and day_validation + and month_validation + and week_validation + ) + if len(values) == 6: + return validation + if len(values) == 7: + year_validation = cls.validate_year(values[6]) + return validation and year_validation