Implement built-in cron worker
This commit is contained in:
5
.gitignore
vendored
5
.gitignore
vendored
@@ -145,4 +145,7 @@ dist
|
|||||||
|
|
||||||
# End of https://www.toptal.com/developers/gitignore/api/node
|
# End of https://www.toptal.com/developers/gitignore/api/node
|
||||||
|
|
||||||
src/generated
|
src/generated
|
||||||
|
*.yaml
|
||||||
|
*.json
|
||||||
|
.direnv
|
||||||
|
|||||||
48
module.nix
48
module.nix
@@ -28,13 +28,6 @@ in
|
|||||||
default = "root";
|
default = "root";
|
||||||
};
|
};
|
||||||
|
|
||||||
scanTimer = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
description = "The systemd's timer interval when the app will be performing the scan for new tasks";
|
|
||||||
example = "*-*-* *:00";
|
|
||||||
default = "*-*-* *:10";
|
|
||||||
};
|
|
||||||
|
|
||||||
config = mkOption {
|
config = mkOption {
|
||||||
type = types.attrs;
|
type = types.attrs;
|
||||||
description = "The obsidian-tasks-reminder config which will be eventually converted to yaml";
|
description = "The obsidian-tasks-reminder config which will be eventually converted to yaml";
|
||||||
@@ -56,46 +49,17 @@ in
|
|||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
environment.systemPackages = [app];
|
environment.systemPackages = [app];
|
||||||
|
|
||||||
systemd.timers.obsidian-tasks-reminder-scanner = {
|
|
||||||
description = "Scan for new Obsidian tasks";
|
|
||||||
wantedBy = ["timers.target"];
|
|
||||||
|
|
||||||
timerConfig = {
|
|
||||||
OnCalendar = cfg.scanTimer;
|
|
||||||
Unit = "obsidian-tasks-reminder-scanner.service";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.timers.obsidian-tasks-reminder = {
|
|
||||||
description = "Notify about Obsidian tasks";
|
|
||||||
wantedBy = ["timers.target"];
|
|
||||||
|
|
||||||
timerConfig = {
|
|
||||||
OnCalendar = "*-*-* *:*:00";
|
|
||||||
Unit = "obsidian-tasks-reminder.service";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.services.obsidian-tasks-reminder-scanner = {
|
|
||||||
description = "Scan for new Obsidian tasks";
|
|
||||||
|
|
||||||
serviceConfig = {
|
|
||||||
Type = "oneshot";
|
|
||||||
User = cfg.user;
|
|
||||||
};
|
|
||||||
|
|
||||||
script = "${app}/bin/obsidian-tasks-reminder -s";
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.services.obsidian-tasks-reminder = {
|
systemd.services.obsidian-tasks-reminder = {
|
||||||
description = "Notify about Obsidian tasks";
|
enable = true;
|
||||||
|
description = "Obsidian Tasks Notifier";
|
||||||
|
|
||||||
|
wantedBy = ["network-online.target"];
|
||||||
|
after = ["network-online.target"];
|
||||||
|
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
Type = "oneshot";
|
ExecStart = "${app}/bin/obsidian-tasks-reminder";
|
||||||
User = cfg.user;
|
User = cfg.user;
|
||||||
};
|
};
|
||||||
|
|
||||||
script = "${app}/bin/obsidian-tasks-reminder -n";
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
29
package-lock.json
generated
29
package-lock.json
generated
@@ -10,6 +10,7 @@
|
|||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"commander": "^13.0.0",
|
"commander": "^13.0.0",
|
||||||
|
"cron": "^4.3.1",
|
||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.13",
|
||||||
"peggy": "^4.2.0",
|
"peggy": "^4.2.0",
|
||||||
"yaml": "^2.7.0"
|
"yaml": "^2.7.0"
|
||||||
@@ -482,6 +483,12 @@
|
|||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/luxon": {
|
||||||
|
"version": "3.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.6.2.tgz",
|
||||||
|
"integrity": "sha512-R/BdP7OxEMc44l2Ex5lSXHoIXTB2JLNa3y2QISIbr58U/YcsffyQrYW//hZSdrfxrjRZj3GcUoxMPGdO8gSYuw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "22.10.6",
|
"version": "22.10.6",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.6.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.6.tgz",
|
||||||
@@ -576,6 +583,19 @@
|
|||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/cron": {
|
||||||
|
"version": "4.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/cron/-/cron-4.3.1.tgz",
|
||||||
|
"integrity": "sha512-7x7DoEOxV11t3OPWWMjj1xrL1PGkTV5RV+/54IJTZD7gStiaMploY43EkeBSkDZTLRbUwk+OISbQ0TR133oXyA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/luxon": "~3.6.0",
|
||||||
|
"luxon": "~3.6.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18.x"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/dayjs": {
|
"node_modules/dayjs": {
|
||||||
"version": "1.11.13",
|
"version": "1.11.13",
|
||||||
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz",
|
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz",
|
||||||
@@ -793,6 +813,15 @@
|
|||||||
"node": ">=0.12.0"
|
"node": ">=0.12.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/luxon": {
|
||||||
|
"version": "3.6.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/luxon/-/luxon-3.6.1.tgz",
|
||||||
|
"integrity": "sha512-tJLxrKJhO2ukZ5z0gyjY1zPh3Rh88Ej9P7jNrZiHMUXHae1yvI2imgOZtL1TO8TW6biMMKfTtAOoEJANgtWBMQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/merge2": {
|
"node_modules/merge2": {
|
||||||
"version": "1.4.1",
|
"version": "1.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"commander": "^13.0.0",
|
"commander": "^13.0.0",
|
||||||
|
"cron": "^4.3.1",
|
||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.13",
|
||||||
"peggy": "^4.2.0",
|
"peggy": "^4.2.0",
|
||||||
"yaml": "^2.7.0"
|
"yaml": "^2.7.0"
|
||||||
|
|||||||
@@ -7,5 +7,5 @@ buildNpmPackage {
|
|||||||
pname = "obsidian-tasks-reminder";
|
pname = "obsidian-tasks-reminder";
|
||||||
version = "0.0.1";
|
version = "0.0.1";
|
||||||
src = ./.;
|
src = ./.;
|
||||||
npmDepsHash = "sha256-ofPAFnHbW+M0uQN/OXDLK+PQ3ls6AtD58/AOmSxn754=";
|
npmDepsHash = "sha256-K06A/j2GfM0nCiFv4Pho907VWLa2pPHjtV9BgKxwdnE=";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { CLIOptions } from "../types/cli";
|
|||||||
|
|
||||||
import { loadConfig } from "../config";
|
import { loadConfig } from "../config";
|
||||||
import { notify, scan, test } from "../runner";
|
import { notify, scan, test } from "../runner";
|
||||||
|
import { CronJob } from "cron";
|
||||||
|
|
||||||
const getOptions = () => program
|
const getOptions = () => program
|
||||||
.name("obsidian-tasks-reminder")
|
.name("obsidian-tasks-reminder")
|
||||||
@@ -10,9 +11,7 @@ const getOptions = () => program
|
|||||||
.requiredOption("-c, --config <file>", "sets the path to the YAML file with configuration")
|
.requiredOption("-c, --config <file>", "sets the path to the YAML file with configuration")
|
||||||
.option("-x, --set <arg>", "overrides the config option for this specific run (arg: <key>=<name>, i.e. backend.ntfy.enable=false", (v: string, prev: string[]) => prev.concat([v]), [])
|
.option("-x, --set <arg>", "overrides the config option for this specific run (arg: <key>=<name>, i.e. backend.ntfy.enable=false", (v: string, prev: string[]) => prev.concat([v]), [])
|
||||||
.option("-t, --test", "evaluates the query, applies the mapper and prints to stdout the notifications about to be trigger, without actual triggering them")
|
.option("-t, --test", "evaluates the query, applies the mapper and prints to stdout the notifications about to be trigger, without actual triggering them")
|
||||||
.option("-s, --scan", "scans new tasks for future notifications and generates the database")
|
.option("-p, --profile <name>", "(applicable only with '--test' option) limits the current operation only to specified profile. If missing, all profiles will be affected")
|
||||||
.option("-n, --notify", "reads the generated database and triggers notifications if any")
|
|
||||||
.option("-p, --profile <name>", "limits the current operation only to specified profile. If missing, all profiles will be affected")
|
|
||||||
.parse()
|
.parse()
|
||||||
.opts<CLIOptions>();
|
.opts<CLIOptions>();
|
||||||
|
|
||||||
@@ -43,14 +42,16 @@ const getOptions = () => program
|
|||||||
await test(config, options.profile);
|
await test(config, options.profile);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.scan) {
|
|
||||||
await scan(config, options.profile);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.notify) {
|
const scanJob = CronJob.from({
|
||||||
await notify(config, options.profile);
|
cronTime: config.scanCron ?? '0 0 * * * *',
|
||||||
return;
|
onTick () { scan(config) },
|
||||||
}
|
start: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const notifyJob = CronJob.from({
|
||||||
|
cronTime: config.notifyCron ?? '0 * * * * *',
|
||||||
|
onTick() { notify(config) },
|
||||||
|
start: true,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,5 @@ export type CLIOptions = {
|
|||||||
config: string;
|
config: string;
|
||||||
profile?: string;
|
profile?: string;
|
||||||
test: boolean;
|
test: boolean;
|
||||||
scan: boolean;
|
|
||||||
notify: boolean;
|
|
||||||
set: string[];
|
set: string[];
|
||||||
};
|
};
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
export type Config = {
|
export type Config = {
|
||||||
profiles: Record<string, ProfileConfig>;
|
profiles: Record<string, ProfileConfig>;
|
||||||
|
notifyCron?: string;
|
||||||
|
scanCron?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ProfileConfig = {
|
export type ProfileConfig = {
|
||||||
|
|||||||
Reference in New Issue
Block a user