private void BuildPatch(PatchDefinition definition, BuildDefinition fromDefinition, BuildDefinition toDefinition) { var skipAmount = Math.Max(fromDefinition.Entries.Length, toDefinition.Entries.Length) - definition.Entries.Count; for (int i = 0; i < skipAmount; i++) { _context.ReportProgress(string.Format(_context.LocalizedMessages.PatchSkippingFile)); } foreach (var entry in definition.Entries) { switch (entry.Operation) { case PatchOperation.Added: _context.LogProgress(string.Format(_context.LocalizedMessages.PatchAddingFile, entry.RelativePath)); HandleAddedFile(entry); _context.ReportProgress(string.Format(_context.LocalizedMessages.PatchAddedFile, entry.RelativePath)); break; case PatchOperation.Updated: _context.LogProgress(string.Format(_context.LocalizedMessages.PatchPatchingFile, entry.RelativePath)); HandleUpdatedFile(entry); _context.ReportProgress(string.Format(_context.LocalizedMessages.PatchPatchedFile, entry.RelativePath)); break; case PatchOperation.ChangedAttributes: _context.LogProgress(string.Format(_context.LocalizedMessages.PatchChangingAttributesFile, entry.RelativePath)); HandleChangedAttributesFile(entry); _context.ReportProgress(string.Format(_context.LocalizedMessages.PatchChangedAttributesFile, entry.RelativePath)); break; } } }
public List <KnowledgeGroupRecord> UpdateKnowledgeGroups( IList <KnowledgeGroupRecord> importKnowledgeGroups, IKnowledgeGroupService service, ref int modifiedRecords ) { var knowledgeGroupRecords = service.FindAllAsync().Result; var patch = new PatchDefinition <KnowledgeGroupRecord, KnowledgeGroupRecord>( (source, list) => list.SingleOrDefault(a => a.Id == source.Id) ); patch .Map(s => s.Id, t => t.Id) .Map(s => s.Name, t => t.Name) .Map(s => s.Description, t => t.Description) .Map(s => s.FontAwesomeIconCharacterUnicodeAddress, t => t.FontAwesomeIconCharacterUnicodeAddress) .Map(s => s.Order, t => t.Order); var diff = patch.Patch(importKnowledgeGroups, knowledgeGroupRecords); service.ApplyPatchOperationAsync(diff).Wait(); modifiedRecords += diff.Count(a => a.Action != ActionEnum.NotModified); return(diff.Where(a => a.Entity.IsDeleted == 0).Select(a => a.Entity).ToList()); }
private void ValidatePatch(PatchDefinition patchDef, IntPtr address) { // validate that we can at least read the specified location // we could (should) virtualquery here instead to check read/write, but this is lazier Memory.Read(address, 1); // TODO: exe version, once exposed if (patchDef.Validation?.RequiredBytes != null) { var actualBytes = Memory.Read(address, patchDef.Validation.RequiredBytes.Length); for (var i = 0; i < actualBytes.Length; i++) { // null bytes are wildcards, so just skip over them if (patchDef.Validation.RequiredBytes[i] != null && patchDef.Validation.RequiredBytes[i] != actualBytes[i]) { throw new InvalidOperationException(string.Format("Expected bytes at patch address {0} do not match. Expected [{1}], found [{2}]", address, patchDef.Validation.RequiredBytesString, BitConverter.ToString(actualBytes).Replace("-", " "))); } } } // TODO: this should probably go somewhere else, but it's not really useful at the moment anyway if (patchDef.Patch.Location.ToLowerInvariant() != "overwrite") { PluginLog.Log("[WARN] Patch.Location only supports \"overwrite\" for now, defaulting to that behavior"); } if (this.Patches.Any(p => p.Definition.Name == patchDef.Name)) { throw new ArgumentException($"A patch with name {patchDef.Name} already exists"); } }
public List <KnowledgeEntryRecord> UpdateKnowledgeEntries( IList <KnowledgeEntryRecord> importKnowledgeEntries, IKnowledgeEntryService service, ref int modifiedRecords ) { var knowledgeEntryRecords = service.FindAllAsync().Result; var patch = new PatchDefinition <KnowledgeEntryRecord, KnowledgeEntryRecord>( (source, list) => list.SingleOrDefault(a => a.Id == source.Id) ); patch .Map(s => s.Id, t => t.Id) .Map(s => s.KnowledgeGroupId, t => t.KnowledgeGroupId) .Map(s => s.Title, t => t.Title) .Map(s => s.Text, t => t.Text) .Map(s => s.Order, t => t.Order) .Map(s => s.Links, t => t.Links) .Map(s => s.ImageIds, t => t.ImageIds); var diff = patch.Patch(importKnowledgeEntries, knowledgeEntryRecords); service.ApplyPatchOperationAsync(diff).Wait(); modifiedRecords += diff.Count(a => a.Action != ActionEnum.NotModified); return(diff.Where(a => a.Entity.IsDeleted == 0).Select(a => a.Entity).ToList()); }
private void ProcessFile(PatchDefinition definition, PatchDefinitionEntry entry) { switch (entry.Operation) { case PatchOperation.Added: _context.LogProgress(string.Format(_context.LocalizedMessages.UpdateProcessingNewFile, entry.RelativePath)); HandleAddedFile(definition, entry); _context.ReportProgress(string.Format(_context.LocalizedMessages.UpdateProcessedNewFile, entry.RelativePath)); break; case PatchOperation.Deleted: _context.LogProgress(string.Format(_context.LocalizedMessages.UpdateProcessingDeletedFile, entry.RelativePath)); HandleDeletedFile(definition, entry); _context.ReportProgress(string.Format(_context.LocalizedMessages.UpdateProcessedDeletedFile, entry.RelativePath)); break; case PatchOperation.Updated: _context.LogProgress(string.Format(_context.LocalizedMessages.UpdateProcessingUpdatedFile, entry.RelativePath)); HandleUpdatedFile(definition, entry); _context.ReportProgress(string.Format(_context.LocalizedMessages.UpdateProcessedUpdatedFile, entry.RelativePath)); break; case PatchOperation.ChangedAttributes: _context.LogProgress(string.Format(_context.LocalizedMessages.UpdateProcessingChangedAttributesFile, entry.RelativePath)); HandleChangedAttributesFile(definition, entry); _context.ReportProgress(string.Format(_context.LocalizedMessages.UpdateProcessedChangedAttributesFile, entry.RelativePath)); break; } }
private void DownloadPatch(PatchDefinition definition) { DirectoriesManager.Create(_context.Settings.GetTempPath()); var archivePath = _context.Settings.GetDownloadedPatchArchivePath(definition.From, definition.To); var leftAttempts = _context.Settings.PatchDownloadAttempts; var success = false; do { try { Downloader.Download(_context.Settings.GetRemotePatchArchiveUrl(definition.From, definition.To), _context.Settings.GetTempPath()); var downloadedArchiveHash = Hashing.GetFileHash(archivePath); if (downloadedArchiveHash == definition.Hash) { success = true; break; } } catch { // ignored } FilesManager.Delete(archivePath); leftAttempts--; } while (leftAttempts > 0); if (!success) { throw new PatchCannotBeDownloadedException(); } }
private void BuildPatchDefinition(PatchDefinition definition) { definition.Hash = Hashing.GetFileHash(PathsManager.Combine(_context.Settings.GetPatchesFolderPath(), _context.PatchName)); definition.From = _context.VersionFrom; definition.To = _context.VersionTo; File.WriteAllText(_context.Settings.GetPatchIndexPath(_context.VersionFrom, _context.VersionTo), _context.Serializer.Serialize(definition)); }
private void DecompressPatch(PatchDefinition definition) { var path = _context.Settings.GetUncompressedPatchArchivePath(definition.From, definition.To); DirectoriesManager.Create(path); Compressor.Decompress(path, _context.Settings.GetDownloadedPatchArchivePath(definition.From, definition.To), null); }
private void HandleAddedFile(PatchDefinition definition, PatchDefinitionEntry entry) { var sourcePath = PathsManager.Combine(_context.Settings.GetUncompressedPatchArchivePath(definition.From, definition.To), entry.RelativePath); var destinationPath = PathsManager.Combine(_context.Settings.GetGamePath(), entry.RelativePath); FilesManager.Delete(destinationPath); FilesManager.Move(sourcePath, destinationPath); EnsureDefinition(destinationPath, entry); }
private void LoadPatchDefinitions() { if (LoadingPatchDefinitions) { return; } LoadingPatchDefinitions = true; string PatchDefinitionName = cmbPatchDefinitionName.Text; string TargetVersion = cmbTargetVersion.Text; string TargetPath = cmbTargetPath.Text; cmbPatchDefinitionName.SelectedIndex = -1; cmbTargetVersion.SelectedIndex = -1; cmbTargetPath.SelectedIndex = -1; cmbPatchDefinitionName.Items.Clear(); cmbTargetVersion.Items.Clear(); cmbTargetPath.Items.Clear(); cmbPatchDefinitionName.Text = PatchDefinitionName; cmbTargetVersion.Text = TargetVersion; cmbTargetPath.Text = TargetPath; try { string Definitions = File.ReadAllText(txtPatchDefinitionsFile.Text); PatchEngine Engine = new PatchEngine(Definitions); Engine.PatchDefinitions.Where(d => !string.IsNullOrEmpty(d.Name)).Select(d => d.Name).Distinct().ToList().ForEach(n => cmbPatchDefinitionName.Items.Add(n)); PatchDefinition Definition = null; if (cmbPatchDefinitionName.Text.Trim().Length > 0) { Definition = Engine.PatchDefinitions.Where(d => string.Compare(d.Name, cmbPatchDefinitionName.Text.Trim(), true) == 0).FirstOrDefault(); } if (Definition != null) { Definition.TargetVersions.Where(v => !string.IsNullOrEmpty(v.Description)).Select(v => v.Description).Distinct().ToList().ForEach(d => cmbTargetVersion.Items.Add(d)); TargetVersion Version = null; if (cmbTargetVersion.Text.Trim().Length > 0) { Version = Definition.TargetVersions.Where(v => string.Compare(v.Description, cmbTargetVersion.Text.Trim(), true) == 0).FirstOrDefault(); } if (Version != null) { Version.TargetFiles.Where(f => !string.IsNullOrEmpty(f.Path)).Select(f => Path.GetDirectoryName(f.Path)).Distinct().ToList().ForEach(f => cmbTargetPath.Items.Add(f)); } } } catch { } LoadingPatchDefinitions = false; }
private Patch LoadPatch(PatchDefinition patchDef) { PluginLog.Log($"Loading patch {patchDef.Name}"); var address = ResolveAddress(patchDef); ValidatePatch(patchDef, address); return(new Patch() { Address = address, Bytes = patchDef.Patch.Bytes, Definition = patchDef }); }
private PatchDefinition BuildPatchDefinition(BuildDefinition fromDefinition, BuildDefinition toDefinition) { var patchDefinition = new PatchDefinition(); patchDefinition.Entries = new List <PatchDefinitionEntry>(); foreach (var newDefinition in toDefinition.Entries) { var oldDefinition = fromDefinition.Entries.FirstOrDefault(f => f.RelativePath == newDefinition.RelativePath); var alreadyExists = oldDefinition != null; var operation = PatchOperation.Added; if (alreadyExists) { // The file exists in both versions. I have to check what type of change it got. operation = GetOperation(newDefinition, oldDefinition); } if (operation != PatchOperation.Unchanged) { patchDefinition.Entries.Add(new PatchDefinitionEntry() { Operation = operation, RelativePath = newDefinition.RelativePath }); } _context.ReportProgress(string.Format(_context.LocalizedMessages.PatchCollectedPatchData, newDefinition.RelativePath, operation.ToString())); } foreach (var oldDefinition in fromDefinition.Entries) { if (toDefinition.Entries.All(f => f.RelativePath != oldDefinition.RelativePath)) { // The old file does not exist in the new definition. This means it has been deleted. patchDefinition.Entries.Add(new PatchDefinitionEntry() { Operation = PatchOperation.Deleted, RelativePath = oldDefinition.RelativePath }); } _context.ReportProgress(string.Format(_context.LocalizedMessages.PatchCollectedPatchData, oldDefinition.RelativePath, PatchOperation.Deleted.ToString())); } return(patchDefinition); }
private void PerformUpdate(PatchDefinition definition) { _context.LogProgress(string.Format(_context.LocalizedMessages.UpdateDownloadingArchive, definition.From, definition.To)); DownloadPatch(definition); _context.ReportProgress(string.Format(_context.LocalizedMessages.UpdateDownloadedArchive, definition.From, definition.To)); _context.LogProgress(string.Format(_context.LocalizedMessages.UpdateDecompressingArchive, definition.From, definition.To)); DecompressPatch(definition); _context.ReportProgress(string.Format(_context.LocalizedMessages.UpdateDecompressedArchive, definition.From, definition.To)); foreach (var definitionEntry in definition.Entries) { ProcessFile(definition, definitionEntry); } DirectoriesManager.Delete(_context.Settings.GetTempPath()); }
private List <EventRecord> UpdateEventEntries( IList <EventImportRow> ImportEventEntries, IList <EventConferenceTrackRecord> CurrentConferenceTracks, IList <EventConferenceRoomRecord> CurrentConferenceRooms, IList <EventConferenceDayRecord> CurrentConferenceDays, ref int modifiedRecords ) { var eventRecords = _eventService.FindAllAsync().Result; var patch = new PatchDefinition <EventImportRow, EventRecord>( (source, list) => list.SingleOrDefault(a => a.SourceEventId == source.EventId) ); patch.Map(s => s.EventId, t => t.SourceEventId) .Map(s => s.Slug, t => t.Slug) .Map(s => s.Title.Split('–')[0]?.Trim(), t => t.Title) .Map(s => (s.Title + '–').Split('–')[1]?.Trim(), t => t.SubTitle) .Map(s => s.Abstract, t => t.Abstract) .Map( s => CurrentConferenceTracks.Single(a => a.Name == s.ConferenceTrack).Id, t => t.ConferenceTrackId) .Map( s => CurrentConferenceRooms.Single(a => a.Name == s.ConferenceRoom).Id, t => t.ConferenceRoomId) .Map( s => CurrentConferenceDays.Single(a => a.Name == s.ConferenceDayName).Id, t => t.ConferenceDayId) .Map(s => s.Description, t => t.Description) .Map(s => s.Duration, t => t.Duration) .Map(s => s.StartTime, t => t.StartTime) .Map(s => s.EndTime, t => t.EndTime) .Map(s => DateTime.SpecifyKind(CurrentConferenceDays.Single(a => a.Name == s.ConferenceDayName) .Date.Add(s.StartTime), DateTimeKind.Utc).AddHours(-2), t => t.StartDateTimeUtc) .Map(s => DateTime.SpecifyKind(CurrentConferenceDays.Single(a => a.Name == s.ConferenceDayName) .Date.Add(s.EndTime).AddDays(s.StartTime < s.EndTime ? 0 : 1).AddHours(-2), DateTimeKind.Utc), t => t.EndDateTimeUtc) .Map(s => s.PanelHosts, t => t.PanelHosts); var diff = patch.Patch(ImportEventEntries, eventRecords); _eventService.ApplyPatchOperationAsync(diff).Wait(); modifiedRecords += diff.Count(a => a.Action != ActionEnum.NotModified); return(diff.Where(a => a.Entity.IsDeleted == 0).Select(a => a.Entity).ToList()); }
public static List <EventConferenceRoomRecord> UpdateEventConferenceRooms( IList <string> importConferenceRooms, IEventConferenceRoomService service ) { var eventConferenceRoomRecords = service.FindAllAsync().Result; var patch = new PatchDefinition <string, EventConferenceRoomRecord>( (source, list) => list.SingleOrDefault(a => a.Name == source) ); patch.Map(s => s, t => t.Name); var diff = patch.Patch(importConferenceRooms, eventConferenceRoomRecords); service.ApplyPatchOperationAsync(diff).Wait(); return(diff.Where(a => a.Entity.IsDeleted == 0).Select(a => a.Entity).ToList()); }
private List <EventConferenceRoomRecord> UpdateEventConferenceRooms( IList <string> importConferenceRooms, ref int modifiedRecords ) { var eventConferenceRoomRecords = _eventConferenceRoomService.FindAllAsync().Result; var patch = new PatchDefinition <string, EventConferenceRoomRecord>( (source, list) => list.SingleOrDefault(a => a.Name == source) ); patch.Map(s => s, t => t.Name); var diff = patch.Patch(importConferenceRooms, eventConferenceRoomRecords); _eventConferenceRoomService.ApplyPatchOperationAsync(diff).Wait(); modifiedRecords += diff.Count(a => a.Action != ActionEnum.NotModified); return(diff.Where(a => a.Entity.IsDeleted == 0).Select(a => a.Entity).ToList()); }
public static List <EventConferenceDayRecord> UpdateEventConferenceDays( IList <Tuple <DateTime, string> > importConferenceDays, IEventConferenceDayService service ) { var eventConferenceDayRecords = service.FindAllAsync().Result; var patch = new PatchDefinition <Tuple <DateTime, string>, EventConferenceDayRecord>( (source, list) => list.SingleOrDefault(a => a.Date == source.Item1) ); patch.Map(s => s.Item1, t => t.Date) .Map(s => s.Item2, t => t.Name); var diff = patch.Patch(importConferenceDays, eventConferenceDayRecords); service.ApplyPatchOperationAsync(diff).Wait(); return(diff.Where(a => a.Entity.IsDeleted == 0).Select(a => a.Entity).ToList()); }
public static List <EventRecord> UpdateEventEntries( IList <EventImportRow> ImportEventEntries, IList <EventConferenceTrackRecord> CurrentConferenceTracks, IList <EventConferenceRoomRecord> CurrentConferenceRooms, IList <EventConferenceDayRecord> CurrentConferenceDays, IEventService service ) { var eventRecords = service.FindAllAsync().Result; var patch = new PatchDefinition <EventImportRow, EventRecord>( (source, list) => list.SingleOrDefault(a => a.SourceEventId == source.EventId) ); patch.Map(s => s.EventId, t => t.SourceEventId) .Map(s => s.Slug, t => t.Slug) .Map(s => s.Title.Split('|')[0], t => t.Title) .Map(s => (s.Title + '|').Split('|')[1], t => t.SubTitle) .Map(s => s.Abstract, t => t.Abstract) .Map( s => CurrentConferenceTracks.Single(a => a.Name == s.ConferenceTrack).Id, t => t.ConferenceTrackId) .Map( s => CurrentConferenceRooms.Single(a => a.Name == s.ConferenceRoom).Id, t => t.ConferenceRoomId) .Map( s => CurrentConferenceDays.Single(a => a.Name == s.ConferenceDayName).Id, t => t.ConferenceDayId) .Map(s => s.Description, t => t.Description) .Map(s => s.Duration, t => t.Duration) .Map(s => s.StartTime, t => t.StartTime) .Map(s => s.EndTime, t => t.EndTime) .Map(s => s.PanelHosts, t => t.PanelHosts); var diff = patch.Patch(ImportEventEntries, eventRecords); service.ApplyPatchOperationAsync(diff).Wait(); return(diff.Where(a => a.Entity.IsDeleted == 0).Select(a => a.Entity).ToList()); }
private void HandleUpdatedFile(PatchDefinition definition, PatchDefinitionEntry entry) { var filePath = PathsManager.Combine(_context.Settings.GetGamePath(), entry.RelativePath); var fileBackupPath = filePath + ".bak"; var patchPath = PathsManager.Combine(_context.Settings.GetUncompressedPatchArchivePath(definition.From, definition.To), entry.RelativePath + ".patch"); try { FilesManager.Rename(filePath, fileBackupPath); DeltaFileApplier.Apply(fileBackupPath, patchPath, filePath); EnsureDefinition(filePath, entry); } catch { } finally { FilesManager.Delete(fileBackupPath); } }
public static List <KnowledgeGroupRecord> UpdateKnowledgeGroups( IList <KnowledgeGroupRecord> importKnowledgeGroups, IKnowledgeGroupService service ) { var knowledgeGroupRecords = service.FindAllAsync().Result; var patch = new PatchDefinition <KnowledgeGroupRecord, KnowledgeGroupRecord>( (source, list) => list.SingleOrDefault(a => a.Id == source.Id) ); patch .Map(s => s.Id, t => t.Id) .Map(s => s.Name, t => t.Name) .Map(s => s.Description, t => t.Description) .Map(s => s.Order, t => t.Order); var diff = patch.Patch(importKnowledgeGroups, knowledgeGroupRecords); service.ApplyPatchOperationAsync(diff).Wait(); return(diff.Where(a => a.Entity.IsDeleted == 0).Select(a => a.Entity).ToList()); }
private IntPtr ResolveAddress(PatchDefinition patchDef) { var address = scanner.Module.BaseAddress; // if we have a signature, use that as the base instead of the module base if (!string.IsNullOrEmpty(patchDef.Location.Signature)) { // TODO: do we need to handle .data too? address = scanner.ScanText(patchDef.Location.Signature); // ensure that there is only one instance found try { var offset = (int)(address.ToInt64() - scanner.TextSectionBase.ToInt64()); var dupeAddr = scanner.Scan(address + 1, scanner.TextSectionSize - offset, patchDef.Location.Signature); // if we get here, there is a duplicate throw new ArgumentException("Signatures specified in Location.Signature must resolve to a unique address"); } catch (KeyNotFoundException) { // Scan() throws this if not found, so getting here means we are ok } } // if there is an offset, add it to the current base if (!string.IsNullOrEmpty(patchDef.Location.Offset)) { address += int.Parse(patchDef.Location.Offset, NumberStyles.HexNumber | NumberStyles.AllowHexSpecifier); } if (address == scanner.Module.BaseAddress) { throw new ArgumentException("At least one of Location.Signature and Location.Offset must be specified"); } return(address); }
public async Task ImportZipPackageAsync(string fileName) { var importRecords = new List <DealerRecord>(); using (var fileStream = File.OpenRead(fileName)) using (var archive = new ZipArchive(fileStream)) { var csvEntry = archive.Entries.Single(a => a.Name.EndsWith(".csv", StringComparison.CurrentCultureIgnoreCase)); TextReader reader = new StreamReader(csvEntry.Open(), Encoding.GetEncoding(1252)); var csvReader = new CsvReader(reader); csvReader.Configuration.RegisterClassMap <DealerImportRowClassMap>(); var csvRecords = csvReader.GetRecords <DealerImportRow>().ToList(); foreach (var record in csvRecords) { var dealerRecord = new DealerRecord { RegistrationNumber = record.RegNo, AttendeeNickname = record.Nickname, AboutTheArtistText = record.AboutTheArtist, AboutTheArtText = record.AboutTheArt, ArtPreviewCaption = record.ArtPreviewCaption, DisplayName = record.DisplayName, ShortDescription = record.ShortDescription }; dealerRecord.ArtistImageId = await GetImageIdAsync(archive, $"artist_{record.RegNo}.", $"dealer:artist:{record.RegNo}"); dealerRecord.ArtistThumbnailImageId = await GetImageIdAsync(archive, $"thumbnail_{record.RegNo}.", $"dealer:thumbnail:{record.RegNo}"); dealerRecord.ArtPreviewImageId = await GetImageIdAsync(archive, $"art_{record.RegNo}.", $"dealer:art:{record.RegNo}"); ImportLinks(dealerRecord, record.WebsiteUrl); SanitizeFields(dealerRecord); importRecords.Add(dealerRecord); } } var existingRecords = await _dealerService.FindAllAsync(); var patch = new PatchDefinition <DealerRecord, DealerRecord>((source, list) => list.SingleOrDefault(a => a.RegistrationNumber == source.RegistrationNumber)); patch .Map(s => s.RegistrationNumber, t => t.RegistrationNumber) .Map(s => s.AttendeeNickname, t => t.AttendeeNickname) .Map(s => s.AboutTheArtistText, t => t.AboutTheArtistText) .Map(s => s.AboutTheArtText, t => t.AboutTheArtText) .Map(s => s.ArtPreviewCaption, t => t.ArtPreviewCaption) .Map(s => s.DisplayName, t => t.DisplayName) .Map(s => s.ShortDescription, t => t.ShortDescription) .Map(s => s.ArtistImageId, t => t.ArtistImageId) .Map(s => s.ArtistThumbnailImageId, t => t.ArtistThumbnailImageId) .Map(s => s.ArtPreviewImageId, t => t.ArtPreviewImageId) .Map(s => s.Links, t => t.Links); var diff = patch.Patch(importRecords, existingRecords); await _dealerService.ApplyPatchOperationAsync(diff); }
private void HandleDeletedFile(PatchDefinition definition, PatchDefinitionEntry entry) { var path = PathsManager.Combine(_context.Settings.GetGamePath(), entry.RelativePath); FilesManager.Delete(path); }
private void HandleChangedAttributesFile(PatchDefinition definition, PatchDefinitionEntry entry) { var path = PathsManager.Combine(_context.Settings.GetGamePath(), entry.RelativePath); EnsureDefinition(path, entry); }
public async Task ImportZipPackageAsync(string fileName) { var importRecords = new List <DealerRecord>(); using (var fileStream = File.OpenRead(fileName)) using (var archive = new ZipArchive(fileStream)) { var csvEntry = archive.Entries.Single(a => a.Name.EndsWith(".csv", StringComparison.CurrentCultureIgnoreCase)); TextReader reader = new StreamReader(csvEntry.Open(), true); var csvReader = new CsvReader(reader); csvReader.Configuration.RegisterClassMap <DealerImportRowClassMap>(); csvReader.Configuration.Delimiter = ";"; var csvRecords = csvReader.GetRecords <DealerImportRow>().ToList(); _output?.WriteLine($"Parsed {csvRecords.Count} records from CSV"); foreach (var record in csvRecords) { var dealerRecord = new DealerRecord { RegistrationNumber = record.RegNo, AttendeeNickname = record.Nickname, AboutTheArtistText = record.AboutTheArtist, AboutTheArtText = record.AboutTheArt, ArtPreviewCaption = record.ArtPreviewCaption, DisplayName = record.DisplayName, ShortDescription = record.ShortDescription, Merchandise = record.Merchandise, AttendsOnThursday = !string.IsNullOrWhiteSpace(record.AttendsThu), AttendsOnFriday = !string.IsNullOrWhiteSpace(record.AttendsFri), AttendsOnSaturday = !string.IsNullOrWhiteSpace(record.AttendsSat), TelegramHandle = record.Telegram, TwitterHandle = record.Twitter }; dealerRecord.ArtistImageId = await GetImageIdAsync(archive, $"artist_{record.RegNo}.", $"dealer:artist:{record.RegNo}"); dealerRecord.ArtistThumbnailImageId = await GetImageIdAsync(archive, $"thumbnail_{record.RegNo}.", $"dealer:thumbnail:{record.RegNo}"); dealerRecord.ArtPreviewImageId = await GetImageIdAsync(archive, $"art_{record.RegNo}.", $"dealer:art:{record.RegNo}"); ImportLinks(dealerRecord, record.Website); SanitizeFields(dealerRecord); importRecords.Add(dealerRecord); } } var existingRecords = await _dealerService.FindAllAsync(); var patch = new PatchDefinition <DealerRecord, DealerRecord>((source, list) => list.SingleOrDefault(a => a.RegistrationNumber == source.RegistrationNumber)); patch .Map(s => s.RegistrationNumber, t => t.RegistrationNumber) .Map(s => s.AttendeeNickname, t => t.AttendeeNickname) .Map(s => s.AboutTheArtistText, t => t.AboutTheArtistText) .Map(s => s.AboutTheArtText, t => t.AboutTheArtText) .Map(s => s.ArtPreviewCaption, t => t.ArtPreviewCaption) .Map(s => s.DisplayName, t => t.DisplayName) .Map(s => s.ShortDescription, t => t.ShortDescription) .Map(s => s.Merchandise, t => t.Merchandise) .Map(s => s.ArtistImageId, t => t.ArtistImageId) .Map(s => s.ArtistThumbnailImageId, t => t.ArtistThumbnailImageId) .Map(s => s.ArtPreviewImageId, t => t.ArtPreviewImageId) .Map(s => s.TelegramHandle, t => t.TelegramHandle) .Map(s => s.TwitterHandle, t => t.TwitterHandle) .Map(s => s.AttendsOnThursday, t => t.AttendsOnThursday) .Map(s => s.AttendsOnFriday, t => t.AttendsOnFriday) .Map(s => s.AttendsOnSaturday, t => t.AttendsOnSaturday) .Map(s => s.Links, t => t.Links); var diff = patch.Patch(importRecords, existingRecords); await _dealerService.ApplyPatchOperationAsync(diff); _output?.WriteLine($"Added: {diff.Count(a => a.Action == ActionEnum.Add)}"); _output?.WriteLine($"Deleted: {diff.Count(a => a.Action == ActionEnum.Delete)}"); _output?.WriteLine($"Updated: {diff.Count(a => a.Action == ActionEnum.Update)}"); _output?.WriteLine($"Not Modified: {diff.Count(a => a.Action == ActionEnum.NotModified)}"); }
public async Task ExecuteAsync() { _logger.LogDebug("Job started"); var response = string.Empty; using (var client = new HttpClient()) { var url = _configuration["source:url"]; _logger.LogDebug("Fetching data from {url}", url); response = await client.GetStringAsync(url); } if (response == "null") { _logger.LogDebug("Received null response"); return; } var records = JsonConvert.DeserializeObject <JObject[]>(response); var unixReference = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); var mapping = records.Select(j => new { Record = new AnnouncementRecord() { ExternalReference = j["id"].Value <string>(), Area = j["news"]["type"].Value <string>().UppercaseFirst(), Author = j["news"]?["department"]?.Value <string>().UppercaseFirst() ?? "Eurofurence", Title = j["news"]["title"].Value <string>(), Content = j["news"]["message"].Value <string>().RemoveMarkdown(), ValidFromDateTimeUtc = unixReference.AddSeconds(j["date"].Value <double>()).ToUniversalTime(), ValidUntilDateTimeUtc = unixReference .AddSeconds(j["news"]["valid_until"].Value <double>()).ToUniversalTime(), }, Type = j["news"]["type"].Value <string>() }).ToList(); foreach (var item in mapping) { if (new[] { "new", "reschedule" }.Contains(item.Type)) { item.Record.ValidUntilDateTimeUtc = item.Record.ValidFromDateTimeUtc.AddHours(48); } } var existingRecords = await _announcementService.FindAllAsync(); var patch = new PatchDefinition <AnnouncementRecord, AnnouncementRecord>((source, list) => list.SingleOrDefault(a => a.ExternalReference == source.ExternalReference)); patch .Map(s => s.ExternalReference, t => t.ExternalReference) .Map(s => s.Area, t => t.Area) .Map(s => s.Author, t => t.Author) .Map(s => s.Title, t => t.Title) .Map(s => s.Content, t => t.Content) .Map(s => s.ValidUntilDateTimeUtc, t => t.ValidUntilDateTimeUtc) .Map(s => s.ValidFromDateTimeUtc, t => t.ValidFromDateTimeUtc); var diff = patch.Patch(mapping.Select(a => a.Record), existingRecords) .Where(a => !string.IsNullOrEmpty(a.Entity.ExternalReference) && a.Action != ActionEnum.NotModified) .ToList(); _logger.LogDebug("Diff results in {count} new/modified records", diff.Count); if (diff.Count == 0) { return; } _logger.LogInformation("Processing {count} new/modified records", diff.Count); await _announcementService.ApplyPatchOperationAsync(diff); await _pushEventMediator.PushSyncRequestAsync(); foreach (var record in diff.Where(a => a.Action == ActionEnum.Add)) { _logger.LogInformation("Sending push notification for announcement {id} ({title})", record.Entity.Id, record.Entity.Title); await _pushEventMediator.PushAnnouncementNotificationAsync(record.Entity); } _logger.LogDebug("Job finished"); }
// TargetFilePath is relative to the root of the PatchDefinition // OutputFilePath can be null public static void AddPatch(string InputFilePath, string OutputFilePath, string PatchDefinitionName, string TargetVersionDescription, string TargetFilePath, string PathToVisualStudioWithWP8SDK, UInt32 VirtualAddress, CodeType CodeType, string ArmCodeFragment, string PatchDefintionsXmlPath) { SHA1Managed SHA = new SHA1Managed(); // Compile ARM code byte[] CompiledCode = null; if (VirtualAddress != 0) { CompiledCode = ArmCompiler.Compile(PathToVisualStudioWithWP8SDK, VirtualAddress, CodeType, ArmCodeFragment); } // Read original binary byte[] Binary = File.ReadAllBytes(InputFilePath); // Backup original checksum UInt32 ChecksumOffset = GetChecksumOffset(Binary); UInt32 OriginalChecksum = ByteOperations.ReadUInt32(Binary, ChecksumOffset); // Determine Raw Offset PeFile PeFile = new PeFile(Binary); UInt32 RawOffset = 0; if (VirtualAddress != 0) { RawOffset = PeFile.ConvertVirtualAddressToRawOffset(VirtualAddress); } // Add or replace patch string PatchDefintionsXml = File.ReadAllText(PatchDefintionsXmlPath); PatchEngine PatchEngine = new PatchEngine(PatchDefintionsXml); PatchDefinition PatchDefinition = PatchEngine.PatchDefinitions.Where(d => (string.Compare(d.Name, PatchDefinitionName, true) == 0)).FirstOrDefault(); if (PatchDefinition == null) { PatchDefinition = new PatchDefinition(); PatchDefinition.Name = PatchDefinitionName; PatchEngine.PatchDefinitions.Add(PatchDefinition); } TargetVersion TargetVersion = PatchDefinition.TargetVersions.Where(v => (string.Compare(v.Description, TargetVersionDescription, true) == 0)).FirstOrDefault(); if (TargetVersion == null) { TargetVersion = new TargetVersion(); TargetVersion.Description = TargetVersionDescription; PatchDefinition.TargetVersions.Add(TargetVersion); } TargetFile TargetFile = TargetVersion.TargetFiles.Where(f => ((f.Path != null) && (string.Compare(f.Path.TrimStart(new char[] { '\\' }), TargetFilePath.TrimStart(new char[] { '\\' }), true) == 0))).FirstOrDefault(); if (TargetFile == null) { TargetFile = new TargetFile(); TargetVersion.TargetFiles.Add(TargetFile); } TargetFile.Path = TargetFilePath; TargetFile.HashOriginal = SHA.ComputeHash(Binary); Patch Patch; if (VirtualAddress != 0) { Patch = TargetFile.Patches.Where(p => p.Address == RawOffset).FirstOrDefault(); if (Patch == null) { Patch = new Patch(); Patch.Address = RawOffset; TargetFile.Patches.Add(Patch); } Patch.OriginalBytes = new byte[CompiledCode.Length]; Buffer.BlockCopy(Binary, (int)RawOffset, Patch.OriginalBytes, 0, CompiledCode.Length); Patch.PatchedBytes = CompiledCode; } // Apply all patches foreach (Patch CurrentPatch in TargetFile.Patches) { Buffer.BlockCopy(CurrentPatch.PatchedBytes, 0, Binary, (int)CurrentPatch.Address, CurrentPatch.PatchedBytes.Length); } // Calculate checksum // This also modifies the binary // Original checksum is already backed up UInt32 Checksum = CalculateChecksum(Binary); // Add or replace checksum patch Patch = TargetFile.Patches.Where(p => p.Address == ChecksumOffset).FirstOrDefault(); if (Patch == null) { Patch = new Patch(); Patch.Address = ChecksumOffset; TargetFile.Patches.Add(Patch); } Patch.OriginalBytes = new byte[4]; ByteOperations.WriteUInt32(Patch.OriginalBytes, 0, OriginalChecksum); Patch.PatchedBytes = new byte[4]; ByteOperations.WriteUInt32(Patch.PatchedBytes, 0, Checksum); // Calculate hash for patched target file TargetFile.HashPatched = SHA.ComputeHash(Binary); // Write patched file if (OutputFilePath != null) { File.WriteAllBytes(OutputFilePath, Binary); } // Write PatchDefintions PatchEngine.WriteDefinitions(PatchDefintionsXmlPath); }