Search in sources :

Example 66 with JSONObject

use of com.ichi2.utils.JSONObject 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 67 with JSONObject

use of com.ichi2.utils.JSONObject in project AnkiChinaAndroid by ankichinateam.

the class Syncer method sync.

/**
 * Returns 'noChanges', 'fullSync', 'success', etc
 */
// public Object[] sync() throws UnknownHttpResponseException {
// return sync(null);
// }
public Object[] sync(Connection con, long restSpace) throws UnknownHttpResponseException, NoEnoughServerSpaceException {
    mSyncMsg = "";
    setRestSpace(restSpace);
    // if the deck has any pending changes, flush them first and bump mod time
    mCol.getSched()._updateCutoff();
    mCol.save();
    // step 1: login & metadata
    Response ret = mServer.meta();
    if (ret == null) {
        return null;
    }
    int returntype = ret.code();
    if (returntype == 403) {
        return new Object[] { "badAuth" };
    }
    try {
        mCol.getDb().getDatabase().beginTransaction();
        try {
            Timber.i("Sync: getting meta data from server");
            JSONObject rMeta = new JSONObject(ret.body().string());
            mCol.log("rmeta", rMeta);
            mSyncMsg = rMeta.getString("msg");
            if (!rMeta.getBoolean("cont")) {
                // Don't add syncMsg; it can be fetched by UI code using the accessor
                return new Object[] { "serverAbort" };
            } else {
            // don't abort, but ui should show messages after sync finishes
            // and require confirmation if it's non-empty
            }
            throwExceptionIfCancelled(con);
            long rscm = rMeta.getLong("scm");
            int rts = rMeta.getInt("ts");
            mRMod = rMeta.getLong("mod");
            mMaxUsn = rMeta.getInt("usn");
            // skip uname, AnkiDroid already stores and shows it
            trySetHostNum(rMeta);
            Timber.i("Sync: building local meta data");
            JSONObject lMeta = meta();
            mCol.log("lmeta", lMeta);
            mLMod = lMeta.getLong("mod");
            mMinUsn = lMeta.getInt("usn");
            long lscm = lMeta.getLong("scm");
            int lts = lMeta.getInt("ts");
            long diff = Math.abs(rts - lts);
            if (diff > 300) {
                mCol.log("clock off");
                return new Object[] { "clockOff", diff };
            }
            if (mLMod == mRMod) {
                Timber.i("Sync: no changes - returning");
                mCol.log("no changes");
                return new Object[] { "noChanges" };
            } else if (lscm != rscm) {
                Timber.i("Sync: full sync necessary - returning");
                mCol.log("schema diff");
                return new Object[] { "fullSync" };
            }
            mLNewer = mLMod > mRMod;
            // step 1.5: check collection is valid
            if (!mCol.basicCheck()) {
                mCol.log("basic check");
                return new Object[] { "basicCheckFailed" };
            }
            throwExceptionIfCancelled(con);
            // step 2: deletions
            publishProgress(con, R.string.sync_deletions_message);
            Timber.i("Sync: collection removed data");
            JSONObject lrem = removed();
            JSONObject o = new JSONObject();
            o.put("minUsn", mMinUsn);
            o.put("lnewer", mLNewer);
            o.put("graves", lrem);
            Timber.i("Sync: sending and receiving removed data");
            JSONObject rrem = mServer.start(o);
            Timber.i("Sync: applying removed data");
            throwExceptionIfCancelled(con);
            remove(rrem);
            // ... and small objects
            publishProgress(con, R.string.sync_small_objects_message);
            Timber.i("Sync: collection small changes");
            JSONObject lchg = changes();
            JSONObject sch = new JSONObject();
            sch.put("changes", lchg);
            Timber.i("Sync: sending and receiving small changes");
            long needSize = sch.toString().length();
            Timber.i("Sync: sending and receiving small changes size:%d", needSize);
            if (needSize > restSpace && Consts.loginAnkiChina()) {
                throwExceptionIfNoSpace(needSize, restSpace);
            } else {
                restSpace -= needSize;
                setRestSpace(restSpace);
                Timber.i("Sync: remain size %d after for small changes ", restSpace);
            }
            JSONObject rchg = mServer.applyChanges(sch);
            throwExceptionIfCancelled(con);
            Timber.i("Sync: merging small changes");
            try {
                mergeChanges(lchg, rchg);
            } catch (UnexpectedSchemaChange e) {
                mServer.abort();
                _forceFullSync();
            }
            // step 3: stream large tables from server
            publishProgress(con, R.string.sync_download_chunk);
            while (true) {
                throwExceptionIfCancelled(con);
                Timber.i("Sync: downloading chunked data");
                JSONObject chunk = mServer.chunk();
                mCol.log("server chunk", chunk);
                Timber.i("Sync: applying chunked data");
                applyChunk(chunk);
                if (chunk.getBoolean("done")) {
                    break;
                }
            }
            // step 4: stream to server
            publishProgress(con, R.string.sync_upload_chunk);
            List<JSONObject> sechs = new ArrayList<>();
            long chunkSize = 0;
            while (true) {
                throwExceptionIfCancelled(con);
                Timber.i("Sync: collecting chunked data");
                JSONObject chunk = chunk();
                mCol.log("client chunk", chunk);
                JSONObject sech = new JSONObject();
                sech.put("chunk", chunk);
                chunkSize += sech.toString().length();
                sechs.add(sech);
                if (chunk.getBoolean("done")) {
                    break;
                }
            }
            Timber.i("Sync: sending chunked data:%d", chunkSize);
            if (chunkSize > restSpace && Consts.loginAnkiChina()) {
                throwExceptionIfNoSpace(chunkSize, restSpace);
            } else {
                restSpace -= chunkSize;
                setRestSpace(restSpace);
            }
            for (JSONObject object : sechs) {
                mServer.applyChunk(object);
            }
            // step 5: sanity check
            JSONObject c = sanityCheck();
            JSONObject sanity = mServer.sanityCheck2(c);
            if (sanity == null || !"ok".equals(sanity.optString("status", "bad"))) {
                mCol.log("sanity check failed", c, sanity);
                return _forceFullSync();
            }
            // finalize
            publishProgress(con, R.string.sync_finish_message);
            Timber.i("Sync: sending finish command");
            long mod = mServer.finish();
            if (mod == 0) {
                return new Object[] { "finishError" };
            }
            Timber.i("Sync: finishing");
            finish(mod);
            publishProgress(con, R.string.sync_writing_db);
            mCol.getDb().getDatabase().setTransactionSuccessful();
        } catch (NoEnoughServerSpaceException e) {
            // mCol.getDb().getDatabase().endTransaction();
            throw new NoEnoughServerSpaceException(e.rest, e.need);
        // e.printStackTrace();
        // mCol.getDb().getDatabase().endTransaction();
        // return new Object[] {"noServerSpace", e.rest, e.need};
        } finally {
            mCol.getDb().getDatabase().endTransaction();
        }
    } catch (NoEnoughServerSpaceException e) {
        Timber.e("NoEnoughServerSpaceException ");
        throw new NoEnoughServerSpaceException(e.rest, e.need);
    // e.printStackTrace();
    // mCol.getDb().getDatabase().endTransaction();
    // return new Object[] {"noServerSpace", e.rest, e.need};
    } catch (IllegalStateException e) {
        throw new RuntimeException(e);
    } catch (OutOfMemoryError e) {
        AnkiDroidApp.sendExceptionReport(e, "Syncer-sync");
        return new Object[] { "OutOfMemoryError" };
    } catch (IOException e) {
        AnkiDroidApp.sendExceptionReport(e, "Syncer-sync");
        return new Object[] { "IOException" };
    }
    return new Object[] { "success", restSpace };
}
Also used : ArrayList(java.util.ArrayList) IOException(java.io.IOException) Response(okhttp3.Response) JSONObject(com.ichi2.utils.JSONObject) JSONObject(com.ichi2.utils.JSONObject) NoEnoughServerSpaceException(com.ichi2.anki.exception.NoEnoughServerSpaceException)

