Example #1
0
        /// <inheritdoc />
        public void JoinGroup(SessionInfo session, Guid groupId, JoinGroupRequest request, CancellationToken cancellationToken)
        {
            var user = _userManager.GetUserById(session.UserId);

            if (user.SyncPlayAccess == SyncPlayAccess.None)
            {
                _logger.LogWarning("JoinGroup: {0} does not have access to SyncPlay.", session.Id);

                var error = new GroupUpdate <string>()
                {
                    Type = GroupUpdateType.JoinGroupDenied
                };

                _sessionManager.SendSyncPlayGroupUpdate(session.Id, error, CancellationToken.None);
                return;
            }

            lock (_groupsLock)
            {
                ISyncPlayController group;
                _groups.TryGetValue(groupId, out group);

                if (group == null)
                {
                    _logger.LogWarning("JoinGroup: {0} tried to join group {0} that does not exist.", session.Id, groupId);

                    var error = new GroupUpdate <string>()
                    {
                        Type = GroupUpdateType.GroupDoesNotExist
                    };
                    _sessionManager.SendSyncPlayGroupUpdate(session.Id, error, CancellationToken.None);
                    return;
                }

                if (!HasAccessToItem(user, group.GetPlayingItemId()))
                {
                    _logger.LogWarning("JoinGroup: {0} does not have access to {1}.", session.Id, group.GetPlayingItemId());

                    var error = new GroupUpdate <string>()
                    {
                        GroupId = group.GetGroupId().ToString(),
                        Type    = GroupUpdateType.LibraryAccessDenied
                    };
                    _sessionManager.SendSyncPlayGroupUpdate(session.Id, error, CancellationToken.None);
                    return;
                }

                if (IsSessionInGroup(session))
                {
                    if (GetSessionGroup(session).Equals(groupId))
                    {
                        return;
                    }

                    LeaveGroup(session, cancellationToken);
                }

                group.SessionJoin(session, request, cancellationToken);
            }
        }
        public async Task <SignalRServerResponse> Join(JoinGroupRequest request)
        {
            if (request.IsDetector)
            {
                await AddToDetectorGroup();
            }
            else
            {
                await AddToConsumerGroup(request.IsHDMIController);
            }
            // Here we are selecting all the IDs that are currently in the ClientID - GroupName hash and putting them in a list
            IReadOnlyList <string> joinedClients = _clientIDGroupNameHash.Select(cg => cg.Key)
                                                   .Where(id => id != Context.ConnectionId)
                                                   .ToList();
            // build the counts of each group
            ClientGroupStats otherGroupStats = BuildClientGroupStatsResponse();
            // this one contains the group that was just joined
            ClientGroupStats senderGroupStats = BuildClientGroupStatsResponse(true);
            // publish to all clients that have joined a group that there are new group stats.
            await Clients.Clients(joinedClients).SendAsync(nameof(ClientGroupStats), otherGroupStats);

            await Clients.Caller.SendAsync(nameof(ClientGroupStats), senderGroupStats);

            return(new SignalRServerResponse()
            {
                Success = true
            });
        }
        private async Task JoinGroupAsync(CancellationToken cancellationToken)
        {
            if (_disposeCount > 0)
            {
                throw new ObjectDisposedException($"Consumer {{GroupId:{GroupId},MemberId:{MemberId}}} is no longer valid");
            }

            try {
                var protocols = _joinSemaphore.Lock(() => IsLeader ? _memberMetadata?.Values.Select(m => new JoinGroupRequest.GroupProtocol(m)) : null, cancellationToken);
                var request   = new JoinGroupRequest(GroupId, Configuration.GroupHeartbeat, MemberId, ProtocolType, protocols, Configuration.GroupRebalanceTimeout);
                var response  = await Router.SendAsync(request, GroupId, cancellationToken, new RequestContext(protocolType : ProtocolType), Configuration.GroupCoordinationRetry).ConfigureAwait(false);

                OnJoinGroup(response);
                await _stateChangeQueue.EnqueueAsync(ApiKey.SyncGroup, _disposeToken.Token);
            } catch (RequestException ex) {
                switch (ex.ErrorCode)
                {
                case ErrorCode.ILLEGAL_GENERATION:
                case ErrorCode.GROUP_AUTHORIZATION_FAILED:
                case ErrorCode.UNKNOWN_MEMBER_ID:
                case ErrorCode.INCONSISTENT_GROUP_PROTOCOL:
                case ErrorCode.INVALID_SESSION_TIMEOUT:
                    Router.Log.Warn(() => LogEvent.Create(ex));
                    _leaveOnDispose = false;     // no point in attempting to leave the group since it will fail
                    _disposeToken.Cancel();
                    return;
                }
                throw;
            }
        }
