Re-upload history
This commit is contained in:
1 parent
f28e26558d
commit
90916315b9
317 files changed
+73601
-73293
No files matched your search
@@ -1,84 +1,84 @@
|
||||
import win32process
|
||||
import win32job
|
||||
import win32api
|
||||
import win32con
|
||||
import subprocess
|
||||
import win32event
|
||||
|
||||
import time
|
||||
|
||||
class ChildProcessManager:
|
||||
def __init__(self):
|
||||
self.HJob = None
|
||||
self.ProcessId = None
|
||||
self.ProcessHandle = None
|
||||
|
||||
def StartChildProcess(self, exe_path):
|
||||
self._Cleanup()
|
||||
try:
|
||||
self.HJob = win32job.CreateJobObject(None, "")
|
||||
if not self.HJob: raise Exception("Failed To Create Job Object")
|
||||
except Exception as e:
|
||||
print(f"Failed To Create Job Object: {e}")
|
||||
self._Cleanup()
|
||||
return False
|
||||
|
||||
try:
|
||||
info = win32job.QueryInformationJobObject(self.HJob, win32job.JobObjectExtendedLimitInformation)
|
||||
info['BasicLimitInformation']['LimitFlags'] |= win32job.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
|
||||
win32job.SetInformationJobObject(self.HJob, win32job.JobObjectExtendedLimitInformation, info)
|
||||
except Exception as e:
|
||||
print(f"Failed To Set Job Object Information: {e}")
|
||||
self._Cleanup()
|
||||
return False
|
||||
|
||||
startUpInfo = win32process.STARTUPINFO()
|
||||
try:
|
||||
hProcess, hThread, dwProcessId, dwThreadId = win32process.CreateProcess(
|
||||
None, exe_path, None, None, False,
|
||||
win32process.CREATE_NEW_PROCESS_GROUP | win32process.CREATE_SUSPENDED,
|
||||
None, None, startUpInfo
|
||||
)
|
||||
self.ProcessId = dwProcessId
|
||||
self.ProcessHandle = hProcess
|
||||
win32job.AssignProcessToJobObject(self.HJob, hProcess)
|
||||
win32process.ResumeThread(hThread)
|
||||
win32api.CloseHandle(hThread)
|
||||
print(f"Successfully Started Child Process, PID: {dwProcessId}")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"Failed To Start Child Process: {e}")
|
||||
self._Cleanup()
|
||||
return False
|
||||
|
||||
def IsProcessAlive(self):
|
||||
if not self.ProcessId or not self.ProcessHandle: return False
|
||||
try:
|
||||
result = win32event.WaitForSingleObject(self.ProcessHandle, 0)
|
||||
return result == win32con.WAIT_TIMEOUT
|
||||
except Exception as e:
|
||||
print(f"Failed To Check Process Status: {e}")
|
||||
return False
|
||||
def _Cleanup(self):
|
||||
if self.ProcessHandle:
|
||||
try: win32api.CloseHandle(self.ProcessHandle)
|
||||
except: pass
|
||||
self.ProcessHandle = None
|
||||
if self.HJob:
|
||||
try: win32api.CloseHandle(self.HJob)
|
||||
except: pass
|
||||
self.HJob = None
|
||||
self.ProcessId = None
|
||||
def Close(self):
|
||||
self._Cleanup()
|
||||
|
||||
if __name__ == "__main__":
|
||||
manager = ChildProcessManager()
|
||||
if manager.StartChildProcess("notepad.exe"):
|
||||
try:
|
||||
while True:
|
||||
status = "存活" if manager.IsProcessAlive() else "死亡"
|
||||
print(f"子进程状态: {status},PID: {manager.ProcessId}")
|
||||
time.sleep(1)
|
||||
finally:
|
||||
manager.Close()
|
||||
import win32process
|
||||
import win32job
|
||||
import win32api
|
||||
import win32con
|
||||
import subprocess
|
||||
import win32event
|
||||
|
||||
import time
|
||||
|
||||
class ChildProcessManager:
|
||||
def __init__(self):
|
||||
self.HJob = None
|
||||
self.ProcessId = None
|
||||
self.ProcessHandle = None
|
||||
|
||||
def StartChildProcess(self, exe_path):
|
||||
self._Cleanup()
|
||||
try:
|
||||
self.HJob = win32job.CreateJobObject(None, "")
|
||||
if not self.HJob: raise Exception("Failed To Create Job Object")
|
||||
except Exception as e:
|
||||
print(f"Failed To Create Job Object: {e}")
|
||||
self._Cleanup()
|
||||
return False
|
||||
|
||||
try:
|
||||
info = win32job.QueryInformationJobObject(self.HJob, win32job.JobObjectExtendedLimitInformation)
|
||||
info['BasicLimitInformation']['LimitFlags'] |= win32job.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
|
||||
win32job.SetInformationJobObject(self.HJob, win32job.JobObjectExtendedLimitInformation, info)
|
||||
except Exception as e:
|
||||
print(f"Failed To Set Job Object Information: {e}")
|
||||
self._Cleanup()
|
||||
return False
|
||||
|
||||
startUpInfo = win32process.STARTUPINFO()
|
||||
try:
|
||||
hProcess, hThread, dwProcessId, dwThreadId = win32process.CreateProcess(
|
||||
None, exe_path, None, None, False,
|
||||
win32process.CREATE_NEW_PROCESS_GROUP | win32process.CREATE_SUSPENDED,
|
||||
None, None, startUpInfo
|
||||
)
|
||||
self.ProcessId = dwProcessId
|
||||
self.ProcessHandle = hProcess
|
||||
win32job.AssignProcessToJobObject(self.HJob, hProcess)
|
||||
win32process.ResumeThread(hThread)
|
||||
win32api.CloseHandle(hThread)
|
||||
print(f"Successfully Started Child Process, PID: {dwProcessId}")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"Failed To Start Child Process: {e}")
|
||||
self._Cleanup()
|
||||
return False
|
||||
|
||||
def IsProcessAlive(self):
|
||||
if not self.ProcessId or not self.ProcessHandle: return False
|
||||
try:
|
||||
result = win32event.WaitForSingleObject(self.ProcessHandle, 0)
|
||||
return result == win32con.WAIT_TIMEOUT
|
||||
except Exception as e:
|
||||
print(f"Failed To Check Process Status: {e}")
|
||||
return False
|
||||
def _Cleanup(self):
|
||||
if self.ProcessHandle:
|
||||
try: win32api.CloseHandle(self.ProcessHandle)
|
||||
except: pass
|
||||
self.ProcessHandle = None
|
||||
if self.HJob:
|
||||
try: win32api.CloseHandle(self.HJob)
|
||||
except: pass
|
||||
self.HJob = None
|
||||
self.ProcessId = None
|
||||
def Close(self):
|
||||
self._Cleanup()
|
||||
|
||||
if __name__ == "__main__":
|
||||
manager = ChildProcessManager()
|
||||
if manager.StartChildProcess("notepad.exe"):
|
||||
try:
|
||||
while True:
|
||||
status = "存活" if manager.IsProcessAlive() else "死亡"
|
||||
print(f"子进程状态: {status},PID: {manager.ProcessId}")
|
||||
time.sleep(1)
|
||||
finally:
|
||||
manager.Close()
|
||||
+381
-381
@@ -1,382 +1,382 @@
|
||||
from datetime import datetime
|
||||
from apscheduler.schedulers.background import BackgroundScheduler
|
||||
from apscheduler.events import EVENT_JOB_EXECUTED, EVENT_JOB_ERROR
|
||||
from apscheduler.triggers.date import DateTrigger
|
||||
from apscheduler.triggers.cron import CronTrigger
|
||||
from apscheduler.triggers.interval import IntervalTrigger
|
||||
import pytz
|
||||
import logging
|
||||
import uuid
|
||||
import traceback
|
||||
import typing
|
||||
import random
|
||||
|
||||
def GUUID():
|
||||
return str(uuid.uuid3(uuid.NAMESPACE_DNS, str(random.randint(0, 10000000000000000000))))
|
||||
|
||||
|
||||
class Task:
|
||||
"""Task Type, Encapsulating Task Attributes And Behaviors."""
|
||||
|
||||
def __init__(self, task_data: typing.Dict):
|
||||
"""
|
||||
初始化任务
|
||||
:param task_data: 任务数据字典
|
||||
"""
|
||||
self.task_data=task_data
|
||||
self.uuid = task_data.get('TaskUUID', GUUID())
|
||||
self.name = task_data.get('TaskName', 'Unnamed Task')
|
||||
self.e_time_type = task_data.get('ETimeType')
|
||||
self.e_time = task_data.get('ETime')
|
||||
self.r_time_type = task_data.get('RTimeType')
|
||||
self.r_time = task_data.get('RTime')
|
||||
self.r_code = task_data.get('RCode')
|
||||
self.r_type = task_data.get('RType')
|
||||
|
||||
# 验证必要字段
|
||||
if not all([self.e_time_type, self.r_time_type, self.r_code]):
|
||||
raise ValueError("Missing Necessary Task Parameters")
|
||||
|
||||
def is_effective(self) -> bool:
|
||||
"""检查任务是否在生效时间内"""
|
||||
now = datetime.now(pytz.timezone('Asia/Shanghai'))
|
||||
|
||||
try:
|
||||
if self.e_time_type == '1': # 具体时间
|
||||
effective_time = datetime.strptime(self.e_time, '%Y-%m-%d %H:%M:%S')
|
||||
effective_time = pytz.timezone('Asia/Shanghai').localize(effective_time)
|
||||
return now >= effective_time
|
||||
|
||||
elif self.e_time_type == '2': # 每日执行时间
|
||||
hour, minute, second = map(int, self.e_time.split(':'))
|
||||
effective_time = now.replace(hour=hour, minute=minute, second=second)
|
||||
return now >= effective_time
|
||||
|
||||
# 其他类型默认返回True
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"Failed To Check The Effective Time Of Task {self.uuid}: {e}")
|
||||
return False
|
||||
|
||||
def create_trigger(self) -> typing.Optional[typing.Union[DateTrigger, CronTrigger, IntervalTrigger]]:
|
||||
"""根据时间类型创建对应的触发器"""
|
||||
try:
|
||||
if self.r_time_type == '1': # 具体时间
|
||||
return DateTrigger(run_date=datetime.strptime(self.r_time, '%Y-%m-%d %H:%M:%S'))
|
||||
|
||||
elif self.r_time_type == '2': # 每日执行时间
|
||||
hour, minute, second = map(int, self.r_time.split(':'))
|
||||
return CronTrigger(hour=hour, minute=minute, second=second)
|
||||
|
||||
elif self.r_time_type == '3': # 每周循环时间
|
||||
parts = self.r_time.split()
|
||||
day_of_week = parts[0] # 1-7,1=周一
|
||||
hour, minute, second = map(int, parts[1].split(':'))
|
||||
return CronTrigger(day_of_week=day_of_week, hour=hour, minute=minute, second=second)
|
||||
|
||||
elif self.r_time_type == '4': # 月循环时间
|
||||
parts = self.r_time.split()
|
||||
day = parts[0] # 1-31
|
||||
hour, minute, second = map(int, parts[1].split(':'))
|
||||
return CronTrigger(day=day, hour=hour, minute=minute, second=second)
|
||||
|
||||
elif self.r_time_type == '5': # 间隔时间
|
||||
hour, minute, second = map(int, self.r_time.split(':'))
|
||||
return IntervalTrigger(hours=hour, minutes=minute, seconds=second)
|
||||
|
||||
elif self.r_time_type == '6': # 开机时执行
|
||||
return None # 已在调度器中特殊处理
|
||||
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"Failed To Create Scheduler For Task {self.uuid} : {e}")
|
||||
return None
|
||||
|
||||
|
||||
class TaskScheduler:
|
||||
"""任务调度器类,管理所有任务的调度"""
|
||||
|
||||
def __init__(self, ExecuteCallBack=lambda x, y, z: exec(y)):
|
||||
self.ExecuteCallBack=ExecuteCallBack
|
||||
"""初始化调度器"""
|
||||
# 初始化调度器,使用上海时区
|
||||
self.scheduler = BackgroundScheduler(timezone=pytz.timezone('Asia/Shanghai'))
|
||||
self.scheduler.start()
|
||||
|
||||
# 存储任务对象
|
||||
self.tasks: typing.Dict[str, Task] = {}
|
||||
|
||||
# 添加事件监听
|
||||
self.scheduler.add_listener(self._job_listener, EVENT_JOB_EXECUTED | EVENT_JOB_ERROR)
|
||||
|
||||
def _job_listener(self, event):
|
||||
"""Task Execution Event Listener"""
|
||||
if event.code == EVENT_JOB_EXECUTED:
|
||||
print(f"Task {event.job_id} Executed Successfully")
|
||||
elif event.code == EVENT_JOB_ERROR:
|
||||
print(f"Task {event.job_id} Execution Failed: {event.exception}")
|
||||
|
||||
def add_task(self, task_data: typing.Dict) -> bool:
|
||||
"""
|
||||
Add Tasks To The Scheduler
|
||||
:param task_data: Task Data Dictionary
|
||||
:return: Was It Added Successfully?
|
||||
"""
|
||||
try:
|
||||
task = Task(task_data)
|
||||
|
||||
# 检查生效时间是否已过
|
||||
if not task.is_effective():
|
||||
print(f"Task {task.uuid} The Effective Date Has Passed.")
|
||||
return False
|
||||
|
||||
# 处理开机执行的任务
|
||||
if task.r_time_type == '6':
|
||||
print(f"Immediately Execute The StartUp Task: {task.name}")
|
||||
self._execute_code(task_data, task.r_code, task.r_type)
|
||||
return True
|
||||
|
||||
# 创建触发器
|
||||
trigger = task.create_trigger()
|
||||
if not trigger:
|
||||
print(f"Unable To Create A Trigger For Task: {task.uuid}")
|
||||
return False
|
||||
|
||||
# 添加任务到调度器
|
||||
self.scheduler.add_job(
|
||||
self._execute_code,
|
||||
trigger=trigger,
|
||||
args=[task_data, task.r_code, task.r_type],
|
||||
id=task.uuid,
|
||||
name=task.name,
|
||||
misfire_grace_time=60, # 允许60秒的延迟执行
|
||||
)
|
||||
|
||||
# 存储任务对象
|
||||
self.tasks[task.uuid] = task
|
||||
print(f"Task {task.uuid} Has Been Added.")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"Failed To Add Task: {e}")
|
||||
return False
|
||||
|
||||
def remove_task(self, task_uuid: str) -> bool:
|
||||
"""
|
||||
移除任务
|
||||
:param task_uuid: 任务UUID
|
||||
:return: 是否移除成功
|
||||
"""
|
||||
if task_uuid not in self.tasks:
|
||||
print(f"任务 {task_uuid} 不存在")
|
||||
return False
|
||||
|
||||
try:
|
||||
# 从调度器中移除
|
||||
try:
|
||||
self.scheduler.remove_job(task_uuid)
|
||||
except:
|
||||
pass
|
||||
|
||||
# 从任务字典中移除
|
||||
del self.tasks[task_uuid]
|
||||
|
||||
print(f"Task {task_uuid} Has Been Removed")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(traceback.format_exc())
|
||||
print(f"Failed To Remove Task {task_uuid}: {e}")
|
||||
return False
|
||||
|
||||
def get_task(self, task_uuid: str) -> typing.Optional[typing.Dict]:
|
||||
"""
|
||||
获取任务信息
|
||||
:param task_uuid: 任务UUID
|
||||
:return: 任务信息字典或None
|
||||
"""
|
||||
task = self.tasks.get(task_uuid)
|
||||
if not task:
|
||||
return None
|
||||
|
||||
return {
|
||||
'TaskUUID': task.uuid,
|
||||
'TaskName': task.name,
|
||||
'ETimeType': task.e_time_type,
|
||||
'ETime': task.e_time,
|
||||
'RTimeType': task.r_time_type,
|
||||
'RTime': task.r_time,
|
||||
'RCode': task.r_code,
|
||||
'RType': task.r_type
|
||||
}
|
||||
|
||||
def list_tasks(self) -> typing.Dict[str, typing.Dict]:
|
||||
"""Get All Task Information"""
|
||||
return {uuid: self.get_task(uuid) for uuid in self.tasks}
|
||||
|
||||
def _execute_code(self, task: dict, _code: str, _type: str):
|
||||
self.ExecuteCallBack(task, _code, _type)
|
||||
|
||||
def shutdown(self):
|
||||
"""关闭调度器"""
|
||||
self.scheduler.shutdown()
|
||||
print("Task Scheduler Has Been Closed.")
|
||||
"""
|
||||
请你使用python apscheduler做一个调度器,实现以下功能:
|
||||
|
||||
### 1. 初始化调度器
|
||||
```python
|
||||
scheduler = TaskScheduler(ExecuteCallBack=lambda x, y, z: exec(y))
|
||||
```
|
||||
- **参数**:
|
||||
- `ExecuteCallBack`: 任务执行时的回调函数,默认为直接执行Python代码
|
||||
- **功能**: 创建后台调度器实例,使用UTC-8时区
|
||||
|
||||
### 2. 添加任务
|
||||
```python
|
||||
add_task(task_data: dict) -> bool
|
||||
```
|
||||
- **参数**:
|
||||
- `task_data`: 包含任务配置的字典,必须包含以下关键字段:
|
||||
- `ETimeType`: 生效时间类型
|
||||
- `ETime`: 生效时间
|
||||
- `RTimeType`: 执行时间类型
|
||||
- `RTime`: 执行时间
|
||||
- `LTimeType`: 失效时间类型
|
||||
- `LTime`: 失效时间
|
||||
- `RCode`: 要执行的代码
|
||||
- **返回值**: 布尔值表示是否添加成功
|
||||
- **功能**: 根据任务配置创建并调度任务
|
||||
|
||||
### 3. 移除任务
|
||||
```python
|
||||
remove_task(task_uuid: str) -> bool
|
||||
```
|
||||
- **参数**:
|
||||
- `task_uuid`: 要移除的任务ID
|
||||
- **返回值**: 布尔值表示是否移除成功
|
||||
- **功能**: 从调度器中移除指定任务
|
||||
|
||||
### 4. 获取单个任务信息
|
||||
```python
|
||||
get_task(task_uuid: str) -> Optional[dict]
|
||||
```
|
||||
- **参数**:
|
||||
- `task_uuid`: 要查询的任务ID
|
||||
- **返回值**: 包含任务信息的字典或None
|
||||
- **功能**: 获取指定任务的详细配置信息
|
||||
|
||||
### 5. 列出所有任务
|
||||
```python
|
||||
list_tasks() -> Dict[str, Dict]
|
||||
```
|
||||
- **返回值**: 字典格式的所有任务信息,键为任务ID
|
||||
- **功能**: 获取当前所有已调度任务的列表
|
||||
|
||||
### 6. 关闭调度器
|
||||
```python
|
||||
shutdown()
|
||||
```
|
||||
- **功能**: 停止调度器运行,释放资源
|
||||
|
||||
## 任务配置参数详解
|
||||
|
||||
### 生效时间类型 (ETimeType)
|
||||
| 值 | 类型 | ETime格式 | 描述 |
|
||||
|----|------|-----------|------|
|
||||
| '1' | 具体时间 | 'YYYY-MM-DD HH:MM:SS' | 在指定时间点后生效 |
|
||||
| '2' | 每日时间 | 'HH:MM:SS' | 每天指定时间后生效 |
|
||||
| '3' | 永久生效 | 无 | 永久生效 |
|
||||
|
||||
### 执行时间类型 (RTimeType)
|
||||
| 值 | 类型 | RTime格式 | 描述 |
|
||||
|----|------|-----------|------|
|
||||
| '1' | 具体时间 | 'YYYY-MM-DD HH:MM:SS' | 在指定时间点执行一次 |
|
||||
| '2' | 每日执行 | 'HH:MM:SS' | 每天固定时间执行 |
|
||||
| '3' | 每周执行 | 'D HH:MM:SS' | 每周特定星期几执行 (1=周一) |
|
||||
| '4' | 每月执行 | 'D HH:MM:SS' | 每月特定日期执行 |
|
||||
| '5' | 间隔执行 | 'HH:MM:SS' | 按固定间隔重复执行 |
|
||||
| '6' | 开机执行 | 无 | 调度器启动时立即执行 |
|
||||
| '7' | 开机延时执行 | 'SS' | 调度器启动时等待一段时间执行 |
|
||||
|
||||
### 失效时间类型 (LTimeType)
|
||||
| 值 | 类型 | LTime格式 | 描述 |
|
||||
|----|------|-----------|------|
|
||||
| '1' | 具体时间 | 'YYYY-MM-DD HH:MM:SS' | 在指定时间点失生效 |
|
||||
| '2' | 每日时间 | 'HH:MM:SS' | 每天指定时间后失效 |
|
||||
| '3' | 永久生效 | 无 | 不会失效 |
|
||||
|
||||
### 其他参数
|
||||
- `TaskName`: 任务名称(可选)
|
||||
- `TaskUUID`: 任务ID(可选,不提供会自动生成)
|
||||
- `RCode`: 要执行的代码内容
|
||||
- `RType`: 代码类型(Python/Shell等,直接提交给回调,不由调度器处理)
|
||||
|
||||
## 使用流程示例
|
||||
|
||||
1. 初始化调度器
|
||||
2. 准备任务配置字典
|
||||
3. 调用`add_task()`添加任务
|
||||
4. (可选)使用`list_tasks()`查看任务
|
||||
5. (可选)使用`remove_task()`删除任务
|
||||
6. 程序结束时调用`shutdown()`关闭调度器
|
||||
|
||||
## 注意事项
|
||||
|
||||
注意除调度器外还有一个task_dict用于存储所有的task_data,格式{"UUID": task_data},task_data也有相同的UUID,还有是否生效的标志working_status。
|
||||
|
||||
1. 所有时间都使用UTF-8时区(东八区)。
|
||||
2. 任务ID(TaskUUID)必须唯一,不提供会自动生成。
|
||||
3. 开机执行的任务(RTimeType='6')会立即执行,会被添加到调度器中,但是被设置为失效。
|
||||
4. 调度器使用后台线程,主程序需要保持运行状态才能执行定时任务
|
||||
5. 注意任务完成和失效后不要从调度器中移除任务,而是将属性设置为失效。
|
||||
6. 如果是2345时间类型的任务则不可能失效。
|
||||
7. 生效时间3和执行时间6还有失效时间3可以没有ETime和RTime和LTime(或者可以任意填写)。
|
||||
8. 生效时间类型的优先级低于失效时间优先级,也就是即使生效时间为永久生效,如果设置了具体时间失效仍然会失效
|
||||
9. 如果添加出错,允许返回错误信息,以便用户定位问题
|
||||
|
||||
使用以下作为示例
|
||||
1:
|
||||
'ETimeType': '3',
|
||||
'RTimeType': '6',
|
||||
'LTimeType': '1',
|
||||
'LTime': '2025-05-18 03:16:00',
|
||||
'RCode': 'print("HI")',
|
||||
'TaskName': 'HI'
|
||||
正常情况下这个示例由于已经过失效时间而被视为失效,会添加但是被设置为失效因此无法执行
|
||||
|
||||
2:
|
||||
'ETimeType': '3',
|
||||
'RTimeType': '6',
|
||||
'LTimeType': '1',
|
||||
'LTime': '2025-05-18 04:10:00',
|
||||
'RCode': 'print("HI")',
|
||||
'TaskName': 'HI'
|
||||
正常情况下这个示例由于还没过失效时间而不被视为失效,会在添加的同时被执行
|
||||
|
||||
3:
|
||||
'ETimeType': '1',
|
||||
'ETime': '2025-05-18 07:20:40',
|
||||
'RTimeType': '1',
|
||||
'RTime': '2025-05-18 07:20:50',
|
||||
'LTimeType': '1',
|
||||
'LTime': '2025-05-18 07:25:00',
|
||||
'RCode': 'print("HI")',
|
||||
'TaskName': 'HI_Expired'
|
||||
正常情况下这个示例由于还没到生效时间因此不被执行,但是仍然有效,因此到达生效时间和执行时间后才会执行,执行后会被设置为失效,执行前一直有效但不执行
|
||||
但是注意,到达生效时间后不会立刻执行,而是继续等到执行时间才会继续执行,因此任务会在生效时间生效,并在执行时间执行,然后根据类型被选择是否设置为失效
|
||||
如果未到达生效时间不应当被判断为失效,应当使用调度器设置在到达生效时间后自动生效,并在符合执行时间时执行!!!
|
||||
如果未到达生效时间不应当被判断为失效,应当使用调度器设置在到达生效时间后自动生效,并在符合执行时间时执行!!!
|
||||
如果未到达生效时间不应当被判断为失效,应当使用调度器设置在到达生效时间后自动生效,并在符合执行时间时执行!!!
|
||||
如果未到达生效时间不应当被判断为失效,应当使用调度器设置在到达生效时间后自动生效,并在符合执行时间时执行!!!
|
||||
如果未到达生效时间不应当被判断为失效,应当使用调度器设置在到达生效时间后自动生效,并在符合执行时间时执行!!!
|
||||
|
||||
|
||||
4:
|
||||
'ETimeType': '1',
|
||||
'ETime': '2025-05-18 07:20:40',
|
||||
'RTimeType': '6',
|
||||
'LTimeType': '1',
|
||||
'LTime': '2025-05-18 07:25:00',
|
||||
'RCode': 'print("HI")',
|
||||
'TaskName': 'HI_Expired'
|
||||
from datetime import datetime
|
||||
from apscheduler.schedulers.background import BackgroundScheduler
|
||||
from apscheduler.events import EVENT_JOB_EXECUTED, EVENT_JOB_ERROR
|
||||
from apscheduler.triggers.date import DateTrigger
|
||||
from apscheduler.triggers.cron import CronTrigger
|
||||
from apscheduler.triggers.interval import IntervalTrigger
|
||||
import pytz
|
||||
import logging
|
||||
import uuid
|
||||
import traceback
|
||||
import typing
|
||||
import random
|
||||
|
||||
def GUUID():
|
||||
return str(uuid.uuid3(uuid.NAMESPACE_DNS, str(random.randint(0, 10000000000000000000))))
|
||||
|
||||
|
||||
class Task:
|
||||
"""Task Type, Encapsulating Task Attributes And Behaviors."""
|
||||
|
||||
def __init__(self, task_data: typing.Dict):
|
||||
"""
|
||||
初始化任务
|
||||
:param task_data: 任务数据字典
|
||||
"""
|
||||
self.task_data=task_data
|
||||
self.uuid = task_data.get('TaskUUID', GUUID())
|
||||
self.name = task_data.get('TaskName', 'Unnamed Task')
|
||||
self.e_time_type = task_data.get('ETimeType')
|
||||
self.e_time = task_data.get('ETime')
|
||||
self.r_time_type = task_data.get('RTimeType')
|
||||
self.r_time = task_data.get('RTime')
|
||||
self.r_code = task_data.get('RCode')
|
||||
self.r_type = task_data.get('RType')
|
||||
|
||||
# 验证必要字段
|
||||
if not all([self.e_time_type, self.r_time_type, self.r_code]):
|
||||
raise ValueError("Missing Necessary Task Parameters")
|
||||
|
||||
def is_effective(self) -> bool:
|
||||
"""检查任务是否在生效时间内"""
|
||||
now = datetime.now(pytz.timezone('Asia/Shanghai'))
|
||||
|
||||
try:
|
||||
if self.e_time_type == '1': # 具体时间
|
||||
effective_time = datetime.strptime(self.e_time, '%Y-%m-%d %H:%M:%S')
|
||||
effective_time = pytz.timezone('Asia/Shanghai').localize(effective_time)
|
||||
return now >= effective_time
|
||||
|
||||
elif self.e_time_type == '2': # 每日执行时间
|
||||
hour, minute, second = map(int, self.e_time.split(':'))
|
||||
effective_time = now.replace(hour=hour, minute=minute, second=second)
|
||||
return now >= effective_time
|
||||
|
||||
# 其他类型默认返回True
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"Failed To Check The Effective Time Of Task {self.uuid}: {e}")
|
||||
return False
|
||||
|
||||
def create_trigger(self) -> typing.Optional[typing.Union[DateTrigger, CronTrigger, IntervalTrigger]]:
|
||||
"""根据时间类型创建对应的触发器"""
|
||||
try:
|
||||
if self.r_time_type == '1': # 具体时间
|
||||
return DateTrigger(run_date=datetime.strptime(self.r_time, '%Y-%m-%d %H:%M:%S'))
|
||||
|
||||
elif self.r_time_type == '2': # 每日执行时间
|
||||
hour, minute, second = map(int, self.r_time.split(':'))
|
||||
return CronTrigger(hour=hour, minute=minute, second=second)
|
||||
|
||||
elif self.r_time_type == '3': # 每周循环时间
|
||||
parts = self.r_time.split()
|
||||
day_of_week = parts[0] # 1-7,1=周一
|
||||
hour, minute, second = map(int, parts[1].split(':'))
|
||||
return CronTrigger(day_of_week=day_of_week, hour=hour, minute=minute, second=second)
|
||||
|
||||
elif self.r_time_type == '4': # 月循环时间
|
||||
parts = self.r_time.split()
|
||||
day = parts[0] # 1-31
|
||||
hour, minute, second = map(int, parts[1].split(':'))
|
||||
return CronTrigger(day=day, hour=hour, minute=minute, second=second)
|
||||
|
||||
elif self.r_time_type == '5': # 间隔时间
|
||||
hour, minute, second = map(int, self.r_time.split(':'))
|
||||
return IntervalTrigger(hours=hour, minutes=minute, seconds=second)
|
||||
|
||||
elif self.r_time_type == '6': # 开机时执行
|
||||
return None # 已在调度器中特殊处理
|
||||
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"Failed To Create Scheduler For Task {self.uuid} : {e}")
|
||||
return None
|
||||
|
||||
|
||||
class TaskScheduler:
|
||||
"""任务调度器类,管理所有任务的调度"""
|
||||
|
||||
def __init__(self, ExecuteCallBack=lambda x, y, z: exec(y)):
|
||||
self.ExecuteCallBack=ExecuteCallBack
|
||||
"""初始化调度器"""
|
||||
# 初始化调度器,使用上海时区
|
||||
self.scheduler = BackgroundScheduler(timezone=pytz.timezone('Asia/Shanghai'))
|
||||
self.scheduler.start()
|
||||
|
||||
# 存储任务对象
|
||||
self.tasks: typing.Dict[str, Task] = {}
|
||||
|
||||
# 添加事件监听
|
||||
self.scheduler.add_listener(self._job_listener, EVENT_JOB_EXECUTED | EVENT_JOB_ERROR)
|
||||
|
||||
def _job_listener(self, event):
|
||||
"""Task Execution Event Listener"""
|
||||
if event.code == EVENT_JOB_EXECUTED:
|
||||
print(f"Task {event.job_id} Executed Successfully")
|
||||
elif event.code == EVENT_JOB_ERROR:
|
||||
print(f"Task {event.job_id} Execution Failed: {event.exception}")
|
||||
|
||||
def add_task(self, task_data: typing.Dict) -> bool:
|
||||
"""
|
||||
Add Tasks To The Scheduler
|
||||
:param task_data: Task Data Dictionary
|
||||
:return: Was It Added Successfully?
|
||||
"""
|
||||
try:
|
||||
task = Task(task_data)
|
||||
|
||||
# 检查生效时间是否已过
|
||||
if not task.is_effective():
|
||||
print(f"Task {task.uuid} The Effective Date Has Passed.")
|
||||
return False
|
||||
|
||||
# 处理开机执行的任务
|
||||
if task.r_time_type == '6':
|
||||
print(f"Immediately Execute The StartUp Task: {task.name}")
|
||||
self._execute_code(task_data, task.r_code, task.r_type)
|
||||
return True
|
||||
|
||||
# 创建触发器
|
||||
trigger = task.create_trigger()
|
||||
if not trigger:
|
||||
print(f"Unable To Create A Trigger For Task: {task.uuid}")
|
||||
return False
|
||||
|
||||
# 添加任务到调度器
|
||||
self.scheduler.add_job(
|
||||
self._execute_code,
|
||||
trigger=trigger,
|
||||
args=[task_data, task.r_code, task.r_type],
|
||||
id=task.uuid,
|
||||
name=task.name,
|
||||
misfire_grace_time=60, # 允许60秒的延迟执行
|
||||
)
|
||||
|
||||
# 存储任务对象
|
||||
self.tasks[task.uuid] = task
|
||||
print(f"Task {task.uuid} Has Been Added.")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"Failed To Add Task: {e}")
|
||||
return False
|
||||
|
||||
def remove_task(self, task_uuid: str) -> bool:
|
||||
"""
|
||||
移除任务
|
||||
:param task_uuid: 任务UUID
|
||||
:return: 是否移除成功
|
||||
"""
|
||||
if task_uuid not in self.tasks:
|
||||
print(f"任务 {task_uuid} 不存在")
|
||||
return False
|
||||
|
||||
try:
|
||||
# 从调度器中移除
|
||||
try:
|
||||
self.scheduler.remove_job(task_uuid)
|
||||
except:
|
||||
pass
|
||||
|
||||
# 从任务字典中移除
|
||||
del self.tasks[task_uuid]
|
||||
|
||||
print(f"Task {task_uuid} Has Been Removed")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(traceback.format_exc())
|
||||
print(f"Failed To Remove Task {task_uuid}: {e}")
|
||||
return False
|
||||
|
||||
def get_task(self, task_uuid: str) -> typing.Optional[typing.Dict]:
|
||||
"""
|
||||
获取任务信息
|
||||
:param task_uuid: 任务UUID
|
||||
:return: 任务信息字典或None
|
||||
"""
|
||||
task = self.tasks.get(task_uuid)
|
||||
if not task:
|
||||
return None
|
||||
|
||||
return {
|
||||
'TaskUUID': task.uuid,
|
||||
'TaskName': task.name,
|
||||
'ETimeType': task.e_time_type,
|
||||
'ETime': task.e_time,
|
||||
'RTimeType': task.r_time_type,
|
||||
'RTime': task.r_time,
|
||||
'RCode': task.r_code,
|
||||
'RType': task.r_type
|
||||
}
|
||||
|
||||
def list_tasks(self) -> typing.Dict[str, typing.Dict]:
|
||||
"""Get All Task Information"""
|
||||
return {uuid: self.get_task(uuid) for uuid in self.tasks}
|
||||
|
||||
def _execute_code(self, task: dict, _code: str, _type: str):
|
||||
self.ExecuteCallBack(task, _code, _type)
|
||||
|
||||
def shutdown(self):
|
||||
"""关闭调度器"""
|
||||
self.scheduler.shutdown()
|
||||
print("Task Scheduler Has Been Closed.")
|
||||
"""
|
||||
请你使用python apscheduler做一个调度器,实现以下功能:
|
||||
|
||||
### 1. 初始化调度器
|
||||
```python
|
||||
scheduler = TaskScheduler(ExecuteCallBack=lambda x, y, z: exec(y))
|
||||
```
|
||||
- **参数**:
|
||||
- `ExecuteCallBack`: 任务执行时的回调函数,默认为直接执行Python代码
|
||||
- **功能**: 创建后台调度器实例,使用UTC-8时区
|
||||
|
||||
### 2. 添加任务
|
||||
```python
|
||||
add_task(task_data: dict) -> bool
|
||||
```
|
||||
- **参数**:
|
||||
- `task_data`: 包含任务配置的字典,必须包含以下关键字段:
|
||||
- `ETimeType`: 生效时间类型
|
||||
- `ETime`: 生效时间
|
||||
- `RTimeType`: 执行时间类型
|
||||
- `RTime`: 执行时间
|
||||
- `LTimeType`: 失效时间类型
|
||||
- `LTime`: 失效时间
|
||||
- `RCode`: 要执行的代码
|
||||
- **返回值**: 布尔值表示是否添加成功
|
||||
- **功能**: 根据任务配置创建并调度任务
|
||||
|
||||
### 3. 移除任务
|
||||
```python
|
||||
remove_task(task_uuid: str) -> bool
|
||||
```
|
||||
- **参数**:
|
||||
- `task_uuid`: 要移除的任务ID
|
||||
- **返回值**: 布尔值表示是否移除成功
|
||||
- **功能**: 从调度器中移除指定任务
|
||||
|
||||
### 4. 获取单个任务信息
|
||||
```python
|
||||
get_task(task_uuid: str) -> Optional[dict]
|
||||
```
|
||||
- **参数**:
|
||||
- `task_uuid`: 要查询的任务ID
|
||||
- **返回值**: 包含任务信息的字典或None
|
||||
- **功能**: 获取指定任务的详细配置信息
|
||||
|
||||
### 5. 列出所有任务
|
||||
```python
|
||||
list_tasks() -> Dict[str, Dict]
|
||||
```
|
||||
- **返回值**: 字典格式的所有任务信息,键为任务ID
|
||||
- **功能**: 获取当前所有已调度任务的列表
|
||||
|
||||
### 6. 关闭调度器
|
||||
```python
|
||||
shutdown()
|
||||
```
|
||||
- **功能**: 停止调度器运行,释放资源
|
||||
|
||||
## 任务配置参数详解
|
||||
|
||||
### 生效时间类型 (ETimeType)
|
||||
| 值 | 类型 | ETime格式 | 描述 |
|
||||
|----|------|-----------|------|
|
||||
| '1' | 具体时间 | 'YYYY-MM-DD HH:MM:SS' | 在指定时间点后生效 |
|
||||
| '2' | 每日时间 | 'HH:MM:SS' | 每天指定时间后生效 |
|
||||
| '3' | 永久生效 | 无 | 永久生效 |
|
||||
|
||||
### 执行时间类型 (RTimeType)
|
||||
| 值 | 类型 | RTime格式 | 描述 |
|
||||
|----|------|-----------|------|
|
||||
| '1' | 具体时间 | 'YYYY-MM-DD HH:MM:SS' | 在指定时间点执行一次 |
|
||||
| '2' | 每日执行 | 'HH:MM:SS' | 每天固定时间执行 |
|
||||
| '3' | 每周执行 | 'D HH:MM:SS' | 每周特定星期几执行 (1=周一) |
|
||||
| '4' | 每月执行 | 'D HH:MM:SS' | 每月特定日期执行 |
|
||||
| '5' | 间隔执行 | 'HH:MM:SS' | 按固定间隔重复执行 |
|
||||
| '6' | 开机执行 | 无 | 调度器启动时立即执行 |
|
||||
| '7' | 开机延时执行 | 'SS' | 调度器启动时等待一段时间执行 |
|
||||
|
||||
### 失效时间类型 (LTimeType)
|
||||
| 值 | 类型 | LTime格式 | 描述 |
|
||||
|----|------|-----------|------|
|
||||
| '1' | 具体时间 | 'YYYY-MM-DD HH:MM:SS' | 在指定时间点失生效 |
|
||||
| '2' | 每日时间 | 'HH:MM:SS' | 每天指定时间后失效 |
|
||||
| '3' | 永久生效 | 无 | 不会失效 |
|
||||
|
||||
### 其他参数
|
||||
- `TaskName`: 任务名称(可选)
|
||||
- `TaskUUID`: 任务ID(可选,不提供会自动生成)
|
||||
- `RCode`: 要执行的代码内容
|
||||
- `RType`: 代码类型(Python/Shell等,直接提交给回调,不由调度器处理)
|
||||
|
||||
## 使用流程示例
|
||||
|
||||
1. 初始化调度器
|
||||
2. 准备任务配置字典
|
||||
3. 调用`add_task()`添加任务
|
||||
4. (可选)使用`list_tasks()`查看任务
|
||||
5. (可选)使用`remove_task()`删除任务
|
||||
6. 程序结束时调用`shutdown()`关闭调度器
|
||||
|
||||
## 注意事项
|
||||
|
||||
注意除调度器外还有一个task_dict用于存储所有的task_data,格式{"UUID": task_data},task_data也有相同的UUID,还有是否生效的标志working_status。
|
||||
|
||||
1. 所有时间都使用UTF-8时区(东八区)。
|
||||
2. 任务ID(TaskUUID)必须唯一,不提供会自动生成。
|
||||
3. 开机执行的任务(RTimeType='6')会立即执行,会被添加到调度器中,但是被设置为失效。
|
||||
4. 调度器使用后台线程,主程序需要保持运行状态才能执行定时任务
|
||||
5. 注意任务完成和失效后不要从调度器中移除任务,而是将属性设置为失效。
|
||||
6. 如果是2345时间类型的任务则不可能失效。
|
||||
7. 生效时间3和执行时间6还有失效时间3可以没有ETime和RTime和LTime(或者可以任意填写)。
|
||||
8. 生效时间类型的优先级低于失效时间优先级,也就是即使生效时间为永久生效,如果设置了具体时间失效仍然会失效
|
||||
9. 如果添加出错,允许返回错误信息,以便用户定位问题
|
||||
|
||||
使用以下作为示例
|
||||
1:
|
||||
'ETimeType': '3',
|
||||
'RTimeType': '6',
|
||||
'LTimeType': '1',
|
||||
'LTime': '2025-05-18 03:16:00',
|
||||
'RCode': 'print("HI")',
|
||||
'TaskName': 'HI'
|
||||
正常情况下这个示例由于已经过失效时间而被视为失效,会添加但是被设置为失效因此无法执行
|
||||
|
||||
2:
|
||||
'ETimeType': '3',
|
||||
'RTimeType': '6',
|
||||
'LTimeType': '1',
|
||||
'LTime': '2025-05-18 04:10:00',
|
||||
'RCode': 'print("HI")',
|
||||
'TaskName': 'HI'
|
||||
正常情况下这个示例由于还没过失效时间而不被视为失效,会在添加的同时被执行
|
||||
|
||||
3:
|
||||
'ETimeType': '1',
|
||||
'ETime': '2025-05-18 07:20:40',
|
||||
'RTimeType': '1',
|
||||
'RTime': '2025-05-18 07:20:50',
|
||||
'LTimeType': '1',
|
||||
'LTime': '2025-05-18 07:25:00',
|
||||
'RCode': 'print("HI")',
|
||||
'TaskName': 'HI_Expired'
|
||||
正常情况下这个示例由于还没到生效时间因此不被执行,但是仍然有效,因此到达生效时间和执行时间后才会执行,执行后会被设置为失效,执行前一直有效但不执行
|
||||
但是注意,到达生效时间后不会立刻执行,而是继续等到执行时间才会继续执行,因此任务会在生效时间生效,并在执行时间执行,然后根据类型被选择是否设置为失效
|
||||
如果未到达生效时间不应当被判断为失效,应当使用调度器设置在到达生效时间后自动生效,并在符合执行时间时执行!!!
|
||||
如果未到达生效时间不应当被判断为失效,应当使用调度器设置在到达生效时间后自动生效,并在符合执行时间时执行!!!
|
||||
如果未到达生效时间不应当被判断为失效,应当使用调度器设置在到达生效时间后自动生效,并在符合执行时间时执行!!!
|
||||
如果未到达生效时间不应当被判断为失效,应当使用调度器设置在到达生效时间后自动生效,并在符合执行时间时执行!!!
|
||||
如果未到达生效时间不应当被判断为失效,应当使用调度器设置在到达生效时间后自动生效,并在符合执行时间时执行!!!
|
||||
|
||||
|
||||
4:
|
||||
'ETimeType': '1',
|
||||
'ETime': '2025-05-18 07:20:40',
|
||||
'RTimeType': '6',
|
||||
'LTimeType': '1',
|
||||
'LTime': '2025-05-18 07:25:00',
|
||||
'RCode': 'print("HI")',
|
||||
'TaskName': 'HI_Expired'
|
||||
该任务会在到达生效时间后立即执行,因为RTimeType为6开机执行,执行后会被设置为失效,如果当前时间超过失效时间后则不会执行,直接判断为失效"""
|
||||
+371
-371
@@ -1,372 +1,372 @@
|
||||
import uuid
|
||||
import pytz
|
||||
import logging
|
||||
from datetime import datetime, timedelta
|
||||
from apscheduler.schedulers.background import BackgroundScheduler
|
||||
from apscheduler.triggers.date import DateTrigger
|
||||
from apscheduler.triggers.cron import CronTrigger
|
||||
from apscheduler.triggers.interval import IntervalTrigger
|
||||
|
||||
class TaskScheduler:
|
||||
def __init__(self, ExecuteCallBack=None):
|
||||
# 设置时区为UTC-8
|
||||
self.timezone = pytz.timezone('Asia/Shanghai')
|
||||
# 初始化调度器
|
||||
self.scheduler = BackgroundScheduler(timezone=self.timezone)
|
||||
self.scheduler.start()
|
||||
# 任务数据存储
|
||||
self.task_dict = {}
|
||||
# 设置默认回调函数
|
||||
self.ExecuteCallBack = ExecuteCallBack or (lambda x, y, z: exec(y))
|
||||
# 配置日志
|
||||
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
||||
self.logger = logging.getLogger('TaskScheduler')
|
||||
|
||||
def add_task(self, task_data: dict) -> bool:
|
||||
"""添加新任务到调度器"""
|
||||
try:
|
||||
# 验证任务数据完整性
|
||||
required_fields = ['ETimeType', 'RTimeType', 'LTimeType', 'RCode']
|
||||
for field in required_fields:
|
||||
if field not in task_data:
|
||||
raise ValueError(f"缺少必要字段: {field}")
|
||||
|
||||
# 处理TaskUUID,没有则生成
|
||||
task_uuid = task_data.get('TaskUUID', str(uuid.uuid4()))
|
||||
if task_uuid in self.task_dict:
|
||||
raise ValueError(f"任务ID已存在: {task_uuid}")
|
||||
|
||||
# 处理时间类型和时间值
|
||||
self._validate_time_fields(task_data)
|
||||
|
||||
# 准备完整的任务数据
|
||||
full_task_data = {
|
||||
'TaskUUID': task_uuid,
|
||||
'TaskName': task_data.get('TaskName', f"Task_{task_uuid[:8]}"),
|
||||
'ETimeType': task_data['ETimeType'],
|
||||
'ETime': task_data.get('ETime'),
|
||||
'RTimeType': task_data['RTimeType'],
|
||||
'RTime': task_data.get('RTime'),
|
||||
'LTimeType': task_data['LTimeType'],
|
||||
'LTime': task_data.get('LTime'),
|
||||
'RCode': task_data['RCode'],
|
||||
'RType': task_data.get('RType', 'Python'),
|
||||
'working_status': False, # 默认任务未激活
|
||||
'apscheduler_job_id': None,
|
||||
'creation_time': datetime.now(self.timezone).strftime('%Y-%m-%d %H:%M:%S')
|
||||
}
|
||||
|
||||
# 检查任务是否应该生效
|
||||
if self._should_task_be_active(full_task_data):
|
||||
full_task_data['working_status'] = True
|
||||
# 添加到调度器
|
||||
self._schedule_task(full_task_data)
|
||||
else:
|
||||
self.logger.info(f"任务 {task_uuid} 已添加但当前未激活")
|
||||
|
||||
# 保存任务数据
|
||||
self.task_dict[task_uuid] = full_task_data
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"添加任务失败: {str(e)}")
|
||||
return False
|
||||
|
||||
def remove_task(self, task_uuid: str) -> bool:
|
||||
"""从调度器中移除任务"""
|
||||
try:
|
||||
if task_uuid not in self.task_dict:
|
||||
return False
|
||||
|
||||
task_data = self.task_dict[task_uuid]
|
||||
|
||||
# 如果任务在调度器中,移除它
|
||||
if task_data['apscheduler_job_id'] and self.scheduler.get_job(task_data['apscheduler_job_id']):
|
||||
self.scheduler.remove_job(task_data['apscheduler_job_id'])
|
||||
|
||||
# 从任务字典中删除
|
||||
del self.task_dict[task_uuid]
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"移除任务失败: {str(e)}")
|
||||
return False
|
||||
|
||||
def get_task(self, task_uuid: str) -> dict:
|
||||
"""获取单个任务信息"""
|
||||
return self.task_dict.get(task_uuid)
|
||||
|
||||
def list_tasks(self) -> dict:
|
||||
"""列出所有任务"""
|
||||
return self.task_dict.copy()
|
||||
|
||||
def shutdown(self):
|
||||
"""关闭调度器"""
|
||||
self.scheduler.shutdown()
|
||||
|
||||
def _validate_time_fields(self, task_data):
|
||||
"""验证时间字段的有效性"""
|
||||
# 验证生效时间
|
||||
if task_data['ETimeType'] == '1': # 具体时间
|
||||
if not task_data.get('ETime'):
|
||||
raise ValueError("ETimeType为1时需要提供ETime")
|
||||
self._parse_datetime(task_data['ETime'])
|
||||
elif task_data['ETimeType'] == '2': # 每日时间
|
||||
if not task_data.get('ETime'):
|
||||
raise ValueError("ETimeType为2时需要提供ETime")
|
||||
self._parse_time(task_data['ETime'])
|
||||
elif task_data['ETimeType'] != '3': # 永久生效
|
||||
raise ValueError("无效的ETimeType值")
|
||||
|
||||
# 验证执行时间
|
||||
if task_data['RTimeType'] in ['1', '6', '7']: # 具体时间/开机执行/开机延时执行
|
||||
if task_data['RTimeType'] == '1' and not task_data.get('RTime'):
|
||||
raise ValueError("RTimeType为1时需要提供RTime")
|
||||
if task_data['RTimeType'] == '1':
|
||||
self._parse_datetime(task_data['RTime'])
|
||||
if task_data['RTimeType'] == '7' and not task_data.get('RTime'):
|
||||
raise ValueError("RTimeType为7时需要提供RTime")
|
||||
elif task_data['RTimeType'] in ['2', '3', '4', '5']: # 每日/每周/每月/间隔执行
|
||||
if not task_data.get('RTime'):
|
||||
raise ValueError(f"RTimeType为{task_data['RTimeType']}时需要提供RTime")
|
||||
if task_data['RTimeType'] == '2': # 每日执行
|
||||
self._parse_time(task_data['RTime'])
|
||||
elif task_data['RTimeType'] == '3': # 每周执行
|
||||
parts = task_data['RTime'].split(' ', 1)
|
||||
if len(parts) != 2:
|
||||
raise ValueError("RTimeType为3时RTime格式应为'D HH:MM:SS'")
|
||||
day, time_str = parts
|
||||
if not day.isdigit() or int(day) not in range(1, 8):
|
||||
raise ValueError("RTimeType为3时星期几必须是1-7之间的数字")
|
||||
self._parse_time(time_str)
|
||||
elif task_data['RTimeType'] == '4': # 每月执行
|
||||
parts = task_data['RTime'].split(' ', 1)
|
||||
if len(parts) != 2:
|
||||
raise ValueError("RTimeType为4时RTime格式应为'D HH:MM:SS'")
|
||||
day, time_str = parts
|
||||
if not day.isdigit() or int(day) not in range(1, 32):
|
||||
raise ValueError("RTimeType为4时日期必须是1-31之间的数字")
|
||||
self._parse_time(time_str)
|
||||
elif task_data['RTimeType'] == '5': # 间隔执行
|
||||
self._parse_time(task_data['RTime'])
|
||||
else:
|
||||
raise ValueError("无效的RTimeType值")
|
||||
|
||||
# 验证失效时间
|
||||
if task_data['LTimeType'] == '1': # 具体时间
|
||||
if not task_data.get('LTime'):
|
||||
raise ValueError("LTimeType为1时需要提供LTime")
|
||||
self._parse_datetime(task_data['LTime'])
|
||||
elif task_data['LTimeType'] == '2': # 每日时间
|
||||
if not task_data.get('LTime'):
|
||||
raise ValueError("LTimeType为2时需要提供LTime")
|
||||
self._parse_time(task_data['LTime'])
|
||||
elif task_data['LTimeType'] != '3': # 永久生效
|
||||
raise ValueError("无效的LTimeType值")
|
||||
|
||||
def _should_task_be_active(self, task_data):
|
||||
"""判断任务是否应该处于激活状态"""
|
||||
now = datetime.now(self.timezone)
|
||||
|
||||
# 检查失效时间
|
||||
if task_data['LTimeType'] == '1': # 具体时间失效
|
||||
ltime = self._parse_datetime(task_data['LTime'])
|
||||
if now > ltime:
|
||||
return False
|
||||
elif task_data['LTimeType'] == '2': # 每日时间失效
|
||||
time_obj = self._parse_time(task_data['LTime'])
|
||||
ltime_today = datetime.combine(now.date(), time_obj.time())
|
||||
ltime_today = self.timezone.localize(ltime_today)
|
||||
if now > ltime_today:
|
||||
return False
|
||||
|
||||
# 检查生效时间
|
||||
if task_data['ETimeType'] == '1': # 具体时间生效
|
||||
etime = self._parse_datetime(task_data['ETime'])
|
||||
if now < etime:
|
||||
return False
|
||||
elif task_data['ETimeType'] == '2': # 每日时间生效
|
||||
time_obj = self._parse_time(task_data['ETime'])
|
||||
etime_today = datetime.combine(now.date(), time_obj.time())
|
||||
etime_today = self.timezone.localize(etime_today)
|
||||
if now < etime_today:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def _schedule_task(self, task_data):
|
||||
"""将任务添加到调度器"""
|
||||
try:
|
||||
job_id = task_data['TaskUUID']
|
||||
task_name = task_data['TaskName']
|
||||
rcode = task_data['RCode']
|
||||
rtype = task_data['RType']
|
||||
|
||||
# 根据执行时间类型创建不同的触发器
|
||||
if task_data['RTimeType'] == '1': # 具体时间执行
|
||||
run_date = self._parse_datetime(task_data['RTime'])
|
||||
trigger = DateTrigger(run_date=run_date, timezone=self.timezone)
|
||||
elif task_data['RTimeType'] == '2': # 每日执行
|
||||
time_parts = task_data['RTime'].split(':')
|
||||
hour, minute, second = map(int, time_parts)
|
||||
trigger = CronTrigger(hour=hour, minute=minute, second=second, timezone=self.timezone)
|
||||
elif task_data['RTimeType'] == '3': # 每周执行
|
||||
day, time_str = task_data['RTime'].split(' ', 1)
|
||||
time_parts = time_str.split(':')
|
||||
hour, minute, second = map(int, time_parts)
|
||||
# 转换为APScheduler的星期格式 (0-6)
|
||||
day_of_week = str(int(day) - 1)
|
||||
trigger = CronTrigger(day_of_week=day_of_week, hour=hour, minute=minute, second=second, timezone=self.timezone)
|
||||
elif task_data['RTimeType'] == '4': # 每月执行
|
||||
day, time_str = task_data['RTime'].split(' ', 1)
|
||||
time_parts = time_str.split(':')
|
||||
hour, minute, second = map(int, time_parts)
|
||||
trigger = CronTrigger(day=day, hour=hour, minute=minute, second=second, timezone=self.timezone)
|
||||
elif task_data['RTimeType'] == '5': # 间隔执行
|
||||
time_parts = task_data['RTime'].split(':')
|
||||
hours = int(time_parts[0])
|
||||
minutes = int(time_parts[1])
|
||||
seconds = int(time_parts[2])
|
||||
total_seconds = hours * 3600 + minutes * 60 + seconds
|
||||
trigger = IntervalTrigger(seconds=total_seconds, timezone=self.timezone)
|
||||
elif task_data['RTimeType'] == '6': # 开机执行
|
||||
# 立即执行一次
|
||||
self._execute_task(task_data)
|
||||
# 但不添加到调度器中,因为这种任务只执行一次
|
||||
return
|
||||
elif task_data['RTimeType'] == '7': # 开机延时执行
|
||||
seconds = int(task_data['RTime'])
|
||||
run_date = datetime.now(self.timezone) + timedelta(seconds=seconds)
|
||||
trigger = DateTrigger(run_date=run_date, timezone=self.timezone)
|
||||
else:
|
||||
raise ValueError(f"不支持的RTimeType: {task_data['RTimeType']}")
|
||||
|
||||
# 添加任务到调度器
|
||||
self.scheduler.add_job(
|
||||
func=self._execute_task_wrapper,
|
||||
trigger=trigger,
|
||||
args=[task_data],
|
||||
id=job_id,
|
||||
name=task_name,
|
||||
misfire_grace_time=3600 # 错过执行的宽限期(秒)
|
||||
)
|
||||
|
||||
# 记录任务ID
|
||||
task_data['apscheduler_job_id'] = job_id
|
||||
self.logger.info(f"任务 {job_id} 已调度")
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"调度任务失败: {str(e)}")
|
||||
# 如果调度失败,确保任务状态为未激活
|
||||
task_data['working_status'] = False
|
||||
|
||||
def _execute_task_wrapper(self, task_data):
|
||||
"""任务执行包装器,检查任务是否应该执行"""
|
||||
if self._should_task_be_active(task_data):
|
||||
self._execute_task(task_data)
|
||||
else:
|
||||
self.logger.info(f"任务 {task_data['TaskUUID']} 已失效,不执行")
|
||||
|
||||
def _execute_task(self, task_data):
|
||||
"""执行任务的实际方法"""
|
||||
try:
|
||||
self.logger.info(f"执行任务: {task_data['TaskName']} ({task_data['TaskUUID']})")
|
||||
# 调用回调函数执行任务代码
|
||||
self.ExecuteCallBack(task_data['TaskUUID'], task_data['RCode'], task_data['RType'])
|
||||
except Exception as e:
|
||||
self.logger.error(f"执行任务失败: {str(e)}")
|
||||
|
||||
def _parse_datetime(self, datetime_str):
|
||||
"""解析日期时间字符串"""
|
||||
try:
|
||||
# 尝试解析带时区的格式
|
||||
dt = datetime.fromisoformat(datetime_str.replace('Z', '+00:00'))
|
||||
# 如果没有时区信息,添加本地时区
|
||||
if dt.tzinfo is None:
|
||||
dt = self.timezone.localize(dt)
|
||||
return dt
|
||||
except ValueError:
|
||||
# 尝试常见的日期时间格式
|
||||
for fmt in ('%Y-%m-%d %H:%M:%S', '%Y-%m-%dT%H:%M:%S', '%Y-%m-%d %H:%M:%S.%f'):
|
||||
try:
|
||||
dt = datetime.strptime(datetime_str, fmt)
|
||||
return self.timezone.localize(dt)
|
||||
except ValueError:
|
||||
pass
|
||||
raise ValueError(f"无法解析日期时间: {datetime_str}")
|
||||
|
||||
def _parse_time(self, time_str):
|
||||
"""解析时间字符串"""
|
||||
try:
|
||||
time_obj = datetime.strptime(time_str, '%H:%M:%S')
|
||||
return time_obj
|
||||
except ValueError:
|
||||
raise ValueError(f"无法解析时间: {time_str},格式应为'HH:MM:SS'")
|
||||
|
||||
# 继续对其测试,今天一定完成.idea里的任务!
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
"""
|
||||
### 生效时间类型 (ETimeType)
|
||||
| 值 | 类型 | ETime格式 | 描述 |
|
||||
|----|------|-----------|------|
|
||||
| '1' | 具体时间 | 'YYYY-MM-DD HH:MM:SS' | 在指定时间点后生效 |
|
||||
| '2' | 每日时间 | 'HH:MM:SS' | 每天指定时间后生效 |
|
||||
| '3' | 永久生效 | 无 | 永久生效 |
|
||||
|
||||
### 执行时间类型 (RTimeType)
|
||||
| 值 | 类型 | RTime格式 | 描述 |
|
||||
|----|------|-----------|------|
|
||||
| '1' | 具体时间 | 'YYYY-MM-DD HH:MM:SS' | 在指定时间点执行一次 |
|
||||
| '2' | 每日执行 | 'HH:MM:SS' | 每天固定时间执行 |
|
||||
| '3' | 每周执行 | 'D HH:MM:SS' | 每周特定星期几执行 (1=周一) |
|
||||
| '4' | 每月执行 | 'D HH:MM:SS' | 每月特定日期执行 |
|
||||
| '5' | 间隔执行 | 'HH:MM:SS' | 按固定间隔重复执行 |
|
||||
| '6' | 开机执行 | 无 | 调度器启动时立即执行 |
|
||||
| '7' | 开机延时执行 | 'SS' | 调度器启动时等待一段时间执行 |
|
||||
|
||||
### 失效时间类型 (LTimeType)
|
||||
| 值 | 类型 | LTime格式 | 描述 |
|
||||
|----|------|-----------|------|
|
||||
| '1' | 具体时间 | 'YYYY-MM-DD HH:MM:SS' | 在指定时间点失生效 |
|
||||
| '2' | 每日时间 | 'HH:MM:SS' | 每天指定时间后失效 |
|
||||
| '3' | 永久生效 | 无 | 不会失效 |"""
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# 示例使用
|
||||
if __name__ == "__main__":
|
||||
# 创建调度器实例
|
||||
scheduler = TaskScheduler()
|
||||
|
||||
task1 = {
|
||||
'ETimeType': '1',
|
||||
'ETime': '2025-05-18 07:20:40',
|
||||
'RTimeType': '6',
|
||||
'RTime': '2025-05-18 07:22:50',
|
||||
'LTimeType': '1',
|
||||
'LTime': '2025-05-18 07:25:00',
|
||||
'RCode': 'print("HI")',
|
||||
'TaskName': 'HI_Expired'
|
||||
}
|
||||
|
||||
# 添加任务
|
||||
scheduler.add_task(task1)
|
||||
|
||||
# 列出所有任务
|
||||
print("\n所有任务:")
|
||||
for task_id, task in scheduler.list_tasks().items():
|
||||
print(f"ID: {task_id}, 名称: {task['TaskName']}, 状态: {'激活' if task['working_status'] else '未激活'}")
|
||||
|
||||
# 保持主程序运行
|
||||
try:
|
||||
while True:
|
||||
pass
|
||||
except KeyboardInterrupt:
|
||||
scheduler.shutdown()
|
||||
import uuid
|
||||
import pytz
|
||||
import logging
|
||||
from datetime import datetime, timedelta
|
||||
from apscheduler.schedulers.background import BackgroundScheduler
|
||||
from apscheduler.triggers.date import DateTrigger
|
||||
from apscheduler.triggers.cron import CronTrigger
|
||||
from apscheduler.triggers.interval import IntervalTrigger
|
||||
|
||||
class TaskScheduler:
|
||||
def __init__(self, ExecuteCallBack=None):
|
||||
# 设置时区为UTC-8
|
||||
self.timezone = pytz.timezone('Asia/Shanghai')
|
||||
# 初始化调度器
|
||||
self.scheduler = BackgroundScheduler(timezone=self.timezone)
|
||||
self.scheduler.start()
|
||||
# 任务数据存储
|
||||
self.task_dict = {}
|
||||
# 设置默认回调函数
|
||||
self.ExecuteCallBack = ExecuteCallBack or (lambda x, y, z: exec(y))
|
||||
# 配置日志
|
||||
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
||||
self.logger = logging.getLogger('TaskScheduler')
|
||||
|
||||
def add_task(self, task_data: dict) -> bool:
|
||||
"""添加新任务到调度器"""
|
||||
try:
|
||||
# 验证任务数据完整性
|
||||
required_fields = ['ETimeType', 'RTimeType', 'LTimeType', 'RCode']
|
||||
for field in required_fields:
|
||||
if field not in task_data:
|
||||
raise ValueError(f"缺少必要字段: {field}")
|
||||
|
||||
# 处理TaskUUID,没有则生成
|
||||
task_uuid = task_data.get('TaskUUID', str(uuid.uuid4()))
|
||||
if task_uuid in self.task_dict:
|
||||
raise ValueError(f"任务ID已存在: {task_uuid}")
|
||||
|
||||
# 处理时间类型和时间值
|
||||
self._validate_time_fields(task_data)
|
||||
|
||||
# 准备完整的任务数据
|
||||
full_task_data = {
|
||||
'TaskUUID': task_uuid,
|
||||
'TaskName': task_data.get('TaskName', f"Task_{task_uuid[:8]}"),
|
||||
'ETimeType': task_data['ETimeType'],
|
||||
'ETime': task_data.get('ETime'),
|
||||
'RTimeType': task_data['RTimeType'],
|
||||
'RTime': task_data.get('RTime'),
|
||||
'LTimeType': task_data['LTimeType'],
|
||||
'LTime': task_data.get('LTime'),
|
||||
'RCode': task_data['RCode'],
|
||||
'RType': task_data.get('RType', 'Python'),
|
||||
'working_status': False, # 默认任务未激活
|
||||
'apscheduler_job_id': None,
|
||||
'creation_time': datetime.now(self.timezone).strftime('%Y-%m-%d %H:%M:%S')
|
||||
}
|
||||
|
||||
# 检查任务是否应该生效
|
||||
if self._should_task_be_active(full_task_data):
|
||||
full_task_data['working_status'] = True
|
||||
# 添加到调度器
|
||||
self._schedule_task(full_task_data)
|
||||
else:
|
||||
self.logger.info(f"任务 {task_uuid} 已添加但当前未激活")
|
||||
|
||||
# 保存任务数据
|
||||
self.task_dict[task_uuid] = full_task_data
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"添加任务失败: {str(e)}")
|
||||
return False
|
||||
|
||||
def remove_task(self, task_uuid: str) -> bool:
|
||||
"""从调度器中移除任务"""
|
||||
try:
|
||||
if task_uuid not in self.task_dict:
|
||||
return False
|
||||
|
||||
task_data = self.task_dict[task_uuid]
|
||||
|
||||
# 如果任务在调度器中,移除它
|
||||
if task_data['apscheduler_job_id'] and self.scheduler.get_job(task_data['apscheduler_job_id']):
|
||||
self.scheduler.remove_job(task_data['apscheduler_job_id'])
|
||||
|
||||
# 从任务字典中删除
|
||||
del self.task_dict[task_uuid]
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"移除任务失败: {str(e)}")
|
||||
return False
|
||||
|
||||
def get_task(self, task_uuid: str) -> dict:
|
||||
"""获取单个任务信息"""
|
||||
return self.task_dict.get(task_uuid)
|
||||
|
||||
def list_tasks(self) -> dict:
|
||||
"""列出所有任务"""
|
||||
return self.task_dict.copy()
|
||||
|
||||
def shutdown(self):
|
||||
"""关闭调度器"""
|
||||
self.scheduler.shutdown()
|
||||
|
||||
def _validate_time_fields(self, task_data):
|
||||
"""验证时间字段的有效性"""
|
||||
# 验证生效时间
|
||||
if task_data['ETimeType'] == '1': # 具体时间
|
||||
if not task_data.get('ETime'):
|
||||
raise ValueError("ETimeType为1时需要提供ETime")
|
||||
self._parse_datetime(task_data['ETime'])
|
||||
elif task_data['ETimeType'] == '2': # 每日时间
|
||||
if not task_data.get('ETime'):
|
||||
raise ValueError("ETimeType为2时需要提供ETime")
|
||||
self._parse_time(task_data['ETime'])
|
||||
elif task_data['ETimeType'] != '3': # 永久生效
|
||||
raise ValueError("无效的ETimeType值")
|
||||
|
||||
# 验证执行时间
|
||||
if task_data['RTimeType'] in ['1', '6', '7']: # 具体时间/开机执行/开机延时执行
|
||||
if task_data['RTimeType'] == '1' and not task_data.get('RTime'):
|
||||
raise ValueError("RTimeType为1时需要提供RTime")
|
||||
if task_data['RTimeType'] == '1':
|
||||
self._parse_datetime(task_data['RTime'])
|
||||
if task_data['RTimeType'] == '7' and not task_data.get('RTime'):
|
||||
raise ValueError("RTimeType为7时需要提供RTime")
|
||||
elif task_data['RTimeType'] in ['2', '3', '4', '5']: # 每日/每周/每月/间隔执行
|
||||
if not task_data.get('RTime'):
|
||||
raise ValueError(f"RTimeType为{task_data['RTimeType']}时需要提供RTime")
|
||||
if task_data['RTimeType'] == '2': # 每日执行
|
||||
self._parse_time(task_data['RTime'])
|
||||
elif task_data['RTimeType'] == '3': # 每周执行
|
||||
parts = task_data['RTime'].split(' ', 1)
|
||||
if len(parts) != 2:
|
||||
raise ValueError("RTimeType为3时RTime格式应为'D HH:MM:SS'")
|
||||
day, time_str = parts
|
||||
if not day.isdigit() or int(day) not in range(1, 8):
|
||||
raise ValueError("RTimeType为3时星期几必须是1-7之间的数字")
|
||||
self._parse_time(time_str)
|
||||
elif task_data['RTimeType'] == '4': # 每月执行
|
||||
parts = task_data['RTime'].split(' ', 1)
|
||||
if len(parts) != 2:
|
||||
raise ValueError("RTimeType为4时RTime格式应为'D HH:MM:SS'")
|
||||
day, time_str = parts
|
||||
if not day.isdigit() or int(day) not in range(1, 32):
|
||||
raise ValueError("RTimeType为4时日期必须是1-31之间的数字")
|
||||
self._parse_time(time_str)
|
||||
elif task_data['RTimeType'] == '5': # 间隔执行
|
||||
self._parse_time(task_data['RTime'])
|
||||
else:
|
||||
raise ValueError("无效的RTimeType值")
|
||||
|
||||
# 验证失效时间
|
||||
if task_data['LTimeType'] == '1': # 具体时间
|
||||
if not task_data.get('LTime'):
|
||||
raise ValueError("LTimeType为1时需要提供LTime")
|
||||
self._parse_datetime(task_data['LTime'])
|
||||
elif task_data['LTimeType'] == '2': # 每日时间
|
||||
if not task_data.get('LTime'):
|
||||
raise ValueError("LTimeType为2时需要提供LTime")
|
||||
self._parse_time(task_data['LTime'])
|
||||
elif task_data['LTimeType'] != '3': # 永久生效
|
||||
raise ValueError("无效的LTimeType值")
|
||||
|
||||
def _should_task_be_active(self, task_data):
|
||||
"""判断任务是否应该处于激活状态"""
|
||||
now = datetime.now(self.timezone)
|
||||
|
||||
# 检查失效时间
|
||||
if task_data['LTimeType'] == '1': # 具体时间失效
|
||||
ltime = self._parse_datetime(task_data['LTime'])
|
||||
if now > ltime:
|
||||
return False
|
||||
elif task_data['LTimeType'] == '2': # 每日时间失效
|
||||
time_obj = self._parse_time(task_data['LTime'])
|
||||
ltime_today = datetime.combine(now.date(), time_obj.time())
|
||||
ltime_today = self.timezone.localize(ltime_today)
|
||||
if now > ltime_today:
|
||||
return False
|
||||
|
||||
# 检查生效时间
|
||||
if task_data['ETimeType'] == '1': # 具体时间生效
|
||||
etime = self._parse_datetime(task_data['ETime'])
|
||||
if now < etime:
|
||||
return False
|
||||
elif task_data['ETimeType'] == '2': # 每日时间生效
|
||||
time_obj = self._parse_time(task_data['ETime'])
|
||||
etime_today = datetime.combine(now.date(), time_obj.time())
|
||||
etime_today = self.timezone.localize(etime_today)
|
||||
if now < etime_today:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def _schedule_task(self, task_data):
|
||||
"""将任务添加到调度器"""
|
||||
try:
|
||||
job_id = task_data['TaskUUID']
|
||||
task_name = task_data['TaskName']
|
||||
rcode = task_data['RCode']
|
||||
rtype = task_data['RType']
|
||||
|
||||
# 根据执行时间类型创建不同的触发器
|
||||
if task_data['RTimeType'] == '1': # 具体时间执行
|
||||
run_date = self._parse_datetime(task_data['RTime'])
|
||||
trigger = DateTrigger(run_date=run_date, timezone=self.timezone)
|
||||
elif task_data['RTimeType'] == '2': # 每日执行
|
||||
time_parts = task_data['RTime'].split(':')
|
||||
hour, minute, second = map(int, time_parts)
|
||||
trigger = CronTrigger(hour=hour, minute=minute, second=second, timezone=self.timezone)
|
||||
elif task_data['RTimeType'] == '3': # 每周执行
|
||||
day, time_str = task_data['RTime'].split(' ', 1)
|
||||
time_parts = time_str.split(':')
|
||||
hour, minute, second = map(int, time_parts)
|
||||
# 转换为APScheduler的星期格式 (0-6)
|
||||
day_of_week = str(int(day) - 1)
|
||||
trigger = CronTrigger(day_of_week=day_of_week, hour=hour, minute=minute, second=second, timezone=self.timezone)
|
||||
elif task_data['RTimeType'] == '4': # 每月执行
|
||||
day, time_str = task_data['RTime'].split(' ', 1)
|
||||
time_parts = time_str.split(':')
|
||||
hour, minute, second = map(int, time_parts)
|
||||
trigger = CronTrigger(day=day, hour=hour, minute=minute, second=second, timezone=self.timezone)
|
||||
elif task_data['RTimeType'] == '5': # 间隔执行
|
||||
time_parts = task_data['RTime'].split(':')
|
||||
hours = int(time_parts[0])
|
||||
minutes = int(time_parts[1])
|
||||
seconds = int(time_parts[2])
|
||||
total_seconds = hours * 3600 + minutes * 60 + seconds
|
||||
trigger = IntervalTrigger(seconds=total_seconds, timezone=self.timezone)
|
||||
elif task_data['RTimeType'] == '6': # 开机执行
|
||||
# 立即执行一次
|
||||
self._execute_task(task_data)
|
||||
# 但不添加到调度器中,因为这种任务只执行一次
|
||||
return
|
||||
elif task_data['RTimeType'] == '7': # 开机延时执行
|
||||
seconds = int(task_data['RTime'])
|
||||
run_date = datetime.now(self.timezone) + timedelta(seconds=seconds)
|
||||
trigger = DateTrigger(run_date=run_date, timezone=self.timezone)
|
||||
else:
|
||||
raise ValueError(f"不支持的RTimeType: {task_data['RTimeType']}")
|
||||
|
||||
# 添加任务到调度器
|
||||
self.scheduler.add_job(
|
||||
func=self._execute_task_wrapper,
|
||||
trigger=trigger,
|
||||
args=[task_data],
|
||||
id=job_id,
|
||||
name=task_name,
|
||||
misfire_grace_time=3600 # 错过执行的宽限期(秒)
|
||||
)
|
||||
|
||||
# 记录任务ID
|
||||
task_data['apscheduler_job_id'] = job_id
|
||||
self.logger.info(f"任务 {job_id} 已调度")
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"调度任务失败: {str(e)}")
|
||||
# 如果调度失败,确保任务状态为未激活
|
||||
task_data['working_status'] = False
|
||||
|
||||
def _execute_task_wrapper(self, task_data):
|
||||
"""任务执行包装器,检查任务是否应该执行"""
|
||||
if self._should_task_be_active(task_data):
|
||||
self._execute_task(task_data)
|
||||
else:
|
||||
self.logger.info(f"任务 {task_data['TaskUUID']} 已失效,不执行")
|
||||
|
||||
def _execute_task(self, task_data):
|
||||
"""执行任务的实际方法"""
|
||||
try:
|
||||
self.logger.info(f"执行任务: {task_data['TaskName']} ({task_data['TaskUUID']})")
|
||||
# 调用回调函数执行任务代码
|
||||
self.ExecuteCallBack(task_data['TaskUUID'], task_data['RCode'], task_data['RType'])
|
||||
except Exception as e:
|
||||
self.logger.error(f"执行任务失败: {str(e)}")
|
||||
|
||||
def _parse_datetime(self, datetime_str):
|
||||
"""解析日期时间字符串"""
|
||||
try:
|
||||
# 尝试解析带时区的格式
|
||||
dt = datetime.fromisoformat(datetime_str.replace('Z', '+00:00'))
|
||||
# 如果没有时区信息,添加本地时区
|
||||
if dt.tzinfo is None:
|
||||
dt = self.timezone.localize(dt)
|
||||
return dt
|
||||
except ValueError:
|
||||
# 尝试常见的日期时间格式
|
||||
for fmt in ('%Y-%m-%d %H:%M:%S', '%Y-%m-%dT%H:%M:%S', '%Y-%m-%d %H:%M:%S.%f'):
|
||||
try:
|
||||
dt = datetime.strptime(datetime_str, fmt)
|
||||
return self.timezone.localize(dt)
|
||||
except ValueError:
|
||||
pass
|
||||
raise ValueError(f"无法解析日期时间: {datetime_str}")
|
||||
|
||||
def _parse_time(self, time_str):
|
||||
"""解析时间字符串"""
|
||||
try:
|
||||
time_obj = datetime.strptime(time_str, '%H:%M:%S')
|
||||
return time_obj
|
||||
except ValueError:
|
||||
raise ValueError(f"无法解析时间: {time_str},格式应为'HH:MM:SS'")
|
||||
|
||||
# 继续对其测试,今天一定完成.idea里的任务!
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
"""
|
||||
### 生效时间类型 (ETimeType)
|
||||
| 值 | 类型 | ETime格式 | 描述 |
|
||||
|----|------|-----------|------|
|
||||
| '1' | 具体时间 | 'YYYY-MM-DD HH:MM:SS' | 在指定时间点后生效 |
|
||||
| '2' | 每日时间 | 'HH:MM:SS' | 每天指定时间后生效 |
|
||||
| '3' | 永久生效 | 无 | 永久生效 |
|
||||
|
||||
### 执行时间类型 (RTimeType)
|
||||
| 值 | 类型 | RTime格式 | 描述 |
|
||||
|----|------|-----------|------|
|
||||
| '1' | 具体时间 | 'YYYY-MM-DD HH:MM:SS' | 在指定时间点执行一次 |
|
||||
| '2' | 每日执行 | 'HH:MM:SS' | 每天固定时间执行 |
|
||||
| '3' | 每周执行 | 'D HH:MM:SS' | 每周特定星期几执行 (1=周一) |
|
||||
| '4' | 每月执行 | 'D HH:MM:SS' | 每月特定日期执行 |
|
||||
| '5' | 间隔执行 | 'HH:MM:SS' | 按固定间隔重复执行 |
|
||||
| '6' | 开机执行 | 无 | 调度器启动时立即执行 |
|
||||
| '7' | 开机延时执行 | 'SS' | 调度器启动时等待一段时间执行 |
|
||||
|
||||
### 失效时间类型 (LTimeType)
|
||||
| 值 | 类型 | LTime格式 | 描述 |
|
||||
|----|------|-----------|------|
|
||||
| '1' | 具体时间 | 'YYYY-MM-DD HH:MM:SS' | 在指定时间点失生效 |
|
||||
| '2' | 每日时间 | 'HH:MM:SS' | 每天指定时间后失效 |
|
||||
| '3' | 永久生效 | 无 | 不会失效 |"""
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# 示例使用
|
||||
if __name__ == "__main__":
|
||||
# 创建调度器实例
|
||||
scheduler = TaskScheduler()
|
||||
|
||||
task1 = {
|
||||
'ETimeType': '1',
|
||||
'ETime': '2025-05-18 07:20:40',
|
||||
'RTimeType': '6',
|
||||
'RTime': '2025-05-18 07:22:50',
|
||||
'LTimeType': '1',
|
||||
'LTime': '2025-05-18 07:25:00',
|
||||
'RCode': 'print("HI")',
|
||||
'TaskName': 'HI_Expired'
|
||||
}
|
||||
|
||||
# 添加任务
|
||||
scheduler.add_task(task1)
|
||||
|
||||
# 列出所有任务
|
||||
print("\n所有任务:")
|
||||
for task_id, task in scheduler.list_tasks().items():
|
||||
print(f"ID: {task_id}, 名称: {task['TaskName']}, 状态: {'激活' if task['working_status'] else '未激活'}")
|
||||
|
||||
# 保持主程序运行
|
||||
try:
|
||||
while True:
|
||||
pass
|
||||
except KeyboardInterrupt:
|
||||
scheduler.shutdown()
|
||||
print("\n调度器已关闭")
|
||||
+270
-270
@@ -1,271 +1,271 @@
|
||||
import uuid
|
||||
import pytz
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Dict, Optional, Callable, Any
|
||||
from apscheduler.schedulers.background import BackgroundScheduler
|
||||
from apscheduler.triggers.date import DateTrigger
|
||||
from apscheduler.triggers.cron import CronTrigger
|
||||
from apscheduler.triggers.interval import IntervalTrigger
|
||||
from apscheduler.job import Job
|
||||
|
||||
class TaskScheduler:
|
||||
def __init__(self, ExecuteCallBack: Callable[[str, str, str], Any] = lambda x, y, z: exec(y)):
|
||||
"""
|
||||
初始化调度器
|
||||
|
||||
参数:
|
||||
ExecuteCallBack: 任务执行时的回调函数,默认为直接执行Python代码
|
||||
"""
|
||||
self.scheduler = BackgroundScheduler(timezone=pytz.timezone('Asia/Shanghai')) # UTC+8时区
|
||||
self.task_dict: Dict[str, Dict] = {} # 存储所有任务数据
|
||||
self.ExecuteCallBack = ExecuteCallBack
|
||||
self.scheduler.start()
|
||||
|
||||
def _generate_uuid(self) -> str:
|
||||
"""生成唯一任务ID"""
|
||||
return str(uuid.uuid4())
|
||||
|
||||
def _parse_time(self, time_str: str, time_format: str) -> datetime:
|
||||
"""解析时间字符串为datetime对象"""
|
||||
return datetime.strptime(time_str, time_format).replace(tzinfo=pytz.timezone('Asia/Shanghai'))
|
||||
|
||||
def _get_trigger(self, task_data: Dict) -> Any:
|
||||
"""根据任务数据获取对应的触发器"""
|
||||
rtime_type = task_data['RTimeType']
|
||||
now = datetime.now(pytz.timezone('Asia/Shanghai'))
|
||||
|
||||
if rtime_type == '1': # 具体时间执行一次
|
||||
run_time = self._parse_time(task_data['RTime'], '%Y-%m-%d %H:%M:%S')
|
||||
return DateTrigger(run_date=run_time)
|
||||
|
||||
elif rtime_type == '2': # 每日固定时间执行
|
||||
hour, minute, second = map(int, task_data['RTime'].split(':'))
|
||||
return CronTrigger(hour=hour, minute=minute, second=second, timezone='Asia/Shanghai')
|
||||
|
||||
elif rtime_type == '3': # 每周特定星期几执行
|
||||
day_of_week, time_part = task_data['RTime'].split(' ', 1)
|
||||
hour, minute, second = map(int, time_part.split(':'))
|
||||
return CronTrigger(day_of_week=day_of_week, hour=hour, minute=minute, second=second, timezone='Asia/Shanghai')
|
||||
|
||||
elif rtime_type == '4': # 每月特定日期执行
|
||||
day, time_part = task_data['RTime'].split(' ', 1)
|
||||
hour, minute, second = map(int, time_part.split(':'))
|
||||
return CronTrigger(day=day, hour=hour, minute=minute, second=second, timezone='Asia/Shanghai')
|
||||
|
||||
elif rtime_type == '5': # 固定间隔执行
|
||||
hours, minutes, seconds = map(int, task_data['RTime'].split(':'))
|
||||
delta = timedelta(hours=hours, minutes=minutes, seconds=seconds)
|
||||
return IntervalTrigger(seconds=delta.total_seconds(), timezone='Asia/Shanghai')
|
||||
|
||||
elif rtime_type == '6': # 开机立即执行
|
||||
return DateTrigger(run_date=now)
|
||||
|
||||
elif rtime_type == '7': # 开机延时执行
|
||||
seconds = int(task_data['RTime'])
|
||||
return DateTrigger(run_date=now + timedelta(seconds=seconds))
|
||||
|
||||
else:
|
||||
raise ValueError(f"未知的执行时间类型: {rtime_type}")
|
||||
|
||||
def _check_task_valid(self, task_data: Dict) -> bool:
|
||||
"""检查任务是否有效(未过期)"""
|
||||
now = datetime.now(pytz.timezone('Asia/Shanghai'))
|
||||
|
||||
# 检查生效时间
|
||||
etime_type = task_data['ETimeType']
|
||||
if etime_type == '1': # 具体时间生效
|
||||
effective_time = self._parse_time(task_data['ETime'], '%Y-%m-%d %H:%M:%S')
|
||||
if now < effective_time:
|
||||
return False
|
||||
elif etime_type == '2': # 每日时间生效
|
||||
effective_time = self._parse_time(task_data['ETime'], '%H:%M:%S')
|
||||
now_time = now.time()
|
||||
if now_time < effective_time.time():
|
||||
return False
|
||||
|
||||
# 检查失效时间
|
||||
ltime_type = task_data['LTimeType']
|
||||
if ltime_type == '1': # 具体时间失效
|
||||
expire_time = self._parse_time(task_data['LTime'], '%Y-%m-%d %H:%M:%S')
|
||||
if now >= expire_time:
|
||||
return False
|
||||
elif ltime_type == '2': # 每日时间失效
|
||||
expire_time = self._parse_time(task_data['LTime'], '%H:%M:%S')
|
||||
now_time = now.time()
|
||||
if now_time >= expire_time.time():
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def _execute_task(self, task_uuid: str):
|
||||
"""执行任务的实际函数"""
|
||||
task_data = self.task_dict.get(task_uuid)
|
||||
if not task_data:
|
||||
return
|
||||
|
||||
# 检查任务是否仍然有效
|
||||
if not self._check_task_valid(task_data):
|
||||
task_data['working_status'] = False
|
||||
return
|
||||
|
||||
# 执行回调
|
||||
try:
|
||||
self.ExecuteCallBack(task_uuid, task_data['RCode'], task_data.get('RType', ''))
|
||||
except Exception as e:
|
||||
print(f"执行任务 {task_uuid} 时出错: {str(e)}")
|
||||
|
||||
# 如果是一次性任务,执行后设置为失效
|
||||
if task_data['RTimeType'] in ['1', '6', '7']:
|
||||
task_data['working_status'] = False
|
||||
|
||||
def add_task(self, task_data: Dict) -> bool:
|
||||
"""
|
||||
添加任务到调度器
|
||||
|
||||
参数:
|
||||
task_data: 包含任务配置的字典
|
||||
|
||||
返回值:
|
||||
bool: 是否添加成功
|
||||
"""
|
||||
try:
|
||||
# 验证必要字段
|
||||
required_fields = ['ETimeType', 'RTimeType', 'LTimeType', 'RCode']
|
||||
for field in required_fields:
|
||||
if field not in task_data:
|
||||
raise ValueError(f"缺少必要字段: {field}")
|
||||
|
||||
# 生成或使用提供的任务ID
|
||||
task_uuid = task_data.get('TaskUUID', self._generate_uuid())
|
||||
task_data['TaskUUID'] = task_uuid
|
||||
|
||||
# 设置任务初始状态
|
||||
task_data['working_status'] = self._check_task_valid(task_data)
|
||||
|
||||
# 如果任务已经失效,不添加到调度器
|
||||
if not task_data['working_status']:
|
||||
self.task_dict[task_uuid] = task_data
|
||||
return True
|
||||
|
||||
# 获取触发器
|
||||
trigger = self._get_trigger(task_data)
|
||||
|
||||
# 添加到调度器
|
||||
job = self.scheduler.add_job(
|
||||
self._execute_task,
|
||||
trigger=trigger,
|
||||
args=[task_uuid],
|
||||
id=task_uuid
|
||||
)
|
||||
|
||||
# 存储任务数据
|
||||
self.task_dict[task_uuid] = task_data
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"添加任务失败: {str(e)}")
|
||||
return False
|
||||
|
||||
def remove_task(self, task_uuid: str) -> bool:
|
||||
"""
|
||||
从调度器中移除任务
|
||||
|
||||
参数:
|
||||
task_uuid: 要移除的任务ID
|
||||
|
||||
返回值:
|
||||
bool: 是否移除成功
|
||||
"""
|
||||
if task_uuid not in self.task_dict:
|
||||
return False
|
||||
|
||||
# 从调度器中移除
|
||||
self.scheduler.remove_job(task_uuid)
|
||||
|
||||
# 从任务字典中移除
|
||||
del self.task_dict[task_uuid]
|
||||
return True
|
||||
|
||||
def get_task(self, task_uuid: str) -> Optional[Dict]:
|
||||
"""
|
||||
获取单个任务信息
|
||||
|
||||
参数:
|
||||
task_uuid: 要查询的任务ID
|
||||
|
||||
返回值:
|
||||
dict: 包含任务信息的字典或None
|
||||
"""
|
||||
return self.task_dict.get(task_uuid)
|
||||
|
||||
def list_tasks(self) -> Dict[str, Dict]:
|
||||
"""
|
||||
列出所有任务
|
||||
|
||||
返回值:
|
||||
dict: 所有任务信息的字典,键为任务ID
|
||||
"""
|
||||
return self.task_dict.copy()
|
||||
|
||||
def shutdown(self):
|
||||
"""停止调度器运行,释放资源"""
|
||||
self.scheduler.shutdown(wait=True)
|
||||
|
||||
# 示例使用
|
||||
if __name__ == "__main__":
|
||||
# 初始化调度器
|
||||
scheduler = TaskScheduler()
|
||||
|
||||
# 示例1: 已过期的任务
|
||||
task1 = {
|
||||
'ETimeType': '3',
|
||||
'RTimeType': '6',
|
||||
'LTimeType': '1',
|
||||
'LTime': '2025-05-18 03:16:00',
|
||||
'RCode': 'print("HI from task1")',
|
||||
'TaskName': 'HI'
|
||||
}
|
||||
scheduler.add_task(task1)
|
||||
|
||||
# 示例2: 未过期的任务(会立即执行)
|
||||
task2 = {
|
||||
'ETimeType': '3',
|
||||
'RTimeType': '6',
|
||||
'LTimeType': '1',
|
||||
'LTime': '2025-05-18 09:10:00',
|
||||
'RCode': 'print("HI from task2")',
|
||||
'TaskName': 'HI'
|
||||
}
|
||||
scheduler.add_task(task2)
|
||||
|
||||
# 示例3: 未到生效时间的任务
|
||||
task3 = {
|
||||
'ETimeType': '1',
|
||||
'ETime': '2025-05-18 09:29:10',
|
||||
'RTimeType': '1',
|
||||
'RTime': '2025-05-18 09:29:20',
|
||||
'LTimeType': '1',
|
||||
'LTime': '2025-05-18 09:30:00',
|
||||
'RCode': 'print("HI from task3")',
|
||||
'TaskName': 'HI_Expired'
|
||||
}
|
||||
scheduler.add_task(task3)
|
||||
|
||||
# 示例4: 到达生效时间后立即执行的任务
|
||||
task4 = {
|
||||
'ETimeType': '1',
|
||||
'ETime': '2025-05-18 07:20:40',
|
||||
'RTimeType': '6',
|
||||
'LTimeType': '1',
|
||||
'LTime': '2025-05-18 07:25:00',
|
||||
'RCode': 'print("HI from task4")',
|
||||
'TaskName': 'HI_Expired'
|
||||
}
|
||||
scheduler.add_task(task4)
|
||||
|
||||
# 保持程序运行
|
||||
try:
|
||||
while True:
|
||||
pass
|
||||
except KeyboardInterrupt:
|
||||
import uuid
|
||||
import pytz
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Dict, Optional, Callable, Any
|
||||
from apscheduler.schedulers.background import BackgroundScheduler
|
||||
from apscheduler.triggers.date import DateTrigger
|
||||
from apscheduler.triggers.cron import CronTrigger
|
||||
from apscheduler.triggers.interval import IntervalTrigger
|
||||
from apscheduler.job import Job
|
||||
|
||||
class TaskScheduler:
|
||||
def __init__(self, ExecuteCallBack: Callable[[str, str, str], Any] = lambda x, y, z: exec(y)):
|
||||
"""
|
||||
初始化调度器
|
||||
|
||||
参数:
|
||||
ExecuteCallBack: 任务执行时的回调函数,默认为直接执行Python代码
|
||||
"""
|
||||
self.scheduler = BackgroundScheduler(timezone=pytz.timezone('Asia/Shanghai')) # UTC+8时区
|
||||
self.task_dict: Dict[str, Dict] = {} # 存储所有任务数据
|
||||
self.ExecuteCallBack = ExecuteCallBack
|
||||
self.scheduler.start()
|
||||
|
||||
def _generate_uuid(self) -> str:
|
||||
"""生成唯一任务ID"""
|
||||
return str(uuid.uuid4())
|
||||
|
||||
def _parse_time(self, time_str: str, time_format: str) -> datetime:
|
||||
"""解析时间字符串为datetime对象"""
|
||||
return datetime.strptime(time_str, time_format).replace(tzinfo=pytz.timezone('Asia/Shanghai'))
|
||||
|
||||
def _get_trigger(self, task_data: Dict) -> Any:
|
||||
"""根据任务数据获取对应的触发器"""
|
||||
rtime_type = task_data['RTimeType']
|
||||
now = datetime.now(pytz.timezone('Asia/Shanghai'))
|
||||
|
||||
if rtime_type == '1': # 具体时间执行一次
|
||||
run_time = self._parse_time(task_data['RTime'], '%Y-%m-%d %H:%M:%S')
|
||||
return DateTrigger(run_date=run_time)
|
||||
|
||||
elif rtime_type == '2': # 每日固定时间执行
|
||||
hour, minute, second = map(int, task_data['RTime'].split(':'))
|
||||
return CronTrigger(hour=hour, minute=minute, second=second, timezone='Asia/Shanghai')
|
||||
|
||||
elif rtime_type == '3': # 每周特定星期几执行
|
||||
day_of_week, time_part = task_data['RTime'].split(' ', 1)
|
||||
hour, minute, second = map(int, time_part.split(':'))
|
||||
return CronTrigger(day_of_week=day_of_week, hour=hour, minute=minute, second=second, timezone='Asia/Shanghai')
|
||||
|
||||
elif rtime_type == '4': # 每月特定日期执行
|
||||
day, time_part = task_data['RTime'].split(' ', 1)
|
||||
hour, minute, second = map(int, time_part.split(':'))
|
||||
return CronTrigger(day=day, hour=hour, minute=minute, second=second, timezone='Asia/Shanghai')
|
||||
|
||||
elif rtime_type == '5': # 固定间隔执行
|
||||
hours, minutes, seconds = map(int, task_data['RTime'].split(':'))
|
||||
delta = timedelta(hours=hours, minutes=minutes, seconds=seconds)
|
||||
return IntervalTrigger(seconds=delta.total_seconds(), timezone='Asia/Shanghai')
|
||||
|
||||
elif rtime_type == '6': # 开机立即执行
|
||||
return DateTrigger(run_date=now)
|
||||
|
||||
elif rtime_type == '7': # 开机延时执行
|
||||
seconds = int(task_data['RTime'])
|
||||
return DateTrigger(run_date=now + timedelta(seconds=seconds))
|
||||
|
||||
else:
|
||||
raise ValueError(f"未知的执行时间类型: {rtime_type}")
|
||||
|
||||
def _check_task_valid(self, task_data: Dict) -> bool:
|
||||
"""检查任务是否有效(未过期)"""
|
||||
now = datetime.now(pytz.timezone('Asia/Shanghai'))
|
||||
|
||||
# 检查生效时间
|
||||
etime_type = task_data['ETimeType']
|
||||
if etime_type == '1': # 具体时间生效
|
||||
effective_time = self._parse_time(task_data['ETime'], '%Y-%m-%d %H:%M:%S')
|
||||
if now < effective_time:
|
||||
return False
|
||||
elif etime_type == '2': # 每日时间生效
|
||||
effective_time = self._parse_time(task_data['ETime'], '%H:%M:%S')
|
||||
now_time = now.time()
|
||||
if now_time < effective_time.time():
|
||||
return False
|
||||
|
||||
# 检查失效时间
|
||||
ltime_type = task_data['LTimeType']
|
||||
if ltime_type == '1': # 具体时间失效
|
||||
expire_time = self._parse_time(task_data['LTime'], '%Y-%m-%d %H:%M:%S')
|
||||
if now >= expire_time:
|
||||
return False
|
||||
elif ltime_type == '2': # 每日时间失效
|
||||
expire_time = self._parse_time(task_data['LTime'], '%H:%M:%S')
|
||||
now_time = now.time()
|
||||
if now_time >= expire_time.time():
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def _execute_task(self, task_uuid: str):
|
||||
"""执行任务的实际函数"""
|
||||
task_data = self.task_dict.get(task_uuid)
|
||||
if not task_data:
|
||||
return
|
||||
|
||||
# 检查任务是否仍然有效
|
||||
if not self._check_task_valid(task_data):
|
||||
task_data['working_status'] = False
|
||||
return
|
||||
|
||||
# 执行回调
|
||||
try:
|
||||
self.ExecuteCallBack(task_uuid, task_data['RCode'], task_data.get('RType', ''))
|
||||
except Exception as e:
|
||||
print(f"执行任务 {task_uuid} 时出错: {str(e)}")
|
||||
|
||||
# 如果是一次性任务,执行后设置为失效
|
||||
if task_data['RTimeType'] in ['1', '6', '7']:
|
||||
task_data['working_status'] = False
|
||||
|
||||
def add_task(self, task_data: Dict) -> bool:
|
||||
"""
|
||||
添加任务到调度器
|
||||
|
||||
参数:
|
||||
task_data: 包含任务配置的字典
|
||||
|
||||
返回值:
|
||||
bool: 是否添加成功
|
||||
"""
|
||||
try:
|
||||
# 验证必要字段
|
||||
required_fields = ['ETimeType', 'RTimeType', 'LTimeType', 'RCode']
|
||||
for field in required_fields:
|
||||
if field not in task_data:
|
||||
raise ValueError(f"缺少必要字段: {field}")
|
||||
|
||||
# 生成或使用提供的任务ID
|
||||
task_uuid = task_data.get('TaskUUID', self._generate_uuid())
|
||||
task_data['TaskUUID'] = task_uuid
|
||||
|
||||
# 设置任务初始状态
|
||||
task_data['working_status'] = self._check_task_valid(task_data)
|
||||
|
||||
# 如果任务已经失效,不添加到调度器
|
||||
if not task_data['working_status']:
|
||||
self.task_dict[task_uuid] = task_data
|
||||
return True
|
||||
|
||||
# 获取触发器
|
||||
trigger = self._get_trigger(task_data)
|
||||
|
||||
# 添加到调度器
|
||||
job = self.scheduler.add_job(
|
||||
self._execute_task,
|
||||
trigger=trigger,
|
||||
args=[task_uuid],
|
||||
id=task_uuid
|
||||
)
|
||||
|
||||
# 存储任务数据
|
||||
self.task_dict[task_uuid] = task_data
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"添加任务失败: {str(e)}")
|
||||
return False
|
||||
|
||||
def remove_task(self, task_uuid: str) -> bool:
|
||||
"""
|
||||
从调度器中移除任务
|
||||
|
||||
参数:
|
||||
task_uuid: 要移除的任务ID
|
||||
|
||||
返回值:
|
||||
bool: 是否移除成功
|
||||
"""
|
||||
if task_uuid not in self.task_dict:
|
||||
return False
|
||||
|
||||
# 从调度器中移除
|
||||
self.scheduler.remove_job(task_uuid)
|
||||
|
||||
# 从任务字典中移除
|
||||
del self.task_dict[task_uuid]
|
||||
return True
|
||||
|
||||
def get_task(self, task_uuid: str) -> Optional[Dict]:
|
||||
"""
|
||||
获取单个任务信息
|
||||
|
||||
参数:
|
||||
task_uuid: 要查询的任务ID
|
||||
|
||||
返回值:
|
||||
dict: 包含任务信息的字典或None
|
||||
"""
|
||||
return self.task_dict.get(task_uuid)
|
||||
|
||||
def list_tasks(self) -> Dict[str, Dict]:
|
||||
"""
|
||||
列出所有任务
|
||||
|
||||
返回值:
|
||||
dict: 所有任务信息的字典,键为任务ID
|
||||
"""
|
||||
return self.task_dict.copy()
|
||||
|
||||
def shutdown(self):
|
||||
"""停止调度器运行,释放资源"""
|
||||
self.scheduler.shutdown(wait=True)
|
||||
|
||||
# 示例使用
|
||||
if __name__ == "__main__":
|
||||
# 初始化调度器
|
||||
scheduler = TaskScheduler()
|
||||
|
||||
# 示例1: 已过期的任务
|
||||
task1 = {
|
||||
'ETimeType': '3',
|
||||
'RTimeType': '6',
|
||||
'LTimeType': '1',
|
||||
'LTime': '2025-05-18 03:16:00',
|
||||
'RCode': 'print("HI from task1")',
|
||||
'TaskName': 'HI'
|
||||
}
|
||||
scheduler.add_task(task1)
|
||||
|
||||
# 示例2: 未过期的任务(会立即执行)
|
||||
task2 = {
|
||||
'ETimeType': '3',
|
||||
'RTimeType': '6',
|
||||
'LTimeType': '1',
|
||||
'LTime': '2025-05-18 09:10:00',
|
||||
'RCode': 'print("HI from task2")',
|
||||
'TaskName': 'HI'
|
||||
}
|
||||
scheduler.add_task(task2)
|
||||
|
||||
# 示例3: 未到生效时间的任务
|
||||
task3 = {
|
||||
'ETimeType': '1',
|
||||
'ETime': '2025-05-18 09:29:10',
|
||||
'RTimeType': '1',
|
||||
'RTime': '2025-05-18 09:29:20',
|
||||
'LTimeType': '1',
|
||||
'LTime': '2025-05-18 09:30:00',
|
||||
'RCode': 'print("HI from task3")',
|
||||
'TaskName': 'HI_Expired'
|
||||
}
|
||||
scheduler.add_task(task3)
|
||||
|
||||
# 示例4: 到达生效时间后立即执行的任务
|
||||
task4 = {
|
||||
'ETimeType': '1',
|
||||
'ETime': '2025-05-18 07:20:40',
|
||||
'RTimeType': '6',
|
||||
'LTimeType': '1',
|
||||
'LTime': '2025-05-18 07:25:00',
|
||||
'RCode': 'print("HI from task4")',
|
||||
'TaskName': 'HI_Expired'
|
||||
}
|
||||
scheduler.add_task(task4)
|
||||
|
||||
# 保持程序运行
|
||||
try:
|
||||
while True:
|
||||
pass
|
||||
except KeyboardInterrupt:
|
||||
scheduler.shutdown()
|
||||
+41
-41
@@ -1,41 +1,41 @@
|
||||
import subprocess
|
||||
|
||||
|
||||
class Command:
|
||||
def __init__(self, cmd):
|
||||
self.cmd = cmd
|
||||
#startupinfo = None
|
||||
#if sys.platform.startswith('win'):
|
||||
startupinfo = subprocess.STARTUPINFO()
|
||||
startupinfo.dwFlags = subprocess.STARTF_USESHOWWINDOW
|
||||
startupinfo.wShowWindow = subprocess.SW_HIDE
|
||||
creationflags = subprocess.CREATE_NO_WINDOW | subprocess.DETACHED_PROCESS
|
||||
#else:
|
||||
# creationflags = 0
|
||||
self.result = subprocess.run(
|
||||
cmd,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
universal_newlines=True,
|
||||
shell=False,
|
||||
startupinfo=startupinfo,
|
||||
creationflags=creationflags
|
||||
)
|
||||
self.stdout = self.result.stdout
|
||||
self.stderr = self.result.stderr
|
||||
self.returncode = self.result.returncode
|
||||
def __str__(self):
|
||||
return self.stdout
|
||||
def count(self, substring):
|
||||
return self.stdout.count(substring) + self.stderr.count(substring)
|
||||
def ishad(self, items):
|
||||
if not isinstance(items, (list, tuple, set)): items = [items]
|
||||
return any(self.count(item) > 0 for item in items)
|
||||
def successtatus(self):
|
||||
return self.ishad(["success", "successfully", "成功"])
|
||||
|
||||
a=Command("net start 'TProcess'")
|
||||
print(a.successtatus())
|
||||
|
||||
b=Command("net stop 'TProcess'")
|
||||
print(b.successtatus())
|
||||
import subprocess
|
||||
|
||||
|
||||
class Command:
|
||||
def __init__(self, cmd):
|
||||
self.cmd = cmd
|
||||
#startupinfo = None
|
||||
#if sys.platform.startswith('win'):
|
||||
startupinfo = subprocess.STARTUPINFO()
|
||||
startupinfo.dwFlags = subprocess.STARTF_USESHOWWINDOW
|
||||
startupinfo.wShowWindow = subprocess.SW_HIDE
|
||||
creationflags = subprocess.CREATE_NO_WINDOW | subprocess.DETACHED_PROCESS
|
||||
#else:
|
||||
# creationflags = 0
|
||||
self.result = subprocess.run(
|
||||
cmd,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
universal_newlines=True,
|
||||
shell=False,
|
||||
startupinfo=startupinfo,
|
||||
creationflags=creationflags
|
||||
)
|
||||
self.stdout = self.result.stdout
|
||||
self.stderr = self.result.stderr
|
||||
self.returncode = self.result.returncode
|
||||
def __str__(self):
|
||||
return self.stdout
|
||||
def count(self, substring):
|
||||
return self.stdout.count(substring) + self.stderr.count(substring)
|
||||
def ishad(self, items):
|
||||
if not isinstance(items, (list, tuple, set)): items = [items]
|
||||
return any(self.count(item) > 0 for item in items)
|
||||
def successtatus(self):
|
||||
return self.ishad(["success", "successfully", "成功"])
|
||||
|
||||
a=Command("net start 'TProcess'")
|
||||
print(a.successtatus())
|
||||
|
||||
b=Command("net stop 'TProcess'")
|
||||
print(b.successtatus())
|
||||
+16
-16
@@ -1,17 +1,17 @@
|
||||
import time
|
||||
import os
|
||||
|
||||
|
||||
a=time.time()
|
||||
os.system(r"D:\mingw64\bin\clang test.c")
|
||||
b=time.time()
|
||||
|
||||
print("0", b-a)
|
||||
|
||||
def cov(i):
|
||||
a=time.time()
|
||||
os.system(fr"D:\mingw64\bin\clang -mllvm -threads={i} test.c")
|
||||
print(i, time.time()-a)
|
||||
|
||||
for i in range(1, 16+1):
|
||||
import time
|
||||
import os
|
||||
|
||||
|
||||
a=time.time()
|
||||
os.system(r"D:\mingw64\bin\clang test.c")
|
||||
b=time.time()
|
||||
|
||||
print("0", b-a)
|
||||
|
||||
def cov(i):
|
||||
a=time.time()
|
||||
os.system(fr"D:\mingw64\bin\clang -mllvm -threads={i} test.c")
|
||||
print(i, time.time()-a)
|
||||
|
||||
for i in range(1, 16+1):
|
||||
cov(i)
|
||||
+81
-81
@@ -1,82 +1,82 @@
|
||||
尊敬的 ADB-Explorer 团队您好
|
||||
|
||||
我是 TermiNexus (Github: WYT2WYT)。
|
||||
我和我的朋友都是 ADB-Explorer 的用户和爱好者。
|
||||
希望能为本项目贡献一份力量,将文档、UI 界面或其他相关内容翻译成 中文(简体)。
|
||||
|
||||
翻译计划
|
||||
我们期望能够了解到本项目原本的翻译计划,以至于翻译进度。
|
||||
- 1. 范围:我们需要了解您希望优先翻译哪些部分(如 README?、Wiki?、GUI 文本?等)。
|
||||
- 2. 翻译进度:我们需要了解到哪些部分已经被翻译,哪些部分还需要翻译。
|
||||
- 3. 翻译风格: 我们需要了解您希望翻译的风格(如正式、正式但口语化、正式但更有个性亦或菜单式的翻译?)。
|
||||
- 4. 翻译工期: 您需要给我一个具体的工期,适当放松一些,我们可以根据实际情况调整。
|
||||
- 5. 翻译方式: 我们应当翻译 json 文件还是直接翻译 C# 的字符串,或者您给我们一个表单,具体有您决定。
|
||||
- 6. 交流方式: 我们应该如何交流?Microsoft Teams 还是 Discord?
|
||||
|
||||
其他问题
|
||||
- 1. 项目是否有现成的多语言支持框架(如 i18n 文件)?
|
||||
- 2. 是否有翻译风格或术语需要遵循?
|
||||
- 3. 是否有宗教等需要注意的事项?
|
||||
|
||||
希望我们能参与到本项目中,使用户能够更方便地使用 ADB-Explorer。
|
||||
|
||||
祝愿 ADB-Explorer 项目有一个美好的未来!
|
||||
谢谢!祝商祺!
|
||||
|
||||
TermiNexus (Github: WYT2WYT)
|
||||
2025/5/24
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Hello,
|
||||
|
||||
My friend and I are both active users of ADB-Explorer. We would like to contribute to the project by helping translate the documentation, UI elements, and other relevant content into Chinese (Simplified).
|
||||
|
||||
We would be honored to participate in this project to make ADB-Explorer more accessible to Chinese-speaking users.
|
||||
|
||||
Wishing the ADB-Explorer project continued success!
|
||||
Thank you!
|
||||
|
||||
TermiNexus (GitHub: WYT2WYT)
|
||||
May 25, 2025
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
您好,
|
||||
|
||||
我和我的朋友都是 ADB-Explorer 的用户和爱好者。
|
||||
希望能为本项目贡献一份力量,将文档、UI 界面或其他相关内容翻译成 中文(简体)。
|
||||
|
||||
希望我们能参与到本项目中,使中文用户能够更方便地使用 ADB-Explorer。
|
||||
|
||||
祝愿 ADB-Explorer 项目有一个美好的未来!
|
||||
谢谢!
|
||||
|
||||
TermiNexus (Github: WYT2WYT)
|
||||
尊敬的 ADB-Explorer 团队您好
|
||||
|
||||
我是 TermiNexus (Github: WYT2WYT)。
|
||||
我和我的朋友都是 ADB-Explorer 的用户和爱好者。
|
||||
希望能为本项目贡献一份力量,将文档、UI 界面或其他相关内容翻译成 中文(简体)。
|
||||
|
||||
翻译计划
|
||||
我们期望能够了解到本项目原本的翻译计划,以至于翻译进度。
|
||||
- 1. 范围:我们需要了解您希望优先翻译哪些部分(如 README?、Wiki?、GUI 文本?等)。
|
||||
- 2. 翻译进度:我们需要了解到哪些部分已经被翻译,哪些部分还需要翻译。
|
||||
- 3. 翻译风格: 我们需要了解您希望翻译的风格(如正式、正式但口语化、正式但更有个性亦或菜单式的翻译?)。
|
||||
- 4. 翻译工期: 您需要给我一个具体的工期,适当放松一些,我们可以根据实际情况调整。
|
||||
- 5. 翻译方式: 我们应当翻译 json 文件还是直接翻译 C# 的字符串,或者您给我们一个表单,具体有您决定。
|
||||
- 6. 交流方式: 我们应该如何交流?Microsoft Teams 还是 Discord?
|
||||
|
||||
其他问题
|
||||
- 1. 项目是否有现成的多语言支持框架(如 i18n 文件)?
|
||||
- 2. 是否有翻译风格或术语需要遵循?
|
||||
- 3. 是否有宗教等需要注意的事项?
|
||||
|
||||
希望我们能参与到本项目中,使用户能够更方便地使用 ADB-Explorer。
|
||||
|
||||
祝愿 ADB-Explorer 项目有一个美好的未来!
|
||||
谢谢!祝商祺!
|
||||
|
||||
TermiNexus (Github: WYT2WYT)
|
||||
2025/5/24
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Hello,
|
||||
|
||||
My friend and I are both active users of ADB-Explorer. We would like to contribute to the project by helping translate the documentation, UI elements, and other relevant content into Chinese (Simplified).
|
||||
|
||||
We would be honored to participate in this project to make ADB-Explorer more accessible to Chinese-speaking users.
|
||||
|
||||
Wishing the ADB-Explorer project continued success!
|
||||
Thank you!
|
||||
|
||||
TermiNexus (GitHub: WYT2WYT)
|
||||
May 25, 2025
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
您好,
|
||||
|
||||
我和我的朋友都是 ADB-Explorer 的用户和爱好者。
|
||||
希望能为本项目贡献一份力量,将文档、UI 界面或其他相关内容翻译成 中文(简体)。
|
||||
|
||||
希望我们能参与到本项目中,使中文用户能够更方便地使用 ADB-Explorer。
|
||||
|
||||
祝愿 ADB-Explorer 项目有一个美好的未来!
|
||||
谢谢!
|
||||
|
||||
TermiNexus (Github: WYT2WYT)
|
||||
2025/5/24
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
from cx_Freeze import setup, Executable
|
||||
|
||||
|
||||
from cx_Freeze import setup, Executable
|
||||
|
||||
|
||||
setup( name="TestApp", version="4.1.0.114514", description="This is description", executables=[Executable("test.py")], )
|
||||
+92
-92
@@ -1,93 +1,93 @@
|
||||
import subprocess
|
||||
import time
|
||||
import sys
|
||||
import os
|
||||
import platform
|
||||
|
||||
def setup_environment():
|
||||
"""设置编译所需的环境变量"""
|
||||
# 根据操作系统类型设置PATH
|
||||
if platform.system() == "Windows":
|
||||
os.environ["PATH"] = (
|
||||
r"C:\Program Files (x86)\Windows Kits\10\bin\x64;" +
|
||||
r"C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.40.33807\bin\Hostx64\x64;" +
|
||||
r"D:\mingw64\bin;" +
|
||||
os.environ["PATH"]
|
||||
)
|
||||
else:
|
||||
print("警告: 此脚本主要针对Windows环境优化")
|
||||
|
||||
# 设置CFLAGS
|
||||
if "NAV" in sys.argv:
|
||||
os.environ["CFLAGS"] = (
|
||||
r"-march=native -O3 -s -march=native "
|
||||
r"-L 'D:\mingw64\x86_64-w64-mingw32\include' "
|
||||
r"-L 'C:\Users\Lenovo\Desktop\Termination4\TESTWORK\.ENV\Lib\site-packages\nuitka\build\include' "
|
||||
r"-L 'D:\Python312\include' -no-pie"
|
||||
)
|
||||
else:
|
||||
os.environ["CFLAGS"] = (
|
||||
r"-march=native -O0 "
|
||||
r"-L 'D:\mingw64\x86_64-w64-mingw32\include' "
|
||||
r"-L 'C:\Users\Lenovo\Desktop\Termination4\TESTWORK\.ENV\Lib\site-packages\nuitka\build\include' "
|
||||
r"-L 'D:\Python312\include' -no-pie"
|
||||
)
|
||||
|
||||
def get_nuitka_options():
|
||||
"""获取Nuitka编译选项"""
|
||||
options = [
|
||||
"--standalone",
|
||||
"--onefile",
|
||||
"--lto=yes" if "NAV" in sys.argv else "--lto=no",
|
||||
"--show-progress",
|
||||
"--jobs=8",
|
||||
#"--clang",
|
||||
"--mingw64",
|
||||
"--standalone",
|
||||
"--follow-imports",
|
||||
"--debug",
|
||||
"test.py"
|
||||
]
|
||||
|
||||
# 调试模式选项
|
||||
if "DEBUG" in sys.argv:
|
||||
options.extend([
|
||||
"--debug",
|
||||
#"--no-strip",
|
||||
"--verbose"
|
||||
])
|
||||
else:
|
||||
options.extend([
|
||||
"--assume-yes-for-downloads", # 自动确认下载
|
||||
"--remove-output", # 编译前清理输出目录
|
||||
])
|
||||
|
||||
return options
|
||||
|
||||
def run_nuitka_compilation(options):
|
||||
"""运行Nuitka编译过程"""
|
||||
start_time = time.time()
|
||||
print("开始编译...")
|
||||
|
||||
try:
|
||||
# 构建并执行Nuitka命令
|
||||
result = subprocess.run(
|
||||
[r".\.ENV\SCRIPTS\python.exe", "-m", "nuitka"] + options,
|
||||
)
|
||||
|
||||
print("编译成功!")
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"编译失败: {e}")
|
||||
if e.stdout:
|
||||
print(f"错误详情: {e.stdout}")
|
||||
sys.exit(1)
|
||||
except Exception as e:
|
||||
print(f"发生未知错误: {e}")
|
||||
sys.exit(1)
|
||||
finally:
|
||||
print(f"编译耗时: {time.time() - start_time:.2f}秒")
|
||||
|
||||
if __name__ == "__main__":
|
||||
setup_environment()
|
||||
options = get_nuitka_options()
|
||||
import subprocess
|
||||
import time
|
||||
import sys
|
||||
import os
|
||||
import platform
|
||||
|
||||
def setup_environment():
|
||||
"""设置编译所需的环境变量"""
|
||||
# 根据操作系统类型设置PATH
|
||||
if platform.system() == "Windows":
|
||||
os.environ["PATH"] = (
|
||||
r"C:\Program Files (x86)\Windows Kits\10\bin\x64;" +
|
||||
r"C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.40.33807\bin\Hostx64\x64;" +
|
||||
r"D:\mingw64\bin;" +
|
||||
os.environ["PATH"]
|
||||
)
|
||||
else:
|
||||
print("警告: 此脚本主要针对Windows环境优化")
|
||||
|
||||
# 设置CFLAGS
|
||||
if "NAV" in sys.argv:
|
||||
os.environ["CFLAGS"] = (
|
||||
r"-march=native -O3 -s -march=native "
|
||||
r"-L 'D:\mingw64\x86_64-w64-mingw32\include' "
|
||||
r"-L 'C:\Users\Lenovo\Desktop\Termination4\TESTWORK\.ENV\Lib\site-packages\nuitka\build\include' "
|
||||
r"-L 'D:\Python312\include' -no-pie"
|
||||
)
|
||||
else:
|
||||
os.environ["CFLAGS"] = (
|
||||
r"-march=native -O0 "
|
||||
r"-L 'D:\mingw64\x86_64-w64-mingw32\include' "
|
||||
r"-L 'C:\Users\Lenovo\Desktop\Termination4\TESTWORK\.ENV\Lib\site-packages\nuitka\build\include' "
|
||||
r"-L 'D:\Python312\include' -no-pie"
|
||||
)
|
||||
|
||||
def get_nuitka_options():
|
||||
"""获取Nuitka编译选项"""
|
||||
options = [
|
||||
"--standalone",
|
||||
"--onefile",
|
||||
"--lto=yes" if "NAV" in sys.argv else "--lto=no",
|
||||
"--show-progress",
|
||||
"--jobs=8",
|
||||
#"--clang",
|
||||
"--mingw64",
|
||||
"--standalone",
|
||||
"--follow-imports",
|
||||
"--debug",
|
||||
"test.py"
|
||||
]
|
||||
|
||||
# 调试模式选项
|
||||
if "DEBUG" in sys.argv:
|
||||
options.extend([
|
||||
"--debug",
|
||||
#"--no-strip",
|
||||
"--verbose"
|
||||
])
|
||||
else:
|
||||
options.extend([
|
||||
"--assume-yes-for-downloads", # 自动确认下载
|
||||
"--remove-output", # 编译前清理输出目录
|
||||
])
|
||||
|
||||
return options
|
||||
|
||||
def run_nuitka_compilation(options):
|
||||
"""运行Nuitka编译过程"""
|
||||
start_time = time.time()
|
||||
print("开始编译...")
|
||||
|
||||
try:
|
||||
# 构建并执行Nuitka命令
|
||||
result = subprocess.run(
|
||||
[r".\.ENV\SCRIPTS\python.exe", "-m", "nuitka"] + options,
|
||||
)
|
||||
|
||||
print("编译成功!")
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"编译失败: {e}")
|
||||
if e.stdout:
|
||||
print(f"错误详情: {e.stdout}")
|
||||
sys.exit(1)
|
||||
except Exception as e:
|
||||
print(f"发生未知错误: {e}")
|
||||
sys.exit(1)
|
||||
finally:
|
||||
print(f"编译耗时: {time.time() - start_time:.2f}秒")
|
||||
|
||||
if __name__ == "__main__":
|
||||
setup_environment()
|
||||
options = get_nuitka_options()
|
||||
run_nuitka_compilation(options)
|
||||
+70
-70
@@ -1,71 +1,71 @@
|
||||
import code
|
||||
import inspect
|
||||
from pprint import pprint
|
||||
|
||||
class REBLConsole(code.InteractiveConsole):
|
||||
def __init__(self, locals=None):
|
||||
super().__init__(locals)
|
||||
self._breakpoints = set()
|
||||
|
||||
def showsource(self, obj):
|
||||
"""显示对象源代码"""
|
||||
try:
|
||||
lines, start = inspect.getsourcelines(obj)
|
||||
print(f"Source code of {obj.__name__}:")
|
||||
for i, line in enumerate(lines, start):
|
||||
print(f"{i:4d}: {line.rstrip()}")
|
||||
except (TypeError, OSError):
|
||||
print("No source code available")
|
||||
|
||||
def inspect(self, obj):
|
||||
"""检查对象详细信息"""
|
||||
print(f"Inspecting {type(obj).__name__}:")
|
||||
pprint(dir(obj))
|
||||
if callable(obj):
|
||||
print("\nSignature:")
|
||||
print(inspect.signature(obj))
|
||||
|
||||
def add_breakpoint(self, line_no):
|
||||
"""添加断点"""
|
||||
self._breakpoints.add(line_no)
|
||||
print(f"Breakpoint set at line {line_no}")
|
||||
|
||||
def runcode(self, code_obj):
|
||||
"""执行代码并处理断点"""
|
||||
try:
|
||||
exec(code_obj, self.locals)
|
||||
except SystemExit:
|
||||
raise
|
||||
except:
|
||||
self.showtraceback()
|
||||
|
||||
def start_rebl():
|
||||
"""启动REBL环境"""
|
||||
print("Python REBL - Read Eval Break Loop")
|
||||
print("Type 'help' for available commands")
|
||||
|
||||
console = REBLConsole(locals())
|
||||
|
||||
while True:
|
||||
try:
|
||||
code_input = input("rebl> ")
|
||||
|
||||
if code_input.strip() == "help":
|
||||
print("REBL commands:")
|
||||
print(" help - 显示帮助")
|
||||
print(" inspect(obj) - 检查对象")
|
||||
print(" source(obj) - 显示源代码")
|
||||
print(" break(line) - 设置断点")
|
||||
print(" exit - 退出REBL")
|
||||
continue
|
||||
elif code_input.strip() == "exit":
|
||||
break
|
||||
|
||||
console.push(code_input)
|
||||
except KeyboardInterrupt:
|
||||
print("\nKeyboardInterrupt")
|
||||
except EOFError:
|
||||
break
|
||||
|
||||
if __name__ == "__main__":
|
||||
import code
|
||||
import inspect
|
||||
from pprint import pprint
|
||||
|
||||
class REBLConsole(code.InteractiveConsole):
|
||||
def __init__(self, locals=None):
|
||||
super().__init__(locals)
|
||||
self._breakpoints = set()
|
||||
|
||||
def showsource(self, obj):
|
||||
"""显示对象源代码"""
|
||||
try:
|
||||
lines, start = inspect.getsourcelines(obj)
|
||||
print(f"Source code of {obj.__name__}:")
|
||||
for i, line in enumerate(lines, start):
|
||||
print(f"{i:4d}: {line.rstrip()}")
|
||||
except (TypeError, OSError):
|
||||
print("No source code available")
|
||||
|
||||
def inspect(self, obj):
|
||||
"""检查对象详细信息"""
|
||||
print(f"Inspecting {type(obj).__name__}:")
|
||||
pprint(dir(obj))
|
||||
if callable(obj):
|
||||
print("\nSignature:")
|
||||
print(inspect.signature(obj))
|
||||
|
||||
def add_breakpoint(self, line_no):
|
||||
"""添加断点"""
|
||||
self._breakpoints.add(line_no)
|
||||
print(f"Breakpoint set at line {line_no}")
|
||||
|
||||
def runcode(self, code_obj):
|
||||
"""执行代码并处理断点"""
|
||||
try:
|
||||
exec(code_obj, self.locals)
|
||||
except SystemExit:
|
||||
raise
|
||||
except:
|
||||
self.showtraceback()
|
||||
|
||||
def start_rebl():
|
||||
"""启动REBL环境"""
|
||||
print("Python REBL - Read Eval Break Loop")
|
||||
print("Type 'help' for available commands")
|
||||
|
||||
console = REBLConsole(locals())
|
||||
|
||||
while True:
|
||||
try:
|
||||
code_input = input("rebl> ")
|
||||
|
||||
if code_input.strip() == "help":
|
||||
print("REBL commands:")
|
||||
print(" help - 显示帮助")
|
||||
print(" inspect(obj) - 检查对象")
|
||||
print(" source(obj) - 显示源代码")
|
||||
print(" break(line) - 设置断点")
|
||||
print(" exit - 退出REBL")
|
||||
continue
|
||||
elif code_input.strip() == "exit":
|
||||
break
|
||||
|
||||
console.push(code_input)
|
||||
except KeyboardInterrupt:
|
||||
print("\nKeyboardInterrupt")
|
||||
except EOFError:
|
||||
break
|
||||
|
||||
if __name__ == "__main__":
|
||||
start_rebl()
|
||||
+26
-26
@@ -1,27 +1,27 @@
|
||||
import requests
|
||||
import re
|
||||
import json
|
||||
url = 'https://www.bilibili.com/video/BV1jt421c7yN/'
|
||||
cookie = "buvid3=2844B77E-F527-FB05-1DF5-9FDF834AE3E888277infoc; b_nut=1709986388; i-wanna-go-back=-1; b_ut=7; _uuid=6577D687-BED9-9AE2-106A10-551210627F5AC88087infoc; enable_web_push=DISABLE; buvid4=5ED5B3A0-A998-7D47-3815-9AD9A1B27A4989131-024030912-0Fw3r6dKwZLwPoWOl%2F8HuA%3D%3D; CURRENT_FNVAL=4048; rpdid=|(u|Jmkkuukk0J'u~u|ulR~)~; header_theme_version=CLOSE; fingerprint=c27c0b59dd10dcdc4c14701a58f49669; buvid_fp_plain=undefined; buvid_fp=c27c0b59dd10dcdc4c14701a58f49669; LIVE_BUVID=AUTO6217111182462626; FEED_LIVE_VERSION=V_WATCHLATER_PIP_WINDOW3; bp_video_offset_691902317=925084214145056785; DedeUserID=691902317; DedeUserID__ckMd5=ead312019baad7ed; CURRENT_QUALITY=80; bili_ticket=eyJhbGciOiJIUzI1NiIsImtpZCI6InMwMyIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTYwNDM3MDgsImlhdCI6MTcxNTc4NDQ0OCwicGx0IjotMX0.Rdjc9F5oiEXSn_GylRWm3s2L-Pn8GYfyQS5IZt_Y3-8; bili_ticket_expires=1716043648; SESSDATA=3d6f944f%2C1731336513%2C491d2%2A51CjD5jp6zedAz4nQallTN_akUjFzg2LzJhdKMiJbI1nnw2bs5sp8Y09F7Jj4PofjUyfsSVlktMkF0aDRLN196dVNTeWh0czllbFZTWDlidWRpcnFnaENSNVVNbGNFMGR5bFBqYkcwalhuVklyUGJLVHJtYXo3TVpaTENqQ21rS0RPbldWTDUzRFp3IIEC; bili_jct=2975523315e5bccfa606ac286df61f36; home_feed_column=4; browser_resolution=1396-639; sid=6gr3y4l0; PVID=4; bp_t_offset_691902317=932475264446758937; b_lsid=5E9C415B_18F86EC150D"
|
||||
headers = {
|
||||
"Referer": url,
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
|
||||
"Cookie": cookie
|
||||
}
|
||||
response = requests.get(url=url, headers=headers)
|
||||
html = response.text
|
||||
print(html)
|
||||
title = re.findall('title="(.*?)"', html)[0]
|
||||
print(title)
|
||||
info = re.findall('window.__playinfo__=(.*?)</script>', html)[0]
|
||||
json_data = json.loads(info)
|
||||
video_url = json_data['data']['dash']['video'][0]['baseUrl']
|
||||
print(video_url)
|
||||
audio_url = json_data['data']['dash']['audio'][0]['baseUrl']
|
||||
print(audio_url)
|
||||
video_content = requests.get(url=video_url, headers=headers).content
|
||||
audio_content = requests.get(url=audio_url, headers=headers).content
|
||||
with open('video\\' + title + '.mp4', mode='wb') as v:
|
||||
v.write(video_content)
|
||||
with open('video\\' + title + '.mp3', mode='wb') as a:
|
||||
import requests
|
||||
import re
|
||||
import json
|
||||
url = 'https://www.bilibili.com/video/BV1jt421c7yN/'
|
||||
cookie = "buvid3=2844B77E-F527-FB05-1DF5-9FDF834AE3E888277infoc; b_nut=1709986388; i-wanna-go-back=-1; b_ut=7; _uuid=6577D687-BED9-9AE2-106A10-551210627F5AC88087infoc; enable_web_push=DISABLE; buvid4=5ED5B3A0-A998-7D47-3815-9AD9A1B27A4989131-024030912-0Fw3r6dKwZLwPoWOl%2F8HuA%3D%3D; CURRENT_FNVAL=4048; rpdid=|(u|Jmkkuukk0J'u~u|ulR~)~; header_theme_version=CLOSE; fingerprint=c27c0b59dd10dcdc4c14701a58f49669; buvid_fp_plain=undefined; buvid_fp=c27c0b59dd10dcdc4c14701a58f49669; LIVE_BUVID=AUTO6217111182462626; FEED_LIVE_VERSION=V_WATCHLATER_PIP_WINDOW3; bp_video_offset_691902317=925084214145056785; DedeUserID=691902317; DedeUserID__ckMd5=ead312019baad7ed; CURRENT_QUALITY=80; bili_ticket=eyJhbGciOiJIUzI1NiIsImtpZCI6InMwMyIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTYwNDM3MDgsImlhdCI6MTcxNTc4NDQ0OCwicGx0IjotMX0.Rdjc9F5oiEXSn_GylRWm3s2L-Pn8GYfyQS5IZt_Y3-8; bili_ticket_expires=1716043648; SESSDATA=3d6f944f%2C1731336513%2C491d2%2A51CjD5jp6zedAz4nQallTN_akUjFzg2LzJhdKMiJbI1nnw2bs5sp8Y09F7Jj4PofjUyfsSVlktMkF0aDRLN196dVNTeWh0czllbFZTWDlidWRpcnFnaENSNVVNbGNFMGR5bFBqYkcwalhuVklyUGJLVHJtYXo3TVpaTENqQ21rS0RPbldWTDUzRFp3IIEC; bili_jct=2975523315e5bccfa606ac286df61f36; home_feed_column=4; browser_resolution=1396-639; sid=6gr3y4l0; PVID=4; bp_t_offset_691902317=932475264446758937; b_lsid=5E9C415B_18F86EC150D"
|
||||
headers = {
|
||||
"Referer": url,
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
|
||||
"Cookie": cookie
|
||||
}
|
||||
response = requests.get(url=url, headers=headers)
|
||||
html = response.text
|
||||
print(html)
|
||||
title = re.findall('title="(.*?)"', html)[0]
|
||||
print(title)
|
||||
info = re.findall('window.__playinfo__=(.*?)</script>', html)[0]
|
||||
json_data = json.loads(info)
|
||||
video_url = json_data['data']['dash']['video'][0]['baseUrl']
|
||||
print(video_url)
|
||||
audio_url = json_data['data']['dash']['audio'][0]['baseUrl']
|
||||
print(audio_url)
|
||||
video_content = requests.get(url=video_url, headers=headers).content
|
||||
audio_content = requests.get(url=audio_url, headers=headers).content
|
||||
with open('video\\' + title + '.mp4', mode='wb') as v:
|
||||
v.write(video_content)
|
||||
with open('video\\' + title + '.mp3', mode='wb') as a:
|
||||
a.write(audio_content)
|
||||
+51
-51
@@ -1,51 +1,51 @@
|
||||
"""import requests
|
||||
import re
|
||||
import json
|
||||
|
||||
def get_douyin_video_no_watermark(url):
|
||||
try:
|
||||
# 获取重定向后的真实URL
|
||||
headers = {
|
||||
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1'
|
||||
}
|
||||
response = requests.get(url, headers=headers, allow_redirects=False)
|
||||
real_url = response.headers['Location']
|
||||
|
||||
# 从真实URL中提取视频ID
|
||||
video_id = re.findall(r'/video/(\d+)', real_url)[0]
|
||||
print(real_url)
|
||||
|
||||
# 构造API请求URL
|
||||
api_url = f"https://www.iesdouyin.com/web/api/v2/aweme/iteminfo/?item_ids={video_id}"
|
||||
|
||||
# 获取视频信息
|
||||
response = requests.get(api_url, headers=headers)
|
||||
print(response.text)
|
||||
data = json.loads(response.text)
|
||||
|
||||
# 提取无水印视频URL
|
||||
video_url = data['item_list'][0]['video']['play_addr']['url_list'][0]
|
||||
video_url = video_url.replace('playwm', 'play') # 去除水印关键步骤
|
||||
|
||||
return video_url
|
||||
except Exception as e:
|
||||
print(f"发生错误: {e}")
|
||||
return None
|
||||
|
||||
# 使用示例
|
||||
if __name__ == "__main__":
|
||||
share_url = input("请输入抖音分享链接: ")
|
||||
video_url = get_douyin_video_no_watermark(share_url)
|
||||
|
||||
if video_url:
|
||||
print("无水印视频URL:", video_url)
|
||||
# 下载视频
|
||||
print("正在下载视频...")
|
||||
video_data = requests.get(video_url, headers={'User-Agent': 'Mozilla/5.0'}).content
|
||||
with open('douyin_video.mp4', 'wb') as f:
|
||||
f.write(video_data)
|
||||
print("视频已保存为 douyin_video.mp4")
|
||||
else:
|
||||
print("获取视频失败,请检查链接是否正确")
|
||||
|
||||
"""
|
||||
"""import requests
|
||||
import re
|
||||
import json
|
||||
|
||||
def get_douyin_video_no_watermark(url):
|
||||
try:
|
||||
# 获取重定向后的真实URL
|
||||
headers = {
|
||||
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1'
|
||||
}
|
||||
response = requests.get(url, headers=headers, allow_redirects=False)
|
||||
real_url = response.headers['Location']
|
||||
|
||||
# 从真实URL中提取视频ID
|
||||
video_id = re.findall(r'/video/(\d+)', real_url)[0]
|
||||
print(real_url)
|
||||
|
||||
# 构造API请求URL
|
||||
api_url = f"https://www.iesdouyin.com/web/api/v2/aweme/iteminfo/?item_ids={video_id}"
|
||||
|
||||
# 获取视频信息
|
||||
response = requests.get(api_url, headers=headers)
|
||||
print(response.text)
|
||||
data = json.loads(response.text)
|
||||
|
||||
# 提取无水印视频URL
|
||||
video_url = data['item_list'][0]['video']['play_addr']['url_list'][0]
|
||||
video_url = video_url.replace('playwm', 'play') # 去除水印关键步骤
|
||||
|
||||
return video_url
|
||||
except Exception as e:
|
||||
print(f"发生错误: {e}")
|
||||
return None
|
||||
|
||||
# 使用示例
|
||||
if __name__ == "__main__":
|
||||
share_url = input("请输入抖音分享链接: ")
|
||||
video_url = get_douyin_video_no_watermark(share_url)
|
||||
|
||||
if video_url:
|
||||
print("无水印视频URL:", video_url)
|
||||
# 下载视频
|
||||
print("正在下载视频...")
|
||||
video_data = requests.get(video_url, headers={'User-Agent': 'Mozilla/5.0'}).content
|
||||
with open('douyin_video.mp4', 'wb') as f:
|
||||
f.write(video_data)
|
||||
print("视频已保存为 douyin_video.mp4")
|
||||
else:
|
||||
print("获取视频失败,请检查链接是否正确")
|
||||
|
||||
"""
|
||||
+17
-17
@@ -1,18 +1,18 @@
|
||||
from pynput import keyboard, mouse
|
||||
from threading import Thread
|
||||
import time
|
||||
|
||||
|
||||
def on_press(key):
|
||||
print(key.char if hasattr(key, "char") else key)
|
||||
|
||||
def on_click(x, y, button, pressed):
|
||||
action = '按下' if pressed else '释放'
|
||||
print(f'鼠标{button}在({x}, {y}){action}')
|
||||
|
||||
a=Thread(target=lambda: keyboard.Listener(on_press=on_press).start())
|
||||
b=Thread(target=lambda: mouse.Listener(on_click=on_click).start())
|
||||
|
||||
a.start()
|
||||
b.start()
|
||||
from pynput import keyboard, mouse
|
||||
from threading import Thread
|
||||
import time
|
||||
|
||||
|
||||
def on_press(key):
|
||||
print(key.char if hasattr(key, "char") else key)
|
||||
|
||||
def on_click(x, y, button, pressed):
|
||||
action = '按下' if pressed else '释放'
|
||||
print(f'鼠标{button}在({x}, {y}){action}')
|
||||
|
||||
a=Thread(target=lambda: keyboard.Listener(on_press=on_press).start())
|
||||
b=Thread(target=lambda: mouse.Listener(on_click=on_click).start())
|
||||
|
||||
a.start()
|
||||
b.start()
|
||||
time.sleep(100000)
|
||||
+37
-37
@@ -1,38 +1,38 @@
|
||||
import tkinter as tk
|
||||
from tkinter import ttk
|
||||
import webview
|
||||
import threading
|
||||
|
||||
class WebViewApp:
|
||||
def __init__(self):
|
||||
self.root = tk.Tk()
|
||||
self.root.title("Tkinter + PyWebView")
|
||||
self.root.geometry("800x600")
|
||||
|
||||
# 创建容器Frame
|
||||
self.container = ttk.Frame(self.root)
|
||||
self.container.pack(fill=tk.BOTH, expand=True)
|
||||
|
||||
# 在单独线程中启动WebView
|
||||
self.start_webview()
|
||||
|
||||
self.root.mainloop()
|
||||
|
||||
def start_webview(self):
|
||||
def create_webview():
|
||||
window_handle = self.container.winfo_id()
|
||||
webview.create_window(
|
||||
"Embedded Browser",
|
||||
url="https://www.example.com",
|
||||
width=800,
|
||||
height=600,
|
||||
parent=window_handle
|
||||
)
|
||||
webview.start()
|
||||
|
||||
thread = threading.Thread(target=create_webview)
|
||||
thread.daemon = True
|
||||
thread.start()
|
||||
|
||||
if __name__ == "__main__":
|
||||
import tkinter as tk
|
||||
from tkinter import ttk
|
||||
import webview
|
||||
import threading
|
||||
|
||||
class WebViewApp:
|
||||
def __init__(self):
|
||||
self.root = tk.Tk()
|
||||
self.root.title("Tkinter + PyWebView")
|
||||
self.root.geometry("800x600")
|
||||
|
||||
# 创建容器Frame
|
||||
self.container = ttk.Frame(self.root)
|
||||
self.container.pack(fill=tk.BOTH, expand=True)
|
||||
|
||||
# 在单独线程中启动WebView
|
||||
self.start_webview()
|
||||
|
||||
self.root.mainloop()
|
||||
|
||||
def start_webview(self):
|
||||
def create_webview():
|
||||
window_handle = self.container.winfo_id()
|
||||
webview.create_window(
|
||||
"Embedded Browser",
|
||||
url="https://www.example.com",
|
||||
width=800,
|
||||
height=600,
|
||||
parent=window_handle
|
||||
)
|
||||
webview.start()
|
||||
|
||||
thread = threading.Thread(target=create_webview)
|
||||
thread.daemon = True
|
||||
thread.start()
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = WebViewApp()
|
||||
+38
-38
@@ -1,38 +1,38 @@
|
||||
# -*- mode: python ; coding: utf-8 -*-
|
||||
|
||||
|
||||
a = Analysis(
|
||||
['testpywebview.py'],
|
||||
pathex=[],
|
||||
binaries=[],
|
||||
datas=[],
|
||||
hiddenimports=[],
|
||||
hookspath=[],
|
||||
hooksconfig={},
|
||||
runtime_hooks=[],
|
||||
excludes=[],
|
||||
noarchive=False,
|
||||
optimize=0,
|
||||
)
|
||||
pyz = PYZ(a.pure)
|
||||
|
||||
exe = EXE(
|
||||
pyz,
|
||||
a.scripts,
|
||||
a.binaries,
|
||||
a.datas,
|
||||
[],
|
||||
name='testpywebview',
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
upx_exclude=[],
|
||||
runtime_tmpdir=None,
|
||||
console=True,
|
||||
disable_windowed_traceback=False,
|
||||
argv_emulation=False,
|
||||
target_arch=None,
|
||||
codesign_identity=None,
|
||||
entitlements_file=None,
|
||||
)
|
||||
# -*- mode: python ; coding: utf-8 -*-
|
||||
|
||||
|
||||
a = Analysis(
|
||||
['testpywebview.py'],
|
||||
pathex=[],
|
||||
binaries=[],
|
||||
datas=[],
|
||||
hiddenimports=[],
|
||||
hookspath=[],
|
||||
hooksconfig={},
|
||||
runtime_hooks=[],
|
||||
excludes=[],
|
||||
noarchive=False,
|
||||
optimize=0,
|
||||
)
|
||||
pyz = PYZ(a.pure)
|
||||
|
||||
exe = EXE(
|
||||
pyz,
|
||||
a.scripts,
|
||||
a.binaries,
|
||||
a.datas,
|
||||
[],
|
||||
name='testpywebview',
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
upx_exclude=[],
|
||||
runtime_tmpdir=None,
|
||||
console=True,
|
||||
disable_windowed_traceback=False,
|
||||
argv_emulation=False,
|
||||
target_arch=None,
|
||||
codesign_identity=None,
|
||||
entitlements_file=None,
|
||||
)
|
||||
+41
-41
@@ -1,42 +1,42 @@
|
||||
import os
|
||||
|
||||
def ReadFileRangeFromEnd(FilePath, StartLineFromEnd, EndLineFromEnd, BufferSize=1024 * 10, ReturnType=str):
|
||||
if StartLineFromEnd < 1 or EndLineFromEnd < 1:
|
||||
raise ValueError("Line number must be greater than 0")
|
||||
if StartLineFromEnd > EndLineFromEnd:
|
||||
raise ValueError("StartLineFromEnd must be less than or equal to EndLineFromEnd")
|
||||
LineCount = EndLineFromEnd
|
||||
BufferSize = BufferSize * LineCount
|
||||
with open(FilePath, 'rb') as FileObj:
|
||||
FileObj.seek(0, 2)
|
||||
FileSize = FileObj.tell()
|
||||
BufferSize = min(BufferSize, FileSize)
|
||||
Lines = []
|
||||
CurrentPosition = FileSize
|
||||
FoundLines = 0
|
||||
while CurrentPosition > 0 and FoundLines < LineCount:
|
||||
ReadPosition = max(0, CurrentPosition - BufferSize)
|
||||
ChunkSize = CurrentPosition - ReadPosition
|
||||
FileObj.seek(ReadPosition)
|
||||
Chunk = FileObj.read(ChunkSize)
|
||||
ChunkLines = Chunk.splitlines()
|
||||
ChunkLines = ChunkLines[::-1]
|
||||
for Line in ChunkLines:
|
||||
if FoundLines < LineCount:
|
||||
Lines.append(Line)
|
||||
FoundLines += 1
|
||||
else:
|
||||
break
|
||||
CurrentPosition = ReadPosition
|
||||
Lines = Lines[::-1]
|
||||
StartIndex = max(0, len(Lines) - EndLineFromEnd)
|
||||
EndIndex = len(Lines) - StartLineFromEnd + 1
|
||||
ResultLines = Lines[StartIndex:EndIndex]
|
||||
R = [Line.decode('utf-8', errors='ignore') for Line in ResultLines]
|
||||
if ReturnType == str: return '\n'.join(R)
|
||||
elif ReturnType == list: return R
|
||||
else: raise ValueError("Return Type Error")
|
||||
TempDir = os.getenv("temp")
|
||||
LogFile = os.path.join(TempDir, "T.log")
|
||||
|
||||
import os
|
||||
|
||||
def ReadFileRangeFromEnd(FilePath, StartLineFromEnd, EndLineFromEnd, BufferSize=1024 * 10, ReturnType=str):
|
||||
if StartLineFromEnd < 1 or EndLineFromEnd < 1:
|
||||
raise ValueError("Line number must be greater than 0")
|
||||
if StartLineFromEnd > EndLineFromEnd:
|
||||
raise ValueError("StartLineFromEnd must be less than or equal to EndLineFromEnd")
|
||||
LineCount = EndLineFromEnd
|
||||
BufferSize = BufferSize * LineCount
|
||||
with open(FilePath, 'rb') as FileObj:
|
||||
FileObj.seek(0, 2)
|
||||
FileSize = FileObj.tell()
|
||||
BufferSize = min(BufferSize, FileSize)
|
||||
Lines = []
|
||||
CurrentPosition = FileSize
|
||||
FoundLines = 0
|
||||
while CurrentPosition > 0 and FoundLines < LineCount:
|
||||
ReadPosition = max(0, CurrentPosition - BufferSize)
|
||||
ChunkSize = CurrentPosition - ReadPosition
|
||||
FileObj.seek(ReadPosition)
|
||||
Chunk = FileObj.read(ChunkSize)
|
||||
ChunkLines = Chunk.splitlines()
|
||||
ChunkLines = ChunkLines[::-1]
|
||||
for Line in ChunkLines:
|
||||
if FoundLines < LineCount:
|
||||
Lines.append(Line)
|
||||
FoundLines += 1
|
||||
else:
|
||||
break
|
||||
CurrentPosition = ReadPosition
|
||||
Lines = Lines[::-1]
|
||||
StartIndex = max(0, len(Lines) - EndLineFromEnd)
|
||||
EndIndex = len(Lines) - StartLineFromEnd + 1
|
||||
ResultLines = Lines[StartIndex:EndIndex]
|
||||
R = [Line.decode('utf-8', errors='ignore') for Line in ResultLines]
|
||||
if ReturnType == str: return '\n'.join(R)
|
||||
elif ReturnType == list: return R
|
||||
else: raise ValueError("Return Type Error")
|
||||
TempDir = os.getenv("temp")
|
||||
LogFile = os.path.join(TempDir, "T.log")
|
||||
|
||||
ResultLines = ReadFileRangeFromEnd(LogFile, 1, 300)
|
||||
+9
-9
@@ -1,10 +1,10 @@
|
||||
import sys
|
||||
f=open(sys.argv[0], "rb")
|
||||
s=f.read()
|
||||
f.close()
|
||||
|
||||
print(s)
|
||||
|
||||
f=open("1.dmp", "wb")
|
||||
f.write(s)
|
||||
import sys
|
||||
f=open(sys.argv[0], "rb")
|
||||
s=f.read()
|
||||
f.close()
|
||||
|
||||
print(s)
|
||||
|
||||
f=open("1.dmp", "wb")
|
||||
f.write(s)
|
||||
f.close()
|
||||
+38
-38
@@ -1,38 +1,38 @@
|
||||
# -*- mode: python ; coding: utf-8 -*-
|
||||
|
||||
|
||||
a = Analysis(
|
||||
['testreadme.py'],
|
||||
pathex=[],
|
||||
binaries=[],
|
||||
datas=[],
|
||||
hiddenimports=[],
|
||||
hookspath=[],
|
||||
hooksconfig={},
|
||||
runtime_hooks=[],
|
||||
excludes=[],
|
||||
noarchive=False,
|
||||
optimize=0,
|
||||
)
|
||||
pyz = PYZ(a.pure)
|
||||
|
||||
exe = EXE(
|
||||
pyz,
|
||||
a.scripts,
|
||||
a.binaries,
|
||||
a.datas,
|
||||
[],
|
||||
name='testreadme',
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
upx_exclude=[],
|
||||
runtime_tmpdir=None,
|
||||
console=True,
|
||||
disable_windowed_traceback=False,
|
||||
argv_emulation=False,
|
||||
target_arch=None,
|
||||
codesign_identity=None,
|
||||
entitlements_file=None,
|
||||
)
|
||||
# -*- mode: python ; coding: utf-8 -*-
|
||||
|
||||
|
||||
a = Analysis(
|
||||
['testreadme.py'],
|
||||
pathex=[],
|
||||
binaries=[],
|
||||
datas=[],
|
||||
hiddenimports=[],
|
||||
hookspath=[],
|
||||
hooksconfig={},
|
||||
runtime_hooks=[],
|
||||
excludes=[],
|
||||
noarchive=False,
|
||||
optimize=0,
|
||||
)
|
||||
pyz = PYZ(a.pure)
|
||||
|
||||
exe = EXE(
|
||||
pyz,
|
||||
a.scripts,
|
||||
a.binaries,
|
||||
a.datas,
|
||||
[],
|
||||
name='testreadme',
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
upx_exclude=[],
|
||||
runtime_tmpdir=None,
|
||||
console=True,
|
||||
disable_windowed_traceback=False,
|
||||
argv_emulation=False,
|
||||
target_arch=None,
|
||||
codesign_identity=None,
|
||||
entitlements_file=None,
|
||||
)
|
||||
+4
-4
@@ -1,5 +1,5 @@
|
||||
import tkinter as tk
|
||||
|
||||
|
||||
root = tk.Tk()
|
||||
import tkinter as tk
|
||||
|
||||
|
||||
root = tk.Tk()
|
||||
root.mainloop()
|
||||
Reference in new issue
Block a user