Search in sources :

Example 1 with MediaSyncException

use of com.ichi2.anki.exception.MediaSyncException in project AnkiChinaAndroid by ankichinateam.

the class MediaSyncer method sync.

public String sync(long restSpace) throws UnknownHttpResponseException, MediaSyncException, NoEnoughServerSpaceException {
    // of this class about this difference to the original.
    if (mCol.getMedia().needScan()) {
        mCon.publishProgress(R.string.sync_media_find);
        mCol.log("findChanges");
        try {
            mCol.getMedia().findChanges();
        } catch (SQLException ignored) {
            return "corruptMediaDB";
        }
    }
    // begin session and check if in sync
    int lastUsn = mCol.getMedia().lastUsn();
    JSONObject ret = mServer.begin();
    int srvUsn = ret.getInt("usn");
    if ((lastUsn == srvUsn) && !(mCol.getMedia().haveDirty())) {
        return "noChanges";
    }
    // loop through and process changes from server
    mCol.log("last local usn is " + lastUsn);
    mDownloadCount = 0;
    while (true) {
        // Allow cancellation (note: media sync has no finish command, so just throw)
        if (Connection.getIsCancelled()) {
            Timber.i("Sync was cancelled");
            throw new RuntimeException("UserAbortedSync");
        }
        JSONArray data = mServer.mediaChanges(lastUsn);
        mCol.log("mediaChanges resp count: ", data.length());
        if (data.length() == 0) {
            break;
        }
        List<String> need = new ArrayList<>();
        lastUsn = data.getJSONArray(data.length() - 1).getInt(1);
        for (int i = 0; i < data.length(); i++) {
            // Allow cancellation (note: media sync has no finish command, so just throw)
            if (Connection.getIsCancelled()) {
                Timber.i("Sync was cancelled");
                throw new RuntimeException("UserAbortedSync");
            }
            String fname = data.getJSONArray(i).getString(0);
            int rusn = data.getJSONArray(i).getInt(1);
            String rsum = null;
            if (!data.getJSONArray(i).isNull(2)) {
                // If `rsum` is a JSON `null` value, `.optString(2)` will
                // return `"null"` as a string
                rsum = data.getJSONArray(i).optString(2);
            }
            Pair<String, Integer> info = mCol.getMedia().syncInfo(fname);
            String lsum = info.first;
            int ldirty = info.second;
            mCol.log(String.format(Locale.US, "check: lsum=%s rsum=%s ldirty=%d rusn=%d fname=%s", TextUtils.isEmpty(lsum) ? "" : lsum.subSequence(0, 4), TextUtils.isEmpty(rsum) ? "" : rsum.subSequence(0, 4), ldirty, rusn, fname));
            if (!TextUtils.isEmpty(rsum)) {
                // added/changed remotely
                if (TextUtils.isEmpty(lsum) || !lsum.equals(rsum)) {
                    mCol.log("will fetch");
                    need.add(fname);
                } else {
                    mCol.log("have same already");
                }
                mCol.getMedia().markClean(Collections.singletonList(fname));
            } else if (!TextUtils.isEmpty(lsum)) {
                // deleted remotely
                if (ldirty == 0) {
                    mCol.log("delete local");
                    mCol.getMedia().syncDelete(fname);
                } else {
                    // conflict: local add overrides remote delete
                    mCol.log("conflict; will send");
                }
            } else {
                // deleted both sides
                mCol.log("both sides deleted");
                mCol.getMedia().markClean(Collections.singletonList(fname));
            }
        }
        _downloadFiles(need);
        mCol.log("update last usn to " + lastUsn);
        // commits
        mCol.getMedia().setLastUsn(lastUsn);
    }
    // at this point, we're all up to date with the server's changes,
    // and we need to send our own
    boolean updateConflict = false;
    int toSend = mCol.getMedia().dirtyCount();
    long needSize = mCol.getMedia().getMediaSizeNeededUpload();
    if (needSize >= 0 && restSpace < needSize && Consts.loginAnkiChina()) {
        Timber.d("No Enough Server Space Exception,rest is:" + restSpace + ",need size:" + needSize);
        throw new NoEnoughServerSpaceException(restSpace, needSize);
    }
    while (true) {
        Pair<File, List<String>> changesZip = mCol.getMedia().mediaChangesZip();
        File zip = changesZip.first;
        try {
            List<String> fnames = changesZip.second;
            if (fnames.size() == 0) {
                break;
            }
            mCon.publishProgress(String.format(AnkiDroidApp.getAppResources().getString(R.string.sync_media_changes_count), toSend));
            JSONArray changes = mServer.uploadChanges(zip);
            int processedCnt = changes.getInt(0);
            int serverLastUsn = changes.getInt(1);
            mCol.getMedia().markClean(fnames.subList(0, processedCnt));
            mCol.log(String.format(Locale.US, "processed %d, serverUsn %d, clientUsn %d", processedCnt, serverLastUsn, lastUsn));
            if (serverLastUsn - processedCnt == lastUsn) {
                mCol.log("lastUsn in sync, updating local");
                lastUsn = serverLastUsn;
                // commits
                mCol.getMedia().setLastUsn(serverLastUsn);
            } else {
                mCol.log("concurrent update, skipping usn update");
                // commit for markClean
                mCol.getMedia().getDb().commit();
                updateConflict = true;
            }
            toSend -= processedCnt;
        } finally {
            zip.delete();
        }
    }
    if (updateConflict) {
        mCol.log("restart sync due to concurrent update");
        return sync(restSpace);
    }
    int lcnt = mCol.getMedia().mediacount();
    String sRet = mServer.mediaSanity(lcnt);
    if ("OK".equals(sRet)) {
        return "OK";
    } else {
        mCol.getMedia().forceResync();
        return sRet;
    }
}
Also used : SQLException(android.database.SQLException) JSONArray(com.ichi2.utils.JSONArray) ArrayList(java.util.ArrayList) JSONObject(com.ichi2.utils.JSONObject) ArrayList(java.util.ArrayList) List(java.util.List) File(java.io.File) ZipFile(java.util.zip.ZipFile) NoEnoughServerSpaceException(com.ichi2.anki.exception.NoEnoughServerSpaceException)