Example #4
0
        /// <summary>
        /// Handles the specified request.
        /// </summary>
        /// <param name="request">The request.</param>
        public void Post(SyncPlayJoin request)
        {
            var currentSession = GetSession(_sessionContext);

            Guid groupId;
            Guid playingItemId = Guid.Empty;

            if (!Guid.TryParse(request.GroupId, out groupId))
            {
                Logger.LogError("JoinGroup: {0} is not a valid format for GroupId. Ignoring request.", request.GroupId);
                return;
            }

            // Both null and empty strings mean that client isn't playing anything
            if (!string.IsNullOrEmpty(request.PlayingItemId) && !Guid.TryParse(request.PlayingItemId, out playingItemId))
            {
                Logger.LogError("JoinGroup: {0} is not a valid format for PlayingItemId. Ignoring request.", request.PlayingItemId);
                return;
            }

            var joinRequest = new JoinGroupRequest()
            {
                GroupId       = groupId,
                PlayingItemId = playingItemId
            };

            _syncPlayManager.JoinGroup(currentSession, groupId, joinRequest, CancellationToken.None);
        }
Example #5
0
        public async Task <ServiceResult <object> > AgreeJoin(User owner, JoinGroupRequest request)
        {
            var owns = await OwnsGroup(owner, request.Group);

            if (!owns.ExtraData)
            {
                return(Unauthorized(owns.Detail));
            }
            if (request == null)
            {
                return(NotFound("该加群申请不存在"));
            }
            Context.JoinGroupRequests.Remove(request);
            Context.GroupMemberships.Add(new GroupMembership {
                UserId = request.User.Id, ChatGroupId = request.Group.Id, Role = GroupRole.Member
            });
            if (ConnectionService.IsOnline(request.UserId))
            {
                await HubContext.Groups.AddToGroupAsync(ConnectionService.GetConnectionId(request.UserId), request.GroupId.ToString());
            }
            await NotificationService.NotifyGroupMembers(request.GroupId, $"{request?.User?.Nickname ?? "未命名用户"}加入了群聊", NotificationTypeEnum.NewMemberJoined);

            await Context.SaveChangesAsync();

            return(Success("通过加群成功"));
        }
