Example #1
0
        private async Task <LogEntry[]> GetLogEntries(MuxOptions options)
        {
            switch (options.Strategy)
            {
            case StrategyType.AutoDetect:
            {
                var logFilePath = Path.Combine(options.InputPath, HierarchicalLogFileName);
                if (File.Exists(logFilePath))
                {
                    options.Strategy = StrategyType.Hierarchical;
                }
                else
                {
                    options.Strategy = StrategyType.Flat;
                }
                return(await GetLogEntries(options).ConfigureAwait(false));
            }

            case StrategyType.Hierarchical:
            {
                var logFilePath = Path.Combine(options.InputPath, HierarchicalLogFileName);
                if (!File.Exists(logFilePath))
                {
                    return(null);
                }

                return(await LogUtility.GetEntries(logFilePath, _Logger).ConfigureAwait(false));
            }

            case StrategyType.Flat:
            {
                var logEntries = new List <LogEntry>();
                IEnumerable <string> filePaths;

                if (Options.InputFilePaths.Count() > 0)
                {
                    filePaths = Options.InputFilePaths;
                }
                else if (Options.InputFileNames.Count() > 0)
                {
                    filePaths = Options.InputFileNames.Select(inputFileName => Path.Combine(Options.InputPath, inputFileName));
                }
                else
                {
                    filePaths = Directory.EnumerateFiles(Options.InputPath, "*.*", SearchOption.TopDirectoryOnly);
                }

                foreach (var filePath in filePaths)
                {
                    // filter the input files if a filter is provided.
                    if (Options.InputFilter != null && !Regex.Match(Path.GetFileName(filePath), Options.InputFilter).Success)
                    {
                        continue;
                    }

                    if (filePath.EndsWith(".json") || filePath.EndsWith(".json.rec"))
                    {
                        try
                        {
                            logEntries.AddRange(await LogUtility.GetEntries(filePath, _Logger).ConfigureAwait(false));
                        }
                        catch (FileNotFoundException)
                        {
                            _Logger.LogWarning("Could not read from {FilePath} as it no longer exists. Is another process running that could have removed it?", filePath);
                        }
                        catch (IOException ex) when(ex.Message.Contains("Stale file handle"))          // for Linux
                        {
                            _Logger.LogWarning("Could not read from {FilePath} as the file handle is stale. Is another process running that could have removed it?", filePath);
                        }
                    }
                }
                return(logEntries.ToArray());
            }

            default:
                throw new InvalidOperationException($"Unexpected strategy type '{options.Strategy}'.");
            }
        }
