Skip to main content
Version: 5.x

Realtime Store

With the release of another great feature, Realtime Store for Connected Lenses, we prepared for you a template that showcases its potential. The template shows you how to use the feature for real-time voting.

The Realtime Store adds flexibility to Lens Creators as a way to keep content in sync among all connected users in a Lens. With this, once someone makes a change, all other participants will receive that change. This feature also allows you to set up multiple Real-Time Store for a session. From this guide you will learn how to create such a store and keep it updated so that all the connected users get the shared information.

Cloud Storage is another great feature that allows you to store data remotely. However, keep in mind that it is a different technology. Make sure you do not confuse API methods and approaches to work with either Realtime Store or Cloud Storage.

In order for Realtime Storage Lenses to work correctly, its Lens Visibility must be Public.

Creating a Realtime Store

The first step is creating a connected session. In this guide, you will be focusing on working with a Realtime Store. You can create this store by calling a special method of a session instance:

session.createRealtimeStore(options, onSuccess, onError);

This method takes three arguments: store creation options, onSuccess callback and onError callback. These callbacks will be called when a store is created or there was an error on store creation, respectively.

Session Creation Options

A Realtime Store has its own properties and you can set them depending on your needs.

var options = RealtimeStoreCreateOptions.create();
options.ownership = Ownership.Owned;
options.persistence = Persistence.Session;

Store Ownership

Since you can have multiple stores in a single session, it becomes reasonable to control access to each stores. The ownership property is provided for that purpose. A Realtime Store can be set to Owned or Unowned. Owned, once created, can be updated only by the creator of it, while Unowned can be changed by anyone.

No matter what the ownership of a store is, all users in the session will be notified if the store has changed.

It is possible to change ownership of a store after it has been created. The method shown below provides how it can be done:

//REQUEST OWNERSHIP API
session.requestRealtimeStoreOwnership(
store,
function onSuccess(store) {
log('REQUEST OWNERSHIP API - OnSuccess');
},
function onError(message) {
log('REQUEST OWNERSHIP API - OnError: ' + message);
}
);

//CLEAR OWNERSHIP API
session.clearRealtimeStoreOwnership(
store,
function onSuccess(store) {
log('CLEAR OWNERSHIP API - OnSuccess');
},
function onError(message) {
log('CLEAR OWNERSHIP API - OnError: ' + message);
}
);

Realtime Store Lifetime

Each store has its own lifetime. Some stores can exist as long as at least one of the users stays in the lens experience, while others can be accessible even if all participants have left the session and returned to it later. These are the options that allow you to control a store’s lifetime.

enum Persistence {
// EPHEMERAL indicates the Entity will be deleted after it is broadcast.
Ephemeral = 0,
// OWNER will delete the Entity when the owner leaves.
Owner = 1,
// SESSION will mark an Entity as unowned when the owner leaves. The Entity will be deleted when all clients leave.
Session = 2,
// PERSIST will mark an Entity as unowned when the owner leaves. The Entity will be created as unowned when any client rejoins.
Persist = 3,
};

::: note Leaving a Lens experience in the store lifetime context means that the user left the lens itself into the chat or exited the app. :::

It is also possible to add initial values to the store to be created. To do so, a GeneralDataStore instance has to be created and later on, when you create a store, you can set this instance as the initialStore property of the real time store creation options:

var initialStore = GeneralDataStore.create();
initialStore.putInt('initIntKey', 1);
initialStore.putString('intStringKey', 'initStringValue');

// Add initial store as initialStore property
var options = RealtimeStoreCreateOptions.create();
// …
options.initialStore = initialStore;

Subscribing to the store creation, as well as its updating and deleting events, can be done when creating a new session. You can add needed callbacks to the session creation options like so:

var options = ConnectedLensSessionOptions.create();
options.onRealtimeStoreCreated = _onRealtimeStoreCreated;
options.onRealtimeStoreUpdated = _onRealtimeStoreUpdated;
options.onRealtimeStoreDeleted = _onRealtimeStoreDeleted;
options.onRealtimeStoreOwnershipUpdated = _onRealtimeStoreOwnershipUpdated;
script.connectedLensModule.createSession(options);

This should give a clear understanding that Realtime Stores are tied to session. Once you have recreated a new session, all the callbacks from the stores created for the previous session will not be received.

It is important to understand that in the connected lens experience you will be creating a session twice. First time when you “initiate” the lens by hitting the Start button on your device, and another one when you share the session by inviting other users via invitation, from your Snapchat friends list in other words.