Example #6
0
        /// <inheritdoc />
        public void SessionJoin(SessionInfo session, JoinGroupRequest request, CancellationToken cancellationToken)
        {
            if (session.NowPlayingItem?.Id == _group.PlayingItem.Id && request.PlayingItemId == _group.PlayingItem.Id)
            {
                _group.AddSession(session);
                _syncPlayManager.AddSessionToGroup(session, this);

                var updateSession = NewSyncPlayGroupUpdate(GroupUpdateType.GroupJoined, DateToUTCString(DateTime.UtcNow));
                SendGroupUpdate(session, BroadcastType.CurrentSession, updateSession, cancellationToken);

                var updateOthers = NewSyncPlayGroupUpdate(GroupUpdateType.UserJoined, session.UserName);
                SendGroupUpdate(session, BroadcastType.AllExceptCurrentSession, updateOthers, cancellationToken);

                // Client join and play, syncing will happen client side
                if (!_group.IsPaused)
                {
                    var playCommand = NewSyncPlayCommand(SendCommandType.Play);
                    SendCommand(session, BroadcastType.CurrentSession, playCommand, cancellationToken);
                }
                else
                {
                    var pauseCommand = NewSyncPlayCommand(SendCommandType.Pause);
                    SendCommand(session, BroadcastType.CurrentSession, pauseCommand, cancellationToken);
                }
            }
            else
            {
                var playRequest = new PlayRequest();
                playRequest.ItemIds            = new Guid[] { _group.PlayingItem.Id };
                playRequest.StartPositionTicks = _group.PositionTicks;
                var update = NewSyncPlayGroupUpdate(GroupUpdateType.PrepareSession, playRequest);
                SendGroupUpdate(session, BroadcastType.CurrentSession, update, cancellationToken);
            }
        }
        public async Task ConsumerSyncsGroupAfterJoining()
        {
            var protocol = new JoinGroupRequest.GroupProtocol(new ConsumerProtocolMetadata("mine"));
            var router   = Substitute.For <IRouter>();
            var conn     = Substitute.For <IConnection>();

            router.GetGroupConnectionAsync(Arg.Any <string>(), Arg.Any <CancellationToken>())
            .Returns(_ => Task.FromResult(new GroupConnection(_.Arg <string>(), 0, conn)));
            router.SyncGroupAsync(Arg.Any <SyncGroupRequest>(), Arg.Any <IRequestContext>(), Arg.Any <IRetry>(), Arg.Any <CancellationToken>())
            .Returns(_ => Task.FromResult(new SyncGroupResponse(ErrorCode.NONE, new ConsumerMemberAssignment(new [] { new TopicPartition("name", 0) }))));

            var request  = new JoinGroupRequest(TestConfig.GroupId(), TimeSpan.FromSeconds(30), "", ConsumerEncoder.Protocol, new [] { protocol });
            var memberId = Guid.NewGuid().ToString("N");
            var response = new JoinGroupResponse(ErrorCode.NONE, 1, protocol.protocol_name, memberId, memberId, new [] { new JoinGroupResponse.Member(memberId, new ConsumerProtocolMetadata("mine")) });

            using (new GroupConsumer(router, request.group_id, request.protocol_type, response)) {
                await Task.Delay(300);
            }

#pragma warning disable 4014
            router.Received().SyncGroupAsync(
                Arg.Is((SyncGroupRequest s) => s.group_id == request.group_id && s.member_id == memberId),
                Arg.Any <IRequestContext>(),
                Arg.Any <IRetry>(),
                Arg.Any <CancellationToken>());
            conn.DidNotReceive().SendAsync(
                Arg.Is((HeartbeatRequest s) => s.group_id == request.group_id && s.member_id == memberId),
                Arg.Any <CancellationToken>(),
                Arg.Any <IRequestContext>());
#pragma warning restore 4014
        }
        public async Task ConsumerHeartbeatsWithinTimeLimit(int heartbeatMilliseconds, int totalMilliseconds)
        {
            var protocol = new JoinGroupRequest.GroupProtocol(new ConsumerProtocolMetadata("mine"));
            var router   = Substitute.For <IRouter>();
            var conn     = Substitute.For <IConnection>();

            router.GetGroupConnectionAsync(Arg.Any <string>(), Arg.Any <CancellationToken>())
            .Returns(_ => Task.FromResult(new GroupConnection(_.Arg <string>(), 0, conn)));

            var lastHeartbeat      = DateTimeOffset.UtcNow;
            var heartbeatIntervals = ImmutableArray <TimeSpan> .Empty;

            conn.SendAsync(Arg.Any <HeartbeatRequest>(), Arg.Any <CancellationToken>(), Arg.Any <IRequestContext>())
            .Returns(_ => {
                heartbeatIntervals = heartbeatIntervals.Add(DateTimeOffset.UtcNow - lastHeartbeat);
                lastHeartbeat      = DateTimeOffset.UtcNow;
                return(Task.FromResult(new HeartbeatResponse(ErrorCode.NONE)));
            });
            var request  = new JoinGroupRequest(TestConfig.GroupId(), TimeSpan.FromMilliseconds(heartbeatMilliseconds), "", ConsumerEncoder.Protocol, new [] { protocol });
            var memberId = Guid.NewGuid().ToString("N");
            var response = new JoinGroupResponse(ErrorCode.NONE, 1, protocol.protocol_name, memberId, memberId, new [] { new JoinGroupResponse.Member(memberId, new ConsumerProtocolMetadata("mine")) });

            lastHeartbeat = DateTimeOffset.UtcNow;

            using (new GroupConsumer(router, request.group_id, request.protocol_type, response)) {
                await Task.Delay(totalMilliseconds);
            }

            foreach (var interval in heartbeatIntervals)
            {
                Assert.That((int)interval.TotalMilliseconds, Is.AtMost(heartbeatMilliseconds));
            }
        }