Example 68 with JSONObject

use of com.ichi2.utils.JSONObject in project AnkiChinaAndroid by ankichinateam.

the class Syncer method applyChanges.

public JSONObject applyChanges(JSONObject changes) throws UnexpectedSchemaChange {
    mRChg = changes;
    JSONObject lchg = changes();
    // merge our side before returning
    mergeChanges(lchg, mRChg);
    return lchg;
}
Also used : JSONObject(com.ichi2.utils.JSONObject)

Example 69 with JSONObject

use of com.ichi2.utils.JSONObject in project AnkiChinaAndroid by ankichinateam.

the class Syncer method getModels.

/**
 * Models ********************************************************************
 */
private JSONArray getModels() {
    JSONArray result = new JSONArray();
    if (mCol.getServer()) {
        for (JSONObject m : mCol.getModels().all()) {
            if (m.getInt("usn") >= mMinUsn) {
                result.put(m);
            }
        }
    } else {
        for (JSONObject m : mCol.getModels().all()) {
            if (m.getInt("usn") == -1) {
                m.put("usn", mMaxUsn);
                result.put(m);
            }
        }
        mCol.getModels().save();
    }
    return result;
}
Also used : JSONObject(com.ichi2.utils.JSONObject) JSONArray(com.ichi2.utils.JSONArray)

