Skip to content

Commit bce4805

Browse files
committed
crontab
1 parent 4cc8c78 commit bce4805

10 files changed

+274
-10
lines changed

CommandTrayHost/CommandTrayHost.cpp

+49-8
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@ BOOL ParseProxyList()
458458
lpProxyList[i++] = pos;
459459
//pos = _wcstok(NULL, sep);
460460
pos = wcstok_s(nullptr, sep, &next_token);
461-
}
461+
}
462462
lpProxyList[i] = 0;
463463

464464
for (LPSTR ptr = szRasPbk; *ptr; ptr++)
@@ -633,7 +633,7 @@ BOOL CreateConsole()
633633
}
634634

635635
return TRUE;
636-
}
636+
}
637637
//#pragma warning( pop )
638638
#endif
639639

@@ -723,7 +723,7 @@ BOOL ReloadCmdline()
723723
Sleep(200);
724724
ExecCmdline();
725725
return TRUE;
726-
}
726+
}
727727

728728
#endif
729729

@@ -981,13 +981,30 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
981981
break;
982982
case WM_TIMER:
983983
LOGMESSAGE(L"WM_TIMER tick %d\n", wParam);
984-
switch (wParam)
984+
if (wParam == VM_TIMER_CREATEPROCESS_SHOW)
985985
{
986-
case VM_TIMER_CREATEPROCESS_SHOW:
987986
update_hwnd_all();
988-
break;
987+
988+
}
989+
if (VM_TIMER_BASE <= wParam && wParam <= 0xBF00)
990+
{
991+
int idx = static_cast<int>(wParam - VM_TIMER_BASE);
992+
if (idx >= number_of_configs || idx < 0)
993+
{
994+
msg_prompt(L"Crontab has some fatal error unknown idx! Please report this windows screenshot to author!",
995+
L"Crontab Error",
996+
MB_OK
997+
);
998+
}
999+
else
1000+
{
1001+
handle_crontab(idx);
1002+
}
1003+
}
1004+
else
1005+
{
9891006
//default:
990-
//LOGMESSAGE(L"WM_TIMER tick %d\n", wParam);
1007+
//LOGMESSAGE(L"WM_TIMER tick %d\n", wParam);
9911008
}
9921009
break;
9931010
case WM_CLOSE:
@@ -1108,7 +1125,31 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi
11081125
//ShowTrayIcon(GetWindowsProxy(), NIM_ADD);
11091126
ShowTrayIcon(L"", NIM_ADD);
11101127
//TryDeleteUpdateFiles();
1111-
1128+
#ifdef _DEBUG
1129+
{
1130+
cron_expr expr;
1131+
ZeroMemory(&expr, sizeof(expr));
1132+
const char* err = NULL;
1133+
cron_parse_expr("8 */2 15-16 29 2 *", &expr, &err);
1134+
if (err)LOGMESSAGE(L"cron_parse_expr err: %S\n", err);
1135+
else LOGMESSAGE(L"cron_parse_expr ok!\n");
1136+
assert(0 == err);
1137+
time_t cur = time(NULL);
1138+
time_t next = cron_next(&expr, cur);
1139+
1140+
LOGMESSAGE(L"%lld -> %lld diff:%lld", next, cur, next - cur);
1141+
double dif = difftime(next, cur);
1142+
char buffer[80];
1143+
tm t1, t2;
1144+
localtime_s(&t1, &cur);
1145+
localtime_s(&t2, &next);
1146+
strftime(buffer, ARRAYSIZE(buffer), "%Y-%m-%d_%H:%M:%S", &t1);
1147+
LOGMESSAGE(L"t1:%S %f\n", buffer, dif);
1148+
strftime(buffer, ARRAYSIZE(buffer), "%Y-%m-%d_%H:%M:%S", &t2);
1149+
LOGMESSAGE(L"t2:%S %f\n", buffer, dif);
1150+
LOGMESSAGE(L"%lld\n", ((time_t)-1));
1151+
}
1152+
#endif
11121153
while (GetMessage(&msg, NULL, 0, 0) > 0)
11131154
{
11141155
TranslateMessage(&msg);

CommandTrayHost/CommandTrayHost.h

+1
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,4 @@ BOOL ShowTrayIcon(LPCWSTR lpszProxy, DWORD dwMessage);
3131
#define WM_HOTKEY_TOPMOST (WM_USER + 0x65)
3232

3333
#define VM_TIMER_CREATEPROCESS_SHOW 0x100
34+
#define VM_TIMER_BASE 0x200

CommandTrayHost/configure.cpp

+177-1
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ bool initial_configure()
7171
* 键盘码参考这里 https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
7272
* 大小写无关,顺序无关,如果多个非修饰符的按钮,最后的那个按钮会起作用。
7373
* 热键注册失败,一般是与系统中存在的冲突了,换一个再试
74+
* 8. crontab语法,秒 分 时 日期 月份 星期,比常规crontab多了个秒钟,具体语法使用搜索引擎
75+
* 例子 0 0/10 * * * * 每10分钟运行一次
76+
* 例子 0 1,11,21 * * * 每小时的1分 11分 21分运行一次
77+
* 例子 0 2/10 12-14 * * * 12点到14点,每小时从2分钟开始每10分钟运行一次
7478
*/
7579
"configs": [
7680
{
@@ -118,6 +122,14 @@ bool initial_configure()
118122
"use_builtin_console": false,
119123
"is_gui": false,
120124
"enabled": false,
125+
// 可选
126+
"crontab_config": { // crontab配置
127+
"crontab": "8 */2 15-16 29 2 *", // crontab语法具体参考上面8
128+
"method": "start", // 支持的有 start restart stop
129+
"count": 0, // 0 表示infinite不只限制,大于0的整数,表示运行多少次就不运行了
130+
// 可选
131+
"enabled": true,
132+
},
121133
},
122134
{
123135
"name": "cmd例子3",
@@ -199,6 +211,7 @@ bool initial_configure()
199211
* 6. set "enable_cache": true to enable cache.
200212
* 7. alt win shit ctrl 0-9 A-Z, seperated by space or +. You can also use "ALT+WIN+CTRL+0x20"
201213
* https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
214+
* 8. crontab is from https://github.com/staticlibs/ccronexpr
202215
*/
203216
"configs": [
204217
{
@@ -244,6 +257,14 @@ bool initial_configure()
244257
"use_builtin_console": false,
245258
"is_gui": false,
246259
"enabled": false,
260+
// Optional
261+
"crontab_config": {
262+
"crontab": "8 */2 15-16 29 2 *",
263+
"method": "start", // start restart stop
264+
"count": 0, // times to run, 0 infinite
265+
// Optional
266+
"enabled": true,
267+
},
247268
},
248269
{
249270
"name": "cmd example 3",
@@ -627,6 +648,49 @@ int configure_reader(std::string& out)
627648
{ "restart", iStringType, true, lambda_config_hotkey, lambda_config_hotkey_items_idx },
628649
{ "elevate", iStringType, true, lambda_config_hotkey, lambda_config_hotkey_items_idx },
629650
};
651+
const RapidJsonObjectChecker config_crontab_items[] = {
652+
{ "enabled", iBoolType,true,nullptr,[&allocator](Value& val, PCSTR name)->bool {
653+
if (!val.HasMember(name))
654+
{
655+
val.AddMember(Value{}.SetString(name, allocator), true, allocator);
656+
}
657+
return true;
658+
} },
659+
{ "crontab", iStringType,false,[&allocator](Value& val, PCSTR name)->bool {
660+
if (!val["enabled"].GetBool())return true;
661+
if (val.HasMember("cron_expr"))return false;
662+
const char* crontab = val[name].GetString();
663+
if (crontab[0] == 0)return false;
664+
cron_expr expr;
665+
ZeroMemory(&expr, sizeof(expr)); // if not do this, always get incorrect result
666+
const char* err = NULL;
667+
cron_parse_expr(crontab, &expr, &err);
668+
if (err)
669+
{
670+
LOGMESSAGE(L"cron_parse_expr failed! %S\n",err);
671+
return false;
672+
}
673+
Value v;
674+
v.SetString(reinterpret_cast<const char*>(&expr), sizeof(cron_expr), allocator);
675+
val.AddMember("cron_expr", v, allocator);
676+
return true;
677+
} },
678+
{ "method", iStringType,false,[](Value& val, PCSTR name)->bool {
679+
if (!val["enabled"].GetBool())return true;
680+
const char* method = val[name].GetString();
681+
if (0 == StrCmpA(method,"restart") || 0 == StrCmpA(method, "start") || 0 == StrCmpA(method, "stop"))
682+
{
683+
return true;
684+
}
685+
return false;
686+
} },
687+
{ "count", iIntType, false, [](Value& val, PCSTR name)->bool {
688+
if (!val["enabled"].GetBool())return true;
689+
int count = val[name].GetInt();
690+
if (count < 0)return false;
691+
return true;
692+
} },
693+
};
630694

631695
//type check for items in configs
632696
const RapidJsonObjectChecker config_items[] = {
@@ -692,6 +756,16 @@ int configure_reader(std::string& out)
692756
}
693757
return true;
694758
}},
759+
{ "crontab_config", iObjectType, true, [&config_crontab_items](Value& val, PCSTR name)->bool {
760+
return check_rapidjson_object(
761+
val[name],
762+
config_crontab_items,
763+
ARRAYSIZE(config_crontab_items),
764+
L": One of configs section crontab setting error!",
765+
(utf8_to_wstring(name) + L"crontab_config Type Error").c_str(),
766+
(utf8_to_wstring(val["name"].GetString()) + L" config section").c_str(),
767+
false);
768+
} },
695769
};
696770
PCSTR const global_menu[][2] = {
697771
// with hotkey
@@ -1031,6 +1105,8 @@ int configure_reader(std::string& out)
10311105
}
10321106
return ret;
10331107
}, lambda_menu_check },
1108+
//{ "enable_crontab", iBoolType, true, nullptr },
1109+
//{ "crontabs", iArrayType, true, nullptr }
10341110
};
10351111