Example #9
0
        public async Task <ServiceResult <object> > JoinGroup(User user, ChatGroup chatGroup)
        {
            var membership = Context.GroupMemberships.FirstOrDefault(m => m.UserId == user.Id && m.ChatGroupId == chatGroup.Id);

            if (membership != null)
            {
                return(Exist("您已在该群中"));
            }
            var request = Context.JoinGroupRequests.FirstOrDefault(r => r.User.Id == user.Id && r.Group.Id == chatGroup.Id);

            if (request != null)
            {
                return(Exist("您已经申请加群"));
            }
            request = new JoinGroupRequest {
                User = user, Group = chatGroup
            };
            Context.JoinGroupRequests.Add(request);
            await Context.SaveChangesAsync();

            UserDetailAndGroupDetail detail = new UserDetailAndGroupDetail
            {
                User      = user.ToDetail(),
                Group     = chatGroup.ToDetail(),
                RequestId = request.Id,
            };
            await NotificationService.Notify(chatGroup.Creator.Id, JsonHelper.ToJson(detail), NotificationTypeEnum.JoinRequest);

            return(Success("加群申请成功"));
        }
Example #10
0
        public JoinGroupResponse JoinGroup(String groupId, String memberId, IList <String> topics)
        {
            var request  = new JoinGroupRequest(groupId, memberId, topics.ToArray(), _config.JoinGroupSessionTimeout);
            var response = (JoinGroupResponse)_client.SubmitRequest(_coordinateBroker.ToUri(), request);

            response.TryThrowFirstErrorOccured();
            return(response);
        }
Example #11
0
        public ActionResult SyncPlayJoinGroup(
            [FromBody, Required] JoinGroupRequestDto requestData)
        {
            var currentSession  = RequestHelpers.GetSession(_sessionManager, _authorizationContext, Request);
            var syncPlayRequest = new JoinGroupRequest(requestData.GroupId);

            _syncPlayManager.JoinGroup(currentSession, syncPlayRequest, CancellationToken.None);
            return(NoContent());
        }
        public async Task <bool> JoinGroup([FromBody] JoinGroupRequest req)
        {
            string token = req.token;
            //todo:要根据业务系统的要求,判断这个用户是否能加入这个Group
            MsgHubClient client = new MsgHubClient(msgHubServer);
            await client.JoinGroupAsync(token, req.groupId);

            return(true);
        }
Example #13
0
        public async Task <IActionResult> JoinGroup(JoinGroupRequest request)
        {
            var response = await mediator.Send(request);

            logger.LogResponse(
                $"User #{HttpContext.GetCurrentUserId()} joined group #{request.GroupId} with status: {(response.Member.IsAccepted ? "ACCEPTED" : "WAITING")}",
                response.Error);

            return(this.CreateResponse(response));
        }
Example #14
0
        private void OnSessionControllerConnected(object sender, SessionEventArgs e)
        {
            var session = e.SessionInfo;

            if (_sessionToGroupMap.TryGetValue(session.Id, out var group))
            {
                var request = new JoinGroupRequest(group.GroupId);
                JoinGroup(session, request, CancellationToken.None);
            }
        }
Example #15
0
        public static async Task <JoinGroupResponse> JoinGroupAsync(this IRouter router, string groupId, string protocolType, IEnumerable <IMemberMetadata> metadata, IConsumerConfiguration configuration, CancellationToken cancellationToken)
        {
            var protocols = metadata?.Select(m => new JoinGroupRequest.GroupProtocol(m));
            var request   = new JoinGroupRequest(groupId, configuration.GroupHeartbeat, null, protocolType, protocols, configuration.GroupRebalanceTimeout);
            var response  = await router.SendAsync(request, request.group_id, cancellationToken, new RequestContext(protocolType : request.protocol_type), configuration.GroupCoordinationRetry).ConfigureAwait(false);

            if (response == null || !response.error_code.IsSuccess())
            {
                throw request.ExtractExceptions(response);
            }
            return(response);
        }
