Host calls

Storage

On this page

A plugin's own key-value bytes, its storage tables, and SQL on an external database.

Generated by tools/gen_api_docs.py; do not edit by hand. See host calls for how a call is made and how values are encoded. Each example shows the shape of a Wasm request with its required fields; the values in it are illustrative.

CallWhat it does
storeStores a value for this plugin, under a key of its choosing.
loadReads one back, or None if it was never stored.
storage_getOne row of this plugin's table, as JSON text, or None when there is no such row.
sql_submitQueues SQL for an external MySQL database -- one a website reads, whose schema the plugin owns; not the plugin's own storage.
sql_resultA finished batch's outcome, taken: each statement's affected rows as a JSON list, or why it failed (the database's own message, the URL and password taken out).
storage_putInserts or replaces one row.
storage_put_manyKeeps many rows in one call: each table's in one write of the backend, in the order given.
storage_outcomeWhat became of a storage_put_many.
storage_landWaits, for a bounded time, for this plugin's bulk writes to land: for a plugin's stop.
storage_deleteDeletes one row, answering whether there was one.
storage_scanRows whose key starts with prefix, in byte order of the key, after after when given, at most limit (which is at most 1000) of them.
storage_countHow many rows of the table have a key starting with prefix.
storage_migrateStarts moving this plugin's rows from backend from (which must be the one it is on) to to, and answers at once; storage_migration follows it.
storage_migrationThis plugin's latest migration since the server started, or None.
storage_backendWhich backend this plugin's tables are in: json, sqlite or mysql.
storage_dropDrops one of this plugin's own tables: every row in it, at once, in whichever backend it is in.

store

fn store(plugin: &str, key: &str, value: &[u8]) -> ()

Stores a value for this plugin, under a key of its choosing.

Deliberately bytes and not a document store. A plugin that wants structure brings its own encoding, and the server does not grow a schema it would then have to migrate on behalf of somebody else's data.

Wasm request

FieldTypeRequired
valuestringyes
keystringyes

Router notes: plugin is never sent by a Wasm guest: the server fills it in from the manifest name.

Reply: {"ok": ...} holding the Rust return value (), encoded as in conventions.

{"call": "store", "value": "{\"x\":1}", "key": "home"}

load

fn load(plugin: &str, key: &str) -> Option<Vec<u8>>

Reads one back, or None if it was never stored.

Wasm request

FieldTypeRequired
keystringyes

Router notes: plugin is never sent by a Wasm guest: the server fills it in from the manifest name.

Reply: {"ok": ...} holding the Rust return value Option<Vec<u8>>, encoded as in conventions.

{"call": "load", "key": "home"}

storage_get

fn storage_get(plugin: &str, table: &str, key: &str) -> Result<Option<String>, String>

One row of this plugin's table, as JSON text, or None when there is no such row.

Tables are the storage layer the server owner picks a backend for -- JSON files by default, SQLite or MySQL when plugins/storage.json says so -- and the plugin never knows which. Unlike store, every call here answers an error rather than a default: a database that is down is something the plugin must report, not read as "no rows". Table names are [a-z0-9_]{1,48}, keys at most 256 bytes; see storage.

Wasm request

FieldTypeRequired
tablestringyes
keystringyes

Router notes: plugin is never sent by a Wasm guest: the server fills it in from the manifest name.

Reply: {"ok": ...} holding the Rust return value Result<Option<String>, String>, encoded as in conventions. An Err arrives as {"error": "..."}.

{"call": "storage_get", "table": "homes", "key": "home"}

sql_submit

fn sql_submit(plugin: &str, setting: &str, statements: &str) -> Result<u64, String>

Queues SQL for an external MySQL database -- one a website reads, whose schema the plugin owns; not the plugin's own storage. setting names one of the plugin's own secret settings holding the mysql:// URL, which the server reads so the plugin never handles it. statements is a JSON list of {"sql": "...", "params": [...]} (null, numbers, strings, bools), run in one transaction on a worker. Answers the batch's number at once; its outcome comes from sql_result. At most 8 batches running and 2000 statements a batch.

For server owners: give the plugin a database user of its own, on a database of its own -- not the one the storage layer uses, whose rows are every plugin's. A plugin can also change its own secret settings (setting_set), so this lets an installed plugin open a connection to any host it names: plugins are code the owner chose to run.

Needs: one of the plugin's own secret settings holding the database URL; a setting that is not secret is refused .

Wasm request

FieldTypeRequired
settingstringyes
statementsJSON value, read into the Rust parameter statements: &str; see the doc commentyes

Shape and limits, as the router words its errors: "statements should be a list".

Router notes: The plugin is the manifest's name, as for store: a guest cannot read another plugin's tables by naming it. Values cross as JSON and are kept as JSON text. plugin is never sent by a Wasm guest: the server fills it in from the manifest name.

Reply: {"ok": ...} holding the Rust return value Result<u64, String>, encoded as in conventions. An Err arrives as {"error": "..."}.

{"call": "sql_submit", "setting": "database_url", "statements": "SELECT 1"}

sql_result

fn sql_result(plugin: &str, batch: u64) -> Option<Result<String, String>>

A finished batch's outcome, taken: each statement's affected rows as a JSON list, or why it failed (the database's own message, the URL and password taken out). None while it runs.

Needs: see sql_submit.

Wasm request

FieldTypeRequired
batchwhole numberyes

Shape and limits, as the router words its errors: "batch is out of range".

Router notes: plugin is never sent by a Wasm guest: the server fills it in from the manifest name.

Reply: {"ok": ...} holding the Rust return value Option<Result<String, String>>, encoded as in conventions; objects in it carry ok, error. An Err arrives as {"error": "..."}.

{"call": "sql_result", "batch": 1}

storage_put

fn storage_put(plugin: &str, table: &str, key: &str, value: &str) -> Result<bool, String>

Inserts or replaces one row. The value is JSON text, at most 1 MiB.

Wasm request

FieldTypeRequired
tablestringyes
keystringyes
valueJSON value, read into the Rust parameter value: &str; see the doc commentyes

Shape and limits, as the router words its errors: "value should be the JSON to keep".

Router notes: plugin is never sent by a Wasm guest: the server fills it in from the manifest name.

Reply: {"ok": ...} holding the Rust return value Result<bool, String>, encoded as in conventions. An Err arrives as {"error": "..."}.

{"call": "storage_put", "table": "homes", "key": "home", "value": "{\"x\":1}"}

storage_put_many

fn storage_put_many(plugin: &str, tables: &[(String, Vec<(String, String)>)]) -> Result<u64, String>

Keeps many rows in one call: each table's in one write of the backend, in the order given. At most MAX_PUT_MANY (constants) rows across the tables, values JSON as storage_put takes them. Checked before anything is kept. For a plugin writing faster than a row a call can bear. Over the boundary it is a list of values and, per table, a key for each, so a row kept under several indexes is only sent once.

Answers a ticket once the rows are in the backend's queue, in order with the plugin's other calls, so it never holds the tick for a commit. What became of them is storage_outcome's to say, for that ticket and nothing else. An error starting STORAGE_BUSY (constants) means the backend has fallen behind and these rows were not taken.

Wasm request

FieldTypeRequired
rowslistyes
keysobjectyes

Shape and limits, as the router words its errors: "rows should be a list of values"; "keys should be an object of key lists"; "a table's keys should be a list".

Router notes: plugin is never sent by a Wasm guest: the server fills it in from the manifest name.

Reply: {"ok": ...} holding the Rust return value Result<u64, String>, encoded as in conventions. An Err arrives as {"error": "..."}.

{"call": "storage_put_many", "rows": [{"name": "home"}], "keys": {"homes": ["steve:home"]}}

storage_outcome

fn storage_outcome(plugin: &str, ticket: u64) -> crate::StorageOutcome

What became of a storage_put_many. An outcome is told once.

Wasm request

FieldTypeRequired
ticketwhole number, 0 or moreyes

Shape and limits, as the router words its errors: "ticket should be a whole number".

Router notes: plugin is never sent by a Wasm guest: the server fills it in from the manifest name.

Reply: {"ok": ...} holding the Rust return value crate::StorageOutcome, encoded as in conventions; objects in it carry state, error.

{"call": "storage_outcome", "ticket": 1}

storage_land

fn storage_land(plugin: &str) -> Result<(), String>

Waits, for a bounded time, for this plugin's bulk writes to land: for a plugin's stop.

Wasm request

No fields besides call.

Router notes: plugin is never sent by a Wasm guest: the server fills it in from the manifest name.

Reply: {"ok": ...} holding the Rust return value Result<(), String>, encoded as in conventions. An Err arrives as {"error": "..."}.

{"call": "storage_land"}

storage_delete

fn storage_delete(plugin: &str, table: &str, key: &str) -> Result<bool, String>

Deletes one row, answering whether there was one.

Wasm request

FieldTypeRequired
tablestringyes
keystringyes

Router notes: plugin is never sent by a Wasm guest: the server fills it in from the manifest name.

Reply: {"ok": ...} holding the Rust return value Result<bool, String>, encoded as in conventions. An Err arrives as {"error": "..."}.

{"call": "storage_delete", "table": "homes", "key": "home"}

storage_scan

fn storage_scan(plugin: &str, table: &str, prefix: &str, after: Option<&str>, limit: u32) -> Result<Vec<(String, String)>, String>

Rows whose key starts with prefix, in byte order of the key, after after when given, at most limit (which is at most 1000) of them.

Wasm request

FieldTypeRequired
limitwhole numberyes
tablestringyes
prefixstringyes
afterstringno

Shape and limits, as the router words its errors: "after should be a string or null"; "limit should be 1 to 1000".

Router notes: plugin is never sent by a Wasm guest: the server fills it in from the manifest name.

Reply: {"ok": ...} holding the Rust return value Result<Vec<(String, String)>, String>, encoded as in conventions. An Err arrives as {"error": "..."}.

{"call": "storage_scan", "limit": 100, "table": "homes", "prefix": ""}

storage_count

fn storage_count(plugin: &str, table: &str, prefix: &str) -> Result<u64, String>

How many rows of the table have a key starting with prefix.

Wasm request

FieldTypeRequired
tablestringyes
prefixstringyes

Router notes: plugin is never sent by a Wasm guest: the server fills it in from the manifest name.

Reply: {"ok": ...} holding the Rust return value Result<u64, String>, encoded as in conventions. An Err arrives as {"error": "..."}.

{"call": "storage_count", "table": "homes", "prefix": ""}

storage_migrate

fn storage_migrate(plugin: &str, from: &str, to: &str) -> Result<(), String>

Starts moving this plugin's rows from backend from (which must be the one it is on) to to, and answers at once; storage_migration follows it. Only while an operator or the console is running one of the plugin's commands: the backend is the server owner's choice. Until it ends the plugin's writes are refused; once every table's count and checksum match on both sides, to becomes the plugin's backend.

Needs: an operator (level 3) or the console running one of the plugin's own commands at that moment (see the doc comment).

Wasm request

FieldTypeRequired
fromstringyes
tostringyes

Router notes: plugin is never sent by a Wasm guest: the server fills it in from the manifest name.

Reply: {"ok": ...} holding the Rust return value Result<(), String>, encoded as in conventions; objects in it carry started. An Err arrives as {"error": "..."}.

{"call": "storage_migrate", "from": "json", "to": "sqlite"}

storage_migration

fn storage_migration(plugin: &str) -> Result<Option<crate::storage::Migration>, String>

This plugin's latest migration since the server started, or None.

Wasm request

No fields besides call.

Router notes: plugin is never sent by a Wasm guest: the server fills it in from the manifest name.

Reply: {"ok": ...} holding the Rust return value Result<Option<crate::storage::Migration>, String>, encoded as in conventions; objects in it carry from, to, state, error, tables, rows. An Err arrives as {"error": "..."}.

{"call": "storage_migration"}

storage_backend

fn storage_backend(plugin: &str) -> Result<String, String>

Which backend this plugin's tables are in: json, sqlite or mysql.

Wasm request

No fields besides call.

Router notes: plugin is never sent by a Wasm guest: the server fills it in from the manifest name.

Reply: {"ok": ...} holding the Rust return value Result<String, String>, encoded as in conventions. An Err arrives as {"error": "..."}.

{"call": "storage_backend"}

storage_drop

fn storage_drop(plugin: &str, table: &str) -> Result<bool, String>

Drops one of this plugin's own tables: every row in it, at once, in whichever backend it is in. Answers whether it had any rows. What a wipe does to the tables that belong to one world, without walking them a page at a time. Refused while the plugin is migrating, like any write.

Wasm request

FieldTypeRequired
tablestringyes

Router notes: plugin is never sent by a Wasm guest: the server fills it in from the manifest name.

Reply: {"ok": ...} holding the Rust return value Result<bool, String>, encoded as in conventions. An Err arrives as {"error": "..."}.

{"call": "storage_drop", "table": "homes"}

From docs/api/reference/host-calls/storage.md in the RustMC repository at bbd81209ad.