// Determines whether configuration exists for the meter with the given asset key. private static void ValidateMeterKey(SystemSettings systemSettings, string filePath, string meterKey) { UserAccount xdaUserAccount = new UserAccount(); xdaUserAccount.Name = systemSettings.XDAUsername; xdaUserAccount.Password = systemSettings.XDAPassword; // Determine whether there exists a meter whose asset key matches the given meterKey if (WebAPIHub.GetRecordsWhere <Meter>(systemSettings.XDAAddress, $"AssetKey = '{meterKey}'", xdaUserAccount).Count() == 0) { throw new FileSkippedException($"Skipped file \"{filePath}\" because no meter configuration was found for meter {meterKey}."); } }
// Called when the file processor has picked up a file in one of the watch // directories. This handler validates the file and processes it if able. private void FileProcessor_Processing(object sender, FileProcessorEventArgs fileProcessorEventArgs) { if (m_stopped || m_disposed) { return; } try { string filePath; int priority; filePath = fileProcessorEventArgs.FullPath; priority = fileProcessorEventArgs.RaisedByFileWatcher ? FileWatcherPriority : FileEnumerationPriority; string connectionString = LoadSystemSettings(); SystemSettings systemSettings = new SystemSettings(connectionString); UserAccount userAccount = new UserAccount(); userAccount.Name = systemSettings.XDAUsername; userAccount.Password = systemSettings.XDAPassword; // Determine whether the file has already been // processed or needs to be processed again if (fileProcessorEventArgs.AlreadyProcessed) { DataFile remoteDataFile = WebAPIHub.GetRecordsWhere <DataFile>(systemSettings.XDAAddress, $"FilePathHash = {filePath.GetHashCode()}", userAccount) .Where(file => file.FilePath == filePath) .MaxBy(file => file.ID); if ((object)remoteDataFile != null) { FileGroup remoteFileGroup = WebAPIHub.GetRecordWhere <FileGroup>(systemSettings.XDAAddress, $"ID = {remoteDataFile.FileGroupID}", userAccount); // This will tell us whether the service was stopped in the middle // of processing the last time it attempted to process the file if (remoteFileGroup.ProcessingEndTime > DateTime.MinValue) { // Explicitly use Log.Debug() so that the message does not appear on the remote console, // but include a FileSkippedException so that the message gets routed to the skipped files log FileSkippedException ex = new FileSkippedException($"Skipped file \"{filePath}\" because it has already been processed."); Log.Debug(ex.Message, ex); return; } } } byte[] buffer; try { buffer = File.ReadAllBytes(filePath); } catch (IOException) { // Couldn't read from the file, likely because the // process writing the file isn't finished writing fileProcessorEventArgs.Requeue = true; return; } Crc32 crc32 = new Crc32(); crc32.Update(buffer); int crc = (int)crc32.Value; if (systemSettings.SkipOnCRCHashMatch) { List <FileGroup> fileGroups = WebAPIHub.GetRecordsWhere <FileGroup>(systemSettings.XDAAddress, $"FileHash = {crc}", userAccount) .ToList(); if (fileGroups.Any()) { string fileGroupIDs = string.Join(",", fileGroups.Select(fg => fg.ID)); List <DataFile> dataFiles = WebAPIHub.GetRecordsWhere <DataFile>(systemSettings.XDAAddress, $"FileGroupID IN ({fileGroupIDs})", userAccount) .ToList(); if (dataFiles.Any()) { string dataFileIDs = string.Join(",", dataFiles.Select(dataFile => dataFile.ID)); List <FileBlob> fileBlobs = WebAPIHub.GetRecordsWhere <FileBlob>(systemSettings.XDAAddress, $"DataFileID IN ({dataFileIDs})", userAccount) .ToList(); if (fileBlobs.Any(fileBlob => buffer.SequenceEqual(fileBlob.Blob))) { FileSkippedException ex = new FileSkippedException($"Skipped file \"{filePath}\" because it has already been processed."); Log.Warn(ex.Message, ex); return; } } } } Log.Info($"Pushing file {filePath} into openXDA..."); FileGroup fileGroup = new FileGroup(); fileGroup.FileHash = crc; fileGroup.DataFiles = CreateDataFiles(filePath, systemSettings.XDATimeZoneInfo); SaveFileGroup(fileGroup, systemSettings.XDAAddress, userAccount); string meterKey = GetMeterKey(filePath, systemSettings.FilePattern); Meter meter = WebAPIHub.GetRecordsWhere <Meter>(systemSettings.XDAAddress, $"AssetKey = '{meterKey}'", userAccount).FirstOrDefault(); Dictionary <string, int> idObject = new Dictionary <string, int>(); idObject.Add("FileGroupID", fileGroup.ID); idObject.Add("MeterID", meter.ID); WebAPIHub.ProcessFileGroup(systemSettings.XDAAddress, JObject.FromObject(idObject), userAccount); Log.Info($"Finished pushing file {filePath} into openXDA."); } catch (FileSkippedException) { // Do not wrap FileSkippedExceptions because // these only generate warning messages throw; } catch (Exception ex) { // Wrap all other exceptions to include the file path in the message string message = $"Exception occurred processing file \"{fileProcessorEventArgs.FullPath}\": {ex.Message}"; throw new Exception(message, ex); } }