Example #16
0
    public void joinGroup()
    {
        token = PlayerPrefs.GetString("token");
        JoinGroupRequest joinGroupRequest = new JoinGroupRequest();

        joinGroupRequest.action    = "joinGroup";
        joinGroupRequest.token     = token;
        tempGroupName              = groupNameInput.text;
        joinGroupRequest.groupName = tempGroupName;
        SendWebSocketMessage(JsonUtility.ToJson(joinGroupRequest));
        groupNameInput.text = "";
    }
Example #17
0
        public ActionResult SyncPlayJoinGroup([FromQuery, Required] Guid groupId)
        {
            var currentSession = RequestHelpers.GetSession(_sessionManager, _authorizationContext, Request);

            var joinRequest = new JoinGroupRequest()
            {
                GroupId = groupId
            };

            _syncPlayManager.JoinGroup(currentSession, groupId, joinRequest, CancellationToken.None);
            return(NoContent());
        }
    /// <summary>
    /// Accept player
    /// </summary>
    /// <param name="request">join request</param>
    private void AcceptPlayer(JoinGroupRequest request)
    {
        IPeer peer = request.Accept("SimpleGame");

        // check if peer is connected
        if (peer.isConnected)
        {
            GameObject go = Instantiate(boxPrefab);
            go.SetActive(true);
            ServerSimpleBox component = go.GetComponent <ServerSimpleBox>();
            component.id = peer.Id;
            boxes.Add(component.id, component);
        }
    }
Example #19
0
        public async Task <ServiceResult <object> > RejectJoin(User owner, JoinGroupRequest request)
        {
            var owns = await OwnsGroup(owner, request.Group);

            if (!owns.ExtraData)
            {
                return(Unauthorized(owns.Detail));
            }
            request = Context.JoinGroupRequests.FirstOrDefault(r => r.User.Id == request.User.Id && r.Group.Id == request.Group.Id);
            if (request == null)
            {
                return(NotFound("该加群申请不存在"));
            }
            Context.JoinGroupRequests.Remove(request);
            await Context.SaveChangesAsync();

            return(Success("拒绝加群成功"));
        }
Example #20
0
        public async Task JoinGroupAsync(JoinGroupRequest req)
        {
            string userId         = this.HttpContext.User.GetUserId();
            string appKey         = this.HttpContext.User.GetAppKey();
            string groupName      = this.HttpContext.User.GetGroupName(req.groupId);
            string authentication = this.HttpContext.Request.Headers["Authorization"];
            string token          = authentication.Substring("Bearer ".Length);

            IDatabase db           = redis.GetDatabase();
            string    connectionId = await db.StringGetAsync(token + "_ConnectionId");

            //用groupId做组名
            await this.hubContext.Groups.AddToGroupAsync(connectionId, groupName);

            //如果组不存在,则创建组
            //如果组存在,则用新的组名覆盖旧的
            //加入成员
            await db.SetAddAsync($"{groupName}_Members", userId);
        }
Example #21
0
        /// <summary>
        /// Handles the specified request.
        /// </summary>
        /// <param name="request">The request.</param>
        public void Post(SyncPlayJoin request)
        {
            var currentSession = GetSession(_sessionContext);

            Guid groupId;

            if (!Guid.TryParse(request.GroupId, out groupId))
            {
                Logger.LogError("JoinGroup: {0} is not a valid format for GroupId. Ignoring request.", request.GroupId);
                return;
            }

            var joinRequest = new JoinGroupRequest()
            {
                GroupId = groupId
            };

            _syncPlayManager.JoinGroup(currentSession, groupId, joinRequest, CancellationToken.None);
        }
