Build Your App
Meta allows your Rooms to expose arbitrary key-value metadata that can be set and retrieved at runtime. This can be useful for passing information about the room to clients and MAF Platform service accounts.
Some example use cases for meta include:
Meta entries can be marked as either "public" or "private". Public meta can be accessed by anyone, including clients. Private meta can only be accessed by the app itself (running on MAF Platform) and service accounts. Private meta also includes all public meta. This allows you to store sensitive information in private meta that should not be exposed to clients.
Summary
| Meta Set As | App | Service Accounts | Clients |
|---|---|---|---|
| Public | ✅ | ✅ | ✅ |
| Private | ✅ | ✅ | ❌ |
From an app, you can set and get meta values by accessing app.meta():
use maf::prelude::*;
// Use the `App` extractor to get an interface to additional
// vvv APIs, including meta.
fn host_start_game(app: App, users: Users) -> {
// Set a public meta value, one that clients can read.
// The value can be any type that implements `serde::Serialize` and will be
// serialized to JSON for clients.
app.meta().set(MetaVisibility::Public, "game_state", "in_progress");
// Set a private meta value, one that only the app and service accounts can
// read.
let spy_id = pick_spy(&users);
app.meta().set(MetaVisibility::Private, "spy_id", spy_id);
}
fn host_end_game(app: App) -> {
// Get a meta value. In this example, this value is "given" by a service
// account that created the room, representing whether the game should be
// recorded.
let should_record_game = app
.meta()
// NOTE: Your MAF app can access both public and private meta values.
// See the chart below for more details on visibility.
.get::<bool>("record_game")
.unwrap_or(false);
if should_record_game {
record_game();
}
}
fn build() -> App {
App::builder()
// Initialize the "game_state" meta value to "waiting_for_players".
.meta(MetaVisibility::Public, "game_state", || "waiting_for_players")
.meta(MetaVisibility::Private, "spy_id", || None::<UserId>)
.build()
}
maf::register!(build);
The meta method on AppBuilder can also be used to subscribe to changes from stores, users, or other sources to update meta values dynamically:
use maf::prelude::*;
/// A simple store that holds a counter.
struct CounterStore {
count: i32,
}
impl StoreData for CounterStore { /* ... */ }
fn build() -> App {
App::builder()
.store::<CounterStore>()
// Update the "count" meta value whenever the CounterStore changes.
.meta(MetaVisibility::Public, "count", |store: StoreRef<CounterStore>| {
store.count
})
// Update the "users" meta value to the number of users whenever the
// user list changes.
.meta(MetaVisibility::Public, "users", |users: Users| {
users.count() as i32
})
.build()
}
Both the count and users meta values in this example will be kept up to date automatically when the underlying data changes. The latter is especially useful for keeping track of how many users are currently in a room.
From a service account, Meta values can be accessed via the MAF Platform HTTP API. Meta values are included when creating or retrieving room information:
As an example, GET /api/v1/apps/:org/:app/rooms yields a response:
[
{
"id": "f5934702-8a6b-4fbc-9244-db45b3369a83",
// These meta fields were set by the app running in the room.
"meta": {
"game_state": "in_progress",
"record_game": true
}
// ...other room fields...
}
// ... other rooms ...
]
In TypeScript, the @usemaf/platform package provides type definitions and helper methods for interacting with the MAF Platform API, including meta fields.
On your server, you can retrieve room meta like so:
import { MafServiceClient } from "@usemaf/platform";
const server = new MafServiceClient(/* initialize */);
// Create a new room and access its meta
const newRoom = await server.rooms.create();
console.log(newRoom.meta.game_state); // e.g. "in_progress"
// List all rooms and their meta
const rooms = await server.rooms.list();
for (const room of rooms) {
console.log(`Room ${room.id} is in state ${room.meta.game_state}`);
}
When creating a room via the API, you can also set initial meta values:
import { MafServiceClient } from "@usemaf/platform";
const server = new MafServiceClient(/* initialize */);
const newRoom = await server.rooms.create({
meta: {
// Set a meta value called "message".
message: "welcome to the room!",
// By default, meta values set via the API are private.
// To set public meta, use the object form with visibility.
owner_id: {
visibility: "PRIVATE", // or "PUBLIC"
value: "user_12345",
},
},
});
Meta is not designed for data that changes frequently or cannot be serialized. Using meta for frequently changing data can lead to performance issues as meta changes need to be serialized to JSON and back when updated.