10361112
if (false == check_rapidjson_object(
@@ -1718,6 +1794,85 @@ void update_hwnd_all()
17181794
}
17191795
}
17201796

1797+
void handle_crontab(int idx)
1798+
{
1799+
auto& config_i_ref = (*global_configs_pointer)[idx]; // ["crontab_config"]
1800+
if (json_object_has_member(config_i_ref, "crontab_config"))
1801+
{
1802+
auto& crontab_ref = config_i_ref["crontab_config"];
1803+
extern HWND hWnd;
1804+
KillTimer(hWnd, VM_TIMER_BASE + idx);
1805+
1806+
std::string crontab_method = crontab_ref["method"];
1807+
extern HANDLE ghJob;
1808+
bool enable_cache_backup = enable_cache;
1809+
enable_cache = false;
1810+
if (crontab_method == "start")
1811+
{
1812+
bool to_start = true;
1813+
1814+
if (config_i_ref["running"])
1815+
{
1816+
int64_t handle = config_i_ref["handle"];
1817+
DWORD lpExitCode;
1818+
BOOL retValue = GetExitCodeProcess(reinterpret_cast<HANDLE>(handle), &lpExitCode);
1819+
if (retValue != 0 && lpExitCode == STILL_ACTIVE)
1820+
{
1821+
to_start = false;
1822+
}
1823+
}
1824+
if (to_start)
1825+
{
1826+
config_i_ref["enabled"] = true;
1827+
create_process(config_i_ref, ghJob);
1828+
}
1829+
}
1830+
/*else if (crontab_method == "restart")
1831+
{
1832+
1833+
}
1834+
else if (crontab_method == "stop")*/
1835+
else
1836+
{
1837+
if (config_i_ref["enabled"] && config_i_ref["running"] && config_i_ref["en_job"])
1838+
{
1839+
disable_enable_menu(config_i_ref, ghJob);
1840+
}
1841+
if (crontab_method == "restart")
1842+
{
1843+
disable_enable_menu(config_i_ref, ghJob);
1844+
}
1845+
}
1846+
enable_cache = enable_cache_backup;
1847+
1848+
int crontab_count = crontab_ref["count"];
1849+
1850+
if (crontab_count != 1)
1851+
{
1852+
cron_expr c;
1853+
time_t next_t = 0;
1854+
next_t = cron_next(&c, time(NULL)); // return -1 when failed
1855+
if (next_t > 0)
1856+
{
1857+
next_t *= 1000;
1858+
if (next_t > USER_TIMER_MAXIMUM)next_t = USER_TIMER_MAXIMUM;
1859+
SetTimer(hWnd, VM_TIMER_BASE + idx, static_cast<UINT>(next_t), NULL);
1860+
if (crontab_count > 1)
1861+
{
1862+
crontab_ref["count"] = crontab_count - 1;
1863+
}
1864+
}
1865+
}
1866+
}
1867+
else
1868+
{
1869+
msg_prompt(L"Crontab has no crontab_config! Please report this windows screenshot to author!",
1870+
L"Crontab Error",
1871+
MB_OK
1872+
);
1873+
}
1874+
}
1875+
17211876
void start_all(HANDLE ghJob, bool force)
17221877
{
17231878
//int cmd_idx = 0;
@@ -1737,6 +1892,26 @@ void start_all(HANDLE ghJob, bool force)
17371892
i["enabled"] = true;
17381893
}
17391894
}
1895+
else
1896+
{
1897+
if (json_object_has_member(i, "crontab_config") && i["crontab_config"]["count"]["enabled"])
1898+
{
1899+
cron_expr c;
1900+
if (nullptr != get_cron_expr(i, c))
1901+
{
1902+
//int cront_cnt = i["crontab_config"]["count"];
1903+
extern HWND hWnd;
1904+
time_t next_t = 0;
1905+
next_t = cron_next(&c, time(NULL)); // return -1 when failed
1906+
if (next_t > 0)
1907+
{
1908+
next_t *= 1000;
1909+
if (next_t > USER_TIMER_MAXIMUM)next_t = USER_TIMER_MAXIMUM;
1910+
SetTimer(hWnd, VM_TIMER_BASE + cache_config_cursor, static_cast<UINT>(next_t), NULL);
1911+
}
1912+
}
1913+
}
1914+
}
17401915
bool is_enabled = i["enabled"];
17411916
if (is_enabled)
17421917
{
@@ -2350,7 +2525,8 @@ void create_process(
23502525
void disable_enable_menu(nlohmann::json& jsp, HANDLE ghJob, bool runas_admin)
23512526
{
23522527
bool is_enabled = jsp["enabled"];
2353-
if (false == runas_admin && is_enabled) {
2528+
if (false == runas_admin && is_enabled)
2529+
{
23542530
bool is_running = jsp["running"];
23552531
if (is_running)
23562532
{

CommandTrayHost/configure.h

+2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ void create_process(nlohmann::json& jsp, const HANDLE&, bool runas_admin = false
3535
void show_hide_toggle(nlohmann::json& jsp);
3636
void disable_enable_menu(nlohmann::json& jsp, HANDLE, bool runas_admin = false);
3737

38+
void handle_crontab(int idx);
39+
3840
void hideshow_all(bool is_hideall = true);
3941
void start_all(HANDLE, bool force = false);
4042
void restart_all(HANDLE);

CommandTrayHost/utils.cpp

+18
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,24 @@ int64_t FileSize(PCWSTR name)
257257
return size.QuadPart;
258258
}
259259

260+
void to_json(nlohmann::json& j, const cron_expr& p) {
261+
j = nlohmann::json{ std::string(reinterpret_cast<const char*>(&p),sizeof(cron_expr)) };
262+
}
263+
264+
void from_json(const nlohmann::json& j, cron_expr& p) {
265+
StringCchCopyA(reinterpret_cast<char*>(&p), sizeof(cron_expr), j.get<std::string>().data());
266+
}
267+
268+
cron_expr* get_cron_expr(const nlohmann::json& jsp, cron_expr& result)
269+
{
270+
if (json_object_has_member(jsp, "crontab_config") && json_object_has_member(jsp, "cron_expr"))
271+
{
272+
result = jsp["crontab_config"]["cron_expr"].get<cron_expr>();
273+
return &result;
274+
}
275+
return nullptr;
276+
}
277+
260278
bool json_object_has_member(const nlohmann::json& root, PCSTR query_string)
261279
{
262280
try

CommandTrayHost/utils.hpp

+6
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ bool try_read_optional_json(const nlohmann::json& root, Type& out, PCSTR query_s
4545
return true;
4646
}
4747

48+
//void to_json(nlohmann::json& j, const cron_expr& p);
49+
50+
//void from_json(const nlohmann::json& j, cron_expr& p);
51+
52+
cron_expr* get_cron_expr(const nlohmann::json& jsp, cron_expr& result);
53+
4854
void rapidjson_merge_object(rapidjson::Value &dstObject, rapidjson::Value &srcObject, rapidjson::Document::AllocatorType &allocator);
4955

5056
//! Type of JSON value

0 commit comments

Comments
 (0)