Example #22
0
        public async Task JoinGroup(JoinGroupRequest req)
        {
            string sessionId = req.sessionId;

            if (string.IsNullOrEmpty(sessionId))
            {
                sessionId = this.GenerateSessionID();
                _logger.LogInformation($"GenerateSessionID: SessionID={sessionId}");
            }
            if (req.isEditor)
            {
                if (EditorAlreadyExistsList.Contains(sessionId))
                {
                    _logger.LogInformation($"EditorIsAlreadyExists: SessionID={sessionId}");
                    await Clients.Caller.SendAsync("Joined", new
                    {
                        Succeeded = false,
                        SessionId = "",
                        Message   = "Editorがすでに存在します"
                    });

                    return;
                }
                else
                {
                    EditorAlreadyExistsList.Add(sessionId);
                }
            }
            await Groups.AddToGroupAsync(Context.ConnectionId, sessionId);

            _logger.LogInformation($"UserJoinGroup: ConnectionId={Context.ConnectionId} SessionID={sessionId} Role={(req.isEditor ? "Editor" : "Viewer")}");
            await Clients.Caller.SendAsync("Joined", new
            {
                Succeeded = true,
                SessionId = sessionId,
                Message   = ""
            });

            if (!req.isEditor)
            {
                await Clients.Group(sessionId).SendAsync("JoinNotify");
            }
        }
Example #23
0
        public void JoinGroupRequest(
            [Values(0, 1)] short version,
            [Values("test", "a groupId")] string groupId,
            [Values(1, 20000)] int sessionTimeout,
            [Values("", "an existing member")] string memberId,
            [Values("consumer", "other")] string protocolType,
            [Values(1, 10)] int protocolsPerRequest)
        {
            var protocols = new List <JoinGroupRequest.GroupProtocol>();

            for (var p = 0; p < protocolsPerRequest; p++)
            {
                var bytes = new byte[protocolsPerRequest * 100];
                _randomizer.NextBytes(bytes);
                protocols.Add(new JoinGroupRequest.GroupProtocol(protocolType + p, new ByteMember(bytes)));
            }
            var request = new JoinGroupRequest(groupId, TimeSpan.FromMilliseconds(sessionTimeout), memberId, protocolType, protocols, version >= 1 ? (TimeSpan?)TimeSpan.FromMilliseconds(sessionTimeout * 2) : null);

            request.AssertCanEncodeDecodeRequest(version);
        }
Example #24
0
        public void JoinConsumerGroupRequest(
            [Values("test", "a groupId")] string groupId,
            [Values(1, 20000)] int sessionTimeout,
            [Values("", "an existing member")] string memberId,
            [Values("consumer")] string protocolType,
            [Values(1, 10)] int protocolsPerRequest)
        {
            var encoder   = new ConsumerEncoder();
            var protocols = new List <JoinGroupRequest.GroupProtocol>();

            for (var p = 0; p < protocolsPerRequest; p++)
            {
                var userData = new byte[protocolsPerRequest * 100];
                _randomizer.NextBytes(userData);
                var metadata = new ConsumerProtocolMetadata(0, new [] { groupId, memberId, protocolType }, userData);
                protocols.Add(new JoinGroupRequest.GroupProtocol(protocolType + p, metadata));
            }
            var request = new JoinGroupRequest(groupId, TimeSpan.FromMilliseconds(sessionTimeout), memberId, protocolType, protocols);

            request.AssertCanEncodeDecodeRequest(0, encoder);
        }
