Skip to content

Commit

Permalink
fix issue with updateOnStartup
Browse files Browse the repository at this point in the history
this was, because i do not load cached settings correctly
  • Loading branch information
Heiss committed Aug 8, 2024
1 parent 13aefad commit 69e8001
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 59 deletions.
1 change: 0 additions & 1 deletion main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ export default class VikunjaPlugin extends Plugin {
this.userObject = undefined;
this.labelsApi = new Label(this.app, this);
this.projectsApi = new Projects(this.app, this);
this.cache = new VaultTaskCache(this.app, this);
}

private setupCommands() {
Expand Down
5 changes: 0 additions & 5 deletions src/processing/getTasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,6 @@ class GetTasks implements IAutomatonSteps {
await this.handleDataviewIndex();
}

if (this.plugin.settings.updateOnCursorMovement) {
const tasks = this.plugin.cache.getCachedTasks();
if (this.plugin.settings.debugging) console.log("GetTasks: Using cache", tasks);
return tasks;
}
if (this.plugin.settings.debugging) console.log("Step GetTask: Pulling tasks from vault");
return await this.vaultSearcher.getTasks(this.taskParser);
}
Expand Down
37 changes: 13 additions & 24 deletions src/processing/processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import Plugin from "../../main";
import {App, MarkdownView, moment, Notice, TFile} from "obsidian";
import {PluginTask, VaultSearcher} from "../vaultSearcher/vaultSearcher";
import {TaskFormatter, TaskParser} from "../taskFormats/taskFormats";
import {Automaton, AutomatonStatus, IAutomatonSteps} from "./automaton";
import UpdateTasks from "./updateTasks";
import {Automaton, AutomatonStatus} from "./automaton";
import {EmojiTaskFormatter, EmojiTaskParser} from "../taskFormats/emojiTaskFormat";
import {backendToFindTasks, chooseOutputFile, supportedTasksPluginsFormat} from "../enums";
import {DataviewSearcher} from "../vaultSearcher/dataviewSearcher";
Expand Down Expand Up @@ -119,23 +118,14 @@ class Processor {
* This method should only be triggered on startup of obsidian and only once. After this, we cannot guerantee that the updated information of files are in sync.
*/
async updateTasksOnStartup() {
if (this.plugin.settings.debugging) console.log("Processor: Update tasks in vault and vikunja");
if (this.alreadyUpdateTasksOnStartup) throw new Error("Update tasks on startup can only be called once");
if (this.plugin.commands.isEverythingSetup()) {
if (this.plugin.settings.debugging) console.log("Processor: Found problems in plugin. Have to be fixed first. Syncing is stopped.");
return;
}
if (!this.plugin.settings.updateOnStartup) {
if (this.plugin.settings.debugging) console.log("Processor: Update on startup is disabled");
return;
}
if (this.alreadyUpdateTasksOnStartup) throw new Error("Update tasks on startup can only be called once");
if (this.plugin.settings.debugging) console.log("Processor: Update tasks in vault and vikunja");

const localTasks = await this.vaultSearcher.getTasks(this.taskParser);
const vikunjaTasks = await this.plugin.tasksApi.getAllTasks();

const updateStep: IAutomatonSteps = new UpdateTasks(this.app, this.plugin, this);
await updateStep.step(localTasks, vikunjaTasks);

await this.exec();
this.alreadyUpdateTasksOnStartup = true;
}

Expand Down Expand Up @@ -218,18 +208,17 @@ class Processor {
await this.app.vault.process(file, (data: string) => {
const lines = data.split("\n");
lines.splice(task.lineno, 1, newTask);
const content = lines.join("\n");
try {
this.plugin.cache.update(task);
} catch (e) {
if (metadata) {
// raise error again, if metadata was wanted! otherwise it is expected, that update will fail.
throw e;
}
}
return content;
return lines.join("\n");
});

try {
this.plugin.cache.update(task);
} catch (e) {
if (metadata) {
// raise error again, if metadata was wanted! otherwise it is expected, that update will fail, because id is missing.
throw e;
}
}
}

getVaultSearcher(): VaultSearcher {
Expand Down
41 changes: 29 additions & 12 deletions src/settings/VaultTaskCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,51 +2,63 @@ import VikunjaPlugin from "../../main";
import {App, moment} from "obsidian";
import {PluginTask} from "../vaultSearcher/vaultSearcher";


interface Cache<T> {
[key: number]: T;
}

/*
* This class is used to cache tasks which are updated in Vault, but not in Vikunja.
* This should help to identify modifications in vault without Obsidian.
* Also it makes it possible to update only modified tasks. See issue #9 for more details.
*/
export default class VaultTaskCache {
private static readonly SAVE_TO_DISK_DELAYED_INTERVAL = 250;
plugin: VikunjaPlugin;
app: App;
changesMade: boolean;
private cache: Map<number, PluginTask>
private saveToDiskDelayedListener: number | undefined;

constructor(app: App, plugin: VikunjaPlugin) {
this.app = app;
this.plugin = plugin;
this.changesMade = false;
this.cache = new Map<number, PluginTask>();
this.saveToDiskDelayedListener = undefined;
}

public static fromJson(json: any, app: App, plugin: VikunjaPlugin): VaultTaskCache {
const cache = new VaultTaskCache(app, plugin);
const taskCache = new VaultTaskCache(app, plugin);
console.log("VaultTaskCache: Loading cache from disk", json);
const tempCache = Object.entries(json).map((taskJson: any) => {
const id = parseInt(taskJson[0]);
const task = PluginTask.fromJson(taskJson[1]);
if (task === undefined) {
return undefined
}
const id = task.task.id;
if (id === undefined) {
throw new Error("VaultTaskCache: Task id is not defined");
}
return [id, task];
}).filter((task: any) => task !== undefined);
// @ts-ignore
cache.cache = new Map<number, PluginTask>(tempCache);
console.log("VaultTaskCache: Loaded cache from disk", cache.cache);
return cache;
taskCache.cache = new Map<number, PluginTask>(tempCache);
console.log("VaultTaskCache: Loaded cache from disk", taskCache.cache);
return taskCache;
}

/*
* This function is used to save the cache to disk, but it waits an interval until it is saved.
* It resets the interval everytime, anything calls this method.
*/
async saveCacheToDiskDelayed() {
window.clearInterval(this.saveToDiskDelayedListener);
this.saveToDiskDelayedListener = window.setInterval(async () => {
await this.saveCacheToDisk();
}, VaultTaskCache.SAVE_TO_DISK_DELAYED_INTERVAL);
this.plugin.registerInterval(this.saveToDiskDelayedListener);
}

async saveCacheToDisk() {
if (this.changesMade) {
this.plugin.settings.cache = this.getCachedTasks().map(task => task.toJson());
if (this.plugin.settings.debugging) console.log("VaultTaskCache: Updated cache in settings", this.plugin.settings.cache);
if (this.plugin.settings.debugging) console.log("VaultTaskCache: Saving cache to disk");
await this.plugin.saveSettings();
}
this.changesMade = false;
Expand Down Expand Up @@ -77,8 +89,13 @@ export default class VaultTaskCache {
}
this.cache.set(local.task.id, local);

console.log("VaultTaskCache: Updated cache", this.cache);
this.changesMade = true;

if (this.plugin.settings.saveCacheToDiskImmediately) {
this.saveCacheToDiskDelayed().then(() => {
if (this.plugin.settings.debugging) console.log("VaultTaskCache: Saved cache to disk");
});
}
}

get(id: number): PluginTask | undefined {
Expand Down
56 changes: 39 additions & 17 deletions src/settings/mainSetting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export interface VikunjaPluginSettings {
selectedView: number,
selectBucketForDoneTasks: number,
cache: PluginTask[], // do not touch! Only via settings/VaultTaskCache.ts
saveCacheToDiskImmediately: boolean,
saveCacheToDiskFrequency: number,
updateCompletedStatusImmediately: boolean,
}
Expand Down Expand Up @@ -61,6 +62,7 @@ export const DEFAULT_SETTINGS: VikunjaPluginSettings = {
selectedView: 0,
selectBucketForDoneTasks: 0,
cache: [],
saveCacheToDiskImmediately: true,
saveCacheToDiskFrequency: 1,
updateCompletedStatusImmediately: false,
}
Expand All @@ -75,7 +77,9 @@ export class MainSetting extends PluginSettingTab {
super(app, plugin);
this.plugin = plugin;

this.startCacheListener();
if (!this.plugin.settings.saveCacheToDiskImmediately) {
this.startCacheListener();
}
this.startCronListener();
}

Expand Down Expand Up @@ -202,25 +206,43 @@ export class MainSetting extends PluginSettingTab {
}

new Setting(containerEl)
.setName("Save cache to disk frequency")
.setDesc("This plugin uses a cache to calculate correct dates. Set the interval in minutes to save the cache to disk. Lower values will result in more frequent saves, but may cause performance issues. Set too high, task dates are not correctly calculated, because they are missing in cache in next startup. If you make bulk edits of tasks in your vault, you should set higher value. Cache will be only written, if changes were made since last check. If you are unsure, try lowest value and increase it, if you experience performance issues. Limits are 1 to 60 minutes.")
.addText(text => text
.setValue(this.plugin.settings.saveCacheToDiskFrequency.toString())
.onChange(async (value: string) => {
const parsedNumber = parseInt(value);
if (Number.isNaN(parsedNumber)) {
return;
}
const lowerThanMax = Math.min(parsedNumber, 60);
if (this.plugin.settings.debugging) console.log("Save cache to disk frequency - high limits", lowerThanMax);
const higherThanMin = Math.max(lowerThanMax, 1);
if (this.plugin.settings.debugging) console.log("Save cache to disk frequency - low limits", higherThanMin);
this.plugin.settings.saveCacheToDiskFrequency = higherThanMin;
await this.plugin.saveSettings();
.setName("Update cache to disk immediately")
.setDesc("If enabled, the cache will be written to disk immediately after a change. If disabled, the cache will be written to disk after a certain interval. If you experience performance issues, you should disable this and use a frequency.")
.addToggle(toggle => toggle
.setValue(this.plugin.settings.saveCacheToDiskImmediately)
.onChange(async (value: boolean) => {
this.plugin.settings.saveCacheToDiskImmediately = value;
await this.plugin.saveSettings();
if (value) {
clearInterval(this.cacheListener);
} else {
this.startCacheListener();
}
this.display();
}));

if (!this.plugin.settings.saveCacheToDiskImmediately) {
new Setting(containerEl)
.setName("Save cache to disk frequency")
.setDesc("This plugin uses a cache to calculate correct dates. Set the interval in minutes to save the cache to disk. Lower values will result in more frequent saves, but may cause performance issues. Set too high, task dates are not correctly calculated, because they are missing in cache in next startup. If you make bulk edits of tasks in your vault, you should set higher value. Cache will be only written, if changes were made since last check. If you are unsure, try lowest value and increase it, if you experience performance issues. Limits are 1 to 60 minutes.")
.addText(text => text
.setValue(this.plugin.settings.saveCacheToDiskFrequency.toString())
.onChange(async (value: string) => {
const parsedNumber = parseInt(value);
if (Number.isNaN(parsedNumber)) {
return;
}
const lowerThanMax = Math.min(parsedNumber, 60);
if (this.plugin.settings.debugging) console.log("Save cache to disk frequency - high limits", lowerThanMax);
const higherThanMin = Math.max(lowerThanMax, 1);
if (this.plugin.settings.debugging) console.log("Save cache to disk frequency - low limits", higherThanMin);
this.plugin.settings.saveCacheToDiskFrequency = higherThanMin;
await this.plugin.saveSettings();
this.startCacheListener();
}
)
)
)
}

new Setting(containerEl).setHeading().setName('Vikunja Settings').setDesc('Settings to connect to Vikunja.');

Expand Down

0 comments on commit 69e8001

Please sign in to comment.