Search in sources :

Example 1 with Upgrade

use of com.ichi2.upgrade.Upgrade in project AnkiChinaAndroid by ankichinateam.

the class FullSyncer method download.

@Override
public Object[] download() throws UnknownHttpResponseException {
    InputStream cont;
    ResponseBody body = null;
    try {
        Response ret = super.req("download");
        if (ret == null || ret.body() == null) {
            return null;
        }
        body = ret.body();
        cont = body.byteStream();
    } catch (IllegalArgumentException e1) {
        if (body != null) {
            body.close();
        }
        throw new RuntimeException(e1);
    }
    String path;
    if (mCol != null) {
        Timber.i("Closing collection for full sync");
        // Usual case where collection is non-null
        path = mCol.getPath();
        mCol.close();
        mCol = null;
    } else {
        // Allow for case where collection is completely unreadable
        Timber.w("Collection was unexpectedly null when doing full sync download");
        path = CollectionHelper.getCollectionPath(AnkiDroidApp.getInstance());
    }
    String tpath = path + ".tmp";
    try {
        super.writeToFile(cont, tpath);
        Timber.d("Full Sync - Downloaded temp file");
        FileInputStream fis = new FileInputStream(tpath);
        if ("upgradeRequired".equals(super.stream2String(fis, 15))) {
            Timber.w("Full Sync - 'Upgrade Required' message received");
            return new Object[] { "upgradeRequired" };
        }
    } catch (FileNotFoundException e) {
        Timber.e(e, "Failed to create temp file when downloading collection.");
        throw new RuntimeException(e);
    } catch (IOException e) {
        Timber.e(e, "Full sync failed to download collection.");
        return new Object[] { "sdAccessError" };
    } finally {
        body.close();
    }
    // check the received file is ok
    mCon.publishProgress(R.string.sync_check_download_file);
    DB tempDb = null;
    try {
        tempDb = new DB(tpath);
        if (!"ok".equalsIgnoreCase(tempDb.queryString("PRAGMA integrity_check"))) {
            Timber.e("Full sync - downloaded file corrupt");
            return new Object[] { "remoteDbError" };
        }
    } catch (SQLiteDatabaseCorruptException e) {
        Timber.e("Full sync - downloaded file corrupt");
        return new Object[] { "remoteDbError" };
    } finally {
        if (tempDb != null) {
            tempDb.close();
        }
    }
    Timber.d("Full Sync: Downloaded file was not corrupt");
    // overwrite existing collection
    File newFile = new File(tpath);
    if (newFile.renameTo(new File(path))) {
        Timber.i("Full Sync Success: Overwritten collection with downloaded file");
        return new Object[] { "success" };
    } else {
        Timber.w("Full Sync: Error overwriting collection with downloaded file");
        return new Object[] { "overwriteError" };
    }
}
Also used : FileInputStream(java.io.FileInputStream) InputStream(java.io.InputStream) FileNotFoundException(java.io.FileNotFoundException) SQLiteDatabaseCorruptException(android.database.sqlite.SQLiteDatabaseCorruptException) IOException(java.io.IOException) FileInputStream(java.io.FileInputStream) ResponseBody(okhttp3.ResponseBody) Response(okhttp3.Response) File(java.io.File) DB(com.ichi2.libanki.DB)

Example 2 with Upgrade

use of com.ichi2.upgrade.Upgrade in project Anki-Android by ankidroid.

the class DeckPicker method onFinishedStartup.

/**
 * Perform the following tasks:
 * Automatic backup
 * loadStudyOptionsFragment() if tablet
 * Automatic sync
 */
private void onFinishedStartup() {
    // create backup in background if needed
    BackupManager.performBackupInBackground(getCol().getPath(), getCol().getTime());
    // Force a full sync if flag was set in upgrade path, asking the user to confirm if necessary
    if (mRecommendFullSync) {
        mRecommendFullSync = false;
        try {
            getCol().modSchema();
        } catch (ConfirmModSchemaException e) {
            Timber.w("Forcing full sync");
            e.log();
            // If libanki determines it's necessary to confirm the full sync then show a confirmation dialog
            // We have to show the dialog via the DialogHandler since this method is called via an async task
            Resources res = getResources();
            Message handlerMessage = Message.obtain();
            handlerMessage.what = DialogHandler.MSG_SHOW_FORCE_FULL_SYNC_DIALOG;
            Bundle handlerMessageData = new Bundle();
            handlerMessageData.putString("message", res.getString(R.string.full_sync_confirmation_upgrade) + "\n\n" + res.getString(R.string.full_sync_confirmation));
            handlerMessage.setData(handlerMessageData);
            getDialogHandler().sendMessage(handlerMessage);
        }
    }
    automaticSync();
}
Also used : Message(android.os.Message) Bundle(android.os.Bundle) ConfirmModSchemaException(com.ichi2.anki.exception.ConfirmModSchemaException) Resources(android.content.res.Resources)