Example #25
0
        public async Task JoinGroupAsync(JoinGroupRequest req)
        {
            string userId         = this.HttpContext.User.GetUserId();
            string appKey         = this.HttpContext.User.GetAppKey();
            string groupName      = this.HttpContext.User.GetGroupName(req.groupId);
            string authentication = this.HttpContext.Request.Headers["Authorization"];
            string token          = authentication.Substring("Bearer ".Length);

            //redis连接字符串格式见https://www.cnblogs.com/ArvinZhao/p/6007043.html
            using (ConnectionMultiplexer redis = ConnectionMultiplexer.Connect(redisSetting.Value.Configuration))
            {
                IDatabase db           = redis.GetDatabase(redisSetting.Value.DbId);//默认是访问db0数据库,可以通过方法参数指定数字访问不同的数据库
                string    connectionId = await db.StringGetAsync(token + "_ConnectionId");

                //用groupId做组名
                await this.Context.Groups.AddToGroupAsync(connectionId, groupName);

                //如果组不存在,则创建组
                //如果组存在,则用新的组名覆盖旧的
                //加入成员
                await db.SetAddAsync($"{groupName}_Members", userId);
            }
        }
        public async Task ConsumerHeartbeatsAtDesiredIntervals(int expectedHeartbeats, int heartbeatMilliseconds, int totalMilliseconds)
        {
            var protocol = new JoinGroupRequest.GroupProtocol(new ConsumerProtocolMetadata("mine"));
            var router   = Substitute.For <IRouter>();
            var conn     = Substitute.For <IConnection>();

            router.GetConnectionAsync(Arg.Any <string>(), Arg.Any <string>(), Arg.Any <CancellationToken>())
            .Returns(_ => Task.FromResult(conn));
            router.SyncGroupAsync(Arg.Any <SyncGroupRequest>(), Arg.Any <IRequestContext>(), Arg.Any <IRetry>(), Arg.Any <CancellationToken>())
            .Returns(_ => Task.FromResult(new SyncGroupResponse(ErrorCode.NONE, new ConsumerMemberAssignment(new [] { new TopicPartition("name", 0) }))));
            conn.SendAsync(Arg.Any <HeartbeatRequest>(), Arg.Any <CancellationToken>(), Arg.Any <IRequestContext>())
            .Returns(_ => Task.FromResult(new HeartbeatResponse(ErrorCode.NONE)));

            var config   = new ConsumerConfiguration(heartbeatTimeout: TimeSpan.FromMilliseconds(heartbeatMilliseconds * 2));
            var request  = new JoinGroupRequest(TestConfig.GroupId(), config.GroupHeartbeat, "", ConsumerEncoder.Protocol, new [] { protocol });
            var memberId = Guid.NewGuid().ToString("N");
            var response = new JoinGroupResponse(ErrorCode.NONE, 1, protocol.protocol_name, memberId, memberId, new [] { new JoinGroupResponse.Member(memberId, new ConsumerProtocolMetadata("mine")) });

            using (new GroupConsumer(router, request.group_id, request.protocol_type, response, config)) {
                await Task.Delay(totalMilliseconds);
            }

            Assert.That(conn.ReceivedCalls()
                        .Count(c => {
                if (c.GetMethodInfo().Name != nameof(Connection.SendAsync))
                {
                    return(false);
                }
                var s = c.GetArguments()[0] as HeartbeatRequest;
                if (s == null)
                {
                    return(false);
                }
                return(s.group_id == request.group_id && s.member_id == memberId && s.generation_id == response.generation_id);
            }), Is.InRange(expectedHeartbeats - 1, expectedHeartbeats + 1));
        }
        public async Task ConsumerHeartbeatsUntilDisposed(int heartbeatMilliseconds)
        {
            var protocol = new JoinGroupRequest.GroupProtocol(new ConsumerProtocolMetadata("mine"));
            var router   = Substitute.For <IRouter>();
            var conn     = Substitute.For <IConnection>();

            router.GetConnectionAsync(Arg.Any <string>(), Arg.Any <string>(), Arg.Any <CancellationToken>())
            .Returns(_ => Task.FromResult(conn));
            router.SyncGroupAsync(Arg.Any <SyncGroupRequest>(), Arg.Any <IRequestContext>(), Arg.Any <IRetry>(), Arg.Any <CancellationToken>())
            .Returns(_ => Task.FromResult(new SyncGroupResponse(ErrorCode.NONE, new ConsumerMemberAssignment(new [] { new TopicPartition("name", 0) }))));
            conn.SendAsync(Arg.Any <HeartbeatRequest>(), Arg.Any <CancellationToken>(), Arg.Any <IRequestContext>())
            .Returns(_ => Task.FromResult(new HeartbeatResponse(ErrorCode.NETWORK_EXCEPTION)));

            var heartbeat = TimeSpan.FromMilliseconds(heartbeatMilliseconds);
            var config    = new ConsumerConfiguration(heartbeatTimeout: heartbeat, coordinationRetry: Retry.Until(heartbeat, maximumDelay: TimeSpan.FromMilliseconds(50)));
            var request   = new JoinGroupRequest(TestConfig.GroupId(), config.GroupHeartbeat, "", ConsumerEncoder.Protocol, new [] { protocol });
            var memberId  = Guid.NewGuid().ToString("N");
            var response  = new JoinGroupResponse(ErrorCode.NONE, 1, protocol.protocol_name, memberId, memberId, new [] { new JoinGroupResponse.Member(memberId, new ConsumerProtocolMetadata("mine")) });

            using (new GroupConsumer(router, request.group_id, request.protocol_type, response, config)) {
                await Task.Delay(heartbeatMilliseconds * 3);

#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
                conn.DidNotReceive().SendAsync(
                    Arg.Is((LeaveGroupRequest s) => s.group_id == request.group_id && s.member_id == memberId),
                    Arg.Any <CancellationToken>(),
                    Arg.Any <IRequestContext>());
            }
            conn.Received().SendAsync(
                Arg.Is((LeaveGroupRequest s) => s.group_id == request.group_id && s.member_id == memberId),
                Arg.Any <CancellationToken>(),
                Arg.Any <IRequestContext>());
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed

            Assert.That(conn.ReceivedCalls().Count(c => c.GetMethodInfo().Name == nameof(Connection.SendAsync) && (c.GetArguments()[0] as HeartbeatRequest) != null), Is.AtLeast(2));
        }
