From 5f1ee513f2b77e046b0184d2b3092457e3bc0900 Mon Sep 17 00:00:00 2001 From: Kr328 <39107975+Kr328@users.noreply.github.com> Date: Thu, 20 Feb 2020 00:54:16 +0800 Subject: [PATCH] fix 1 -> 2 migration --- .../service/data/ClashDatabaseMigrations.kt | 146 ++++++++++++------ 1 file changed, 95 insertions(+), 51 deletions(-) diff --git a/service/src/main/java/com/github/kr328/clash/service/data/ClashDatabaseMigrations.kt b/service/src/main/java/com/github/kr328/clash/service/data/ClashDatabaseMigrations.kt index 6e0f6da..5c819c6 100644 --- a/service/src/main/java/com/github/kr328/clash/service/data/ClashDatabaseMigrations.kt +++ b/service/src/main/java/com/github/kr328/clash/service/data/ClashDatabaseMigrations.kt @@ -4,71 +4,115 @@ import android.content.ContentValues import android.database.sqlite.SQLiteDatabase import androidx.room.migration.Migration import androidx.sqlite.db.SupportSQLiteDatabase -import java.security.SecureRandom -import kotlin.math.absoluteValue +import com.github.kr328.clash.core.Global +import com.github.kr328.clash.core.utils.Log +import com.github.kr328.clash.service.Constants +import com.github.kr328.clash.service.util.resolveBase +import com.github.kr328.clash.service.util.resolveProfile +import java.io.File object ClashDatabaseMigrations { val VERSION_1_2 = object : Migration(1, 2) { - override fun migrate(database: SupportSQLiteDatabase) { - database.beginTransaction() - + private fun process(database: SupportSQLiteDatabase) { database.execSQL("ALTER TABLE profiles RENAME TO _profiles") + database.execSQL("ALTER TABLE profile_select_proxies RENAME TO _profile_select_proxies") - database.execSQL( - "CREATE TABLE profiles(" + - "name TEXT NOT NULL, " + - "type INTEGER NOT NULL, " + - "uri TEXT NOT NULL, " + - "file TEXT NOT NULL, " + - "base TEXT NOT NULL" + - "active INTEGER NOT NULL, " + - "last_update INTEGER NOT NULL, " + - "id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)" - ) + database.execSQL("CREATE TABLE IF NOT EXISTS `profiles` (`name` TEXT NOT NULL, `type` INTEGER NOT NULL, `uri` TEXT NOT NULL, `source` TEXT, `active` INTEGER NOT NULL, `last_update` INTEGER NOT NULL, `update_interval` INTEGER NOT NULL, `id` INTEGER NOT NULL, PRIMARY KEY(`id`))") + database.execSQL("CREATE TABLE IF NOT EXISTS `profile_select_proxies` (`profile_id` INTEGER NOT NULL, `proxy` TEXT NOT NULL, `selected` TEXT NOT NULL, PRIMARY KEY(`profile_id`, `proxy`), FOREIGN KEY(`profile_id`) REFERENCES `profiles`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )") - val cursor = - database.query("SELECT name, token, file, active, last_update FROM _profile") - val random = SecureRandom() - val bases = mutableSetOf() + try { + val cursor = + database.query("SELECT name, token, file, active, last_update, id FROM _profiles") - cursor.moveToFirst() - while (!cursor.isAfterLast) { - // old - val name = cursor.getString(0) - val token = cursor.getString(1) - val file = cursor.getString(2) - val active = cursor.getInt(3) - val lastUpdate = cursor.getLong(4) - - // new - val type = when { - token.startsWith("url") -> ClashProfileEntity.TYPE_URL - token.startsWith("file") -> ClashProfileEntity.TYPE_FILE - else -> ClashProfileEntity.TYPE_UNKNOWN + Global.application.filesDir.resolve(Constants.CLASH_DIR).listFiles()?.forEach { + it.deleteRecursively() } - val uri = token.removePrefix("url|").removePrefix("file|") - var base = random.nextLong().absoluteValue - while (bases.contains(base)) - base = random.nextLong().absoluteValue + cursor.moveToFirst() + while (!cursor.isAfterLast) { + // old + // name, token, file, active, last_update, id + val name = cursor.getString(0) + val token = cursor.getString(1) + val file = cursor.getString(2) + val active = cursor.getInt(3) + val lastUpdate = cursor.getLong(4) + val id = cursor.getLong(5) - database.insert("profiles", - SQLiteDatabase.CONFLICT_ABORT, - ContentValues().apply { - put("name", name) - put("type", type) - put("uri", uri) - put("file", file) - put("active", active) - put("last_update", lastUpdate) - put("base", base.toString()) - }) + // new + // name, type, uri, source, active, last_update, update_interval, id + val type = when { + token.startsWith("url") -> ClashProfileEntity.TYPE_URL + token.startsWith("file") -> ClashProfileEntity.TYPE_FILE + else -> ClashProfileEntity.TYPE_UNKNOWN + } + + File(file).renameTo(resolveProfile(id)) + resolveBase(id).mkdirs() + + database.insert("profiles", + SQLiteDatabase.CONFLICT_ABORT, + ContentValues().apply { + put("name", name) + put("type", type) + put("uri", token.removePrefix("url|").removePrefix("file|")) + putNull("source") + put("active", active) + put("last_update", lastUpdate) + put("update_interval", 0) + put("id", id) + }) + + cursor.moveToNext() + } + cursor.close() + } + catch (e: Exception) { + Log.d("Migration profiles failure", e) + } + + try { + val cursor = database.query("SELECT profile_id, proxy, selected FROM _profile_select_proxies ORDER BY id") + + cursor.moveToFirst() + while (!cursor.isAfterLast) { + // old + // profile_id, proxy, selected, id + val profileId = cursor.getLong(0) + val proxy: String = cursor.getString(1) + val selected = cursor.getString(2) + + // new + // profile_id, proxy, selected + + database.insert("profile_select_proxies", + SQLiteDatabase.CONFLICT_REPLACE, + ContentValues().apply { + put("profile_id", profileId) + put("proxy", proxy) + put("selected", selected) + }) + + cursor.moveToNext() + } + cursor.close() + } + catch (e: Exception) { + Log.d("Migration selected failure") } - cursor.close() database.execSQL("DROP TABLE _profiles") + database.execSQL("DROP TABLE _profile_select_proxies") + } - database.endTransaction() + override fun migrate(database: SupportSQLiteDatabase) { + try { + process(database) + Log.i("Database Migrated 1 -> 2") + } + catch (e: Exception) { + Log.e("Migration failure", e) + } } } } \ No newline at end of file