Swap to using uuids and document user functions

This commit is contained in:
Callum Loh 2023-03-26 00:30:12 +00:00
parent 54614b6132
commit 62e2ef6b7c
7 changed files with 68 additions and 12 deletions

View file

@ -27,6 +27,24 @@ Each job also has three toggable options
# Functionality
## API / UserScripts
An API is exposed to add user functions via Javascript. The name is treated as a UUID for the job ensure that this is consistent across reloads of Obsidian to ensure that locks / last run data is usable.
An instance of the Obsidian app is passed to all user function as the first and only paramater.
To clear locks for jobs added via the API you can add a job with the corrosponding name and then pass the name to the `clearJobLock(name: string)`
Example of a user function
```javascript
const cron = app.plugins.plugins.cron;
cron.addCronJob('addCronJob', "* * * * 3", {"enableMobile": true}, function(app){console.log('Job has ran!')});
```
## Sync
Obsidian cron has the ability to hook into the native Obsidian Sync plugin. When enabled all locks, cron runs & commands will wait for Obsidian Sync to be fully completed before running any cron jobs.

29
package-lock.json generated
View file

@ -11,11 +11,13 @@
"dependencies": {
"@popperjs/core": "^2.11.6",
"cron-parser": "^4.8.1",
"eslint": "^8.36.0"
"eslint": "^8.36.0",
"uuid": "^9.0.0"
},
"devDependencies": {
"@semantic-release/git": "^10.0.1",
"@types/node": "^16.11.6",
"@types/uuid": "^9.0.1",
"@typescript-eslint/eslint-plugin": "5.29.0",
"@typescript-eslint/parser": "5.29.0",
"builtin-modules": "3.3.0",
@ -1110,6 +1112,12 @@
"@types/estree": "*"
}
},
"node_modules/@types/uuid": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.1.tgz",
"integrity": "sha512-rFT3ak0/2trgvp4yYZo5iKFEPsET7vKydKF+VRCxlQ9bpheehyAJH89dAkaLEq/j/RZXJIqcgsmPJKUP1Z28HA==",
"dev": true
},
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "5.29.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.29.0.tgz",
@ -7624,6 +7632,14 @@
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"dev": true
},
"node_modules/uuid": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz",
"integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==",
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/validate-npm-package-license": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
@ -8500,6 +8516,12 @@
"@types/estree": "*"
}
},
"@types/uuid": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.1.tgz",
"integrity": "sha512-rFT3ak0/2trgvp4yYZo5iKFEPsET7vKydKF+VRCxlQ9bpheehyAJH89dAkaLEq/j/RZXJIqcgsmPJKUP1Z28HA==",
"dev": true
},
"@typescript-eslint/eslint-plugin": {
"version": "5.29.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.29.0.tgz",
@ -13067,6 +13089,11 @@
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"dev": true
},
"uuid": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz",
"integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg=="
},
"validate-npm-package-license": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",

View file

