Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Persistent storage

Some services keep state between notifications (an OAuth token, a login session, a channel lookup) in a small key/value store per URL, so the next notification does not log in or look things up again:

ServiceWhat is storedKept for
Telegramthe bot owner (bot_owner) when no chat id is givenuntil removed
Opsgenie, Jirarequest ids of open alerts60 days
Nextcloudgroup member lookups1 day
SendPulseaccess tokenexpires_in minus 10 s
WeChataccess tokenexpires_in minus 300 s; dropped on token errors
Office 365access token (memory only), sender from/name, rotated refresh tokentoken lifetime
Blueskyresolved DID and service endpoint, sessionsession 3590 s
Mattermostchannel ids (c:<channel>)20 days
Vapid (Web Push)generated key pair, subscriptions.json, retired (expired) endpointsretired: 30 days
Matrixlogin session, joined rooms, user lookups, end-to-end encryption keys (?keystore=DIR keeps this URL’s store under DIR)until removed or expired
Reddit, RingCentral, Emby, Jellyfinsession or tokenlifetime of the target (memory only)

Other services write nothing to disk.

Where it lives

The command line uses persistent storage by default:

Default
Location~/.local/share/mercurio/cache (%APPDATA%/Mercurio/cache on Windows)
Override-S PATH / --storage-path PATH, else $APPRISE_STORAGE_PATH
Prune age30 days; -SPD / --storage-prune-days or $APPRISE_STORAGE_PRUNE_DAYS

Each URL gets a namespace directory named after its URL id:

<storage path>/<url id>/cache.json   the entries of this namespace
<storage path>/<url id>/tmp/         staging area for atomic writes
<storage path>/<url id>/var/         service files (Vapid keys and subscriptions)

cache.json maps each key to {"v": value, "x": expiry} (the expiry in Unix seconds or null). The file is read before a URL’s first notification and rewritten when it changed, as the storage mode says (--storage-mode / -SM, APPRISE_STORAGE_MODE for the server, Asset::storage_mode in the library):

  • auto (default): once a notification is over;
  • flush: also before each request or connection of a notification, so a send cut short keeps what it saved (a token from a login step);
  • memory: never; the store lives in memory even with a storage path.

Directories are created on the first write with mode 0700, files with 0600. Files are written to tmp/ and renamed into place. A file that is not valid JSON is removed with a warning. When no saved entry is left, cache.json is deleted.

Services can also keep a value in memory only (an access token, for example): such entries are never written and live as long as the target.

Without a storage path (the library default) every store is in memory. So are the stores of URLs with ?store=no or of services that opt out of URL ids.

URL ids

The namespace is named by a URL id: a SHA-256 hash of the parts that identify the account (scheme, user, password, host, port, path and the secure flag), cut to 8 hexadecimal characters by default. Two URLs that differ only in options share a namespace. Some services hash their own parts instead (for example only the bot token for Telegram).

--storage-uid-length N (-SUL, APPRISE_STORAGE_UID_LENGTH, at least 2; the server accepts 2 to 64) keeps N characters instead, which moves every URL to a new namespace. In the library, Asset::storage_idlen (0 keeps all 64) and Asset::storage_salt (bytes hashed first) work like Apprise’s storage_idlen and storage_salt, so the ids match Apprise’s for the same settings.

?store=no keeps a URL’s store in memory even when a storage path is set.

mercurio storage

mercurio storage [list|prune|clear] [UID-prefix...|URL...] [-S PATH] [-c CONFIG] [-g TAG] [-d]

The action may be abbreviated (l, p, c); clean is accepted for clear. list is the default.

  • list: URL ids of the configured services (from URLs on the command line, -c, $APPRISE_URLS or the default configuration files) next to what is on disk. Each row shows the size and a state: active (on disk and configured), unused (configured, nothing stored yet), stale (on disk, not configured; only shown when no -g is given).
  • prune: remove store files not modified for -SPD days (default 30).
  • clear: remove every store file.

Arguments containing :// select URLs; other arguments are URL id prefixes. -g restricts the action to tagged configuration entries. -d shows what prune or clear would remove without removing it. Empty namespace directories are removed after a prune.

$ mercurio storage -S /tmp/demo/store "json://localhost/hook?tag=ci"
   1. e058d7a2                                             0.00B    unused
      - json://localhost/...
      tags: ci

$ mercurio storage prune -d -S /tmp/demo/store
abcdef12: would remove /tmp/demo/store/abcdef12/cache.json

Prune and clear only remove mercurio’s own files; other files in a namespace directory are left alone.

In the library

Mercurio::new() keeps stores in memory. Give the Asset a storage path to persist them:

#![allow(unused)]
fn main() {
use mercurio::{Asset, Mercurio};

let dir = std::env::temp_dir().join("mercurio-book-storage");
let mut m = Mercurio::new().asset(Asset::default().with_storage(&dir));
m.add("json://example.com/hook")?;
Ok::<(), mercurio::Error>(())
}

A YAML configuration can set the path under asset: (storage_path, a mercurio extension, see Asset overrides). Each ReportEntry carries the url_id of its target.

mercurio::store::PersistentStore is usable on its own; services read their namespace as Context::store.