Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Track file access time, new hook based on access time #87

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

dljsjr
Copy link
Contributor

@dljsjr dljsjr commented Feb 20, 2025

This PR adds a new optional intrinsic field $atime?: DateTime to the File interface, and updates the MarkdownPage, Canvas, and GenericFile implementations to conform. $atime is also added to the JSON representations for the above 3 classes:

Some type narrowing utilities for the indexable interfaces were added during this work to assist with satisfying the type checker:

We track $atime using the Obsidian Workspace file-open event:

We also add a new hook, useLastOpenedFiles, for getting a list of the most recently accessed files via this new metadata:

This field will track the last access time of the file in the stored
metadata.

It's added as a part of the `File` interface definition, and implemented for
`MarkdownPage`, `Canvas`, and `GenericFile`, as well as their JSON representations.
Because `File`, `Taggable`, `Linkbearing`, and `Fieldbearing` don't have any
type overlap with `Indexable` itself, direct casting via `as` isn't possible.

We introduce user-defined type-guards to get around this. This adds type narrowing guards
for the above mentioned four interfaces.
We utilize the `Workspace`'s `file-open` event for this. We register
for the event, then update the `$atime` if we already have existing
metadata for the file.

Because we know that file access is non-mutating, we don't perform a
full reload when this happens. We manually set the `$atime` intrinsic
and then call `store` on the file object without recursive sub-storers,
as we don't need to re-parse the file contents or other fields in this
case.

This happens for any `TFile` that has a corresponding datastore entry for its
`path` and whose metadata has the `FILE_TYPE` in its `$types` array.

If the file is a Markdown or Canvas file, we trigger the persister as well.

We then trigger an `update` for the new index revision.
Adds a new Hook to the API that returns a list of files, sorted from
most recent to least recent access time.

The hook is backed by a query for all `@file` metadata objects that have
a populated `$atime` intrinsic.

If the query returns no results, we fall back to the Obsidian
`Workspace`'s `getLastOpenFiles()` function, which returns the last 10
opened file paths without additional any additional information, and we
map those paths to their datastore metadata objects.

Because Obsidian itself doesn't track access times, we aren't really able
to use the fallback list to update our metadata. We just use it to improve
the UX around this new hook.
@blacksmithgu
Copy link
Owner

I'm a bit worried about having this data actually be inside of Datacore's index - the index currently is only updated when the underlying file changes, whereas this now introduces updates on every file open potentially which can be much higher cadence.

Additionally, I believe if you mutate the file, the access time will be lost since the indexer and FileStats object do not have last access time.

As an interim, perhaps we can add the hook where recent file accesses are stored directly via a queue of recent file accesses? We can persist it to local storage as well to make it work across loads.

@dljsjr
Copy link
Contributor Author

dljsjr commented Mar 5, 2025

I actually have some more changes locally that address the mutation story, but I was starting to feel bad about inundating you with unsolicited PR's with non-trivial scope.

That said, it's not a very ergonomic change set, a different data structure might in fact be more appropriate like you're suggesting. So I'll probably evaluate a different approach instead of pushing those changes up.

Anecdotally, I haven't seen any issues with index updates triggering on file access, and I've built a few dashboards on top of this. But I do see where there could be potential for problems with updating the revision with every access. So I'll look at that while I'm revisiting this as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants