Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion Assets/Plugins/StreamChat/Core/IStreamChatClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,26 @@ public interface IStreamChatClient : IDisposable, IStreamChatClientEventsListene
/// Invite to a <see cref="IStreamChannel"/> was rejected
/// </summary>
event ChannelInviteHandler ChannelInviteRejected;

/// <summary>
/// Local user was added to a channel as a member. This event fires only for channels that are not tracked locally.
/// Use this event to get notified when the local user is added to a new channel. For tracked channels, use the <see cref="IStreamChannel.MemberAdded"/> event.
/// </summary>
event ChannelMemberAddedHandler AddedToChannelAsMember;

/// <summary>
/// Local user was removed from a channel as a member. This event fires only for channels that are not tracked locally.
/// Use this event to get notified when the local user was removed from a channel. For tracked channels use <see cref="IStreamChannel.MemberRemoved"/> event
/// </summary>
event ChannelMemberRemovedHandler RemovedFromChannelAsMember;

/// <summary>
/// Current connection state
/// </summary>
ConnectionState ConnectionState { get; }

/// <summary>
/// Is client connected. Subscribe to <see cref="Connected"/> to get notified when connection is established
/// Is client connected. Subscribe to <see cref="Connected"/> event to get notified when connection is established
/// </summary>
bool IsConnected { get; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public interface IStreamChannel : IStreamStatefulModel
/// <summary>
/// Event fired when a <see cref="IStreamChannelMember"/> was added, updated, or removed.
/// </summary>
event StreamChannelMemberAnyChangeHandler MembersChanged;
event StreamChannelMemberAnyChangeHandler MembersChanged; //StreamTodo: typo, this should be MemberChanged

/// <summary>
/// Event fired when visibility of this channel changed. Check <see cref="IStreamChannel.Hidden"/> to know if channel is hidden
Expand Down
89 changes: 58 additions & 31 deletions Assets/Plugins/StreamChat/Core/StreamChatClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,17 @@ namespace StreamChat.Core
//StreamTodo: Handle restoring state after lost connection

public delegate void ChannelInviteHandler(IStreamChannel channel, IStreamUser invitee);


/// <summary>
/// Member added to the channel handler
/// </summary>
public delegate void ChannelMemberAddedHandler(IStreamChannel channel, IStreamChannelMember member);

/// <summary>
/// Member removed from the channel handler
/// </summary>
public delegate void ChannelMemberRemovedHandler(IStreamChannel channel, IStreamChannelMember member);

public sealed class StreamChatClient : IStreamChatClient
{
public event ConnectionMadeHandler Connected;
Expand All @@ -65,6 +75,9 @@ public sealed class StreamChatClient : IStreamChatClient
public event ChannelInviteHandler ChannelInviteReceived;
public event ChannelInviteHandler ChannelInviteAccepted;
public event ChannelInviteHandler ChannelInviteRejected;

public event ChannelMemberAddedHandler AddedToChannelAsMember;
public event ChannelMemberRemovedHandler RemovedFromChannelAsMember;

public const int QueryUsersLimitMaxValue = 30;
public const int QueryUsersOffsetMaxValue = 1000;
Expand Down Expand Up @@ -197,33 +210,9 @@ public Task DisconnectUserAsync()

public bool IsLocalUser(IStreamUser user) => LocalUserData.User == user;

public async Task<IStreamChannel> GetOrCreateChannelWithIdAsync(ChannelType channelType, string channelId,
public Task<IStreamChannel> GetOrCreateChannelWithIdAsync(ChannelType channelType, string channelId,
string name = null, IDictionary<string, object> optionalCustomData = null)
{
StreamAsserts.AssertChannelTypeIsValid(channelType);
StreamAsserts.AssertChannelIdLength(channelId);

var requestBodyDto = new ChannelGetOrCreateRequestInternalDTO
{
Presence = true,
State = true,
Watch = true,
Data = new ChannelRequestInternalDTO
{
Name = name,
},
};

if (optionalCustomData != null && optionalCustomData.Any())
{
requestBodyDto.Data.AdditionalProperties = optionalCustomData?.ToDictionary(x => x.Key, x => x.Value);
}

var channelResponseDto = await InternalLowLevelClient.InternalChannelApi.GetOrCreateChannelAsync(
channelType,
channelId, requestBodyDto);
return _cache.TryCreateOrUpdate(channelResponseDto);
}
=> InternalGetOrCreateChannelWithIdAsync(channelType, channelId, name, presence: true, state: true, watch: true, optionalCustomData);

public async Task<IStreamChannel> GetOrCreateChannelWithMembersAsync(ChannelType channelType,
IEnumerable<IStreamUser> members, IDictionary<string, object> optionalCustomData = null)
Expand Down Expand Up @@ -579,6 +568,36 @@ void IStreamChatClientEventsListener.Destroy()
void IStreamChatClientEventsListener.Update() => InternalLowLevelClient.Update(_timeService.DeltaTime);

internal StreamChatLowLevelClient InternalLowLevelClient { get; }

// We probably don't want to expose the presence, state, watch params to the public API
internal async Task<IStreamChannel> InternalGetOrCreateChannelWithIdAsync(ChannelType channelType, string channelId,
string name = null, bool presence = true, bool state = true, bool watch = true,
IDictionary<string, object> optionalCustomData = null)
{
StreamAsserts.AssertChannelTypeIsValid(channelType);
StreamAsserts.AssertChannelIdLength(channelId);

var requestBodyDto = new ChannelGetOrCreateRequestInternalDTO
{
Presence = presence,
State = state,
Watch = watch,
Data = new ChannelRequestInternalDTO
{
Name = name,
},
};

if (optionalCustomData != null && optionalCustomData.Any())
{
requestBodyDto.Data.AdditionalProperties = optionalCustomData?.ToDictionary(x => x.Key, x => x.Value);
}

var channelResponseDto = await InternalLowLevelClient.InternalChannelApi.GetOrCreateChannelAsync(
channelType,
channelId, requestBodyDto);
return _cache.TryCreateOrUpdate(channelResponseDto);
}

internal IStreamLocalUserData UpdateLocalUser(OwnUserInternalDTO ownUserInternalDto)
{
Expand Down Expand Up @@ -843,15 +862,23 @@ private void OnMarkReadNotification(NotificationMarkReadEventInternalDTO eventDt
_localUserData.InternalHandleMarkReadNotification(eventDto);
}

private void OnAddedToChannelNotification(NotificationAddedToChannelEventInternalDTO obj)
private void OnAddedToChannelNotification(NotificationAddedToChannelEventInternalDTO eventDto)
{
//StreamTodo: IMPLEMENT
var channel = _cache.TryCreateOrUpdate(eventDto.Channel);
var member = _cache.TryCreateOrUpdate(eventDto.Member);
_cache.TryCreateOrUpdate(eventDto.Member.User);

AddedToChannelAsMember?.Invoke(channel, member);
}

private void OnRemovedFromChannelNotification(
NotificationRemovedFromChannelEventInternalDTO obj)
NotificationRemovedFromChannelEventInternalDTO eventDto)
{
//StreamTodo: IMPLEMENT
var channel = _cache.TryCreateOrUpdate(eventDto.Channel);
var member = _cache.TryCreateOrUpdate(eventDto.Member);
_cache.TryCreateOrUpdate(eventDto.Member.User);

RemovedFromChannelAsMember?.Invoke(channel, member);
}

private void OnInvitedNotification(NotificationInvitedEventInternalDTO eventDto)
Expand Down
161 changes: 161 additions & 0 deletions Assets/Plugins/StreamChat/Samples/EventsSamples.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
using System.Threading.Tasks;
using StreamChat.Core;
using StreamChat.Core.Models;
using StreamChat.Core.StatefulModels;

namespace StreamChat.Samples
{
internal class EventsSamples
{
public async Task QueryChannelsEvents()
{
// Get a single channel
var channel = await Client.GetOrCreateChannelWithIdAsync(ChannelType.Messaging, "my-channel-id");

channel.MessageReceived += OnMessageReceived;
channel.MessageUpdated += OnMessageUpdated;
channel.MessageDeleted += OnMessageDeleted;

channel.ReactionAdded += OnReactionAdded;
channel.ReactionUpdated += OnReactionUpdated;
channel.ReactionRemoved += OnReactionRemoved;

channel.MemberAdded += OnMemberAdded;
channel.MemberRemoved += OnMemberRemoved;
channel.MemberUpdated += OnMemberUpdated;

channel.MembersChanged += OnMembersChanged;
channel.VisibilityChanged += OnVisibilityChanged;
channel.MuteChanged += OnMuteChanged;
channel.Truncated += OnTruncated;
channel.Updated += OnUpdated;
channel.WatcherAdded += OnWatcherAdded;
channel.WatcherRemoved += OnWatcherRemoved;
channel.UserStartedTyping += OnUserStartedTyping;
channel.UserStoppedTyping += OnUserStoppedTyping;
channel.TypingUsersChanged += OnTypingUsersChanged;
}

private void OnMessageReceived(IStreamChannel channel, IStreamMessage message)
{
}

private void OnMessageUpdated(IStreamChannel channel, IStreamMessage message)
{
}

private void OnMessageDeleted(IStreamChannel channel, IStreamMessage message, bool isharddelete)
{
}

private void OnReactionAdded(IStreamChannel channel, IStreamMessage message, StreamReaction reaction)
{
}

private void OnReactionUpdated(IStreamChannel channel, IStreamMessage message, StreamReaction reaction)
{
}

private void OnReactionRemoved(IStreamChannel channel, IStreamMessage message, StreamReaction reaction)
{
}

private void OnMemberAdded(IStreamChannel channel, IStreamChannelMember member)
{
}

private void OnMemberRemoved(IStreamChannel channel, IStreamChannelMember member)
{
}

private void OnMemberUpdated(IStreamChannel channel, IStreamChannelMember member)
{
}

private void OnMembersChanged(IStreamChannel channel, IStreamChannelMember member, OperationType operationType)
{
}

private void OnVisibilityChanged(IStreamChannel channel, bool isVisible)
{
}

private void OnMuteChanged(IStreamChannel channel, bool isMuted)
{
}

private void OnTruncated(IStreamChannel channel)
{
}

private void OnUpdated(IStreamChannel channel)
{
}

private void OnWatcherAdded(IStreamChannel channel, IStreamUser user)
{
}

private void OnWatcherRemoved(IStreamChannel channel, IStreamUser user)
{
}

private void OnUserStartedTyping(IStreamChannel channel, IStreamUser user)
{
}

private void OnUserStoppedTyping(IStreamChannel channel, IStreamUser user)
{
}

private void OnTypingUsersChanged(IStreamChannel channel)
{
}

public void ClientEvents()
{
Client.AddedToChannelAsMember += OnAddedToChannelAsMember;
Client.RemovedFromChannelAsMember += OnRemovedFromChannel;
}

private void OnAddedToChannelAsMember(IStreamChannel channel, IStreamChannelMember member)
{
// channel - new channel to which local user was just added
// member - object containing channel membership information
}

private void OnRemovedFromChannel(IStreamChannel channel, IStreamChannelMember member)
{
// channel - channel from which local user was removed
// member - object containing channel membership information
}

public void ConnectionEvents()
{
Client.Connected += OnConnected;
Client.Disconnected += OnDisconnected;
Client.ConnectionStateChanged += OnConnectionStateChanged;
}

private void OnConnectionStateChanged(ConnectionState previous, ConnectionState current)
{
}

private void OnDisconnected()
{
}

private void OnConnected(IStreamLocalUserData localUserData)
{
}

public void Unsubscribe()
{
Client.Connected -= OnConnected;
Client.Disconnected -= OnDisconnected;
Client.ConnectionStateChanged -= OnConnectionStateChanged;
}

private IStreamChatClient Client { get; } = StreamChatClient.CreateDefaultClient();
}
}
3 changes: 3 additions & 0 deletions Assets/Plugins/StreamChat/Samples/EventsSamples.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using NUnit.Framework;
using StreamChat.Core;
using StreamChat.Core.Exceptions;
using StreamChat.Core.InternalDTO.Requests;
using StreamChat.Core.Requests;
using StreamChat.Core.StatefulModels;
using StreamChat.Libs.Auth;
Expand Down Expand Up @@ -48,11 +49,11 @@ protected static IEnumerable<AuthCredentials> OtherAdminUsersCredentials
/// <summary>
/// Create temp channel with random id that will be removed in [TearDown]
/// </summary>
protected async Task<IStreamChannel> CreateUniqueTempChannelAsync(string name = null)
protected async Task<IStreamChannel> CreateUniqueTempChannelAsync(string name = null, bool watch = true)
{
var channelId = "random-channel-11111-" + Guid.NewGuid();

var channelState = await Client.GetOrCreateChannelWithIdAsync(ChannelType.Messaging, channelId, name);
var channelState = await Client.InternalGetOrCreateChannelWithIdAsync(ChannelType.Messaging, channelId, name, watch: watch);
_tempChannels.Add(channelState);
return channelState;
}
Expand Down Expand Up @@ -210,28 +211,32 @@ private static async Task ConnectAndExecuteAsync(Func<Task> test)
throw new AggregateException($"Failed all attempts. Last Exception: {exceptions.Last().Message} ", exceptions);
}
}

private async Task DeleteTempChannelsAsync()
{
if (_tempChannels.Count == 0)
{
return;
}

try
{
await Client.DeleteMultipleChannelsAsync(_tempChannels, isHardDelete: true);
}
catch (StreamApiException streamApiException)
for (int i = 0; i < 5; i++)
{
if (streamApiException.Code == StreamApiException.RateLimitErrorHttpStatusCode)
try
{
await Task.Delay(500);
await Client.DeleteMultipleChannelsAsync(_tempChannels, isHardDelete: true);
}
catch (StreamApiException streamApiException)
{
if (streamApiException.Code == StreamApiException.RateLimitErrorHttpStatusCode)
{
await Task.Delay(1000);
}

Debug.Log($"Try {nameof(DeleteTempChannelsAsync)} again due to exception: " + streamApiException);
Debug.Log($"Attempt {i} failed. Try {nameof(DeleteTempChannelsAsync)} again due to exception: " + streamApiException);
continue;
}

await Client.DeleteMultipleChannelsAsync(_tempChannels, isHardDelete: true);
break;
}

_tempChannels.Clear();
Expand Down
Loading