Beispiel #1
0
        public async Task <demoResult> CallFromUser(RouteCallDto model)
        {
            var errorMessage = ValidateBaseParams(model);

            if (string.IsNullOrEmpty(errorMessage) && string.IsNullOrEmpty(model.FromExtension))
            {
                errorMessage = "FromExtension not set.";
            }
            else if (!model.FromCallId.HasValue)
            {
                errorMessage = "FromCallId not set.";
            }

            if (!string.IsNullOrEmpty(errorMessage))
            {
                _logger.Warning(errorMessage);
                return(BadRequest(ErrorCodes.ValidationError));
            }

            var result = await _asteriskAriApiService.CallFromUser(model);

            if (result.IsFailure)
            {
                return(Answer(result));
            }

            return(Ok());
        }
        /// <summary>
        /// Создать канал для пользователя, который принимает входящий вызов
        /// </summary>
        public async Task <Result> AcceptIncomingCall(RouteCallDto routeDto)
        {
            if (!routeDto.FromCallId.HasValue)
            {
                _logger.Warning("AcceptIncomingCall. Missing id waiting incoming call");
                return(Result.Failure(ErrorCodes.ValidationError));
            }

            if (!routeDto.LineId.HasValue)
            {
                _logger.Warning("AcceptIncomingCall. LineId not found.");
                return(Result.Failure(ErrorCodes.ValidationError));
            }

            _logger.Information($"AcceptIncomingCall. Пользователь {routeDto.ToExtension} принимает вызов c Id {routeDto.FromCallId}. CallId: {routeDto.ToCallId}");

            var incomingCallChannel = await _channelRepository.GetChannelByCallId(routeDto.FromCallId.Value);

            if (incomingCallChannel == null)
            {
                _logger.Warning("AcceptIncomingCall. Incoming call channel not found.");
                return(Result.Failure(ErrorCodes.ChannelNotFound));
            }

            var args = new StasisStartEventArgs
            {
                EventType = StasisStartEventType.AcceptIncomingCall,
                ChannelId = incomingCallChannel.ChannelId,
                RouteData = routeDto
            };

            var originateResult = await OriginateAsync(args, incomingCallChannel.Extension, routeDto.ToExtension);

            return(originateResult);
        }
Beispiel #3
0
        public async Task <demoResult> ExchangeRoles(RouteCallDto model)
        {
            string errorMessage = null;

            if (!model.LineId.HasValue)
            {
                errorMessage = "LineId not set.";
            }
            else if (!model.FromCallId.HasValue)
            {
                errorMessage = "FromCallId not set.";
            }
            else if (model.ToCallId == default)
            {
                errorMessage = "ToCallId not set.";
            }

            if (!string.IsNullOrEmpty(errorMessage))
            {
                _logger.Warning(errorMessage);
                return(BadRequest(ErrorCodes.ValidationError));
            }

            var result = await _asteriskAriApiService.ExchangeRoles(model);

            if (result.IsFailure)
            {
                return(Answer(result));
            }

            return(Ok());
        }
        public async Task AddAssistant_WithCorrectData_ShouldSucceed()
        {
            var routeDto = new RouteCallDto
            {
                LineId     = Guid.NewGuid(),
                FromCallId = Guid.NewGuid(),
                ToCallId   = Guid.NewGuid(),
            };

            var expectedBridgeId = "someBridgeId";
            var expectedAppName  = "ccng";
            var expectedEndpoint = "PJSIP/@kamailio";
            var expectedAppArgs  = GetEncodedAppArgs(CreateStasisArgs(null, expectedBridgeId, StasisStartEventType.Assistant, routeDto));

            string appNameResult  = null;
            string endpointResult = null;
            string appArgsResult  = null;

            var ariClientMock = new Mock <IAriClient>();

            ariClientMock.Setup(x => x.Channels.OriginateAsync(
                                    It.IsAny <string>(),
                                    It.IsAny <string>(),
                                    It.IsAny <string>(),
                                    It.IsAny <long?>(),
                                    It.IsAny <string>(),
                                    It.IsAny <string>(),
                                    It.IsAny <string>(),
                                    It.IsAny <string>(),
                                    It.IsAny <int?>(),
                                    null,
                                    It.IsAny <string>(),
                                    It.IsAny <string>(),
                                    It.IsAny <string>(),
                                    It.IsAny <string>()
                                    ))
            .Callback <string, string, string, long?, string, string, string, string, int?,
                       IDictionary <string, string>, string, string, string, string>(
                (endpoint, extension, context, priority, label, app, appArgs, callerId, timeout, variables,
                 channelId, otherChannelId, originator, formats) =>
            {
                appNameResult  = app;
                endpointResult = endpoint;
                appArgsResult  = appArgs;
            });

            var ariClient     = ariClientMock.Object;
            var ariApiService = GetAsteriskAriApiService(ariClient);

            // Act
            var result = await ariApiService.AddAssistant(routeDto);

            // Assert
            result.IsSuccess.ShouldBeTrue();
            appNameResult.ShouldBe(expectedAppName);
            endpointResult.ShouldBe(expectedEndpoint);
            appArgsResult.ShouldBe(expectedAppArgs);
        }
        /// <summary>
        /// Принудительное удаление канала из звонка
        /// </summary>>
        public async Task ForceHangUp(RouteCallDto model)
        {
            var args = new StasisStartEventArgs
            {
                RouteData = model
            };

            await _commandFactory.GetCommand(StasisStartEventType.ForceHangUpCommand).Execute(null, args);
        }
        /// <summary>
        /// Поменяться ролями между двумя участниками линии вызова
        /// </summary>
        public async Task <Result> ExchangeRoles(RouteCallDto routeDto)
        {
            _logger.WithTag("line_id", routeDto.LineId)
            .WithTag("from_call_id", routeDto.FromCallId)
            .WithTag("to_extension", routeDto.ToExtension)
            .Information($"ExchangeRoles. MainCallId: {routeDto.FromCallId}. Assistant: {routeDto.ToExtension}.");

            return(await _ariWebSocketService.SwitchMainUser(routeDto));
        }
