Channels

Each channel is identified by a unique channelId, which is any string that uniquely identifies the channel and is immutable through its lifetime.

There can be only one channel with a particular channelId: if you try to create a channel with an existing channelId, an error will be thrown.

There are three ways of obtaining a channel: via create, join, or get. They all return a LiveObject with the final channel model. However, createChannel() guarentees that the requested channel is a new channel, whereas joinChannel() will attempt to join an existing channel first, and create a new channel if it does not exist yet. Unless there is an absoute requirement to create a new channel, we recommend to always use joinChannel(), as its behavior is the most aligned with most chat room experiences. Lastly channelForId() only gives you back the channel LiveObject, but it won't make the current user join said channel.

Channel management methods are all contained in a ChannelRepository class. Before calling any channel methods, you must ensure to first instantiate a repository instance.

import { ChannelRepository } from 'eko-sdk';
const channelRepo = new ChannelRepository();

Create Channel

import { EkoChannelType } from 'eko-sdk';
const liveChannel = channelRepo.createChannel({
channelId: 'channel1',
type: EkoChannelType.Standard,
userIds: [ 'user1', 'user2' ],
})
.catch(err => {
// Handle channel create error (non-unique channelID)
});
liveChannel.once('dataUpdated', model => {
console.log(`Channel created: ${model.channelId}`);
});

The above code creates a channel and prints out the channelId once it has been successfully created. It first instantiates the ChannelRepository, a class that contains all channel related methods. Then it calls createChannel() to obtain the LiveObject and observe it in order to obtain the final channel model.

Note that the event listener was registered using once(). Unlike on(), once() will automatically unregister the event listener once the first event was emitted. This is useful if you just need to use the model once but do not need to listen to further events.

In the case that there is already an existing channel with the same channelId, the LiveObject will notify you with an error object.

Join Channel

const liveChannel = channelRepo.joinChannel({
channelId: 'channel2',
type: EkoChannelType.Standard,
});
liveChannel.once('dataUpdated', data => {
...
});

joinChannel() is an idempotent method, this means it can be called multiple times throughout the lifecycle of the application, and you can expect this method to always return the same channel. Because of this, you can also use joinChannel() any time you need to fetch a channel, even if you know the user may already be in the channel.

Get Channel

If you want only to fetch a channel's data without joining, you can use the channelForId() method:

const liveChannel = channelRepo.channelForId('channel3');
liveChannel.once('dataUpdated', data => {
...
});

Channel Query

The ChannelRepository provides a simple allChannels property that returns a LiveCollection of all the channels that belongs to the current user. Like other LiveCollections, the returned collection will automatically update and notify you on any channel modifications (e.g. new channel, left channel, modified channel).

const channels = channelRepo.allChannels();
channels.on('dataUpdated', models => {
// reload data
});
// unobserve data changes once you are finished
channels.removeAllListeners('dataUpdated');

Channel Filtering

There are methods to obtain channels that only match specific criteria:

  • the filter parameter let you filter channels based on the logged-in user membership status

  • the includingTags and excludingTags parameters let you filter channels based on the tags set (or not set) in each channel

const channels = channelRepo.channelsWithFilters({
tags: [1,2,3],
excludingTags: [4,5,6],
})
channels.on('dataUpdated', models => {
// reload data
});

Metadata

Metadata is a general purpose data store that is automatically synchronized to all users of a channel. It is meant as an elegant mechanism to store contextual information about a specific channel. The data can be any number of JSON key value pairs up to 100 kb. Example use cases include:

  • Conversation title or cover photo

  • Global conversation settings

Metadata is implemented with last writer wins semantics on the entire store. This means that multiple mutations by independent users to the metadata object will result in a single stored value. No locking, merging, or other coordination is performed across participants.

To set metadata, simply call the following method:

channelRepo.setMetadata({
channelId: 'channel1',
metadata: { hello: 'world' },
})
.then(() => {
// success
}).catch(error => {
console.log('Metadata set fail');
});

The promise notifies you when metadata has been successfully set. The latest metadata of the channel is always exposed as part of the metadata property on the channel model.

Display Name

Every channel contains an optional displayName property. This property is mainly used to identify the channel in push notifications, but it is also exposed to the application via channel model.

You can set a channel's displayName with the following methods:

channelRepo.setDisplayName({
channelId: 'channel1',
displayName: 'Channel Eko',
})
.then(() => {
// success
}).catch(error => {
// handle error
});

A promise is provided to inform you when the displayName has been successfully set, or if there was an error in the request.

Participation

All participation related methods in a channel fall under a seperate ChannelMembershipRepository class. Before calling any participation methods, you must ensure to first instantiate a repository instance using a valid channelId:

import { ChannelMembershipRepository } from 'eko-sdk';
const channelMembershipRepo = new ChannelMembershipRepository('channel1');

Also you can access a ChannelMembershipRepository instance by the membership property of a channel LiveObject model:

const channelMembershipRepo = liveChannel.model.membership;

Members Query

The membership repository provides a list of all members in the given channel as a LiveObject.

const members = channelMembershipRepo.members();
members.on('dataUpdated', models => {
// reload member table
});
// unobserve data changes once you are finished
members.removeAllListeners('dataUpdated');

Manage Members

The membership repository also provides classes to add and remove members, as well as removing yourself as a member of the channel (leaving the channel).

// add 'user1' and 'user2' to this channel
channelMembershipRepo.addMembers({
userIds: [ 'user1', 'user2' ],
})
.then(() => {
// success
}).catch(error => {
// handle error
});
// remove 'user3' from this channel
channelMembershipRepo.removeUsers({
userIds: [ 'user3' ],
})
.then(() => {
// success
}).catch(error => {
// handle error
});
// leave this channel
channelMembershipRepo.leave().catch(error => { ... });

Reading Status And Unread Count

The ChannelMembership also exposes an unreadCount property that reflects the number of messages that the current user has yet to read for a given channel.

console.log(channelMembership.unreadCount) // 0

To let the server know when the current user is reading one channel, hence resetting that channel unreadCount to zero, the participation membership exposes the startReading and stopReading methods.

You can call both methods as much you want, the SDK takes care of multi-platform management: therefore a user can read multiple channels, from one or multiple platform at once. In case of an abrupt disconnection (whether because the app was killed, or the internet went down etc) the SDK backend will automatically call the stopReading on the user's behalf.

// start reading a channel
ChannelMembershipRepository.startReading()
// stop reading a channel
ChannelMembershipRepository.stopReading()