Example #2
0
        private async Task <bool> JsonIntegrityCheck()
        {
            var tempFiles = new List <Tuple <string, string> >();
            var noErrors  = true;

            _Logger.LogDebug($"Starting integrity check of the directory {_InputDirectory}");

            foreach (var jsonFile in Directory.EnumerateFiles(_InputDirectory, "*.json", SearchOption.TopDirectoryOnly))
            {
                _Logger.LogDebug($"JsonIntegrityCheck starting processing file {jsonFile}");

                try
                {
                    if (File.Exists(jsonFile + ".fail"))
                    {
                        _Logger.LogDebug($"File {jsonFile} is already marked as fail-checked. Skipping...");
                        continue;
                    }

                    var logEntries = await LogUtility.GetEntries(jsonFile, _Logger).ConfigureAwait(false);

                    if (logEntries == null)
                    {
                        continue;
                    }

                    var errorList = new List <string>();
                    var isValid   = true;

                    void AddToErrorList(string message)
                    {
                        isValid = false;
                        _Logger.LogDebug($"JsonIntegrityCheck adds new line to error list for file {jsonFile}: {message}");
                        errorList.Add(message);
                    }

                    try
                    {
                        var      startEntry          = GetEvent(logEntries, LogEntry.TypeStartRecording);
                        var      stopEntry           = GetEvent(logEntries, LogEntry.TypeStopRecording);
                        string   audioFilePath       = null;
                        string   videoFilePath       = null;
                        DateTime?firstAudioTimestamp = null;
                        DateTime?firstVideoTimestamp = null;
                        DateTime?lastAudioTimestamp  = null;
                        DateTime?lastVideoTimestamp  = null;
                        var      addDataBlock        = false;
                        var      addRecordStopTS     = false;
                        var      addFirstAudioTS     = false;
                        var      addFirstVideoTS     = false;
                        var      calcLastAudioTS     = false;
                        var      calcLastVideoTS     = false;
                        var      addAudioPath        = false;
                        var      addVideoPath        = false;

                        if (startEntry == null)
                        {
                            AddToErrorList($"Event \"{LogEntry.TypeStartRecording}\" is missing");
                        }

                        if (stopEntry == null)
                        {
                            AddToErrorList($"Event \"{LogEntry.TypeStopRecording}\" is missing");
                        }

                        if (isValid)
                        {
                            bool ReportIfMissing <T>(T var, string nodeName, string sectionName)
                            {
                                if (var?.Equals(default(T)) == null)
                                {
                                    AddToErrorList($"JSON node \"{nodeName}\" is missing in section \"{sectionName}\".");
                                    return(true);
                                }

                                return(false);
                            }

                            void ReportIfDifferent <T>(T var1, T var2, string nodeName) where T : class, IComparable <T>
                            {
                                if (var1 != null && var2 != null && !var1.Equals(var2))
                                {
                                    AddToErrorList($"Value of JSON node \"{nodeName}\" is different between section \"{LogEntry.TypeStartRecording}\" and \"{LogEntry.TypeStopRecording}\".");
                                }
                            }

                            ReportIfMissing((startEntry.Timestamp.Ticks == 0) ? (DateTime?)null : startEntry.Timestamp, nameof(startEntry.Timestamp), LogEntry.TypeStartRecording);
                            ReportIfMissing(startEntry.ApplicationId, nameof(startEntry.ApplicationId), LogEntry.TypeStartRecording);
                            ReportIfMissing(startEntry.ChannelId, nameof(startEntry.ChannelId), LogEntry.TypeStartRecording);
                            ReportIfMissing(startEntry.ConnectionId, nameof(startEntry.ConnectionId), LogEntry.TypeStartRecording);

                            ReportIfMissing(stopEntry.ApplicationId, nameof(stopEntry.ApplicationId), LogEntry.TypeStopRecording);
                            ReportIfMissing(stopEntry.ChannelId, nameof(stopEntry.ChannelId), LogEntry.TypeStopRecording);
                            ReportIfMissing(stopEntry.ConnectionId, nameof(stopEntry.ConnectionId), LogEntry.TypeStopRecording);

                            ReportIfDifferent(startEntry.ExternalId, stopEntry.ExternalId, nameof(stopEntry.ExternalId));
                            ReportIfDifferent(startEntry.ApplicationId, stopEntry.ApplicationId, nameof(stopEntry.ApplicationId));
                            ReportIfDifferent(startEntry.ChannelId, stopEntry.ChannelId, nameof(stopEntry.ChannelId));
                            ReportIfDifferent(startEntry.ConnectionId, stopEntry.ConnectionId, nameof(stopEntry.ConnectionId));

                            var data = stopEntry.Data;
                            if (data != null)
                            {
                                audioFilePath       = data.AudioFile;
                                videoFilePath       = data.VideoFile;
                                firstAudioTimestamp = data.AudioFirstFrameTimestamp;
                                firstVideoTimestamp = data.VideoFirstFrameTimestamp;
                                lastAudioTimestamp  = data.AudioFirstFrameTimestamp;
                                lastVideoTimestamp  = data.VideoLastFrameTimestamp;
                            }

                            if (stopEntry.Timestamp.Ticks > 0 && startEntry.Timestamp > stopEntry.Timestamp)
                            {
                                AddToErrorList("Start recording timestamp must not be greater than stop recording timestamp.");
                            }

                            addRecordStopTS = (stopEntry.Timestamp.Ticks == 0);

                            if (audioFilePath != null && !File.Exists(audioFilePath))
                            {
                                AddToErrorList($"Audio file {audioFilePath} is missing.");
                            }

                            if (videoFilePath != null && !File.Exists(videoFilePath))
                            {
                                AddToErrorList($"Video file {videoFilePath} is missing.");
                            }

                            if (isValid)
                            {
                                var baseName  = Path.GetFileNameWithoutExtension(jsonFile);
                                var audioPath = Path.Combine(_InputDirectory, baseName + ".mka");
                                var videoPath = Path.Combine(_InputDirectory, baseName + ".mkv");

                                if (data == null)
                                {
                                    addDataBlock = true;
                                }

                                if (File.Exists(audioPath))
                                {
                                    if (firstAudioTimestamp == null)
                                    {
                                        addFirstAudioTS     = true;
                                        firstAudioTimestamp = (startEntry.Timestamp.Ticks == 0) ? (DateTime?)null : startEntry.Timestamp;

                                        if (firstAudioTimestamp == null)
                                        {
                                            AddToErrorList($"JSON file has audio file but neither \"timestamp\" nor \"audioFirstFrameTimestamp\" defined in section \"{LogEntry.TypeStopRecording}\". File cannot be recovered");
                                        }
                                    }

                                    if (audioFilePath == null)
                                    {
                                        addAudioPath  = true;
                                        audioFilePath = audioPath;
                                    }
                                }

                                if (File.Exists(videoPath))
                                {
                                    if (firstVideoTimestamp == null)
                                    {
                                        addFirstVideoTS     = true;
                                        firstVideoTimestamp = (startEntry.Timestamp.Ticks == 0) ? (DateTime?)null : startEntry.Timestamp;

                                        if (firstVideoTimestamp == null)
                                        {
                                            AddToErrorList($"JSON file has audio file but neither \"timestamp\" nor \"videoFirstFrameTimestamp\" defined in section \"{LogEntry.TypeStopRecording}\". File cannot be recovered");
                                        }
                                    }

                                    if (videoFilePath == null)
                                    {
                                        addVideoPath  = true;
                                        videoFilePath = videoPath;
                                    }
                                }

                                if (audioFilePath == null && videoFilePath == null)
                                {
                                    AddToErrorList($"JSON file does not have any media file referred in \"data\" block of the section \"{LogEntry.TypeStopRecording}\" and it cannot be reconstructed (no auido or video file found).");
                                }
                                else
                                {
                                    if (audioFilePath != null && lastAudioTimestamp == null)
                                    {
                                        calcLastAudioTS = true;
                                    }

                                    if (videoFilePath != null && lastVideoTimestamp == null)
                                    {
                                        calcLastVideoTS = true;
                                    }
                                }
                            }
                        }

                        if (isValid && (addDataBlock || addAudioPath || addVideoPath || addRecordStopTS || addFirstAudioTS || addFirstVideoTS || calcLastAudioTS || calcLastVideoTS))
                        {
                            _Logger.LogDebug($"Calculating last frame durations for file {jsonFile}");

                            var tempFile = jsonFile + ".tmp.$$$";
                            var pair     = Tuple.Create(jsonFile, tempFile);

                            if (calcLastAudioTS)
                            {
                                var duration = await GetDuration(audioFilePath, true).ConfigureAwait(false);

                                if (duration != null)
                                {
                                    lastAudioTimestamp = firstAudioTimestamp + duration;
                                    _Logger.LogDebug($"Calculated last audio frame timestamp for file {jsonFile}: {lastAudioTimestamp} (duration: {duration}).");
                                }
                                else
                                {
                                    lastAudioTimestamp = firstAudioTimestamp;
                                    _Logger.LogDebug($"Calculated last audio frame timestamp for file {jsonFile}: {lastAudioTimestamp} (duration: cannot be calculated).");
                                }
                            }

                            if (calcLastVideoTS)
                            {
                                var duration = await GetDuration(videoFilePath, false).ConfigureAwait(false);

                                if (duration != null)
                                {
                                    lastVideoTimestamp = firstVideoTimestamp + duration;
                                    _Logger.LogDebug($"Calculated last video frame timestamp for file {jsonFile}: {lastVideoTimestamp} (duration: {duration}).");
                                }
                                else
                                {
                                    lastVideoTimestamp = firstVideoTimestamp;
                                    _Logger.LogDebug($"Calculated last audio frame timestamp for file {jsonFile}: {lastVideoTimestamp} (duration: cannot be calculated).");
                                }
                            }

                            if (addDataBlock)
                            {
                                stopEntry.Data = new LogEntryData();
                            }

                            if (addFirstAudioTS)
                            {
                                stopEntry.Data.AudioFirstFrameTimestamp = firstAudioTimestamp;
                            }

                            if (addFirstVideoTS)
                            {
                                stopEntry.Data.VideoFirstFrameTimestamp = firstVideoTimestamp;
                            }

                            if (addAudioPath)
                            {
                                stopEntry.Data.AudioFile = audioFilePath;
                            }

                            if (addVideoPath)
                            {
                                stopEntry.Data.VideoFile = videoFilePath;
                            }

                            if (addRecordStopTS)
                            {
                                DateTime?stopRecTimestamp;
                                if (lastAudioTimestamp != null && lastVideoTimestamp != null)
                                {
                                    stopRecTimestamp = ((lastAudioTimestamp > lastVideoTimestamp) ? lastAudioTimestamp : lastVideoTimestamp);
                                }
                                else
                                {
                                    stopRecTimestamp = lastAudioTimestamp ?? lastVideoTimestamp;
                                }

                                if (stopRecTimestamp != null)
                                {
                                    stopEntry.Timestamp = (DateTime)stopRecTimestamp;
                                }
                            }

                            if (calcLastAudioTS && lastAudioTimestamp != null)
                            {
                                stopEntry.Data.AudioLastFrameTimestamp = lastAudioTimestamp;
                            }

                            if (calcLastVideoTS && lastVideoTimestamp != null)
                            {
                                stopEntry.Data.VideoLastFrameTimestamp = lastVideoTimestamp;
                            }

                            File.WriteAllText(tempFile, JsonConvert.SerializeObject(logEntries, new JsonSerializerSettings
                            {
                                ContractResolver = new CamelCasePropertyNamesContractResolver()
                            }));

                            tempFiles.Add(pair);
                        }
                    }