Beispiel #7
0
        public async Task <demoResult> ForceHangUp(RouteCallDto model)
        {
            if (model.ToCallId == Guid.Empty)
            {
                return(BadRequest(ErrorCodes.ValidationError));
            }

            await _asteriskAriApiService.ForceHangUp(model);

            return(Ok());
        }
        private StasisStartEventArgs CreateStasisArgs(string channelId, string bridgeId, StasisStartEventType eventType,
                                                      RouteCallDto dto)
        {
            var args = new StasisStartEventArgs
            {
                EventType = eventType,
                ChannelId = channelId,
                RouteData = dto,
                BridgeId  = bridgeId
            };

            return(args);
        }
        /// <summary>
        /// Инициализировать прямой вызов от пользователя на номер <see cref="RouteCallDto.ToExtension"/>
        /// </summary>
        /// <remarks>
        /// При вызове Originate создается только канал для пользователя, который звонит на номер назначения.
        /// Канал для участника, которому звонит пользователь, будет создан после создания канала оператора при обработке события StasisStartEvent
        /// </remarks>
        public async Task <Result> CallFromUser(RouteCallDto routeDto)
        {
            var logMessage = $"Call from {routeDto.FromExtension} to {routeDto.ToExtension}. CallId: {routeDto.ToCallId} LineId: {routeDto.LineId}";

            _logger.Information($"CallFromUser. {logMessage}");

            var args = new StasisStartEventArgs
            {
                EventType = StasisStartEventType.CallFromUser,
                RouteData = routeDto
            };

            var originateResult = await OriginateAsync(args, "Служба 112", args.RouteData.FromExtension);

            return(originateResult);
        }
Beispiel #10
0
        /// <summary>
        /// Создать snoop-копию канала для записи
        /// </summary>
        /// <param name="channelId">Идентификатор исходного канала</param>
        /// <param name="extension">Номер</param>
        /// <param name="role">Роль канала</param>
        /// <param name="forCommonRecord">Признак того, что копия канала создана для записи разговора всех участников в один файл</param>
        /// <param name="callId">Идентификатор звонка</param>
        /// <param name="lineId">Идентификатор линии</param>
        /// <returns>SnoopChannelId</returns>
        private async Task <Result <string> > CreateSnoopChannelForRecording(
            string channelId,
            string extension,
            ChannelRoleType role,
            bool forCommonRecord,
            Guid callId,
            Guid?lineId)
        {
            if (!_asteriskOptions.RecordingEnabled)
            {
                return(Result.Failure(ErrorCodes.RecordingError));
            }

            var routeData = new RouteCallDto
            {
                ToCallId = callId,
                LineId   = lineId
            };

            var snoopChannelId = GetSnoopChannelIdForRecord(role, extension);
            var snoopArgs      = new StasisStartEventArgs
            {
                EventType         = StasisStartEventType.IgnoreStasisEvent,
                ChannelId         = snoopChannelId,
                OriginalChannelId = channelId,
                RouteData         = routeData
            };

            var encodedArgs = JsonSerializer.EncodeData(snoopArgs);
            await AriClient.SnoopChannel(channelId, "in", "none", encodedArgs, snoopChannelId);

            if (forCommonRecord)
            {
                return(Result.Success(snoopChannelId));
            }

            var recordingResult = await StartRecordingChannel(snoopChannelId, callId, lineId);

            if (recordingResult.IsFailure)
            {
                Logger.Information($"CreateSnoopChannelForRecording. StartRecordingChannelError: {recordingResult.ErrorMessage}");
                return(Result.Failure(ErrorCodes.RecordingError));
            }

            return(Result.Success(snoopChannelId));
        }
        /// <summary>
        /// Поменяться ролями между главным в разговоре и ассистентом
        /// </summary>
        public async Task <Result> SwitchMainUser(RouteCallDto routeDto)
        {
            try
            {
                var args = new StasisStartEventArgs
                {
                    RouteData = routeDto
                };

                await _commandFactory.GetCommand(StasisStartEventType.SwitchRolesCommand).Execute(null, args);

                return(Result.Success());
            }
            catch (Exception e)
            {
                _logger.Warning(e.Message);
                return(Result.Failure(ErrorCodes.UnableToSwitchMainUser));
            }
        }