Example #28
0
        /// <inheritdoc />
        public void JoinGroup(SessionInfo session, JoinGroupRequest request, CancellationToken cancellationToken)
        {
            if (session == null)
            {
                throw new InvalidOperationException("Session is null!");
            }

            if (request == null)
            {
                throw new InvalidOperationException("Request is null!");
            }

            var user = _userManager.GetUserById(session.UserId);

            // Locking required to access list of groups.
            lock (_groupsLock)
            {
                _groups.TryGetValue(request.GroupId, out Group group);

                if (group == null)
                {
                    _logger.LogWarning("Session {SessionId} tried to join group {GroupId} that does not exist.", session.Id, request.GroupId);

                    var error = new GroupUpdate <string>(Guid.Empty, GroupUpdateType.GroupDoesNotExist, string.Empty);
                    _sessionManager.SendSyncPlayGroupUpdate(session, error, CancellationToken.None);
                    return;
                }

                // Group lock required to let other requests end first.
                lock (group)
                {
                    if (!group.HasAccessToPlayQueue(user))
                    {
                        _logger.LogWarning("Session {SessionId} tried to join group {GroupId} but does not have access to some content of the playing queue.", session.Id, group.GroupId.ToString());

                        var error = new GroupUpdate <string>(group.GroupId, GroupUpdateType.LibraryAccessDenied, string.Empty);
                        _sessionManager.SendSyncPlayGroupUpdate(session, error, CancellationToken.None);
                        return;
                    }

                    if (_sessionToGroupMap.TryGetValue(session.Id, out var existingGroup))
                    {
                        if (existingGroup.GroupId.Equals(request.GroupId))
                        {
                            // Restore session.
                            UpdateSessionsCounter(session.UserId, 1);
                            group.SessionJoin(session, request, cancellationToken);
                            return;
                        }

                        var leaveGroupRequest = new LeaveGroupRequest();
                        LeaveGroup(session, leaveGroupRequest, cancellationToken);
                    }

                    if (!_sessionToGroupMap.TryAdd(session.Id, group))
                    {
                        throw new InvalidOperationException("Could not add session to group!");
                    }

                    UpdateSessionsCounter(session.UserId, 1);
                    group.SessionJoin(session, request, cancellationToken);
                }
            }
        }
        public async Task <SignalRServerResponse> Join(JoinGroupRequest request)
        {
            await _connection.StartAsync();

            return(await MutableCallSameMethodOnTheHub <SignalRServerResponse>(_connection, new object[] { request }));
        }
Example #30
0
 public ValueTask <JoinGroupResponse> JoinGroup(JoinGroupRequest request)
 => SendRequest(ApiKey.JoinGroup, 5, request, new JoinGroupRequestWriter(), new JoinGroupResponseReader());