Session Store

Session store is a shared realtime key-value store that is accessible by everyone in the room. Think of it as additional top-level data associated with a session. Session store can be used to achieve features like pinned text, spotlight (bringing a particular peer into a center stage for everyone in the room), etc.

Session store is persisted throughout a session and is cleared once the last peer leaves the room.

It is recommended to plan an interface for session store so that the app gets to know before hand what keys it needs to observe. If you're using Typescript, using an interface for session store also provides better type-safety and auto-completion. Read Typescript Usage section to know more.

💡 Session Store vs Peer Metadata

While peer metadata is associated with individual peers and each peer can have their own metadata, session store remains the same for every peer in the room.

Usage

Actions required to operate session store live under hmsActions.sessionStore.

Setting session store

Use the set method to set a value under a particular key. Once a value is set under a key, it will be available for other peers in the room who are observing this key.

hmsActions.sessionStore.set('key1', 'value1');

To remove a particular a key, you can call set with the key alone(which is equivalent to setting the value under the key to undefined).

hmsActions.sessionStore.set('key1');

Fetching session metadata

Observe/unobserve

To get updates with the latest values from the session store for a set of keys, the app needs to observe that particular set of keys. This is done keeping in mind the scalability of the session store and not every peer will need access to every key.

This could be done after being successfully connected to the room.

// in a top level component const Conference = () => { const hmsActions = useHMSActions(); const isConnected = useHMSStore(selectIsConnectedToRoom); useEffect(() => { if (isConnected) { hmsActions.sessionStore.observe(['pinnedMessage', 'spotlight']); } }, [hmsActions, isConnected]); return <div>{/** layout to render peers */}</div>; };

Access a particular key

The latest value under a key can be accessed from HMSStore using the selectSessionStore selector.

