< Summary

Class:DCL.Social.Friends.FriendsController
Assembly:FriendsController
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/FriendsController/FriendsController.cs
Covered lines:321
Uncovered lines:98
Coverable lines:419
Total lines:948
Line coverage:76.6% (321 of 419)
Covered branches:0
Total branches:0
Covered methods:50
Total methods:66
Method coverage:75.7% (50 of 66)

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
FriendsController()0%110100%
FriendsController(...)0%110100%
Initialize()0%220100%
<Initialize()0%19.5912062.5%
Dispose()0%110100%
GetUserStatus(...)0%6200%
ContainsStatus(...)0%6200%
RequestFriendshipAsync()0%7.647076.47%
GetAllocatedFriends()0%110100%
AcceptFriendshipAsync()0%7.297081.82%
RejectFriendshipAsync()0%6.476076.47%
IsFriend(...)0%6200%
RemoveFriendAsync()0%20400%
GetFriendsAsync()0%7.347080.95%
GetFriendsAsync()0%27.3112052.63%
GetFriendRequestsAsync()0%12.0512093.18%
GetFriendsWithDirectMessages(...)0%2100%
GetFriendsWithDirectMessages(...)0%2100%
TryGetAllocatedFriendRequest(...)0%3.333066.67%
GetAllocatedFriendRequestByUser(...)0%14140100%
GetFriendshipStatus()0%72800%
CancelRequestByUserIdAsync()0%56700%
CancelRequestAsync()0%13.127050%
HandlePeerDeletedFriendship(...)0%2.152066.67%
HandlePeerAcceptedFriendRequest(...)0%4.844062.5%
RemoveFriendRequestFromRejection(...)0%110100%
RemoveFriendRequestFromCancellation(...)0%2100%
RemoveFriendRequestAndUpdateFriendshipStatus(...)0%3.013088.89%
<AddFriendToCacheAndTriggerFriendshipUpdate()0%4.594066.67%
AddFriendToCacheAndTriggerFriendshipUpdate(...)0%330100%
RemoveFriendFromCacheAndTriggerFriendshipUpdate(...)0%72800%
InitializeFriendships(...)0%4.054085.71%
FriendNotFound(...)0%6200%
AddFriendsWithDirectMessages(...)0%550100%
UpdateUserPresence(...)0%2.032080%
UpdateTotalFriendRequests(...)0%220100%
UpdateTotalFriends(...)0%110100%
UpdateUserStatus(...)0%5.585071.43%
ReceiveFriendRequest(...)0%2.062075%
HandleUpdateFriendshipStatus(...)0%330100%
UpdateFriendshipStatus(...)0%770100%
ToFriendshipStatus(...)0%880100%
AddFriends(...)0%440100%
ToFriendRequest(...)0%110100%
AddFriendRequests(...)0%20400%
AddIncomingFriendRequest(...)0%110100%
AddIncomingFriendRequest(...)0%4.054085.71%
AddOutgoingFriendRequest(...)0%110100%
AddOutgoingFriendRequest(...)0%3.043083.33%
ToFriendshipAction(...)0%30500%
WaitForFeatureFlagsToBeInitialized()0%440100%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/FriendsController/FriendsController.cs

