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); }
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)); }
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); }
/// <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)); } }
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()); }
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)); }