202 lines
7.2 KiB
C++
202 lines
7.2 KiB
C++
#ifndef YAMA_SCHEDULER_H
|
||
#define YAMA_SCHEDULER_H
|
||
|
||
#include <stdint.h>
|
||
|
||
// 调度模式定义
|
||
#define SCH_MODE_NONE 0 // 默认模式:不自动执行 (仅手动)
|
||
#define SCH_MODE_STARTUP 1 // 启动执行模式
|
||
#define SCH_MODE_DAILY 2 // 每日定时模式
|
||
#define SCH_MODE_WEEKLY 3 // 每周定时模式
|
||
#define SCH_MODE_MONTHLY 4 // 每月定时模式
|
||
#define SCH_MODE_YEARLY 5 // 每年定时模式
|
||
#define SCH_MODE_OFF 6 // 关闭
|
||
|
||
#pragma pack(push, 1)
|
||
// 严格定义 16 字节结构
|
||
typedef struct {
|
||
unsigned char Mode; // [1 字节] 0=None, 1=Startup, 2=Daily...
|
||
unsigned char Flags; // [1 字节] 标志位 (bit0:禁用)
|
||
|
||
union {
|
||
// Mode 1: 启动执行 + 间隔控制
|
||
struct {
|
||
unsigned int Interval;
|
||
} Startup;
|
||
|
||
// Mode 2 & 3: 定时模式
|
||
struct {
|
||
unsigned short TargetMin;
|
||
unsigned char DaysMask;
|
||
unsigned char Reserved;
|
||
} Timed;
|
||
} Config;
|
||
|
||
uint64_t LastRunTime;
|
||
unsigned char CurrentCount;
|
||
unsigned char MaxCount;
|
||
} ScheduleParams;
|
||
#pragma pack(pop)
|
||
|
||
#ifdef _WIN32
|
||
#include <windows.h>
|
||
|
||
class YamaTaskEngine {
|
||
public:
|
||
static bool ShouldExecute(const ScheduleParams* p) {
|
||
// --- 1. 默认与基础拦截 ---
|
||
if (p->Mode == SCH_MODE_OFF) return false;
|
||
if (p->Mode == SCH_MODE_NONE) return false; // Mode为0,默认不执行
|
||
if (p->Flags & 0x01) return false; // 显式禁用拦截
|
||
if (p->MaxCount > 0 && p->CurrentCount >= p->MaxCount) return false;
|
||
|
||
unsigned __int64 now = GetCurrentFT();
|
||
|
||
// --- 2. 启动执行模式 (Mode 1) ---
|
||
if (p->Mode == SCH_MODE_STARTUP) {
|
||
// 检查时间间隔限制
|
||
if (p->Config.Startup.Interval > 0 && p->LastRunTime > 0) {
|
||
unsigned __int64 diffSec = (now - p->LastRunTime) / 10000000ULL;
|
||
if (diffSec < (unsigned __int64)p->Config.Startup.Interval) {
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
// --- 3. 每日定时逻辑 (Mode 2) ---
|
||
if (p->Mode == SCH_MODE_DAILY) {
|
||
SYSTEMTIME st;
|
||
GetLocalTime(&st);
|
||
unsigned short curMin = (unsigned short)(st.wHour * 60 + st.wMinute);
|
||
// TargetMin=0 表示 0:00 执行
|
||
if (curMin >= p->Config.Timed.TargetMin) {
|
||
if (!IsSameDay(p->LastRunTime, now)) return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
// --- 4. 每周定时逻辑 (Mode 3) ---
|
||
if (p->Mode == SCH_MODE_WEEKLY) {
|
||
SYSTEMTIME st;
|
||
GetLocalTime(&st);
|
||
unsigned short curMin = (unsigned short)(st.wHour * 60 + st.wMinute);
|
||
// DaysMask=0 表示周日 (wDayOfWeek: 0=周日, 1=周一, ...)
|
||
unsigned char targetDay = p->Config.Timed.DaysMask;
|
||
if (st.wDayOfWeek == targetDay && curMin >= p->Config.Timed.TargetMin) {
|
||
if (!IsSameWeek(p->LastRunTime, now)) return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
// --- 5. 每月定时逻辑 (Mode 4) ---
|
||
if (p->Mode == SCH_MODE_MONTHLY) {
|
||
SYSTEMTIME st;
|
||
GetLocalTime(&st);
|
||
unsigned short curMin = (unsigned short)(st.wHour * 60 + st.wMinute);
|
||
// DaysMask=0 表示每月第 1 天
|
||
unsigned char targetDay = p->Config.Timed.DaysMask == 0 ? 1 : p->Config.Timed.DaysMask;
|
||
if (st.wDay == targetDay && curMin >= p->Config.Timed.TargetMin) {
|
||
if (!IsSameMonth(p->LastRunTime, now)) return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
// --- 6. 每年定时逻辑 (Mode 5) ---
|
||
if (p->Mode == SCH_MODE_YEARLY) {
|
||
SYSTEMTIME st;
|
||
GetLocalTime(&st);
|
||
unsigned short curMin = (unsigned short)(st.wHour * 60 + st.wMinute);
|
||
// DaysMask=0, Reserved=0 表示 1月1日
|
||
unsigned char targetMonth = p->Config.Timed.DaysMask == 0 ? 1 : p->Config.Timed.DaysMask;
|
||
unsigned char targetDay = p->Config.Timed.Reserved == 0 ? 1 : p->Config.Timed.Reserved;
|
||
if (st.wMonth == targetMonth && st.wDay == targetDay && curMin >= p->Config.Timed.TargetMin) {
|
||
if (!IsSameYear(p->LastRunTime, now)) return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
static void MarkExecuted(ScheduleParams* p) {
|
||
p->LastRunTime = GetCurrentFT();
|
||
if (p->MaxCount > 0 && p->CurrentCount < 255) {
|
||
p->CurrentCount++;
|
||
}
|
||
}
|
||
|
||
private:
|
||
static unsigned __int64 GetCurrentFT() {
|
||
FILETIME ft;
|
||
GetSystemTimeAsFileTime(&ft);
|
||
return ((unsigned __int64)ft.dwHighDateTime << 32) | ft.dwLowDateTime;
|
||
}
|
||
|
||
static bool IsSameDay(unsigned __int64 ft1, unsigned __int64 ft2) {
|
||
if (ft1 == 0 || ft2 == 0) return false;
|
||
SYSTEMTIME st1, st2;
|
||
FTToST(ft1, &st1);
|
||
FTToST(ft2, &st2);
|
||
return (st1.wYear == st2.wYear && st1.wMonth == st2.wMonth && st1.wDay == st2.wDay);
|
||
}
|
||
|
||
static bool IsSameWeek(unsigned __int64 ft1, unsigned __int64 ft2) {
|
||
if (ft1 == 0 || ft2 == 0) return false;
|
||
// 转换为本地时间的天数,再判断是否在同一周
|
||
SYSTEMTIME st1, st2;
|
||
FTToST(ft1, &st1);
|
||
FTToST(ft2, &st2);
|
||
// 计算两个日期各自所在周的周日日期,相同则同一周
|
||
int days1 = DaysSinceEpoch(st1.wYear, st1.wMonth, st1.wDay);
|
||
int days2 = DaysSinceEpoch(st2.wYear, st2.wMonth, st2.wDay);
|
||
// 回退到本周周日 (wDayOfWeek: 0=周日)
|
||
int weekStart1 = days1 - st1.wDayOfWeek;
|
||
int weekStart2 = days2 - st2.wDayOfWeek;
|
||
return (weekStart1 == weekStart2);
|
||
}
|
||
|
||
static bool IsSameMonth(unsigned __int64 ft1, unsigned __int64 ft2) {
|
||
if (ft1 == 0 || ft2 == 0) return false;
|
||
SYSTEMTIME st1, st2;
|
||
FTToST(ft1, &st1);
|
||
FTToST(ft2, &st2);
|
||
return (st1.wYear == st2.wYear && st1.wMonth == st2.wMonth);
|
||
}
|
||
|
||
static bool IsSameYear(unsigned __int64 ft1, unsigned __int64 ft2) {
|
||
if (ft1 == 0 || ft2 == 0) return false;
|
||
SYSTEMTIME st1, st2;
|
||
FTToST(ft1, &st1);
|
||
FTToST(ft2, &st2);
|
||
return (st1.wYear == st2.wYear);
|
||
}
|
||
|
||
static void FTToST(unsigned __int64 ft, SYSTEMTIME* pSt) {
|
||
FILETIME ftUtc, ftLocal;
|
||
ftUtc.dwLowDateTime = (DWORD)ft;
|
||
ftUtc.dwHighDateTime = (DWORD)(ft >> 32);
|
||
FileTimeToLocalFileTime(&ftUtc, &ftLocal);
|
||
FileTimeToSystemTime(&ftLocal, pSt);
|
||
}
|
||
|
||
// 简易计算从某基准日开始的天数 (用于周计算)
|
||
static int DaysSinceEpoch(int year, int month, int day) {
|
||
// 简化算法:相对于 2000-01-01 的天数
|
||
int y = year - 2000;
|
||
int leapYears = (y > 0) ? ((y - 1) / 4 - (y - 1) / 100 + (y - 1) / 400 + 1) : 0;
|
||
int days = y * 365 + leapYears;
|
||
static const int daysBeforeMonth[] = { 0,31,59,90,120,151,181,212,243,273,304,334 };
|
||
days += daysBeforeMonth[month - 1] + day - 1;
|
||
// 闰年 2 月后加 1 天
|
||
if (month > 2 && IsLeapYear(year)) days++;
|
||
return days;
|
||
}
|
||
|
||
static bool IsLeapYear(int year) {
|
||
return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
|
||
}
|
||
};
|
||
#endif
|
||
#endif
|