Files
Questionnaire-App/app/src/main/java/com/dano/test1/DatabaseUploader.kt

202 lines
7.6 KiB
Kotlin

package com.dano.test1
import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.util.Base64
import android.util.Log
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import android.database.Cursor
import okhttp3.*
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody.Companion.asRequestBody
import org.json.JSONArray
import org.json.JSONObject
import java.io.File
import java.io.IOException
import kotlin.system.exitProcess
object DatabaseUploader {
private const val DB_NAME = "questionnaire_database"
private const val SERVER_FULL_URL = "http://49.13.157.44/uploadFull.php"
private const val SERVER_DELTA_URL = "http://49.13.157.44/uploadDelta.php"
private const val SERVER_CHECK_URL = "http://49.13.157.44/checkDatabaseExists.php"
private const val API_TOKEN = "MEIN_SUPER_GEHEIMES_TOKEN_12345"
private val client = OkHttpClient()
fun uploadDatabase(context: Context) {
CoroutineScope(Dispatchers.IO).launch {
try {
val dbFile = context.getDatabasePath(DB_NAME)
if (!dbFile.exists()) {
Log.e("UPLOAD", "Datenbankdatei existiert nicht: ${dbFile.absolutePath}")
return@launch
}
// WAL-Checkpoint
try {
val db = SQLiteDatabase.openDatabase(
dbFile.absolutePath,
null,
SQLiteDatabase.OPEN_READWRITE
)
db.rawQuery("PRAGMA wal_checkpoint(FULL);", null).use { cursor ->
if (cursor.moveToFirst()) {
try {
Log.d("UPLOAD", "WAL-Checkpoint result: ${cursor.getInt(0)}")
} catch (_: Exception) {}
}
}
db.close()
Log.d("UPLOAD", "WAL-Checkpoint erfolgreich.")
} catch (e: Exception) {
Log.e("UPLOAD", "Fehler beim WAL-Checkpoint", e)
}
val exists = checkDatabaseExists()
if (exists) {
Log.d("UPLOAD", "Server-Datenbank vorhanden → Delta-Upload")
uploadDelta(dbFile)
} else {
Log.d("UPLOAD", "Keine Server-Datenbank → Full-Upload")
uploadFull(dbFile)
}
} catch (e: Exception) {
Log.e("UPLOAD", "Fehler beim Hochladen der DB", e)
}
}
}
private fun checkDatabaseExists(): Boolean {
return try {
val request = Request.Builder()
.url(SERVER_CHECK_URL)
.get()
.build()
client.newCall(request).execute().use { response ->
if (!response.isSuccessful) {
Log.e("UPLOAD", "checkDatabaseExists HTTP error: ${response.code}")
return false
}
val body = response.body?.string() ?: return false
try {
val j = JSONObject(body)
j.optBoolean("exists", false)
} catch (e: Exception) {
body.contains("exists", ignoreCase = true)
}
}
} catch (e: Exception) {
Log.e("UPLOAD", "Fehler bei Server-Prüfung", e)
false
}
}
private fun uploadFull(file: File) {
val requestBody = MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart(
"file", file.name,
file.asRequestBody("application/octet-stream".toMediaTypeOrNull())
)
.addFormDataPart("token", API_TOKEN)
.build()
val request = Request.Builder()
.url(SERVER_FULL_URL)
.post(requestBody)
.build()
client.newCall(request).enqueue(serverCallback(file))
}
private fun uploadDelta(file: File) {
try {
val db = SQLiteDatabase.openDatabase(file.absolutePath, null, SQLiteDatabase.OPEN_READONLY)
val data = JSONObject().apply {
put("clients", queryToJsonArray(db, "SELECT clientCode FROM clients"))
put("questionnaires", queryToJsonArray(db, "SELECT id FROM questionnaires"))
put("questions", queryToJsonArray(db, "SELECT questionId, questionnaireId, question FROM questions"))
put("answers", queryToJsonArray(db, "SELECT clientCode, questionId, answerValue FROM answers"))
put("completed_questionnaires",
queryToJsonArray(db, "SELECT clientCode, questionnaireId, timestamp, isDone, sumPoints FROM completed_questionnaires")
)
}
db.close()
val requestBody = MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("token", API_TOKEN)
.addFormDataPart("data", data.toString())
.build()
val request = Request.Builder()
.url(SERVER_DELTA_URL)
.post(requestBody)
.build()
client.newCall(request).enqueue(serverCallback(file))
} catch (e: Exception) {
Log.e("UPLOAD", "Fehler beim Delta-Upload", e)
}
}
private fun queryToJsonArray(db: SQLiteDatabase, query: String): JSONArray {
val cursor = db.rawQuery(query, null)
val jsonArray = JSONArray()
cursor.use {
val columnNames = it.columnNames
while (it.moveToNext()) {
val obj = JSONObject()
for (col in columnNames) {
val idx = it.getColumnIndex(col)
if (idx >= 0) {
when (it.getType(idx)) {
Cursor.FIELD_TYPE_INTEGER -> obj.put(col, it.getLong(idx))
Cursor.FIELD_TYPE_FLOAT -> obj.put(col, it.getDouble(idx))
Cursor.FIELD_TYPE_STRING -> obj.put(col, it.getString(idx))
Cursor.FIELD_TYPE_NULL -> obj.put(col, JSONObject.NULL)
Cursor.FIELD_TYPE_BLOB -> {
val blob = it.getBlob(idx)
obj.put(col, Base64.encodeToString(blob, Base64.NO_WRAP))
}
else -> obj.put(col, it.getString(idx))
}
}
}
jsonArray.put(obj)
}
}
return jsonArray
}
private fun serverCallback(file: File) = object : Callback {
override fun onFailure(call: Call, e: IOException) {
Log.e("UPLOAD", "Upload fehlgeschlagen: ${e.message}")
}
override fun onResponse(call: Call, response: Response) {
val body = try { response.body?.string() ?: "Keine Response" } catch (e: Exception) { "Fehler beim Lesen der Response: ${e.message}" }
if (response.isSuccessful) {
Log.d("UPLOAD", "Upload erfolgreich: $body")
if (file.delete()) {
Log.d("UPLOAD", "Lokale DB gelöscht.")
exitProcess(0)
} else {
Log.e("UPLOAD", "Löschen der lokalen DB fehlgeschlagen.")
}
} else {
Log.e("UPLOAD", "Upload fehlgeschlagen: ${response.code} $body")
}
}
}
}