Skip to content
Open
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
5 changes: 5 additions & 0 deletions Assets/Plugins/StreamChat/Changelog.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
Unreleased:
Features:

* Add IStreamClientConfig.OptimisticMessageInsert (default true). When true (the existing behavior), a message you send is inserted into the local channel state and raised via IStreamChannel.MessageReceived immediately, before the server's message.new echo arrives. Set it to false to skip the optimistic local insert and wait for the server echo instead, so every participant - including the sender - observes messages in the same server-defined order. Useful when consistent cross-client ordering matters more than instant local feedback (e.g. a shared, broadcast-ordered feed).

v5.5.0:
Features:

Expand Down
13 changes: 13 additions & 0 deletions Assets/Plugins/StreamChat/Core/Configs/IStreamClientConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,18 @@ public interface IStreamClientConfig
/// Disabled - no logs will be emitted. Not recommended in general - this could be only viable if you're capturing all of the thrown exceptions and handling the logging on your own.
/// </summary>
StreamLogLevel LogLevel { get; set; }

/// <summary>
/// Whether a message you send is optimistically inserted into the local channel state and
/// raised via <see cref="StatefulModels.IStreamChannel.MessageReceived"/> immediately, before
/// the server's `message.new` WebSocket echo arrives. Defaults to <c>true</c>.
///
/// When <c>true</c> (default), the sender sees their own message right away and the later
/// WebSocket echo is de-duplicated. When <c>false</c>, the locally sent message is not added
/// to the channel until its server echo arrives, so every participant - including the sender -
/// observes messages in the same server-defined order. Disable this when consistent cross-client
/// ordering matters more than instant local feedback (e.g. a shared, broadcast-ordered feed).
/// </summary>
bool OptimisticMessageInsert { get; set; }
}
}
2 changes: 2 additions & 0 deletions Assets/Plugins/StreamChat/Core/Configs/StreamClientConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,7 @@ public class StreamClientConfig : IStreamClientConfig
public static IStreamClientConfig Default { get; set; } = new StreamClientConfig();

public StreamLogLevel LogLevel { get; set; } = StreamLogLevel.FailureOnly;

public bool OptimisticMessageInsert { get; set; } = true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,8 @@ public void Dispose()

internal IInternalThreadsApi InternalThreadsApi { get; }

internal IStreamClientConfig Config => _config;

internal async Task<OwnUserInternalDTO> ConnectUserAsync(string apiKey, string userId,
ITokenProvider tokenProvider, CancellationToken cancellationToken = default)
{
Expand Down
20 changes: 17 additions & 3 deletions Assets/Plugins/StreamChat/Core/StatefulModels/StreamChannel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -205,9 +205,23 @@ public async Task<IStreamMessage> SendNewMessageAsync(StreamSendMessageRequest s
var replyAlreadyInCache = !string.IsNullOrEmpty(responseMessageId)
&& Cache.Messages.TryGet(responseMessageId, out _);

//StreamTodo: we update internal cache message without server confirmation that message got accepted. e.g. message could be rejected
//It's ok to update the cache "in good faith" to not introduce update delay but we should handle if message got rejected
InternalAppendOrUpdateMessage(response.Message, out var streamMessage);
StreamMessage streamMessage;
if (LowLevelClient.Config.OptimisticMessageInsert)
{
//StreamTodo: we update internal cache message without server confirmation that message got accepted. e.g. message could be rejected
//It's ok to update the cache "in good faith" to not introduce update delay but we should handle if message got rejected
InternalAppendOrUpdateMessage(response.Message, out streamMessage);
}
else
{
// Optimistic insert disabled (see IStreamClientConfig.OptimisticMessageInsert): don't add
// the sent message to the local timeline or raise MessageReceived here. The server's
// message.new echo delivers it instead, so every participant - including the sender -
// observes messages in the same server-defined order. Still update the cache so the
// returned message is tracked and the WS echo resolves to (and dedups against) the same
// instance.
streamMessage = Cache.TryCreateOrUpdate(response.Message, out _);
}

// Optimistic parent.ReplyCount bump for thread replies on the local sender. Without
// this, after InternalAppendOrUpdateMessage the reply is in cache and any subsequent
Expand Down
Loading