Package floobits.common.protocol.buf

Source Code of floobits.common.protocol.buf.TextBuf

package floobits.common.protocol.buf;

import floobits.common.Constants;
import floobits.common.Encoding;
import floobits.common.OutboundRequestHandler;
import floobits.common.dmp.FlooDmp;
import floobits.common.dmp.FlooPatchPosition;
import floobits.common.dmp.diff_match_patch;
import floobits.common.interfaces.IContext;
import floobits.common.interfaces.IDoc;
import floobits.common.interfaces.IFile;
import floobits.common.protocol.FlooPatch;
import floobits.utilities.Flog;
import org.apache.commons.codec.digest.DigestUtils;

import java.util.LinkedList;
import java.util.List;


public class TextBuf extends Buf<String> {
    protected static FlooDmp dmp = new FlooDmp();

    public TextBuf(String path, Integer id, String buf, String md5, IContext context, OutboundRequestHandler outbound) {
        super(path, id, buf, md5, context, outbound);
        if (buf != null) {
            this.buf = Constants.NEW_LINE.matcher(buf).replaceAll("\n");
        }
        this.encoding = Encoding.UTF8;
    }


    public void read () {
        IDoc d = getVirtualDoc();
        if (d == null) {
            return;
        }
        this.buf = d.getText();
        this.md5 = DigestUtils.md5Hex(this.buf);
    }

    public void write() {
        if (!isPopulated()) {
            Flog.warn("Unable to write %s because it's not populated yet.", path);
            return;
        }

        IDoc d = getVirtualDoc();
        if (d != null) {
            synchronized (context) {
                try {
                    context.setListener(false);
                    d.setReadOnly(false);
                    d.setText(buf);
                } finally {
                    context.setListener(true);
                }
                return;
            }
        }

        Flog.warn("Tried to write to null document: %s", path);

        IFile virtualFile = getOrCreateFile();
        try {
            virtualFile.setBytes(buf.getBytes());
        } catch (Throwable e) {
            Flog.warn(e);
            context.errorMessage("The Floobits plugin was unable to write to a file.");
        }
    }

    synchronized public void set(String s, String newMD5) {
        buf = s == null ? null : Constants.NEW_LINE.matcher(s).replaceAll("\n");
        md5 = newMD5;
    }

    public String serialize() {
        return buf;
    }

    @Override
    public void send_patch(IFile virtualFile) {
        IDoc d = context.iFactory.getDocument(virtualFile);
        if (d == null) {
            Flog.warn("Can't get document to read from disk for sending patch %s", path);
            return;
        }
        send_patch(d.getText());
    }

    public void send_patch(String current) {

        String before_md5;
        String textPatch;
        String after_md5;

        String previous = buf;
        before_md5 = md5;
        after_md5 = DigestUtils.md5Hex(current);
        LinkedList<diff_match_patch.Patch> patches = dmp.patch_make(previous, current);
        textPatch = dmp.patch_toText(patches);

        set(current, after_md5);
        if (before_md5.equals(after_md5)) {
            Flog.log("Not patching %s because no change.", path);
            return;
        }
       outbound.patch(textPatch, before_md5, this);
    }

    private void getBuf() {
        cancelTimeout();
        outbound.getBuf(id);
    }

    private void setGetBufTimeout() {
        final int buf_id = id;
        cancelTimeout();
        timeout = context.setTimeout(2000, new Runnable() {
            @Override
            public void run() {
                Flog.info("Sending get buf after timeout.");
                outbound.getBuf(buf_id);
            }
        });
    }

    public void patch(final FlooPatch res) {
        final TextBuf b = this;
        Flog.info("Got _on_patch");

        String oldText = buf;
        IFile virtualFile = b.getVirtualFile();
        if (virtualFile == null) {
            Flog.warn("VirtualFile is null, no idea what do do. Aborting everything %s", this);
            getBuf();
            return;
        }
        IDoc d = context.iFactory.getDocument(virtualFile);
        if (d == null) {
            Flog.warn("Document not found for %s", virtualFile);
            getBuf();
            return;
        }
        String viewText;
        if (!virtualFile.exists()) {
            viewText = oldText;
        } else {
            viewText = d.getText();
            if (viewText.equals(oldText)) {
                b.forced_patch = false;
            } else if (!b.forced_patch) {
                b.forced_patch = true;
                oldText = viewText;
                b.send_patch(viewText);
                Flog.warn("Sending force patch for %s. this is dangerous!", b.path);
            }
        }

        b.cancelTimeout();

        String md5Before = DigestUtils.md5Hex(viewText);
        if (!md5Before.equals(res.md5_before)) {
            Flog.warn("starting md5s don't match for %s. this is dangerous!", b.path);
        }

        List<diff_match_patch.Patch> patches =  dmp.patch_fromText(res.patch);
        final Object[] results = dmp.patch_apply((LinkedList<diff_match_patch.Patch>) patches, oldText);
        final String patchedContents = (String) results[0];
        final boolean[] patchesClean = (boolean[]) results[1];
        final FlooPatchPosition[] positions = (FlooPatchPosition[]) results[2];

        for (boolean clean : patchesClean) {
            if (!clean) {
                Flog.log("Patch not clean for %s. Sending get_buf and setting readonly.", d);
                getBuf();
                return;
            }
        }
        // XXX: If patchedContents have carriage returns this will be a problem:
        String md5After = DigestUtils.md5Hex(patchedContents);
        if (!md5After.equals(res.md5_after)) {
            Flog.info("MD5 after mismatch (ours %s remote %s)", md5After, res.md5_after);
        }

        if (!d.makeWritable()) {
            Flog.info("Document: %s is not writable.", d);
            return;
        }

        String text = d.patch(positions);
        if (text == null) {
            getBuf();
            return;
        }

        String md5FromDoc = DigestUtils.md5Hex(text);
        if (!md5FromDoc.equals(res.md5_after)) {
            Flog.info("md5FromDoc mismatch (ours %s remote %s)", md5FromDoc, res.md5_after);
            b.setGetBufTimeout();
        }

        b.set(text, md5FromDoc);
        Flog.log("Patched %s", res.path);
    }
}
TOP

Related Classes of floobits.common.protocol.buf.TextBuf

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.