public void WriteDocument(DocumentItem item, SmugglerProgressBase.CountsWithLastEtagAndAttachments progress) { if (item.Attachments != null) { throw new NotSupportedException(); } var document = item.Document; using (document) { if (_options.OperateOnTypes.HasFlag(DatabaseItemType.Attachments)) { WriteUniqueAttachmentStreams(document, progress); } if (First == false) { Writer.WriteComma(); } First = false; Writer.WriteDocument(_context, document, metadataOnly: false, _filterMetadataProperty); } }
private void WriteUniqueAttachmentStreams(Document document, SmugglerProgressBase.CountsWithLastEtagAndAttachments progress) { if ((document.Flags & DocumentFlags.HasAttachments) != DocumentFlags.HasAttachments || document.Data.TryGet(Constants.Documents.Metadata.Key, out BlittableJsonReaderObject metadata) == false || metadata.TryGet(Constants.Documents.Metadata.Attachments, out BlittableJsonReaderArray attachments) == false) { return; } if (_attachmentStreamsAlreadyExported == null) { _attachmentStreamsAlreadyExported = new HashSet <string>(); } foreach (BlittableJsonReaderObject attachment in attachments) { if (attachment.TryGet(nameof(AttachmentName.Hash), out LazyStringValue hash) == false) { progress.Attachments.ErroredCount++; throw new ArgumentException($"Hash field is mandatory in attachment's metadata: {attachment}"); } progress.Attachments.ReadCount++; if (_attachmentStreamsAlreadyExported.Add(hash)) { using (var stream = _source.GetAttachmentStream(hash, out string tag)) { if (stream == null) { progress.Attachments.ErroredCount++; throw new ArgumentException($"Document {document.Id} seems to have a attachment hash: {hash}, but no correlating hash was found in the storage."); } WriteAttachmentStream(hash, stream, tag); } } } }
public async Task Attachments() { var destination = new DatabaseDestination(Database); var options = new DatabaseSmugglerOptionsServerSide { OperateOnTypes = DatabaseItemType.Attachments, SkipRevisionCreation = true }; destination.Initialize(options, null, buildVersion: default); using (var documentActions = destination.Documents()) using (var buffered = new BufferedStream(RequestBodyStream())) #pragma warning disable CS0618 // Type or member is obsolete using (var reader = new BsonReader(buffered)) #pragma warning restore CS0618 // Type or member is obsolete { var result = LegacyAttachmentUtils.GetObject(reader); const string idProperty = "@id"; const string etagProperty = "@etag"; const string metadataProperty = "@metadata"; const string dataProperty = "data"; string lastAttachmentEtag = null; var progress = new SmugglerProgressBase.CountsWithLastEtagAndAttachments(); foreach (var attachmentObject in result.Values) { if (!(attachmentObject is Dictionary <string, object> attachmentDictionary)) { throw new InvalidDataException("attachmentObject isn't a Dictionary<string, object>"); } if (attachmentDictionary.TryGetValue(idProperty, out var attachmentKeyObject) == false) { throw new InvalidDataException($"{idProperty} doesn't exist"); } if (!(attachmentKeyObject is string attachmentKey)) { throw new InvalidDataException($"{idProperty} isn't of type string"); } if (attachmentDictionary.TryGetValue(etagProperty, out var lastAttachmentEtagObject) == false) { throw new InvalidDataException($"{etagProperty} doesn't exist"); } if (!(lastAttachmentEtagObject is byte[] lastAttachmentEtagByteArray)) { throw new InvalidDataException($"{etagProperty} isn't of type byte[]"); } lastAttachmentEtag = LegacyAttachmentUtils.ByteArrayToEtagString(lastAttachmentEtagByteArray); if (attachmentDictionary.TryGetValue(metadataProperty, out object metadataObject) == false) { throw new InvalidDataException($"{metadataProperty} doesn't exist"); } if (!(metadataObject is Dictionary <string, object> metadata)) { throw new InvalidDataException($"{idProperty} isn't of type string"); } if (metadata.TryGetValue("Raven-Delete-Marker", out var deletedObject) && deletedObject is bool deletedObjectAsBool && deletedObjectAsBool) { var id = StreamSource.GetLegacyAttachmentId(attachmentKey); documentActions.DeleteDocument(id); continue; } var djv = new DynamicJsonValue(); foreach (var keyValue in metadata) { var key = keyValue.Key; if (key.Equals("Raven-Replication-Source") || key.Equals("Raven-Replication-Version") || key.Equals("Raven-Replication-History")) { continue; } djv[key] = keyValue.Value; } var contextToUse = documentActions.GetContextForNewDocument(); var metadataBlittable = contextToUse.ReadObject(djv, "metadata"); if (attachmentDictionary.TryGetValue(dataProperty, out object dataObject) == false) { throw new InvalidDataException($"{dataProperty} doesn't exist"); } if (!(dataObject is byte[] data)) { throw new InvalidDataException($"{dataProperty} isn't of type byte[]"); } using (var dataStream = new MemoryStream(data)) { var attachment = new DocumentItem.AttachmentStream { Stream = documentActions.GetTempStream() }; var attachmentDetails = StreamSource.GenerateLegacyAttachmentDetails(contextToUse, dataStream, attachmentKey, metadataBlittable, ref attachment); var documentItem = new DocumentItem { Document = new Document { Data = StreamSource.WriteDummyDocumentForAttachment(contextToUse, attachmentDetails), Id = attachmentDetails.Id, ChangeVector = string.Empty, Flags = DocumentFlags.HasAttachments, LastModified = Database.Time.GetUtcNow() }, Attachments = new List <DocumentItem.AttachmentStream> { attachment } }; documentActions.WriteDocument(documentItem, progress); } } using (ContextPool.AllocateOperationContext(out DocumentsOperationContext context)) { var replicationSource = GetSourceReplicationInformation(context, GetRemoteServerInstanceId(), out var documentId); replicationSource.LastAttachmentEtag = lastAttachmentEtag; replicationSource.Source = GetFromServer(); replicationSource.LastModified = DateTime.UtcNow; await SaveSourceReplicationInformation(replicationSource, context, documentId); } } }