#pragma warning restore VSTHRD103 private async Task <Unit> StartProcess(StartFFmpegSession request, CancellationToken cancellationToken) { TimeSpan idleTimeout = await _configElementRepository .GetValue <int>(ConfigElementKey.FFmpegSegmenterTimeout) .Map(maybeTimeout => maybeTimeout.Match(i => TimeSpan.FromSeconds(i), () => TimeSpan.FromMinutes(1))); using IServiceScope scope = _serviceScopeFactory.CreateScope(); HlsSessionWorker worker = scope.ServiceProvider.GetRequiredService <HlsSessionWorker>(); _ffmpegSegmenterService.SessionWorkers.AddOrUpdate(request.ChannelNumber, _ => worker, (_, _) => worker); // fire and forget worker _ = worker.Run(request.ChannelNumber, idleTimeout, cancellationToken) .ContinueWith( _ => _ffmpegSegmenterService.SessionWorkers.TryRemove( request.ChannelNumber, out IHlsSessionWorker _), TaskScheduler.Default); string playlistFileName = Path.Combine( FileSystemLayout.TranscodeFolder, request.ChannelNumber, "live.m3u8"); IConfigElementRepository repo = scope.ServiceProvider.GetRequiredService <IConfigElementRepository>(); int initialSegmentCount = await repo.GetValue <int>(ConfigElementKey.FFmpegInitialSegmentCount) .Map(maybeCount => maybeCount.Match(identity, () => 1)); await WaitForPlaylistSegments(playlistFileName, initialSegmentCount, worker, cancellationToken); return(Unit.Default); }
private Task <Validation <BaseError, Unit> > FolderMustBeEmpty(StartFFmpegSession request) { string folder = Path.Combine(FileSystemLayout.TranscodeFolder, request.ChannelNumber); _logger.LogDebug("Preparing transcode folder {Folder}", folder); _localFileSystem.EnsureFolderExists(folder); _localFileSystem.EmptyFolder(folder); return(Task.FromResult <Validation <BaseError, Unit> >(Unit.Default)); }
private Task <Validation <BaseError, Unit> > SessionMustBeInactive(StartFFmpegSession request) { var result = Optional(_ffmpegSegmenterService.SessionWorkers.TryAdd(request.ChannelNumber, null)) .Where(success => success) .Map(_ => Unit.Default) .ToValidation <BaseError>(new ChannelSessionAlreadyActive()); if (result.IsFail && _ffmpegSegmenterService.SessionWorkers.TryGetValue( request.ChannelNumber, out IHlsSessionWorker worker)) { worker?.Touch(); } return(result.AsTask()); }
public Task <Either <BaseError, Unit> > Handle(StartFFmpegSession request, CancellationToken cancellationToken) => Validate(request) .MapT(_ => StartProcess(request, cancellationToken)) // this weirdness is needed to maintain the error type (.ToEitherAsync() just gives BaseError) #pragma warning disable VSTHRD103 .Bind(v => v.ToEither().MapLeft(seq => seq.Head()).MapAsync <BaseError, Task <Unit>, Unit>(identity));
private Task <Validation <BaseError, Unit> > Validate(StartFFmpegSession request) => SessionMustBeInactive(request) .BindT(_ => FolderMustBeEmpty(request));