Example 2 with MediaSyncException

use of com.ichi2.anki.exception.MediaSyncException in project AnkiChinaAndroid by ankichinateam.

the class RemoteMediaServer method mediaSanity.

// args: local
public String mediaSanity(int lcnt) throws UnknownHttpResponseException, MediaSyncException {
    try {
        Response resp = super.req("mediaSanity", HttpSyncer.getInputStream(Utils.jsonToString(new JSONObject().put("local", lcnt))));
        JSONObject jresp = new JSONObject(resp.body().string());
        return _dataOnly(jresp, String.class);
    } catch (IOException | NullPointerException e) {
        throw new RuntimeException(e);
    }
}
Also used : Response(okhttp3.Response) JSONObject(com.ichi2.utils.JSONObject) IOException(java.io.IOException)

Example 3 with MediaSyncException

use of com.ichi2.anki.exception.MediaSyncException in project AnkiChinaAndroid by ankichinateam.

the class RemoteMediaServer method uploadChanges.

public JSONArray uploadChanges(File zip) throws UnknownHttpResponseException, MediaSyncException {
    try {
        // no compression, as we compress the zip file instead
        Response resp = super.req("uploadChanges", new FileInputStream(zip), 0);
        JSONObject jresp = new JSONObject(resp.body().string());
        return _dataOnly(jresp, JSONArray.class);
    } catch (IOException | NullPointerException e) {
        throw new RuntimeException(e);
    }
}
Also used : Response(okhttp3.Response) JSONObject(com.ichi2.utils.JSONObject) IOException(java.io.IOException) FileInputStream(java.io.FileInputStream)

Example 4 with MediaSyncException

use of com.ichi2.anki.exception.MediaSyncException in project Anki-Android by ankidroid.

the class RemoteMediaServer method begin.

public JSONObject begin() throws UnknownHttpResponseException, MediaSyncException {
    try {
        mPostVars = HashUtil.HashMapInit(2);
        mPostVars.put("k", mHKey);
        mPostVars.put("v", String.format(Locale.US, "ankidroid,%s,%s", VersionUtils.getPkgVersionName(), Utils.platDesc()));
        Response resp = super.req("begin", HttpSyncer.getInputStream(Utils.jsonToString(new JSONObject())));
        JSONObject jresp = new JSONObject(resp.body().string());
        JSONObject ret = _dataOnly(jresp, JSONObject.class);
        mSKey = ret.getString("sk");
        return ret;
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}
Also used : Response(okhttp3.Response) JSONObject(com.ichi2.utils.JSONObject) IOException(java.io.IOException)

Example 5 with MediaSyncException

use of com.ichi2.anki.exception.MediaSyncException in project Anki-Android by ankidroid.

the class RemoteMediaServer method mediaChanges.

// args: lastUsn
public JSONArray mediaChanges(int lastUsn) throws UnknownHttpResponseException, MediaSyncException {
    try {
        mPostVars = HashUtil.HashMapInit(1);
        mPostVars.put("sk", mSKey);
        Response resp = super.req("mediaChanges", HttpSyncer.getInputStream(Utils.jsonToString(new JSONObject().put("lastUsn", lastUsn))));
        JSONObject jresp = new JSONObject(resp.body().string());
        return _dataOnly(jresp, JSONArray.class);
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}
Also used : Response(okhttp3.Response) JSONObject(com.ichi2.utils.JSONObject) IOException(java.io.IOException)

Aggregations

JSONObject (com.ichi2.utils.JSONObject)11 IOException (java.io.IOException)10 Response (okhttp3.Response)8 MediaSyncException (com.ichi2.anki.exception.MediaSyncException)2 NoEnoughServerSpaceException (com.ichi2.anki.exception.NoEnoughServerSpaceException)2 UnknownHttpResponseException (com.ichi2.anki.exception.UnknownHttpResponseException)2 Collection (com.ichi2.libanki.Collection)2 FullSyncer (com.ichi2.libanki.sync.FullSyncer)2 HostNum (com.ichi2.libanki.sync.HostNum)2 HttpSyncer (com.ichi2.libanki.sync.HttpSyncer)2 MediaSyncer (com.ichi2.libanki.sync.MediaSyncer)2 RemoteMediaServer (com.ichi2.libanki.sync.RemoteMediaServer)2 RemoteServer (com.ichi2.libanki.sync.RemoteServer)2 Syncer (com.ichi2.libanki.sync.Syncer)2 JSONException (com.ichi2.utils.JSONException)2 FileInputStream (java.io.FileInputStream)2 SQLException (android.database.SQLException)1 Pair (android.util.Pair)1 ConflictResolution (com.ichi2.async.Connection.ConflictResolution)1 CustomSyncServerUrlException (com.ichi2.libanki.sync.CustomSyncServerUrlException)1