const val = hmsStore.getState(selectSessionStore('key1'); const unsub = hmsStore.subscribe(val => console.log(val), selectSessionStore('key1'));

Typescript Usage

It is recommended to use an interface for session store when instantiating HMSReactiveStore or HMSRoomProvider. This provides type-safety and better auto-completion when using set/observe actions increasing developer productivity and reducing surface area for bugs.

interface SessionStore { pinnedMessage: string; spotlight: string; usefulLinks: string[]; } const hms = new HMSReactiveStore<{ sessionStore: SessionStore }>();

Limitations and workarounds in Alpha release

  • No permission support - anyone can read/write session metadata. If you want to restrict access to session metadata, you have to do it on your app level logic.
  • Locks to ensure consistency of the data. If two peers update it at the same time, it will be a race condition for which one succeeds last, overwriting whatever was before.

Limits

  • Max payload size for data can be 1KB.
  • Maximum 100 keys are supported with 64KB limit applied to all keys combined.
  • Metadata size for 64 KB also include the key size.

Example - Pin Message

You can use session store to pin information so that it's available for everyone in the room - even for newly joined peers. In this example we'll pin a chat message that's important in React.

PinnedChat

Hook to set pinned message - useSetPinnedMessage

import { useCallback } from 'react'; import { selectPeerNameByID, selectSessionStore, useHMSActions, useHMSStore, useHMSVanillaStore } from '@100mslive/react-sdk'; export const useSetPinnedMessage = () => { const hmsActions = useHMSActions(); const vanillaStore = useHMSVanillaStore(); const pinnedMessage = useHMSStore(selectSessionStore('pinnedMessage')); const setPinnedMessage = useCallback( /** * @param {import("@100mslive/react-sdk").HMSMessage | undefined} message */ async (message) => { const peerName = vanillaStore.getState(selectPeerNameByID(message?.sender)) || message?.senderName; const newPinnedMessage = message ? peerName ? `${peerName}: ${message.message}` : message.message : null; if (newPinnedMessage !== pinnedMessage) { await hmsActions.sessionStore.set('pinnedMessage', newPinnedMessage); } }, [hmsActions, vanillaStore, pinnedMessage] ); return { setPinnedMessage }; };

Display the pinned message

We'll also use the same function returned from the hook to clear the pinned chat by passing in no arguments

import { useHMSStore } from '@100mslive/react-sdk'; import { Box, Flex, IconButton, Text } from '@100mslive/roomkit-react'; import { CrossIcon, PinIcon } from '@100mslive/react-icons'; import { useSetPinnedMessage } from '../hooks/useSetPinnedMessage'; const PinnedMessage = () => { const pinnedMessage = useHMSStore(selectSessionStore('pinnedMessage')); const { setPinnedMessage } = useSetPinnedMessage(); return pinnedMessage ? ( <Flex> <Box> <PinIcon /> </Box> <Text variant="sm">{pinnedMessage}</Text> <IconButton onClick={() => setPinnedMessage()}> <CrossIcon /> </IconButton> </Flex> ) : null; };

Example - Spotlight

You can use session store to bring a particular peer/set of peers to center stage for everyone in the room

Action to spotlight a particular tile

// https://github.com/100mslive/100ms-web/blob/sync-webapp/src/components/TileMenu.jsx import { selectSessionStore, useHMSActions, useHMSStore } from '@100mslive/react-sdk'; import { StyledMenuTile } from '@100mslive/roomkit-react'; const isSameTile = ({ trackId, videoTrackID, audioTrackID }) => trackId && ((videoTrackID && videoTrackID === trackId) || (audioTrackID && audioTrackID === trackId)); // render it in your tile menu const SpotlightActions = ({ audioTrackID, videoTrackID }) => { const hmsActions = useHMSActions(); const spotlightTrackId = useHMSStore(selectSessionStore('spotlight')); const isTileSpotlighted = isSameTile({ trackId: spotlightTrackId, videoTrackID, audioTrackID }); const setSpotlightTrackId = (trackId) => hmsActions.sessionStore.set('spotlight', trackId); return ( <StyledMenuTile.ItemButton onClick={() => isTileSpotlighted ? setSpotlightTrackId() : setSpotlightTrackId(videoTrackID || audioTrackID) }> <StarIcon /> <span> {isTileSpotlighted ? 'Remove from Spotlight' : 'Spotlight Tile for everyone'} </span> </StyledMenuTile.ItemButton> ); };

Center Stage/Spotlight View

// https://github.com/100mslive/100ms-web/blob/sync-webapp/src/layouts/PinnedTrackView.jsx import React from 'react'; import { selectPeers, selectVideoTrackByPeerID, useHMSStore } from '@100mslive/react-sdk'; import { Flex } from '@100mslive/roomkit-react'; import VideoTile from '../components/VideoTile'; const CenterStageView = () => { // can be audio or video track, if tile with only audio track is pinned const spotlightTrackId = useHMSStore(selectSessionStore('spotlight')); const spotlightTrack = useHMSStore(selectTrackByID(spotlightTrackId)); const peerVideoTrack = useHMSStore(selectVideoTrackByPeerID(spotlightTrack.peerId)); const spotlightVideoTrack = spotlightTrack && spotlightTrack.type === 'audio' ? peerVideoTrack : spotlightTrack; const peers = (useHMSStore(selectPeers) || []).filter( (peer) => peer.videoTrack || peer.audioTrack || peer.auxiliaryTracks.length > 0 ); if (peers.length === 0) { return null; } const showSidePane = spotlightTrack && peers.length > 1; return ( <Flex css={{ size: '100%' }}> <Flex> <VideoTile key={spotlightTrack.id} trackId={spotlightVideoTrack?.id} peerId={spotlightTrack.peerId} /> </Flex> {showSidePane && ( <GridSidePaneView peers={peers.filter((peer) => peer.id !== spotlightTrack.peerId)} /> )} </Flex> ); }; export default CenterStageView;

Have a suggestion? Recommend changes ->

Was this helpful?

1234