Example 70 with JSONObject

use of com.ichi2.utils.JSONObject in project AnkiChinaAndroid by ankichinateam.

the class Syncer method chunk.

public JSONObject chunk() {
    JSONObject buf = new JSONObject();
    buf.put("done", false);
    int lim = 250;
    List<Integer> colTypes = null;
    while (!mTablesLeft.isEmpty() && lim > 0) {
        String curTable = mTablesLeft.getFirst();
        if (mCursor == null) {
            mCursor = cursorForTable(curTable);
        }
        colTypes = columnTypesForQuery(curTable);
        JSONArray rows = new JSONArray();
        int count = mCursor.getColumnCount();
        int fetched = 0;
        while (mCursor.moveToNext()) {
            JSONArray r = new JSONArray();
            for (int i = 0; i < count; i++) {
                switch(colTypes.get(i)) {
                    case TYPE_STRING:
                        r.put(mCursor.getString(i));
                        break;
                    case TYPE_FLOAT:
                        r.put(mCursor.getDouble(i));
                        break;
                    case TYPE_INTEGER:
                        r.put(mCursor.getLong(i));
                        break;
                }
            }
            rows.put(r);
            if (++fetched == lim) {
                break;
            }
        }
        if (fetched != lim) {
            // table is empty
            mTablesLeft.removeFirst();
            mCursor.close();
            mCursor = null;
            // if we're the client, mark the objects as having been sent
            if (!mCol.getServer()) {
                mCol.getDb().execute("UPDATE " + curTable + " SET usn=" + mMaxUsn + " WHERE usn=-1");
            }
        }
        buf.put(curTable, rows);
        lim -= fetched;
    }
    if (mTablesLeft.isEmpty()) {
        buf.put("done", true);
    }
    return buf;
}
Also used : JSONObject(com.ichi2.utils.JSONObject) JSONArray(com.ichi2.utils.JSONArray)

Aggregations

JSONObject (com.ichi2.utils.JSONObject)272 JSONArray (com.ichi2.utils.JSONArray)110 ArrayList (java.util.ArrayList)59 Test (org.junit.Test)55 Collection (com.ichi2.libanki.Collection)46 IOException (java.io.IOException)40 RobolectricTest (com.ichi2.anki.RobolectricTest)34 JSONException (com.ichi2.utils.JSONException)34 Note (com.ichi2.libanki.Note)33 Model (com.ichi2.libanki.Model)31 HashMap (java.util.HashMap)31 SuppressLint (android.annotation.SuppressLint)29 JSONObject (org.json.JSONObject)27 Response (okhttp3.Response)25 JSONException (org.json.JSONException)24 NonNull (androidx.annotation.NonNull)23 Card (com.ichi2.libanki.Card)21 File (java.io.File)21 Map (java.util.Map)20 Intent (android.content.Intent)19