Example #1
0
func (d *Document) CalculateEdit() {

	text := d.GetText()

	// Calculate differences.
	diffs := dmp.DiffMain(d.Shadow.Content, text, false)
	diffs = dmp.DiffCleanupEfficiency(diffs)

	// Calculate patch.
	patches := dmp.PatchMake(d.Shadow.Content, diffs)
	if len(patches) < 1 {
		// No differences.
		return
	}
	patchesText := dmp.PatchToText(patches)

	// Increment shadow.
	d.Shadow.Content = text
	d.Shadow.LocalVersion++

	// Add edit to edit queue.
	edit := Edit{Version: d.Shadow.LocalVersion, Patch: patchesText, MD5: checksum.MD5(d.Shadow.Content)}
	d.Edits.Enqueue(edit)

}
Example #2
0
func (d *Document) ApplyEdits(version int, edits []Edit) error {

	if version < d.Shadow.LocalVersion && version == d.Backup.LocalVersion {
		// Edits are based on an old version. Use the backup shadow.
		d.RestoreBackup()

	} else if version < d.Shadow.LocalVersion && version != d.Backup.LocalVersion {
		// Edits are based on an old version, but somehow the backup is out of sync. Reinitialize and accept loss.
		return fmt.Errorf("patch failed: version mismatch (backup out of sync: client remote %d, backup local %d)", version, d.Backup.LocalVersion)

	} else if version > d.Shadow.LocalVersion {
		// Somehow, the client received a version we never had. Reinitialize and accept loss.
		return fmt.Errorf("patch failed: version mismatch (client ahead of source: client remote %d, server local %d)", version, d.Shadow.LocalVersion)

	}

	// Versions match - apply patch
	for _, edit := range edits {

		if edit.Version <= d.Shadow.RemoteVersion {
			// Already handled
			continue

		} else if edit.Version > d.Shadow.RemoteVersion+1 {
			// Somehow we've skipped one version. Reinitialize and accept loss.
			return fmt.Errorf("patch failed: version mismatch (missing version)")

		}

		// Versions match - apply patch
		patch, _ := dmp.PatchFromText(edit.Patch)

		// Apply to shadow (strict)
		newShadow := *d.Shadow
		newShadow.Content, _ = dmp.PatchApply(patch, d.Shadow.Content)
		newShadow.RemoteVersion = edit.Version

		if checksum.MD5(newShadow.Content) != edit.MD5 {
			// Strict patch unsuccessful. Reinitialize and accept loss.
			return fmt.Errorf("patch failed: strict patch unsuccessful")
		}

		// Strict patch successful.
		d.Shadow = &newShadow

		// Copy shadow to backup.
		d.TakeBackup()

		// Apply to text (fuzzy).
		newText, _ := dmp.PatchApply(patch, d.GetText())
		d.SetText(newText)

	}

	return nil

}