A Realtime Store must be created in the onConnected callback.

Creating One Store

As mentioned, having multiple stores gives you a lot of flexibility. Although for this particular voting example it is enough to have only one store. And to help you with heavy lifting, there is a SessionController script which takes care of creating that one store and keeps track of it. Consider it as a superset or a wrapper over the Connected Lens module that provides a higher API level for dealing with it.

It has its own callbacks to which you can subscribe and perform needed actions when they are thrown. The most important one is “onReady”. When you work with connected lenses there are multiple lower level callbacks that will be called, like: onSessionCreated, onSessionShared, onConnected. You may find more information about it in the session creation guide. The “onReady” callback will be called when all these lower level callbacks are received.

Another important usage of the SessionController is that it allows the creation of the real time store if it has not been created yet in this session or in the earlier sessions. As we mentioned above, each store has its own lifetime. And for the Persistent store, we don’t need to recreate it every time the lens experience starts, as it “lives” as long as the associated session exists. Or, speaking more accurately, it will be recreated automatically if someone joins the session.

All the previous stores are recreated for the user who joins the session. Which means they will have as many onRealtimeStoreCreate callbacks as the number of stores that have been created. This is always true for Persistent stores. Although for stores with session lifetime, if every user leaves the session, all such stores will be deleted. And if any of the users re-enter that session, they will not get any onRealtimeStore created callbacks, as all the stores have already been deleted.

The SessionController also serves another useful purpose. It can imitate the user connections in Lens Studio, which can help you to develop the lens and handle events when users will be joining the session. By default it requests from the backend the local user ID and makes it available when ready, so you can easily use it for your needs.

Writing into Realtime Store

Updating a real time store is a trivial task. One just needs to call a respective method depending on what type of value needs to be added. For integer or string values, for example, putInt or putString has to be called with key and value as arguments. If the store does not have a provided key, it will create one automatically.

//ADD API
store.putInt('intKey', 2);
store.putString('stringKey', 'stringValue');

For complete reference of all types of values that can be added into a real time store, please refer to the API reference.

Reading Realtime Store

Reading from store can be done by calling “get” methods depending on the value type you want to read. For integers or strings it is:

//READ API
store.getInt('intKey');
store.getString('stringKey');

When reading and writing values it might be useful to check if a store has a requested key. The “has” method can help here. This method returns true or false depending on the key existance:

// Request key existance
store.has('intKey');

Deleting Realtime Store

If you no longer need a real time store, it is pretty simple to delete it by calling the designed for it method:

//DELETE API
session.deleteRealtimeStore(
store,
function onSuccess(store) {
log('DELETE API - OnSuccess');
},
function onError(message) {
log('DELETE API - OnError: ' + message);
}
);

Template Structure

If you want to use the template or its parts as is, here are some insights of its structure. In its essence the template replicates Declarative approach for managing UI. UI components are so-called stateful components, which means each component has its own state, that it can change and automatically reflect the change.

The heavy lifting of updating the components and making them respond to updates is done by the StatefulComponent script, which you can find to be attached to most scene objects. This script holds its state and passes it, once updated, to the Builder scripts that do the actual UI building. You also can find such Builder scripts attached right below StatefulComponents where they are used.

Thus, whenever a StatefulComponent has its state updated, it calls the corresponding Builder script and its build method with the updated state.

The main StatefulComponent is attached to the Orthographic Camera scene object and it is the entry point for the Lens. The builder attached to the scene object also communicates with the SessionController. The SessionController helps us keep things encapsulated by containing everything related to the connected session. All other scripts just receive updates from this main builder. Some scripts, when they need it, can call a corresponding method of the SessionController builder and react to its updated state. For example the RestartSession script.

Some things might raise questions, like: what is the script.component property in every builder and where does it comes from? This is done when the StatefulComponent, governing this builder, does its own initialization. It simply adds the component property to the builder if found. But as it initializes before the builder, by the time the builder does its own job, it already has the added component property.

You might see those sort of “mysterious” arbitrary functions used in builder scripts. Those are also added by the StatefulComponent to itself and their existence is conditioned by its properties that make links between the new property to add and the scene component that property has to control.

This is a brief description of who the UI part of the template works under the hood, and going into further details would distract us from the main topic of this guide. So we will keep it simple and focused on the Realtime Store usage.

Conclusion

Use this template for developing some creative connected experiences that require a single, and accessible by all users, real time store or create your own sophisticated solutions with this very flexible Realtime Store feature.

Was this page helpful?
Yes
No

AI-Powered Search