@ -16,6 +16,7 @@
"devDependencies": {
"@semantic-release/git": "^10.0.1",
"@types/node": "^16.11.6",
"@types/uuid": "^9.0.1",
"@typescript-eslint/eslint-plugin": "5.29.0",
"@typescript-eslint/parser": "5.29.0",
"builtin-modules": "3.3.0",
@ -32,7 +33,8 @@
"dependencies": {
"@popperjs/core": "^2.11.6",
"cron-parser": "^4.8.1",
"eslint": "^8.36.0"
"eslint": "^8.36.0",
"uuid": "^9.0.0"
},
"release": {
"tagFormat": "${version}",

View file

@ -22,15 +22,17 @@ export default class Job {
settings: CronJobSettings
job: CronJobFunc | string
name: string
id: string
noRunReason: string
public constructor(name: string, job: CronJobFunc | string, frequency: string, settings: CronJobSettings, app: App, plugin: Cron, syncChecker: SyncChecker) {
public constructor(id: string, name: string, job: CronJobFunc | string, frequency: string, settings: CronJobSettings, app: App, plugin: Cron, syncChecker: SyncChecker) {
this.syncChecker = syncChecker;
this.plugin = plugin;
this.app = app;
this.lockManager = new CronLockManager(name, settings, plugin, syncChecker)
this.lockManager = new CronLockManager(id, settings, plugin, syncChecker)
this.name = name;
this.id = id;
this.job = job;
this.frequency = frequency;
this.settings = settings;
@ -74,9 +76,9 @@ export default class Job {
private jobIntervalPassed(): boolean {
// job never ran
if(!this.plugin.settings.locks[this.name].lastRun) return true
const lastRun = this.lockManager.lastRun()
if(!lastRun) return true
const lastRun = window.moment(this.plugin.settings.locks[this.name].lastRun)
const prevRun = window.moment(parseExpression(this.frequency).prev().toDate())
return prevRun.isAfter(lastRun)
}

View file

@ -51,6 +51,10 @@ export default class CronLockManager {
this.plugin.settings.locks[this.job].locked = false
}
lastRun(): string | undefined {
return this.plugin.settings.locks[this.job].lastRun;
}
resetLastRun(): void {
this.plugin.settings.locks[this.job].lastRun = undefined
}

View file

@ -13,6 +13,7 @@ export interface CronSettings {
}
export interface CRONJob {
id: string
name: string
job: string
frequency: string
@ -66,10 +67,10 @@ export default class Cron extends Plugin {
}
}
public addCronJob(name: string, job: CronJobFunc, frequency: string, settings: CronJobSettings) {
public addCronJob(name: string, frequency: string, settings: CronJobSettings, job: CronJobFunc) {
if(this.jobs[name]) throw new Error("CRON Job already exists")
this.jobs[name] = new Job(name, job, frequency, settings, this.app, this, this.syncChecker)
this.jobs[name] = new Job(name, name, job, frequency, settings, this.app, this, this.syncChecker)
}
public async runJob(name: string) {
@ -91,11 +92,11 @@ export default class Cron extends Plugin {
public loadCrons() {
this.settings.crons.forEach(cronjob => {
if(cronjob.frequency === "" || cronjob.job === "" || cronjob.name === "") {
if(cronjob.frequency === "" || cronjob.job === "") {
return;
}
this.jobs[cronjob.name] = new Job(cronjob.name, cronjob.job, cronjob.frequency, cronjob.settings, this.app, this, this.syncChecker)
this.jobs[cronjob.id] = new Job(cronjob.id, cronjob.name, cronjob.job, cronjob.frequency, cronjob.settings, this.app, this, this.syncChecker)
});
}

View file

@ -1,4 +1,5 @@
import { App, PluginSettingTab, Setting } from 'obsidian';
import { v4 as uuidv4 } from 'uuid';
import { CommandSuggest } from './commandSuggest';
import type Cron from './main';
@ -112,7 +113,7 @@ export default class CronSettingTab extends PluginSettingTab {
button.setIcon(jobLocked ? "lucide-lock" : "lucide-unlock")
.setTooltip("Toggle job lock (clear lock if accidentally left locked)")
.onClick(() => {
this.plugin.settings.locks[cronjob.name].locked = !jobLocked;
this.plugin.settings.locks[cronjob.id].locked = !jobLocked;
this.plugin.saveSettings();
// refresh
this.display()
@ -134,7 +135,7 @@ export default class CronSettingTab extends PluginSettingTab {
.setTooltip("Delete Job")
.onClick(() => {
this.plugin.settings.crons.splice(index, 1)
delete this.plugin.settings.locks[cronjob.name]
delete this.plugin.settings.locks[cronjob.id]
this.plugin.saveSettings();
// Force refresh
this.display();
@ -149,6 +150,7 @@ export default class CronSettingTab extends PluginSettingTab {
.setCta()
.onClick(() => {
this.plugin.settings.crons.push({
id: uuidv4(),
name: "",
job: "",
frequency: "",