Example 3 with Upgrade

use of com.ichi2.upgrade.Upgrade in project Anki-Android by ankidroid.

the class Syncer method sanityCheck.

public JSONObject sanityCheck() {
    JSONObject result = new JSONObject();
    try {
        if (mCol.getDb().queryScalar("SELECT count() FROM cards WHERE nid NOT IN (SELECT id FROM notes)") != 0) {
            Timber.e("Sync - SanityCheck: there are cards without mother notes");
            result.put("client", "missing notes");
            return result;
        }
        if (mCol.getDb().queryScalar("SELECT count() FROM notes WHERE id NOT IN (SELECT DISTINCT nid FROM cards)") != 0) {
            Timber.e("Sync - SanityCheck: there are notes without cards");
            result.put("client", "missing cards");
            return result;
        }
        if (mCol.getDb().queryScalar("SELECT count() FROM cards WHERE usn = -1") != 0) {
            Timber.e("Sync - SanityCheck: there are unsynced cards");
            result.put("client", "cards had usn = -1");
            return result;
        }
        if (mCol.getDb().queryScalar("SELECT count() FROM notes WHERE usn = -1") != 0) {
            Timber.e("Sync - SanityCheck: there are unsynced notes");
            result.put("client", "notes had usn = -1");
            return result;
        }
        if (mCol.getDb().queryScalar("SELECT count() FROM revlog WHERE usn = -1") != 0) {
            Timber.e("Sync - SanityCheck: there are unsynced revlogs");
            result.put("client", "revlog had usn = -1");
            return result;
        }
        if (mCol.getDb().queryScalar("SELECT count() FROM graves WHERE usn = -1") != 0) {
            Timber.e("Sync - SanityCheck: there are unsynced graves");
            result.put("client", "graves had usn = -1");
            return result;
        }
        for (Deck g : mCol.getDecks().all()) {
            if (g.getInt("usn") == -1) {
                Timber.e("Sync - SanityCheck: unsynced deck: %s", g.getString("name"));
                result.put("client", "deck had usn = -1");
                return result;
            }
        }
        if (mCol.getTags().minusOneValue()) {
            Timber.e("Sync - SanityCheck: there are unsynced tags");
            result.put("client", "tag had usn = -1");
            return result;
        }
        boolean found = false;
        for (JSONObject m : mCol.getModels().all()) {
            if (mCol.getServer()) {
                // the web upgrade was mistakenly setting usn
                if (m.getInt("usn") < 0) {
                    m.put("usn", 0);
                    found = true;
                }
            } else {
                if (m.getInt("usn") == -1) {
                    Timber.e("Sync - SanityCheck: unsynced model: %s", m.getString("name"));
                    result.put("client", "model had usn = -1");
                    return result;
                }
            }
        }
        if (found) {
            mCol.getModels().save();
        }
        // check for missing parent decks
        mCol.getSched().deckDueList();
        // return summary of deck
        JSONArray check = new JSONArray();
        JSONArray counts = new JSONArray();
        // #5666 - not in libAnki
        // We modified mReportLimit inside the scheduler, and this causes issues syncing dynamic decks.
        AbstractSched syncScheduler = mCol.createScheduler(SYNC_SCHEDULER_REPORT_LIMIT);
        syncScheduler.resetCounts();
        Counts counts_ = syncScheduler.counts();
        counts.put(counts_.getNew());
        counts.put(counts_.getLrn());
        counts.put(counts_.getRev());
        check.put(counts);
        check.put(mCol.getDb().queryScalar("SELECT count() FROM cards"));
        check.put(mCol.getDb().queryScalar("SELECT count() FROM notes"));
        check.put(mCol.getDb().queryScalar("SELECT count() FROM revlog"));
        check.put(mCol.getDb().queryScalar("SELECT count() FROM graves"));
        check.put(mCol.getModels().all().size());
        check.put(mCol.getDecks().all().size());
        check.put(mCol.getDecks().allConf().size());
        result.put("client", check);
        return result;
    } catch (JSONException e) {
        Timber.e(e, "Syncer.sanityCheck()");
        throw new RuntimeException(e);
    }
}
Also used : Counts(com.ichi2.libanki.sched.Counts) JSONObject(com.ichi2.utils.JSONObject) AbstractSched(com.ichi2.libanki.sched.AbstractSched) JSONArray(com.ichi2.utils.JSONArray) Deck(com.ichi2.libanki.Deck) JSONException(com.ichi2.utils.JSONException)

Example 4 with Upgrade

use of com.ichi2.upgrade.Upgrade in project Anki-Android by ankidroid.

the class FullSyncer method download.