Beispiel #12
0
        public async Task <demoResult> AddToConference(RouteCallDto model)
        {
            var errorMessage = ValidateBaseParams(model);

            if (!string.IsNullOrEmpty(errorMessage))
            {
                _logger.Warning(errorMessage);
                return(BadRequest(ErrorCodes.ValidationError));
            }

            var result = await _asteriskAriApiService.AddToConference(model);

            if (result.IsFailure)
            {
                return(Answer(result));
            }

            return(Ok());
        }
Beispiel #13
0
        private static string ValidateBaseParams(RouteCallDto model)
        {
            string errorMessage = null;

            if (!model.LineId.HasValue)
            {
                errorMessage = "LineId not set.";
            }
            else if (model.ToCallId == Guid.Empty)
            {
                errorMessage = "ToCallId not set.";
            }
            else if (string.IsNullOrEmpty(model.ToExtension))
            {
                errorMessage = "ToExtension not set.";
            }

            return(errorMessage);
        }
        private async Task <Result> AddAssistantSpecificType(RouteCallDto routeDto, StasisStartEventType eventType)
        {
            _logger.WithTag("to_call_id", routeDto.ToCallId)
            .WithTag("from_call_id", routeDto.FromCallId)
            .WithTag("assistant_extension", routeDto.ToExtension)
            .Information($"Add {eventType}. FromCallId: {routeDto.FromCallId}. Assistant: {routeDto.ToExtension}. CallId: {routeDto.ToCallId}");

            if (!routeDto.LineId.HasValue)
            {
                _logger.Warning($"Add{eventType}. LineId not found.");
                return(Result.Failure(ErrorCodes.ValidationError));
            }

            if (!routeDto.FromCallId.HasValue)
            {
                _logger.Warning($"Add{eventType}. FromCallId not found.");
                return(Result.Failure(ErrorCodes.ValidationError));
            }

            var setMainChannelResult = await SetMainUser(routeDto.LineId.Value, routeDto.FromCallId.Value);

            if (setMainChannelResult.IsFailure)
            {
                _logger.Warning($"Add{eventType}. {setMainChannelResult.ErrorMessage}");
                return(Result.Failure(setMainChannelResult.ErrorCode));
            }

            var fromCallChannel = await _channelRepository.GetChannelByCallId(routeDto.FromCallId.Value);

            var args = new StasisStartEventArgs
            {
                EventType = eventType,
                BridgeId  = setMainChannelResult.Value.BridgeId,
                RouteData = routeDto
            };

            var originateResult = await OriginateAsync(args, fromCallChannel.Extension, args.RouteData.ToExtension);

            return(originateResult);
        }
        /// <summary>
        /// Добавить участника в разговор в режиме конференции
        /// </summary>
        public async Task <Result> AddToConference(RouteCallDto routeDto)
        {
            _logger.Information($"Add {routeDto.ToExtension} in conference mode. CallId: {routeDto.ToCallId}, LineId: {routeDto.LineId}");

            if (!routeDto.LineId.HasValue)
            {
                _logger.Warning("AddToConference. LineId not found.");
                return(Result.Failure(ErrorCodes.ValidationError));
            }

            var lineId   = routeDto.LineId.Value;
            var bridgeId = await _channelRepository.GetMainBridgeId(lineId);

            if (bridgeId == null)
            {
                _logger.Warning($"AddToConference. Main Bridge not found. LineId: {lineId}");
                return(Result.Failure(ErrorCodes.BridgeNotFound));
            }

            Channel fromCallChannel = null;

            if (routeDto.FromCallId.HasValue)
            {
                fromCallChannel = await _channelRepository.GetChannelByCallId(routeDto.FromCallId.Value);
            }

            var args = new StasisStartEventArgs
            {
                EventType = StasisStartEventType.Conference,
                BridgeId  = bridgeId,
                RouteData = routeDto
            };

            var originateResult = await OriginateAsync(args, fromCallChannel?.Extension, args.RouteData.ToExtension);

            return(originateResult);
        }
 /// <summary>
 /// Принудительное удаление канала из звонка
 /// </summary>>
 public async Task ForceHangUp(RouteCallDto model)
 {
     _logger.Information($"ForceHangUp. Принудительное удаление канала: {model.ToCallId}");
     await _ariWebSocketService.ForceHangUp(model);
 }
 /// <summary>
 /// Сделать вызов пользователя в режиме частичного ассистирования
 /// </summary>
 public async Task <Result> AddPartialAssistant(RouteCallDto routeDto)
 {
     _logger.Information($"AddPartialAssistant. Add partial assistant {routeDto.ToExtension}");
     return(await AddAssistantSpecificType(routeDto, StasisStartEventType.PartialAssistant));
 }