val channelClient = client.channel(channelType = "messaging", channelId = "general")
channelClient.watch().enqueue { result ->
if (result.isSuccess) {
val channel: Channel = result.data()
} else {
// Handle result.error()
}
}
Watching a Channel
The call to channel.watch does a few different things in one API call:
It creates the channel if it doesn’t exist yet (if this user has the right permissions to create a channel)
It queries the channel state and returns members, watchers and messages
It watches the channel state and tells the server that you want to receive events when anything in this channel changes
To start watching a channel
The examples below show how to watch a channel. Note that you need to be connected as a user before you can watch a channel.
const state = await channel.watch();
final state = await channel.watch();
/// Channels are watched automatically when they're synchronized.
/// 1: Create a `ChannelId` that represents the channel you want to watch.
let channelId = ChannelId(type: .messaging, id: "general")
/// 2: Use the `ChatClient` to create a `ChatChannelController` with the `ChannelId`.
let channelController = chatClient.channelController(for: channelId)
/// 3: Call `ChatChannelController.synchronize` to watch the channel.
channelController.synchronize { error in
if let error = error {
/// 4: Handle possible errors
print(error)
}
}
const FChannelProperties Properties{
TEXT("messaging"), // Type
TEXT("general"), // Id
};
Client->WatchChannel(
Properties,
[](UChatChannel* Channel)
{
// Started watching channel
});
var filters = new IFieldFilterRule[]
{
UserFilter.Id.EqualsTo("other-user-id")
};
// find user you want to start chat with
var users = await Client.QueryUsersAsync(filters);
var otherUser = users.First();
var localUser = Client.LocalUserData.User;
// Get channel by ID
var channel = await Client.GetOrCreateChannelWithIdAsync(ChannelType.Messaging, channelId: "my-channel-id");
// Get channel with users combination
var channelWithUsers
= await Client.GetOrCreateChannelWithMembersAsync(ChannelType.Messaging,
new[] { localUser, otherUser });
// Access properties
Debug.Log(channel.Name);
Debug.Log(channel.Members);
Debug.Log(channel.Name);
Debug.Log(channel.Name);
// Subscribe to events so you can react to updates
channel.MessageReceived += OnMessageReceived;
channel.MessageUpdated += OnMessageUpdated;
channel.MessageDeleted += OnMessageDeleted;
channel.ReactionAdded += OnReactionAdded;
channel.ReactionUpdated += OnReactionUpdated;
channel.ReactionRemoved += OnReactionRemoved;
// You can also access all currently watched channels via
foreach (var c in Client.WatchedChannels)
{
// Every queried channel is automatically watched and starts receiving updates from the server
}
ChannelClient channelClient = client.channel("messaging", "general");
channelClient.watch().enqueue(result -> {
if (result.isSuccess()) {
Channel channel = result.data();
} else {
// Handle result.error()
}
});
Response Schema
Name | Type | Description |
---|---|---|
config | object | The configuration for the channel type. |
channel | object | The Channel object. |
online | integer | Number of online members. |
watchers | object | Users that are watching this channel. Represented as a mapping from the user id to the user object. |
members | object | Channel members. Represented as a mapping from the user id to the user object. |
read | object | Read messages grouped by user id. Represented as a mapping from the user id to the message object. |
Watching a channel only works if you have connected as a user to the chat API
Watchers vs Members
The concepts of watchers vs members can require a bit of clarification:
members : a permanent association between a user and a channel. If the user is online and not watching the channel they will receive a notification event, if they are offline they will receive a push notification.
watchers : the list of watchers is temporary. It’s anyone who is currently watching the channel.
Being able to send messages, and otherwise engage with a channel as a non-member requires certain permissions. For example, we have pre-configured permissions on our livestream channel type to allow non-members to interact, but in the messaging channel type, only members of the channel can interact.
Watching Multiple Channels
The default queryChannels API returns channels and starts watching them. There is no need to also use channel.watch on the channels returned from queryChannels
val request = QueryChannelsRequest(
filter = Filters.and(
Filters.eq("type", "messaging"),
Filters.`in`("members", listOf(currentUserId)),
),
offset = 0,
limit = 10,
querySort = QuerySortByField.descByName("last_message_at")
).apply {
// Watches the channels automatically
watch = true
state = true
}
// Run query on ChatClient
client.queryChannels(request).enqueue { result ->
if (result.isSuccess) {
val channels: List<Channel> = result.data()
} else {
// Handle result.error()
}
}
// first let’s create a filter to make messaging channels that include a specific user
const filter = { type: 'messaging', members: { $in: [user_id] } };
// we can also define a sort order of most recent messages first
const sort = { last_message_at: -1 };
// finally, we can query for those channels, automatically watching them for the
// currently connected user
const channels = await client.queryChannels(filter, sort, {watch:true});
// first let’s create a filter to make messaging channels that include a specific user
final filter = {
"type": "messaging",
"members": {
"\$in": [user_id]
}
};
// we can also define a sort order of most recent messages first
final sort = [SortOption("last_message_at", direction: SortOption.DESC)];
// finally, we can query for those channels, automatically watching them for the
// currently connected user
final channels = await client.queryChannels(
filter: filter,
sort: sort,
options: {
"watch": true,
"state": true,
},
);
/// Channels are watched automatically when they're synchronized.
let channelListController = client.channelListController(
query: .init(
filter: .and(
[.equal(.type, to: .messaging),
.containMembers(userIds: [user_id])
]
),
sort: [.init(key: .lastMessageAt, isAscending: true)]
)
)
/// Call `synchronize` to watch the channel.
channelListController.synchronize { error in
if let error = error {
/// 4: Handle possible errors
print(error)
}
}
const FString UserId = TEXT("my-user-id");
const FFilter Filter = FFilter::In(TEXT("members"), {UserId});
const TArray<FChannelSortOption> SortOptions{{EChannelSortField::LastMessageAt, ESortDirection::Descending}};
Client->QueryChannels(
Filter,
SortOptions,
EChannelFlags::State | EChannelFlags::Watch, // Flags
{}, // Pagination Options
[](const TArray<UChatChannel*> ReceivedChannels)
{
// Started watching channels
});
var localUser = Client.LocalUserData.User;
var filters = new IFieldFilterRule[]
{
// Get channels where local user is a member
ChannelFilter.Members.In(localUser.Id)
};
var channels = await Client.QueryChannelsAsync(filters);
// Get all currently watched channels
foreach (var channel in channels)
{
// Access properties
Debug.Log(channel.Name);
Debug.Log(channel.Members);
Debug.Log(channel.Name);
Debug.Log(channel.Name);
// Subscribe to events so you can react to updates
channel.MessageReceived += OnMessageReceived;
channel.MessageUpdated += OnMessageUpdated;
channel.MessageDeleted += OnMessageDeleted;
channel.ReactionAdded += OnReactionAdded;
channel.ReactionUpdated += OnReactionUpdated;
channel.ReactionRemoved += OnReactionRemoved;
}
FilterObject filter = Filters.and(
Filters.eq("type", "messaging"),
Filters.in("members", Arrays.asList(currentUserId))
);
int offset = 0;
int limit = 10;
QuerySortByField<Channel> sort = QuerySortByField.descByName("last_message_at");
int messageLimit = 0;
int memberLimit = 0;
QueryChannelsRequest request = new QueryChannelsRequest(filter, offset, limit, sort, messageLimit, memberLimit)
.withWatch() // Watches the channels automatically
.withState();
// Run query on ChatClient
client.queryChannels(request).enqueue((result) -> {
if (result.isSuccess()) {
List<Channel> channels = result.data();
} else {
// Handle result.error()
}
});
Stop Watching a Channel
To stop receiving channel events:
channelClient.stopWatching().enqueue { result ->
if (result.isSuccess) {
// Channel unwatched
} else {
// Handle result.error()
}
}
// we can also stop watching a channel
const stopWatching = await channel.stopWatching();
// we can also stop watching a channel
final stopWatching = await channel.stopWatching();
Channel->StopWatching();
await channel.StopWatchingAsync();
channelClient.stopWatching().enqueue(result -> {
if (result.isSuccess()) {
// Channel unwatched
} else {
// Handle result.error()
}
});
channelController.stopWatching { error in
// …
}
Watcher Count
To get the watcher count of a channel:
val request = QueryChannelRequest().withState()
channelClient.query(request).enqueue { result ->
if (result.isSuccess) {
val channel: Channel = result.data()
channel.watcherCount
} else {
// Handle result.error()
}
}
// filter on a specific channel cid
const filter = { cid: channelCID };
// sort by most recent messages first
const sort = { last_message_at: -1 };
// retrieve our channels
const channels = await client.queryChannels(filter, sort);
// each channel object has a state collection with a watcher_count property
return channels[0].state.watcher_count
// create a new channel of type “livestream” with name “watch-this-channel”
final channel = client.channel("livestream", id: "watch-this-channel");
// retrieve our channels
channel.query();
// each channel object has a state collection with a watcher_count property
return channel.state.watcherCount;
/// Channels are watched automatically when they're synchronized.
/// 1: Create a `ChannelId` that represents the channel you want to watch.
let channelId = ChannelId(type: .messaging, id: "general")
/// 2: Use the `ChatClient` to create a `ChatChannelController` with the `ChannelId`.
client.channelController(for: .init(cid: channelId, watchersLimit: 25))
/// 3: Call `ChatChannelController.synchronize` to watch the channel.
channelController.synchronize { error in
if let error = error {
/// 4: Handle possible errors
print(error)
}
// Access watcherCount
channelController.channel?.watcherCount
}
const FChannelProperties Properties{
TEXT("livestream"), // Type
TEXT("watch-this-channel"), // Id
};
Client->WatchChannel(
Properties,
[](const UChatChannel* Channel)
{
// Do something with:
Channel->State.WatcherCount;
});
Debug.Log(channel.WatcherCount);
QueryChannelRequest request = new QueryChannelRequest().withState();
channelClient.query(request).enqueue((result) -> {
if (result.isSuccess()) {
Channel channel = result.data();
channel.getWatcherCount();
} else {
// Handle result.error()
}
});
Paginating Channel Watchers with channel.query
val request = QueryChannelRequest()
.withWatchers(limit = 5, offset = 0)
channelClient.query(request).enqueue { result ->
if (result.isSuccess) {
val channel: Channel = result.data()
val watchers: List<User> = channel.watchers
} else {
// Handle result.error()
}
}
// create a new channel of type “livestream” with name “watch-this-channel”
const channel = client.channel("livestream", "watch-this-channel", {});
// now query the newly created channel for watchers, retrieving the first 5
const result = await channel.query({
watchers: { limit: 5, offset: 0 },
});
return result.watchers;
// create a new channel of type “livestream” with name “watch-this-channel”
final channel = client.channel("livestream", id: "watch-this-channel");
// now query the newly created channel for watchers, retrieving the first 5
final result = await channel.query(
watchersPagination: PaginationParams(
limit: 5,
offset: 0,
),
);
return result.watchers;
/// Channels are watched automatically when they're synchronized.
/// 1: Create a `ChannelId` that represents the channel you want to watch.
let channelId = ChannelId(type: .messaging, id: "general")
/// 2: Use the `ChatClient` to create a `ChatChannelController` with the `ChannelId`.
client.channelController(for: .init(cid: channelId, watchersLimit: 25))
/// 3: Call `ChatChannelController.synchronize` to watch the channel.
channelController.synchronize { error in
if let error = error {
/// 4: Handle possible errors
print(error)
}
// Access watcherCount
channelController.channel?.lastActiveWatchers
}
// Query the first 5 watchers of a channel
const FUserPaginationOptions WatcherPagination{
5, // Limit
0, // Offset
};
Channel->Query(
EChannelFlags::State, // Flags
{}, // Message Pagination
{}, // Member Pagination
WatcherPagination,
[]
{
// Do something with:
Channel->State.Watchers;
});
// Will be implemented soon, raise a GitHub issue if you need this https://github.com/GetStream/stream-chat-unity/issues/new
int limit = 5;
int offset = 0;
QueryChannelRequest request = new QueryChannelRequest().withWatchers(limit, offset);
channelClient.query(request).enqueue((result) -> {
if (result.isSuccess()) {
Channel channel = result.data();
List<User> watchers = channel.getWatchers();
} else {
// Handle result.error()
}
});
The maximum limit that can be used is 300, and the maximum offset that can be used is 10 000.
Listening to Changes in Watchers
A user already watching the channel can listen to users starting and stopping watching the channel with the realtime events:
// Start watching channel
channelClient.watch().enqueue {
/* Handle result */
}
// Subscribe for watching events
channelClient.subscribeFor(
UserStartWatchingEvent::class,
UserStopWatchingEvent::class,
) { event ->
when (event) {
is UserStartWatchingEvent -> {
// User who started watching the channel
val user = event.user
}
is UserStopWatchingEvent -> {
// User who stopped watching the channel
val user = event.user
}
}
}
const channel = client.channel("livestream", "watch-this-channel", {});
channel.watch();
channel.on("user.watching.start", (event) => {
// handle watch started event
console.log(`${event.user.id} started watching`);
});
channel.on("user.watching.stop", (event) => {
// handle watch stopped event
console.log(`${event.user.id} stopped watching`);
});
final channel = client.channel("livestream", id: "watch-this-channel");
await channel.watch();
// handle watch started event
channel
.on("user.watching.start")
.listen((event) => print('${event.user.id} started watching'));
// handle watch stopped event
channel
.on("user.watching.stop")
.listen((event) => print('${event.user.id} stopped watching'));
let controller = client.watcherListController(query: .init(cid: .init(type: .messaging, id: "general")))
class MyChannelWatcherListDelegate: ChatChannelWatcherListControllerDelegate {
func channelWatcherListController(_ controller: ChatChannelWatcherListController, didChangeWatchers changes: [ListChange<ChatUser>]) {
// handle change
}
}
controller.delegate = MyChannelWatcherListDelegate()
controller.synchronize()
Channel->On<FUserWatchingStartEvent>(
[](const FUserWatchingStartEvent& Event)
{
// Do something with:
Event.User;
});
Channel->On<FUserWatchingStopEvent>(
[](const FUserWatchingStopEvent& Event)
{
// Do something with:
Event.User;
});
public async Task ListenToChangesInWatchers()
{
// Get IStreamChannel reference by Client.GetOrCreateChannel or Client.QueryChannels
var channel = await Client.GetOrCreateChannelWithIdAsync(ChannelType.Messaging, channelId: "my-channel-id");
// Subscribe to events
channel.WatcherAdded += OnWatcherAdded;
channel.WatcherRemoved += OnWatcherRemoved;
}
private void OnWatcherAdded(IStreamChannel channel, IStreamUser user)
{
}
private void OnWatcherRemoved(IStreamChannel channel, IStreamUser user)
{
}
// Start watching channel
channelClient.watch().enqueue((result) -> {
/* Handle result */
});
// Subscribe for watching events
channelClient.subscribeFor(
new Class[]{
UserStartWatchingEvent.class,
UserStopWatchingEvent.class,
},
(event) -> {
if (event instanceof UserStartWatchingEvent) {
// User who started watching the channel
User user = ((UserStartWatchingEvent) event).getUser();
} else if (event instanceof UserStopWatchingEvent) {
// User who stopped watching the channel
User user = ((UserStopWatchingEvent) event).getUser();
}
}
);