public void AckRequest(string host, AcknowledgeDto acknowledgeDto) { using (var cf = GetChannelFactory(host)) { cf.CreateChannel().AckRequest(acknowledgeDto); } }
private void ConfirmPendingUpdate(Document document, AcknowledgeDto dto) { var result = _diffMatchPatch.patch_apply(document.PendingUpdate.Patch, document.Content); if (CheckResultIsValidOtherwiseReOpen(result, dto.DocumentId)) { document.PendingUpdate.NewRevisionId = dto.NewRevisionId; document.PendingUpdate.NewHash = dto.NewHash; UpdateDocument(document, document.PendingUpdate, result); } var currentText = _editor.GetText(dto.DocumentId); if (document.Content != currentText) { //send next update var updateDto = CreateUpdateDto(document, currentText); document.PendingUpdate = updateDto; SendUpdateToDocumentOwner(document, updateDto); } else { document.PendingUpdate = null; } }
public void AckRequest(AcknowledgeDto dto) { //do we know the document? if (_documents.ContainsKey(dto.DocumentId)) { var document = _documents[dto.DocumentId]; if (document.Owner != _memberName && document.PendingUpdate != null) { if (document.PendingUpdate.PreviousRevisionId == dto.PreviousRevisionId && document.PendingUpdate.PreviousHash.SequenceEqual(dto.PreviousHash)) { ConfirmPendingUpdate(document, dto); } else if (document.OutOfSyncAcknowledge != null) { document.OutOfSyncAcknowledge = dto; } else { ReOpenDocument(document.Id); } } } }
private void CreatePatchForUpdate(Document document, UpdateDto updateDto) { var currentRevision = document.GetCurrentRevision(); var lastUpdate = currentRevision.UpdateDto; //non existing revision - used as null object var secondLastUpdate = new UpdateDto { NewRevisionId = -1 }; if (document.CurrentRevisionId > FIRST_VALID_REVISON_ID) { secondLastUpdate = document.GetRevision(document.CurrentRevisionId - 1).UpdateDto; } bool creationSucessfull = false; //update is either based on current version //or on previous version where // - the member which initialised the previous version was the owner itself // - or a member with a lower member name (and thus the given update will be applied afterwards) //) if (IsFirstPreviousOfSecond(lastUpdate, updateDto) || (IsFirstPreviousOfSecond(secondLastUpdate, updateDto) && MemberOfFirstUpdateIsOwnerOrLowerMember(lastUpdate, updateDto) ) ) { var result = _diffMatchPatch.patch_apply(updateDto.Patch, document.Content); if (result.Item2.All(x => x)) { document.Content = result.Item1; creationSucessfull = true; } else { HandleErrorOnUpdate(updateDto); } } else { var revision = document.GetRevision(updateDto.PreviousRevisionId); if (revision.Id + SUPPORTED_NUM_OF_REACTIVE_UPDATES >= currentRevision.Id) { var nextRevision = document.GetRevision(revision.Id + 1); //move to next revision as long as while ( nextRevision.UpdateDto.PreviousHash.SequenceEqual(updateDto.PreviousHash) && MemberOfFirstUpdateIsNotOwnerAndHigherMember(updateDto, nextRevision.UpdateDto) && nextRevision.Id < currentRevision.Id) { revision = nextRevision; nextRevision = document.GetRevision(nextRevision.Id + 1); } var content = revision.Content; var tmpRevision = revision; var patch = updateDto.Patch; //apply all patches on top of the found revision while (tmpRevision.Id <= currentRevision.Id) { var result = _diffMatchPatch.patch_apply(patch, content); if (result.Item2.All(x => x)) { content = result.Item1; if (tmpRevision.Id == currentRevision.Id) { break; } tmpRevision = document.GetRevision(tmpRevision.Id + 1); patch = tmpRevision.UpdateDto.Patch; } else { HandleErrorOnUpdate(updateDto); } } document.Content = content; updateDto.Patch = _diffMatchPatch.patch_make(currentRevision.Content, content); creationSucessfull = true; } } if (creationSucessfull) { document.CurrentRevisionId = currentRevision.Id + 1; document.CurrentHash = GetHash(document.Content); updateDto.NewRevisionId = document.CurrentRevisionId; updateDto.NewHash = document.CurrentHash; document.AddRevision(new Revision { Id = document.CurrentRevisionId, Content = document.Content, UpdateDto = updateDto }); if (IsNotOwnUpdate(updateDto)) { _editor.UpdateText(updateDto.DocumentId, document.Content); var acknowledgeDto = new AcknowledgeDto { PreviousRevisionId = updateDto.PreviousRevisionId, PreviousHash = updateDto.PreviousHash, NewRevisionId = updateDto.NewRevisionId, NewHash = updateDto.NewHash, DocumentId = document.Id }; _communication.AckRequest(updateDto.MemberHost, acknowledgeDto); } var newUpdateDto = new UpdateDto { DocumentId = document.Id, MemberName = updateDto.MemberName, MemberHost = _serverHost, PreviousRevisionId = updateDto.PreviousRevisionId, PreviousHash = updateDto.PreviousHash, NewRevisionId = updateDto.NewRevisionId, NewHash = updateDto.NewHash, Patch = updateDto.Patch, EditorCount = document.EditorCount }; foreach (var editorHost in document.Editors().Values) { if (updateDto.MemberHost != editorHost) { try { _communication.UpdateRequest(editorHost, newUpdateDto); } catch (EndpointNotFoundException) { document.Editors().Remove(editorHost); } } } } else if (IsNotOwnUpdate(updateDto)) { HandleErrorOnUpdate(updateDto); } }
private void CreatePatchForUpdate(Document document, UpdateDto updateDto) { var currentRevision = document.GetCurrentRevision(); var lastUpdate = currentRevision.UpdateDto; //non existing revision - used as null object var secondLastUpdate = new UpdateDto {NewRevisionId = -1}; if (document.CurrentRevisionId > FIRST_VALID_REVISON_ID) { secondLastUpdate=document.GetRevision(document.CurrentRevisionId - 1).UpdateDto; } bool creationSucessfull = false; //update is either based on current version //or on previous version where // - the member which initialised the previous version was the owner itself // - or a member with a lower member name (and thus the given update will be applied afterwards) //) if (IsFirstPreviousOfSecond(lastUpdate, updateDto) || (IsFirstPreviousOfSecond(secondLastUpdate, updateDto) && MemberOfFirstUpdateIsOwnerOrLowerMember(lastUpdate, updateDto) ) ) { var result = _diffMatchPatch.patch_apply(updateDto.Patch, document.Content); if (result.Item2.All(x => x)) { document.Content = result.Item1; creationSucessfull = true; }else { HandleErrorOnUpdate(updateDto); } } else { var revision = document.GetRevision(updateDto.PreviousRevisionId); if (revision.Id + SUPPORTED_NUM_OF_REACTIVE_UPDATES >= currentRevision.Id) { var nextRevision = document.GetRevision(revision.Id + 1); //move to next revision as long as while ( nextRevision.UpdateDto.PreviousHash.SequenceEqual(updateDto.PreviousHash) && MemberOfFirstUpdateIsNotOwnerAndHigherMember(updateDto, nextRevision.UpdateDto) && nextRevision.Id < currentRevision.Id) { revision = nextRevision; nextRevision = document.GetRevision(nextRevision.Id + 1); } var content = revision.Content; var tmpRevision = revision; var patch = updateDto.Patch; //apply all patches on top of the found revision while (tmpRevision.Id <= currentRevision.Id) { var result = _diffMatchPatch.patch_apply(patch, content); if (result.Item2.All(x => x)) { content = result.Item1; if (tmpRevision.Id == currentRevision.Id) { break; } tmpRevision = document.GetRevision(tmpRevision.Id + 1); patch = tmpRevision.UpdateDto.Patch; } else { HandleErrorOnUpdate(updateDto); } } document.Content = content; updateDto.Patch = _diffMatchPatch.patch_make(currentRevision.Content, content); creationSucessfull = true; } } if (creationSucessfull) { document.CurrentRevisionId = currentRevision.Id + 1; document.CurrentHash = GetHash(document.Content); updateDto.NewRevisionId = document.CurrentRevisionId; updateDto.NewHash = document.CurrentHash; document.AddRevision(new Revision { Id = document.CurrentRevisionId, Content = document.Content, UpdateDto = updateDto }); if (IsNotOwnUpdate(updateDto)) { _editor.UpdateText(updateDto.DocumentId, document.Content); var acknowledgeDto = new AcknowledgeDto { PreviousRevisionId = updateDto.PreviousRevisionId, PreviousHash = updateDto.PreviousHash, NewRevisionId = updateDto.NewRevisionId, NewHash = updateDto.NewHash, DocumentId = document.Id }; _communication.AckRequest(updateDto.MemberHost, acknowledgeDto); } var newUpdateDto = new UpdateDto { DocumentId = document.Id, MemberName = updateDto.MemberName, MemberHost = _serverHost, PreviousRevisionId = updateDto.PreviousRevisionId, PreviousHash = updateDto.PreviousHash, NewRevisionId = updateDto.NewRevisionId, NewHash = updateDto.NewHash, Patch = updateDto.Patch, EditorCount = document.EditorCount }; foreach (var editorHost in document.Editors().Values) { if (updateDto.MemberHost != editorHost) { try { _communication.UpdateRequest(editorHost, newUpdateDto); } catch (EndpointNotFoundException) { document.Editors().Remove(editorHost); } } } } else if (IsNotOwnUpdate(updateDto)) { HandleErrorOnUpdate(updateDto); } }