#LineLine coverage
 1using Cysharp.Threading.Tasks;
 2using DCl.Social.Friends;
 3using DCL.Tasks;
 4using System;
 5using System.Collections.Generic;
 6using System.Linq;
 7using System.Threading;
 8using UnityEngine;
 9
 10namespace DCL.Social.Friends
 11{
 12    public class FriendsController : IFriendsController
 13    {
 14        private const string USE_SOCIAL_CLIENT_FEATURE_FLAG = "use-social-client";
 2215        private static readonly Comparer<long> DESCENDING_LONG_COMPARER = Comparer<long>.Create((l, l1) => -l.CompareTo(
 16
 17        private readonly IFriendsApiBridge apiBridge;
 18        private readonly ISocialApiBridge socialApiBridge;
 19
 20        // Used only when social client feature flag is false
 45021        private readonly Dictionary<string, FriendRequest> friendRequests = new ();
 22
 45023        private readonly Dictionary<string, FriendRequest> incomingFriendRequestsById = new ();
 45024        private readonly Dictionary<string, FriendRequest> outgoingFriendRequestsById = new ();
 45025        private readonly SortedList<long, FriendRequest> incomingFriendRequestsByTimestamp = new (DESCENDING_LONG_COMPAR
 45026        private readonly SortedList<long, FriendRequest> outgoingFriendRequestsByTimestamp = new (DESCENDING_LONG_COMPAR
 45027        private readonly Dictionary<string, UserStatus> friends = new ();
 45028        private readonly SortedList<string, UserStatus> friendsSortedByName = new ();
 29        private readonly DataStore dataStore;
 30        private readonly IUserProfileBridge userProfileBridge;
 31
 45032        private CancellationTokenSource controllerCancellationTokenSource = new ();
 33        private UniTaskCompletionSource featureFlagsInitializedTask;
 34        private int totalFriendCount;
 35        private int totalReceivedFriendRequestCount;
 36        private int totalSentFriendRequestCount;
 37
 60838        private FeatureFlag featureFlags => dataStore.featureFlags.flags.Get();
 39
 15840        private bool useSocialApiBridge => featureFlags.IsFeatureEnabled(USE_SOCIAL_CLIENT_FEATURE_FLAG);
 41
 042        public int AllocatedFriendCount => friends.Count(f => f.Value.friendshipStatus == FriendshipStatus.FRIEND);
 1443        public bool IsInitialized { get; private set; }
 44
 045        public int ReceivedRequestCount => friends.Values.Count(status => status.friendshipStatus == FriendshipStatus.RE
 46
 47        public int TotalFriendCount
 48        {
 249            get => useSocialApiBridge ? friends.Count : totalFriendCount;
 350            private set => totalFriendCount = value;
 51        }
 52
 053        public int TotalFriendRequestCount => TotalReceivedFriendRequestCount + TotalSentFriendRequestCount;
 54
 55        public int TotalReceivedFriendRequestCount
 56        {
 457            get => useSocialApiBridge ? incomingFriendRequestsById.Count : totalReceivedFriendRequestCount;
 1058            private set => totalReceivedFriendRequestCount = value;
 59        }
 60
 61        public int TotalSentFriendRequestCount
 62        {
 363            get => useSocialApiBridge ? outgoingFriendRequestsById.Count : totalSentFriendRequestCount;
 364            private set => totalSentFriendRequestCount = value;
 65        }
 66
 167        public int TotalFriendsWithDirectMessagesCount { get; private set; }
 68
 69        public event Action<string, UserStatus> OnUpdateUserStatus;
 70        public event Action<string, FriendshipAction> OnUpdateFriendship;
 71        public event Action<string> OnFriendNotFound;
 72        public event Action OnInitialized;
 73        public event Action<List<FriendWithDirectMessages>> OnAddFriendsWithDirectMessages;
 74        public event Action<int, int> OnTotalFriendRequestUpdated;
 75        public event Action<FriendRequest> OnFriendRequestReceived;
 76        public event Action<FriendRequest> OnSentFriendRequestApproved;
 77
 45078        public FriendsController(IFriendsApiBridge apiBridge, ISocialApiBridge socialApiBridge, DataStore dataStore,
 79            IUserProfileBridge userProfileBridge)
 80        {
 45081            this.apiBridge = apiBridge;
 45082            this.socialApiBridge = socialApiBridge;
 45083            this.dataStore = dataStore;
 45084            this.userProfileBridge = userProfileBridge;
 45085        }
 86
 87        public void Initialize()
 88        {
 45089            controllerCancellationTokenSource = controllerCancellationTokenSource.SafeRestart();
 90
 91            // TODO: wrap this events into socialApiBridge since it wont be supported by the social service
 45092            apiBridge.OnUserPresenceUpdated += UpdateUserPresence;
 45093            apiBridge.OnFriendWithDirectMessagesAdded += AddFriendsWithDirectMessages;
 94
 95            async UniTask InitializeSocialClientAsync(CancellationToken cancellationToken)
 96            {
 8697                if (!useSocialApiBridge) return;
 98
 99                try
 100                {
 101
 6102                    AllFriendsInitializationMessage info = await socialApiBridge.GetInitializationInformationAsync(cance
 6103                    InitializeFriendships(info);
 104
 20105                    foreach (string friendId in info.Friends)
 4106                        AddFriendToCacheAndTriggerFriendshipUpdate(friendId);
 107
 12108                    foreach (FriendRequest friendRequest in info.IncomingFriendRequests)
 0109                        AddIncomingFriendRequest(friendRequest, false);
 110
 12111                    foreach (FriendRequest friendRequest in info.OutgoingFriendRequests)
 0112                        AddOutgoingFriendRequest(friendRequest, false);
 113
 6114                    OnTotalFriendRequestUpdated?.Invoke(TotalReceivedFriendRequestCount, TotalSentFriendRequestCount);
 6115                }
 116                catch (Exception ex)
 117                {
 0118                    Debug.LogError("Couldn't initialize friendship information");
 0119                    Debug.LogException(ex);
 0120                }
 46121            }
 122
 123            void SubscribeToCorrespondingBridgeEvents()
 124            {
 46125                if (useSocialApiBridge)
 126                {
 6127                    socialApiBridge.OnIncomingFriendRequestAdded += AddIncomingFriendRequest;
 6128                    socialApiBridge.OnOutgoingFriendRequestAdded += AddOutgoingFriendRequest;
 6129                    socialApiBridge.OnFriendRequestAccepted += HandlePeerAcceptedFriendRequest;
 6130                    socialApiBridge.OnDeletedByFriend += HandlePeerDeletedFriendship;
 6131                    socialApiBridge.OnFriendRequestRejected += RemoveFriendRequestFromRejection;
 6132                    socialApiBridge.OnFriendRequestCanceled += RemoveFriendRequestFromCancellation;
 133                }
 134                else
 135                {
 40136                    apiBridge.OnInitialized += InitializeFriendships;
 137
 138                    // TODO (NEW FRIEND REQUESTS): remove when we don't need to keep the retro-compatibility with the ol
 40139                    apiBridge.OnFriendRequestsAdded += AddFriendRequests;
 40140                    apiBridge.OnFriendRequestReceived += ReceiveFriendRequest;
 40141                    apiBridge.OnTotalFriendRequestCountUpdated += UpdateTotalFriendRequests;
 40142                    apiBridge.OnTotalFriendCountUpdated += UpdateTotalFriends;
 40143                    apiBridge.OnFriendshipStatusUpdated += HandleUpdateFriendshipStatus;
 40144                    apiBridge.OnFriendNotFound += FriendNotFound;
 145                }
 40146            }
 147
 450148            if (featureFlags.IsInitialized)
 149            {
 27150                SubscribeToCorrespondingBridgeEvents();
 27151                InitializeSocialClientAsync(controllerCancellationTokenSource.Token).Forget();
 152            }
 153            else
 154            {
 423155                WaitForFeatureFlagsToBeInitialized(controllerCancellationTokenSource.Token)
 156                   .ContinueWith(() =>
 157                    {
 19158                        SubscribeToCorrespondingBridgeEvents();
 19159                        InitializeSocialClientAsync(controllerCancellationTokenSource.Token).Forget();
 19160                    })
 161                   .Forget();
 162            }
 423163        }
 164
 165        public void Dispose()
 166        {
 423167            controllerCancellationTokenSource.SafeCancelAndDispose();
 168
 423169            socialApiBridge.OnIncomingFriendRequestAdded -= AddIncomingFriendRequest;
 423170            socialApiBridge.OnOutgoingFriendRequestAdded -= AddOutgoingFriendRequest;
 423171            socialApiBridge.OnFriendRequestAccepted -= HandlePeerAcceptedFriendRequest;
 423172            socialApiBridge.OnDeletedByFriend -= HandlePeerDeletedFriendship;
 423173            socialApiBridge.OnFriendRequestRejected -= RemoveFriendRequestFromRejection;
 423174            socialApiBridge.OnFriendRequestCanceled -= RemoveFriendRequestFromCancellation;
 175
 423176            apiBridge.OnInitialized -= InitializeFriendships;
 177
 178            // TODO (NEW FRIEND REQUESTS): remove when we don't need to keep the retro-compatibility with the old versio
 423179            apiBridge.OnFriendRequestsAdded -= AddFriendRequests;
 423180            apiBridge.OnFriendRequestReceived -= ReceiveFriendRequest;
 423181            apiBridge.OnFriendNotFound -= FriendNotFound;
 423182            apiBridge.OnFriendWithDirectMessagesAdded -= AddFriendsWithDirectMessages;
 423183            apiBridge.OnUserPresenceUpdated -= UpdateUserPresence;
 423184            apiBridge.OnFriendshipStatusUpdated -= HandleUpdateFriendshipStatus;
 423185            apiBridge.OnTotalFriendRequestCountUpdated -= UpdateTotalFriendRequests;
 423186            apiBridge.OnTotalFriendCountUpdated -= UpdateTotalFriends;
 423187        }
 188
 189        public UserStatus GetUserStatus(string userId)
 190        {
 0191            if (!friends.ContainsKey(userId))
 0192                return new UserStatus { userId = userId, friendshipStatus = FriendshipStatus.NOT_FRIEND };
 193
 0194            return friends[userId];
 195        }
 196
 197        public bool ContainsStatus(string friendId, FriendshipStatus status)
 198        {
 0199            if (!friends.ContainsKey(friendId)) return false;
 0200            return friends[friendId].friendshipStatus == status;
 201        }
 202
 203        public async UniTask<FriendRequest> RequestFriendshipAsync(string friendUserId, string messageBody, Cancellation
 204        {
 2205            cancellationToken.ThrowIfCancellationRequested();
 206
 207            FriendRequest friendRequest;
 208
 2209            if (useSocialApiBridge)
 210            {
 1211                friendRequest = await socialApiBridge.RequestFriendshipAsync(friendUserId, messageBody, cancellationToke
 1212                outgoingFriendRequestsById[friendRequest.FriendRequestId] = friendRequest;
 213                // it's impossible to have duplicated timestamps for two different correctly created friend requests
 1214                outgoingFriendRequestsByTimestamp[friendRequest.Timestamp.Ticks] = friendRequest;
 215
 1216                OnTotalFriendRequestUpdated?.Invoke(TotalReceivedFriendRequestCount, TotalSentFriendRequestCount);
 217            }
 218            else
 219            {
 1220                RequestFriendshipConfirmationPayload payload = await apiBridge.RequestFriendshipAsync(friendUserId, mess
 221
 1222                FriendRequestPayload friendRequestPayload = payload.friendRequest;
 223
 1224                friendRequest = new (friendRequestPayload.friendRequestId,
 225                    DateTimeOffset.FromUnixTimeMilliseconds(friendRequestPayload.timestamp).DateTime,
 226                    friendRequestPayload.from,
 227                    friendRequestPayload.to,
 228                    friendRequestPayload.messageBody);
 229
 1230                friendRequests[friendRequest.FriendRequestId] = friendRequest;
 231            }
 232
 2233            UpdateFriendshipStatus(new FriendshipUpdateStatusMessage
 234                { action = FriendshipAction.REQUESTED_TO, userId = friendRequest.To });
 235
 2236            return friendRequest;
 2237        }
 238
 239        public Dictionary<string, UserStatus> GetAllocatedFriends() =>
 1240            new (friends);
 241
 242        public async UniTask<FriendRequest> AcceptFriendshipAsync(string friendRequestId, CancellationToken cancellation
 243        {
 2244            cancellationToken.ThrowIfCancellationRequested();
 245
 246            FriendRequest request;
 247
 2248            if (useSocialApiBridge)
 249            {
 1250                request = incomingFriendRequestsById[friendRequestId];
 1251                await socialApiBridge.AcceptFriendshipAsync(request.From, cancellationToken);
 252
 1253                incomingFriendRequestsById.Remove(request.FriendRequestId);
 1254                incomingFriendRequestsByTimestamp.Remove(request.Timestamp.Ticks);
 1255                outgoingFriendRequestsById.Remove(request.FriendRequestId);
 1256                outgoingFriendRequestsByTimestamp.Remove(request.Timestamp.Ticks);
 257
 1258                AddFriendToCacheAndTriggerFriendshipUpdate(request.From);
 259
 1260                OnTotalFriendRequestUpdated?.Invoke(TotalReceivedFriendRequestCount, TotalSentFriendRequestCount);
 261
 1262                return request;
 263            }
 264
 1265            AcceptFriendshipPayload payload = await apiBridge.AcceptFriendshipAsync(friendRequestId, cancellationToken);
 266
 1267            FriendRequestPayload requestPayload = payload.FriendRequest;
 1268            request = ToFriendRequest(requestPayload);
 1269            friendRequests.Remove(request.FriendRequestId);
 270
 1271            UpdateFriendshipStatus(new FriendshipUpdateStatusMessage
 272                { action = FriendshipAction.APPROVED, userId = request.From });
 273
 1274            return request;
 2275        }
 276
 277        public async UniTask<FriendRequest> RejectFriendshipAsync(string friendRequestId, CancellationToken cancellation
 278        {
 2279            cancellationToken.ThrowIfCancellationRequested();
 280
 281            FriendRequest friendRequest;
 282
 2283            if (useSocialApiBridge)
 284            {
 1285                friendRequest = incomingFriendRequestsById[friendRequestId];
 1286                await socialApiBridge.RejectFriendshipAsync(friendRequest.From, cancellationToken);
 1287                RemoveFriendRequestAndUpdateFriendshipStatus(friendRequest.From, FriendshipAction.REJECTED);
 1288                return friendRequest;
 289            }
 290
 1291            RejectFriendshipPayload payload = await apiBridge.RejectFriendshipAsync(friendRequestId, cancellationToken);
 292
 1293            FriendRequestPayload requestPayload = payload.FriendRequestPayload;
 1294            friendRequest = ToFriendRequest(requestPayload);
 1295            friendRequests.Remove(friendRequest.FriendRequestId);
 296
 1297            UpdateFriendshipStatus(new FriendshipUpdateStatusMessage
 298                { action = FriendshipAction.REJECTED, userId = friendRequest.From });
 299
 1300            return friendRequest;
 2301        }
 302
 303        public bool IsFriend(string userId) =>
 0304            friends.ContainsKey(userId) && friends[userId].friendshipStatus == FriendshipStatus.FRIEND;
 305
 306        public async UniTask RemoveFriendAsync(string friendId, CancellationToken cancellationToken)
 307        {
 0308            if (!useSocialApiBridge)
 309            {
 0310                apiBridge.RemoveFriend(friendId);
 0311                return;
 312            }
 313
 0314            await socialApiBridge.DeleteFriendshipAsync(friendId, cancellationToken);
 0315            RemoveFriendFromCacheAndTriggerFriendshipUpdate(friendId);
 0316        }
 317
 318        public async UniTask<string[]> GetFriendsAsync(int limit, int skip, CancellationToken cancellationToken = defaul
 319        {
 14320            if (useSocialApiBridge)
 321            {
 12322                int startIndex = skip;
 12323                int endIndex = Math.Min(skip + limit, friendsSortedByName.Count) - 1;
 12324                int arraySize = endIndex - startIndex + 1;
 325
 12326                var friendIds = new string[arraySize];
 327
 44328                for (int i = startIndex; i <= endIndex; i++)
 329                {
 10330                    string key = friendsSortedByName.Keys[i];
 10331                    friendIds[i - startIndex] = friendsSortedByName[key].userId;
 332                }
 333
 12334                return friendIds;
 335            }
 336
 2337            var payload = await apiBridge.GetFriendsAsync(limit, skip, cancellationToken);
 2338            await UniTask.SwitchToMainThread();
 339
 2340            TotalFriendCount = payload.totalFriends;
 2341            AddFriends(payload.friends);
 342
 2343            return payload.friends;
 14344        }
 345
 346        public async UniTask<IReadOnlyList<string>> GetFriendsAsync(string userNameOrId, int limit, CancellationToken ca
 347        {
 2348            if (useSocialApiBridge)
 349            {
 2350                var friendsToReturn = new List<string>();
 351
 17352                foreach (var friend in friendsSortedByName.Values)
 353                {
 7354                    if (friend.userName.IndexOf(userNameOrId, StringComparison.OrdinalIgnoreCase) >= 0 ||
 3355                        friend.userId.IndexOf(userNameOrId, StringComparison.OrdinalIgnoreCase) >= 0) { friendsToReturn.
 356
 7357                    if (friendsToReturn.Count >= limit) { break; }
 358                }
 359
 2360                return friendsToReturn;
 361            }
 362
 0363            var payload = await apiBridge.GetFriendsAsync(userNameOrId, limit, cancellationToken);
 0364            await UniTask.SwitchToMainThread();
 365
 0366            TotalFriendCount = payload.totalFriends;
 0367            AddFriends(payload.friends);
 368
 0369            return payload.friends;
 2370        }
 371
 372        public async UniTask<IReadOnlyList<FriendRequest>> GetFriendRequestsAsync(int sentLimit, int sentSkip, int recei
 373        {
 3374            cancellationToken.ThrowIfCancellationRequested();
 375
 3376            if (useSocialApiBridge)
 377            {
 1378                int sentCount = outgoingFriendRequestsByTimestamp.Values.Count;
 1379                int receivedCount = incomingFriendRequestsByTimestamp.Values.Count;
 380
 1381                int capacity = sentCount - sentSkip + receivedCount - receivedSkip;
 1382                if (capacity <= 0) return new List<FriendRequest>(0);
 383
 1384                List<FriendRequest> result = new List<FriendRequest>(capacity);
 385
 10386                for (int i = receivedSkip; i < receivedSkip + receivedLimit && i < incomingFriendRequestsByTimestamp.Val
 387                {
 4388                    var receivedRequest = incomingFriendRequestsByTimestamp.Values[i];
 4389                    result.Add(receivedRequest);
 390                }
 391
 10392                for (int i = sentSkip; i < sentSkip + sentLimit && i < outgoingFriendRequestsByTimestamp.Values.Count; i
 393                {
 4394                    var sentRequest = outgoingFriendRequestsByTimestamp.Values[i];
 4395                    result.Add(sentRequest);
 396                }
 397
 1398                return result;
 399            }
 400
 2401            var payload = await apiBridge.GetFriendRequestsAsync(sentLimit, sentSkip, receivedLimit, receivedSkip, cance
 402
 2403            TotalReceivedFriendRequestCount = payload.totalReceivedFriendRequests;
 2404            TotalSentFriendRequestCount = payload.totalSentFriendRequests;
 2405            OnTotalFriendRequestUpdated?.Invoke(TotalReceivedFriendRequestCount, TotalSentFriendRequestCount);
 406
 2407            List<FriendRequest> receivedFriendRequestsToAdd = new List<FriendRequest>();
 408
 14409            foreach (var friendRequest in payload.requestedFrom)
 410            {
 5411                cancellationToken.ThrowIfCancellationRequested();
 412
 5413                var request = ToFriendRequest(friendRequest);
 5414                friendRequests[request.FriendRequestId] = request;
 5415                receivedFriendRequestsToAdd.Add(request);
 416
 5417                UpdateFriendshipStatus(new FriendshipUpdateStatusMessage
 418                    { action = FriendshipAction.REQUESTED_FROM, userId = friendRequest.from });
 419            }
 420
 12421            foreach (var friendRequest in payload.requestedTo)
 422            {
 4423                cancellationToken.ThrowIfCancellationRequested();
 424
 4425                var request = ToFriendRequest(friendRequest);
 4426                friendRequests[request.FriendRequestId] = request;
 4427                receivedFriendRequestsToAdd.Add(request);
 428
 4429                UpdateFriendshipStatus(new FriendshipUpdateStatusMessage
 430                    { action = FriendshipAction.REQUESTED_TO, userId = friendRequest.to });
 431            }
 432
 2433            return receivedFriendRequestsToAdd;
 3434        }
 435
 436        // TODO: implement async function and make the new social service support
 437        public void GetFriendsWithDirectMessages(int limit, int skip) =>
 0438            apiBridge.GetFriendsWithDirectMessages("", limit, skip);
 439
 440        // TODO: implement async function and make the new social service support
 441        public void GetFriendsWithDirectMessages(string userNameOrId, int limit) =>
 0442            apiBridge.GetFriendsWithDirectMessages(userNameOrId, limit, 0);
 443
 444        public bool TryGetAllocatedFriendRequest(string friendRequestId, out FriendRequest result)
 445        {
 9446            if (!useSocialApiBridge)
 9447                return friendRequests.TryGetValue(friendRequestId, out result);
 448
 0449            return incomingFriendRequestsById.TryGetValue(friendRequestId, out result)
 450                   || outgoingFriendRequestsById.TryGetValue(friendRequestId, out result);
 451        }
 452
 453        public FriendRequest GetAllocatedFriendRequestByUser(string userId)
 454        {
 22455            long max = long.MinValue;
 22456            FriendRequest result = null;
 457
 22458            if (useSocialApiBridge)
 459            {
 21460                foreach (var request in incomingFriendRequestsById.Values)
 461                {
 5462                    if (request.From != userId && request.To != userId) continue;
 1463                    if (request.Timestamp.Ticks <= max) continue;
 1464                    result = request;
 1465                    max = request.Timestamp.Ticks;
 1466                    break;
 467                }
 468
 14469                foreach (var request in outgoingFriendRequestsById.Values)
 470                {
 2471                    if (request.From != userId && request.To != userId) continue;
 472
 473                    // we do check for max here because within a single session there can be a
 474                    // sent and a received request with the same user and we want to show the latest one
 2475                    if (request.Timestamp.Ticks <= max) continue;
 2476                    return request;
 477                }
 478            }
 479            else
 480            {
 68481                foreach (var request in friendRequests.Values)
 482                {
 18483                    if (request.From != userId && request.To != userId) continue;
 6484                    if (request.Timestamp.Ticks <= max) continue;
 6485                    result = request;
 6486                    max = request.Timestamp.Ticks;
 487                }
 488            }
 489
 20490            return result;
 2491        }
 492
 493        public async UniTask<FriendshipStatus> GetFriendshipStatus(string userId, CancellationToken cancellationToken)
 494        {
 0495            if (useSocialApiBridge)
 496            {
 0497                if (friends.TryGetValue(userId, out UserStatus status))
 0498                    return status.friendshipStatus;
 499
 0500                FriendRequest friendRequest = GetAllocatedFriendRequestByUser(userId);
 0501                if (friendRequest == null) return FriendshipStatus.NOT_FRIEND;
 0502                if (outgoingFriendRequestsById.ContainsKey(friendRequest.FriendRequestId))
 0503                    return FriendshipStatus.REQUESTED_TO;
 0504                if (incomingFriendRequestsById.ContainsKey(friendRequest.FriendRequestId))
 0505                    return FriendshipStatus.REQUESTED_FROM;
 0506                return FriendshipStatus.NOT_FRIEND;
 507            }
 508            else
 509            {
 0510                FriendshipStatus status = await apiBridge.GetFriendshipStatus(userId, cancellationToken);
 511
 0512                UpdateFriendshipStatus(new FriendshipUpdateStatusMessage
 513                {
 514                    action = ToFriendshipAction(status),
 515                    userId = userId,
 516                });
 517
 0518                return status;
 519            }
 0520        }
 521
 522        public async UniTask<FriendRequest> CancelRequestByUserIdAsync(string friendUserId, CancellationToken cancellati
 523        {
 0524            cancellationToken.ThrowIfCancellationRequested();
 525
 0526            FriendRequest request = GetAllocatedFriendRequestByUser(friendUserId);
 527
 0528            if (request == null) throw new Exception($"No friend request for user: {friendUserId}");
 529
 0530            if (useSocialApiBridge)
 531            {
 0532                await socialApiBridge.CancelFriendshipAsync(request.To, cancellationToken);
 0533                RemoveFriendRequestAndUpdateFriendshipStatus(request.To, FriendshipAction.CANCELLED);
 534            }
 535            else
 536            {
 0537                await apiBridge.CancelRequestAsync(request.FriendRequestId, cancellationToken);
 538
 0539                friendRequests.Remove(request.FriendRequestId);
 540
 0541                UpdateFriendshipStatus(new FriendshipUpdateStatusMessage
 542                    { action = FriendshipAction.CANCELLED, userId = friendUserId });
 543            }
 544
 0545            return request;
 546
 0547        }
 548
 549        public async UniTask<FriendRequest> CancelRequestAsync(string friendRequestId, CancellationToken cancellationTok
 550        {
 1551            cancellationToken.ThrowIfCancellationRequested();
 552            FriendRequest friendRequest;
 553
 1554            if (useSocialApiBridge)
 555            {
 0556                if (TryGetAllocatedFriendRequest(friendRequestId, out friendRequest))
 557                {
 0558                    await socialApiBridge.CancelFriendshipAsync(friendRequest.To, cancellationToken);
 0559                    RemoveFriendRequestAndUpdateFriendshipStatus(friendRequest.To, FriendshipAction.CANCELLED);
 560                }
 561                else
 0562                    throw new Exception($"Friend request does not exist: {friendRequestId}");
 563            }
 564            else
 565            {
 1566                CancelFriendshipConfirmationPayload payload = await apiBridge.CancelRequestAsync(friendRequestId, cancel
 567
 1568                friendRequest = ToFriendRequest(payload.friendRequest);
 569
 1570                friendRequests.Remove(friendRequest.FriendRequestId);
 571
 1572                UpdateFriendshipStatus(new FriendshipUpdateStatusMessage
 573                    { action = FriendshipAction.CANCELLED, userId = friendRequest.To });
 574            }
 575
 1576            return friendRequest;
 1577        }
 578
 579        private void HandlePeerDeletedFriendship(string friendId)
 580        {
 1581            var friendRequest = GetAllocatedFriendRequestByUser(friendId);
 582
 1583            if (friendRequest != null)
 584            {
 0585                outgoingFriendRequestsById.Remove(friendRequest.FriendRequestId);
 0586                outgoingFriendRequestsByTimestamp.Remove(friendRequest.Timestamp.Ticks);
 587            }
 588
 1589            UpdateFriendshipStatus(new FriendshipUpdateStatusMessage
 590            {
 591                userId = friendId,
 592                action = FriendshipAction.DELETED
 593            });
 1594        }
 595
 596        private void HandlePeerAcceptedFriendRequest(string friendId)
 597        {
 2598            var friendRequest = GetAllocatedFriendRequestByUser(friendId);
 599
 2600            if (friendRequest != null)
 601            {
 0602                outgoingFriendRequestsById.Remove(friendRequest.FriendRequestId);
 0603                outgoingFriendRequestsByTimestamp.Remove(friendRequest.Timestamp.Ticks);
 604            }
 605
 2606            AddFriendToCacheAndTriggerFriendshipUpdate(friendId);
 607
 2608            if (friendRequest != null)
 0609                OnSentFriendRequestApproved?.Invoke(friendRequest);
 2610        }
 611
 612        private void RemoveFriendRequestFromRejection(string userId) =>
 1613            RemoveFriendRequestAndUpdateFriendshipStatus(userId, FriendshipAction.REJECTED);
 614
 615        private void RemoveFriendRequestFromCancellation(string userId) =>
 0616            RemoveFriendRequestAndUpdateFriendshipStatus(userId, FriendshipAction.CANCELLED);
 617
 618        private void RemoveFriendRequestAndUpdateFriendshipStatus(string userId,
 619            FriendshipAction newFriendshipAction)
 620        {
 2621            var friendRequest = GetAllocatedFriendRequestByUser(userId);
 622
 2623            if (friendRequest != null)
 624            {
 2625                incomingFriendRequestsById.Remove(friendRequest.FriendRequestId);
 2626                incomingFriendRequestsByTimestamp.Remove(friendRequest.Timestamp.Ticks);
 627
 2628                outgoingFriendRequestsById.Remove(friendRequest.FriendRequestId);
 2629                outgoingFriendRequestsByTimestamp.Remove(friendRequest.Timestamp.Ticks);
 630            }
 631
 2632            UpdateFriendshipStatus(new FriendshipUpdateStatusMessage
 633            {
 634                userId = userId,
 635                action = newFriendshipAction
 636            });
 637
 2638            OnTotalFriendRequestUpdated?.Invoke(TotalReceivedFriendRequestCount, TotalSentFriendRequestCount);
 0639        }
 640
 641        private void AddFriendToCacheAndTriggerFriendshipUpdate(string friendId)
 642        {
 643            async UniTaskVoid IndexUserByNameAsync(UserStatus status, CancellationToken cancellationToken)
 644            {
 7645                UserProfile profile = userProfileBridge.Get(status.userId)
 646                                      ?? await userProfileBridge.RequestFullUserProfileAsync(status.userId, cancellation
 647
 7648                status.userName = profile.userName;
 7649                friendsSortedByName[profile.userName] = status;
 7650            }
 651
 652            UserStatus status;
 653
 7654            if (friends.TryGetValue(friendId, out status))
 1655                status.friendshipStatus = FriendshipStatus.FRIEND;
 656            else
 657            {
 6658                status = new UserStatus
 659                {
 660                    friendshipStatus = FriendshipStatus.FRIEND,
 661                    userId = friendId,
 662                };
 663
 6664                friends[friendId] = status;
 665            }
 666
 7667            IndexUserByNameAsync(status, controllerCancellationTokenSource.Token).Forget();
 668
 7669            OnUpdateFriendship?.Invoke(friendId, FriendshipAction.APPROVED);
 3670        }
 671
 672        private void RemoveFriendFromCacheAndTriggerFriendshipUpdate(string userId)
 673        {
 0674            if (!this.friends.ContainsKey(userId))
 675            {
 0676                Debug.LogWarning($"Tried to remove non existing friend {userId}");
 0677                return;
 678            }
 679
 0680            var friend = this.friends[userId];
 0681            this.friends.Remove(userId);
 682
 0683            if (string.IsNullOrEmpty(friend.userName))
 684            {
 0685                string userNameFound = null;
 686
 0687                foreach (UserStatus status in friendsSortedByName.Values)
 688                {
 0689                    if (status.userId != userId) continue;
 0690                    userNameFound = status.userName;
 0691                    break;
 692                }
 693
 0694                if (!string.IsNullOrEmpty(userNameFound))
 0695                    friendsSortedByName.Remove(userNameFound);
 696            }
 697            else
 0698                friendsSortedByName.Remove(friend.userName);
 699
 0700            OnUpdateFriendship?.Invoke(userId, FriendshipAction.DELETED);
 0701        }
 702
 703        private void InitializeFriendships(FriendshipInitializationMessage msg)
 704        {
 7705            if (IsInitialized) return;
 706
 7707            IsInitialized = true;
 708
 7709            TotalReceivedFriendRequestCount = msg.totalReceivedRequests;
 7710            OnTotalFriendRequestUpdated?.Invoke(TotalReceivedFriendRequestCount, TotalSentFriendRequestCount);
 7711            OnInitialized?.Invoke();
 1712        }
 713
 714        private void FriendNotFound(string name) =>
 0715            OnFriendNotFound?.Invoke(name);
 716
 717        private void AddFriendsWithDirectMessages(AddFriendsWithDirectMessagesPayload friendsWithDMs)
 718        {
 1719            TotalFriendsWithDirectMessagesCount = friendsWithDMs.totalFriendsWithDirectMessages;
 720
 4721            var friendIds = friendsWithDMs.currentFriendsWithDirectMessages.Select(messages => messages.userId);
 722
 8723            foreach (var friendId in friendIds)
 724            {
 3725                UpdateFriendshipStatus(new FriendshipUpdateStatusMessage
 726                    { action = FriendshipAction.APPROVED, userId = friendId });
 727            }
 728
 1729            OnAddFriendsWithDirectMessages?.Invoke(friendsWithDMs.currentFriendsWithDirectMessages.ToList());
 1730        }
 731
 732        private void UpdateUserPresence(UserStatus newUserStatus)
 733        {
 1734            if (!friends.ContainsKey(newUserStatus.userId)) return;
 735
 736            // Kernel doesn't send the friendship status on this call, we have to keep it or it gets defaulted
 1737            newUserStatus.friendshipStatus = friends[newUserStatus.userId].friendshipStatus;
 1738            UpdateUserStatus(newUserStatus);
 1739        }
 740
 741        // TODO (Joni): this should be called after AddFriendRequests / RemoveFriendRequest
 742        private void UpdateTotalFriendRequests(UpdateTotalFriendRequestsPayload msg)
 743        {
 1744            TotalReceivedFriendRequestCount = msg.totalReceivedRequests;
 1745            TotalSentFriendRequestCount = msg.totalSentRequests;
 1746            OnTotalFriendRequestUpdated?.Invoke(TotalReceivedFriendRequestCount, TotalSentFriendRequestCount);
 1747        }
 748
 749        private void UpdateTotalFriends(UpdateTotalFriendsPayload msg)
 750        {
 1751            TotalFriendCount = msg.totalFriends;
 1752        }
 753
 754        private void UpdateUserStatus(UserStatus newUserStatus)
 755        {
 1756            if (!friends.ContainsKey(newUserStatus.userId))
 757            {
 0758                friends.Add(newUserStatus.userId, newUserStatus);
 0759                OnUpdateUserStatus?.Invoke(newUserStatus.userId, newUserStatus);
 760            }
 761            else
 762            {
 1763                if (!friends[newUserStatus.userId].Equals(newUserStatus))
 764                {
 1765                    friends[newUserStatus.userId] = newUserStatus;
 1766                    OnUpdateUserStatus?.Invoke(newUserStatus.userId, newUserStatus);
 767                }
 768            }
 1769        }
 770
 771        private void ReceiveFriendRequest(FriendRequestPayload msg)
 772        {
 2773            FriendRequest request = ToFriendRequest(msg);
 774
 2775            friendRequests[msg.friendRequestId] = request;
 2776            OnFriendRequestReceived?.Invoke(request);
 0777        }
 778
 779        // TODO (Joni): Replace by according friend event from RPC Bridge
 780        private void HandleUpdateFriendshipStatus(FriendshipUpdateStatusMessage msg)
 781        {
 7782            UpdateFriendshipStatus(msg);
 783
 7784            var friendRequest = GetAllocatedFriendRequestByUser(msg.userId);
 785
 7786            if (msg.action == FriendshipAction.APPROVED)
 1787                OnSentFriendRequestApproved?.Invoke(friendRequest);
 6788        }
 789
 790        private void UpdateFriendshipStatus(FriendshipUpdateStatusMessage msg)
 791        {
 46792            FriendshipStatus friendshipStatus = ToFriendshipStatus(msg.action);
 46793            string userId = msg.userId;
 794
 46795            if (friends.ContainsKey(userId) && friends[userId].friendshipStatus == friendshipStatus)
 1796                return;
 797
 45798            if (!friends.ContainsKey(userId))
 799            {
 42800                friends.Add(userId, new UserStatus { userId = userId });
 801
 802                // Not adding the user to friendsSortedByName because this is only called in the legacy flow of a friend
 803            }
 804
 45805            friends[userId].friendshipStatus = friendshipStatus;
 806
 45807            if (friendshipStatus == FriendshipStatus.NOT_FRIEND)
 808            {
 9809                var friend = this.friends[userId];
 9810                friends.Remove(userId);
 811
 9812                if (!string.IsNullOrEmpty(friend.userName))
 1813                    friendsSortedByName.Remove(friend.userName);
 814            }
 815
 45816            OnUpdateFriendship?.Invoke(userId, msg.action);
 21817        }
 818
 819        private static FriendshipStatus ToFriendshipStatus(FriendshipAction action)
 820        {
 821            switch (action)
 822            {
 823                case FriendshipAction.NONE:
 824                    break;
 825                case FriendshipAction.APPROVED:
 8826                    return FriendshipStatus.FRIEND;
 827                case FriendshipAction.REJECTED:
 4828                    return FriendshipStatus.NOT_FRIEND;
 829                case FriendshipAction.CANCELLED:
 2830                    return FriendshipStatus.NOT_FRIEND;
 831                case FriendshipAction.REQUESTED_FROM:
 16832                    return FriendshipStatus.REQUESTED_FROM;
 833                case FriendshipAction.REQUESTED_TO:
 16834                    return FriendshipStatus.REQUESTED_TO;
 835                case FriendshipAction.DELETED:
 2836                    return FriendshipStatus.NOT_FRIEND;
 837            }
 838
 1839            return FriendshipStatus.NOT_FRIEND;
 840        }
 841
 842        private void AddFriends(IEnumerable<string> friendIds)
 843        {
 10844            foreach (var friendId in friendIds)
 845            {
 3846                if (!friends.ContainsKey(friendId))
 3847                    friends.Add(friendId, new UserStatus { userId = friendId });
 848
 3849                friends[friendId].friendshipStatus = ToFriendshipStatus(FriendshipAction.APPROVED);
 850            }
 2851        }
 852
 853        private FriendRequest ToFriendRequest(FriendRequestPayload friendRequest) =>
 14854            new (
 855                friendRequest.friendRequestId,
 856                DateTimeOffset.FromUnixTimeMilliseconds(friendRequest.timestamp).DateTime,
 857                friendRequest.from,
 858                friendRequest.to,
 859                friendRequest.messageBody);
 860
 861        // TODO (NEW FRIEND REQUESTS): remove when we don't need to keep the retro-compatibility with the old version
 862        private void AddFriendRequests(AddFriendRequestsPayload msg)
 863        {
 0864            TotalReceivedFriendRequestCount = msg.totalReceivedFriendRequests;
 0865            TotalSentFriendRequestCount = msg.totalSentFriendRequests;
 0866            OnTotalFriendRequestUpdated?.Invoke(TotalReceivedFriendRequestCount, TotalSentFriendRequestCount);
 867
 0868            foreach (var userId in msg.requestedFrom)
 869            {
 0870                UpdateFriendshipStatus(new FriendshipUpdateStatusMessage
 871                    { action = FriendshipAction.REQUESTED_FROM, userId = userId });
 872            }
 873
 0874            foreach (var userId in msg.requestedTo)
 875            {
 0876                UpdateFriendshipStatus(new FriendshipUpdateStatusMessage
 877                    { action = FriendshipAction.REQUESTED_TO, userId = userId });
 878            }
 0879        }
 880
 881        private void AddIncomingFriendRequest(FriendRequest friendRequest) =>
 10882            AddIncomingFriendRequest(friendRequest, true);
 883
 884        private void AddIncomingFriendRequest(FriendRequest friendRequest, bool notify)
 885        {
 10886            this.incomingFriendRequestsById[friendRequest.FriendRequestId] = friendRequest;
 10887            this.incomingFriendRequestsByTimestamp[friendRequest.Timestamp.Ticks] = friendRequest;
 888
 10889            UpdateFriendshipStatus(new FriendshipUpdateStatusMessage
 890                { action = FriendshipAction.REQUESTED_FROM, userId = friendRequest.From });
 891
 10892            if (notify)
 893            {
 10894                OnTotalFriendRequestUpdated?.Invoke(TotalReceivedFriendRequestCount, TotalSentFriendRequestCount);
 10895                OnFriendRequestReceived?.Invoke(friendRequest);
 896            }
 0897        }
 898
 899        private void AddOutgoingFriendRequest(FriendRequest friendRequest) =>
 9900            AddOutgoingFriendRequest(friendRequest, true);
 901
 902        private void AddOutgoingFriendRequest(FriendRequest friendRequest, bool notify)
 903        {
 9904            this.outgoingFriendRequestsById[friendRequest.FriendRequestId] = friendRequest;
 9905            this.outgoingFriendRequestsByTimestamp[friendRequest.Timestamp.Ticks] = friendRequest;
 906
 9907            UpdateFriendshipStatus(new FriendshipUpdateStatusMessage
 908                { action = FriendshipAction.REQUESTED_TO, userId = friendRequest.From });
 909
 9910            if (notify)
 9911                OnTotalFriendRequestUpdated?.Invoke(TotalReceivedFriendRequestCount, TotalSentFriendRequestCount);
 0912        }
 913
 914        private FriendshipAction ToFriendshipAction(FriendshipStatus status)
 915        {
 916            switch (status)
 917            {
 918                case FriendshipStatus.FRIEND:
 0919                    return FriendshipAction.APPROVED;
 920                case FriendshipStatus.NOT_FRIEND:
 921                default:
 0922                    return FriendshipAction.NONE;
 923                case FriendshipStatus.REQUESTED_TO:
 0924                    return FriendshipAction.REQUESTED_TO;
 925                case FriendshipStatus.REQUESTED_FROM:
 0926                    return FriendshipAction.REQUESTED_FROM;
 927            }
 928        }
 929
 930        private async UniTask WaitForFeatureFlagsToBeInitialized(CancellationToken cancellationToken)
 931        {
 423932            if (featureFlagsInitializedTask == null)
 933            {
 423934                featureFlagsInitializedTask = new UniTaskCompletionSource();
 935
 936                void CompleteTaskAndUnsubscribe(FeatureFlag current, FeatureFlag previous)
 937                {
 59938                    dataStore.featureFlags.flags.OnChange -= CompleteTaskAndUnsubscribe;
 59939                    featureFlagsInitializedTask.TrySetResult();
 59940                }
 941
 423942                dataStore.featureFlags.flags.OnChange += CompleteTaskAndUnsubscribe;
 943            }
 944
 1269945            await featureFlagsInitializedTask.Task.AttachExternalCancellation(cancellationToken);
 19946        }
 947    }
 948}

Methods/Properties

FriendsController()
FriendsController(DCl.Social.Friends.IFriendsApiBridge, DCL.Social.Friends.ISocialApiBridge, DCL.DataStore, IUserProfileBridge)
featureFlags()
useSocialApiBridge()
AllocatedFriendCount()
IsInitialized()
IsInitialized(System.Boolean)
ReceivedRequestCount()
TotalFriendCount()
TotalFriendCount(System.Int32)
TotalFriendRequestCount()
TotalReceivedFriendRequestCount()
TotalReceivedFriendRequestCount(System.Int32)
TotalSentFriendRequestCount()
TotalSentFriendRequestCount(System.Int32)
TotalFriendsWithDirectMessagesCount()
TotalFriendsWithDirectMessagesCount(System.Int32)
Initialize()
<Initialize()
Dispose()
GetUserStatus(System.String)
ContainsStatus(System.String, DCL.Social.Friends.FriendshipStatus)
RequestFriendshipAsync()
GetAllocatedFriends()
AcceptFriendshipAsync()
RejectFriendshipAsync()
IsFriend(System.String)
RemoveFriendAsync()
GetFriendsAsync()
GetFriendsAsync()
GetFriendRequestsAsync()
GetFriendsWithDirectMessages(System.Int32, System.Int32)
GetFriendsWithDirectMessages(System.String, System.Int32)
TryGetAllocatedFriendRequest(System.String, DCL.Social.Friends.FriendRequest&)
GetAllocatedFriendRequestByUser(System.String)
GetFriendshipStatus()
CancelRequestByUserIdAsync()
CancelRequestAsync()
HandlePeerDeletedFriendship(System.String)
HandlePeerAcceptedFriendRequest(System.String)
RemoveFriendRequestFromRejection(System.String)
RemoveFriendRequestFromCancellation(System.String)
RemoveFriendRequestAndUpdateFriendshipStatus(System.String, DCL.Social.Friends.FriendshipAction)
<AddFriendToCacheAndTriggerFriendshipUpdate()
AddFriendToCacheAndTriggerFriendshipUpdate(System.String)
RemoveFriendFromCacheAndTriggerFriendshipUpdate(System.String)
InitializeFriendships(DCL.Social.Friends.FriendshipInitializationMessage)
FriendNotFound(System.String)
AddFriendsWithDirectMessages(DCL.Social.Friends.AddFriendsWithDirectMessagesPayload)
UpdateUserPresence(UserStatus)
UpdateTotalFriendRequests(DCl.Social.Friends.UpdateTotalFriendRequestsPayload)
UpdateTotalFriends(DCL.Social.Friends.UpdateTotalFriendsPayload)
UpdateUserStatus(UserStatus)
ReceiveFriendRequest(DCL.Social.Friends.FriendRequestPayload)
HandleUpdateFriendshipStatus(DCL.Social.Friends.FriendshipUpdateStatusMessage)
UpdateFriendshipStatus(DCL.Social.Friends.FriendshipUpdateStatusMessage)
ToFriendshipStatus(DCL.Social.Friends.FriendshipAction)
AddFriends(System.Collections.Generic.IEnumerable[String])
ToFriendRequest(DCL.Social.Friends.FriendRequestPayload)
AddFriendRequests(DCL.Social.Friends.AddFriendRequestsPayload)
AddIncomingFriendRequest(DCL.Social.Friends.FriendRequest)
AddIncomingFriendRequest(DCL.Social.Friends.FriendRequest, System.Boolean)
AddOutgoingFriendRequest(DCL.Social.Friends.FriendRequest)
AddOutgoingFriendRequest(DCL.Social.Friends.FriendRequest, System.Boolean)
ToFriendshipAction(DCL.Social.Friends.FriendshipStatus)
WaitForFeatureFlagsToBeInitialized()