@NonNull
public ConnectionResultType download() throws UnknownHttpResponseException {
    InputStream cont;
    ResponseBody body = null;
    try {
        Response ret = super.req("download");
        if (ret == null || ret.body() == null) {
            return null;
        }
        body = ret.body();
        cont = body.byteStream();
    } catch (IllegalArgumentException e1) {
        if (body != null) {
            body.close();
        }
        throw new RuntimeException(e1);
    }
    String path;
    if (mCol != null) {
        Timber.i("Closing collection for full sync");
        // Usual case where collection is non-null
        path = mCol.getPath();
        mCol.close();
        mCol = null;
    } else {
        // Allow for case where collection is completely unreadable
        Timber.w("Collection was unexpectedly null when doing full sync download");
        path = CollectionHelper.getCollectionPath(AnkiDroidApp.getInstance());
    }
    String tpath = path + ".tmp";
    try {
        super.writeToFile(cont, tpath);
        Timber.d("Full Sync - Downloaded temp file");
        FileInputStream fis = new FileInputStream(tpath);
        if ("upgradeRequired".equals(super.stream2String(fis, 15))) {
            Timber.w("Full Sync - 'Upgrade Required' message received");
            return UPGRADE_REQUIRED;
        }
    } catch (FileNotFoundException e) {
        Timber.e(e, "Failed to create temp file when downloading collection.");
        throw new RuntimeException(e);
    } catch (IOException e) {
        Timber.e(e, "Full sync failed to download collection.");
        return SD_ACCESS_ERROR;
    } finally {
        body.close();
    }
    // check the received file is ok
    mCon.publishProgress(R.string.sync_check_download_file);
    DB tempDb = null;
    try {
        tempDb = new DB(tpath);
        if (!"ok".equalsIgnoreCase(tempDb.queryString("PRAGMA integrity_check"))) {
            Timber.e("Full sync - downloaded file corrupt");
            return REMOTE_DB_ERROR;
        }
    } catch (SQLiteDatabaseCorruptException e) {
        Timber.e("Full sync - downloaded file corrupt");
        return REMOTE_DB_ERROR;
    } finally {
        if (tempDb != null) {
            tempDb.close();
        }
    }
    Timber.d("Full Sync: Downloaded file was not corrupt");
    // overwrite existing collection
    File newFile = new File(tpath);
    if (newFile.renameTo(new File(path))) {
        Timber.i("Full Sync Success: Overwritten collection with downloaded file");
        return SUCCESS;
    } else {
        Timber.w("Full Sync: Error overwriting collection with downloaded file");
        return OVERWRITE_ERROR;
    }
}
Also used : Response(okhttp3.Response) FileInputStream(java.io.FileInputStream) InputStream(java.io.InputStream) FileNotFoundException(java.io.FileNotFoundException) SQLiteDatabaseCorruptException(android.database.sqlite.SQLiteDatabaseCorruptException) IOException(java.io.IOException) File(java.io.File) FileInputStream(java.io.FileInputStream) DB(com.ichi2.libanki.DB) ResponseBody(okhttp3.ResponseBody) NonNull(androidx.annotation.NonNull)

Example 5 with Upgrade

use of com.ichi2.upgrade.Upgrade in project Anki-Android by ankidroid.

the class RustTest method collectionIsVersion11AfterOpen.

@Test
public void collectionIsVersion11AfterOpen() throws BackendException, IOException {
    // This test will be decommissioned, but before we get an upgrade strategy, we need to ensure we're not upgrading the database.
    String path = Shared.getTestFilePath(getTestContext(), "initial_version_2_12_1.anki2");
    Collection collection = Storage.Collection(getTestContext(), path);
    int ver = collection.getDb().queryScalar("select ver from col");
    MatcherAssert.assertThat(ver, is(11));
}
Also used : Collection(com.ichi2.libanki.Collection) Test(org.junit.Test)

Aggregations

File (java.io.File)7 Intent (android.content.Intent)6 SharedPreferences (android.content.SharedPreferences)6 View (android.view.View)6 Resources (android.content.res.Resources)5 Bundle (android.os.Bundle)5 TextView (android.widget.TextView)5 Collection (com.ichi2.libanki.Collection)5 JSONException (com.ichi2.utils.JSONException)5 SQLiteDatabaseCorruptException (android.database.sqlite.SQLiteDatabaseCorruptException)4 Message (android.os.Message)4 NonNull (androidx.annotation.NonNull)4 SearchView (androidx.appcompat.widget.SearchView)4 ConfirmModSchemaException (com.ichi2.anki.exception.ConfirmModSchemaException)4 FileInputStream (java.io.FileInputStream)4 FileNotFoundException (java.io.FileNotFoundException)4 IOException (java.io.IOException)4 InputStream (java.io.InputStream)4 List (java.util.List)4 BroadcastReceiver (android.content.BroadcastReceiver)3