Use JSON format when backing up calls and messages

This commit is contained in:
Juha Heinanen
2026-07-28 09:21:21 +03:00
parent c23f77addd
commit 0a231f6542
4 changed files with 89 additions and 25 deletions

View File

@ -578,6 +578,7 @@ class BaresipService: Service() {
CallHistoryNew.restore()
Blocked.restore()
BlockRule.restore()
Message.restore()
val recordings = File(filesDir, "recordings")
@ -586,6 +587,7 @@ class BaresipService: Service() {
Log.d(TAG, "Clearing recordings")
CallHistoryNew.clearRecordings()
CallHistoryNew.save()
Message.save()
if (recordings.exists())
recordings.deleteRecursively()
restored.delete()
@ -593,8 +595,6 @@ class BaresipService: Service() {
File(filesDir, "recordings").mkdir()
File(filesDir, "tmp").mkdir()
Message.restore()
}.start()
hotSpotAddresses = Utils.hotSpotAddresses()

View File

@ -1,18 +1,22 @@
package com.tutpro.baresip
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.IOException
import java.io.ObjectInputStream
import java.io.ObjectOutputStream
import java.io.Serializable
import java.util.GregorianCalendar
class CallHistoryNew(val aor: String, val peerUri: String, val direction: String) : Serializable {
@Serializable
class CallHistoryNew(val aor: String, val peerUri: String, val direction: String) : java.io.Serializable {
// Set to time when call is established (if ever) or stopTime if call was completed elsewhere
@Serializable(with = Utils.GregorianCalendarSerializer::class)
var startTime: GregorianCalendar? = null
@Serializable(with = Utils.GregorianCalendarSerializer::class)
var stopTime = GregorianCalendar() // Set to time when call is closed
var rejected = false
var recording = arrayOf("", "") // Encoder and decoder recording files, merged file is in [0]
@ -77,31 +81,49 @@ class CallHistoryNew(val aor: String, val peerUri: String, val direction: String
}
Log.d(TAG, "Saving history of ${historyCopy.size} calls")
val file = File(BaresipService.filesPath + "/call_history")
try {
val jsonString = Json.encodeToString(historyCopy)
file.writeText(jsonString)
} catch (e: Exception) {
Log.e(TAG, "Serialization exception: $e")
try {
val fos = FileOutputStream(file)
val oos = ObjectOutputStream(fos)
oos.writeObject(historyCopy)
oos.close()
fos.close()
} catch (e: IOException) {
Log.e(TAG, "OutputStream exception: $e")
e.printStackTrace()
} catch (e2: IOException) {
Log.e(TAG, "OutputStream exception: $e2")
}
}
}
fun restore() {
val file = File(BaresipService.filesPath + "/call_history")
if (file.exists()) {
val content = file.readText()
if (content.startsWith("[")) {
try {
val restoredHistory = Json.decodeFromString<List<CallHistoryNew>>(content)
BaresipService.callHistory = ArrayList(restoredHistory)
Log.d(TAG, "Restored history of ${BaresipService.callHistory.size} calls from JSON")
return
} catch (e: Exception) {
Log.d(TAG, "JSON restore failed, trying Java serialization: $e")
}
}
try {
val fis = FileInputStream(file)
val ois = ObjectInputStream(fis)
@Suppress("UNCHECKED_CAST")
val restoredHistory = ois.readObject() as? List<CallHistoryNew>
if (restoredHistory != null)
if (restoredHistory != null) {
BaresipService.callHistory = ArrayList(restoredHistory)
Log.d(TAG, "Restored history of ${BaresipService.callHistory.size} calls from Java")
save()
}
ois.close()
fis.close()
Log.d(TAG, "Restored history of ${BaresipService.callHistory.size} calls")
} catch (e: Exception) {
Log.e(TAG, "InputStream exception: - $e")
}

View File

@ -1,10 +1,13 @@
package com.tutpro.baresip
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import java.io.*
@Serializable
class Message(val aor: String, val peerUri: String, val message: String, val timeStamp: Long,
var direction: Int, var responseCode: Int, var responseReason: String,
var new: Boolean): Serializable {
var new: Boolean): java.io.Serializable {
fun add() {
val updatedMessages = synchronized(BaresipService.messages) {
@ -42,6 +45,9 @@ class Message(val aor: String, val peerUri: String, val message: String, val tim
companion object {
@Suppress("unused")
const val serialVersionUID: Long = 434313168853691766L
const val MESSAGE_HISTORY_SIZE = 100
fun messages(): List<Message> {
@ -132,31 +138,51 @@ class Message(val aor: String, val peerUri: String, val message: String, val tim
BaresipService.messages.toList()
}
val file = File(BaresipService.filesPath, "messages")
try {
val jsonString = Json.encodeToString(messagesCopy)
file.writeText(jsonString)
Log.d(TAG, "Saved ${messagesCopy.size} messages in JSON")
} catch (e: Exception) {
Log.e(TAG, "Serialization exception", e)
try {
val fos = FileOutputStream(file)
val oos = ObjectOutputStream(fos)
oos.writeObject(messagesCopy)
oos.close()
fos.close()
Log.d(TAG, "Saved ${messagesCopy.size} messages")
} catch (e: IOException) {
Log.e(TAG, "OutputStream exception", e)
Log.d(TAG, "Saved ${messagesCopy.size} messages in Java")
} catch (e2: IOException) {
Log.e(TAG, "OutputStream exception", e2)
}
}
}
fun restore() {
val file = File(BaresipService.filesPath, "messages")
if (file.exists()) {
val content = file.readText()
if (content.startsWith("[")) {
try {
val restoredMessages = Json.decodeFromString<List<Message>>(content)
BaresipService.messages = restoredMessages
Log.d(TAG, "Restored ${BaresipService.messages.size} messages from JSON")
return
} catch (e: Exception) {
Log.d(TAG, "JSON restore failed, trying Java serialization: $e")
}
}
try {
val fis = FileInputStream(file)
val ois = ObjectInputStream(fis)
@Suppress("UNCHECKED_CAST")
val restoredMessages = ois.readObject() as? List<Message>
if (restoredMessages != null)
if (restoredMessages != null) {
BaresipService.messages = restoredMessages
Log.d(TAG, "Restored ${BaresipService.messages.size} messages from Java")
save()
}
ois.close()
fis.close()
Log.d(TAG, "Restored ${BaresipService.messages.size} messages")
} catch (e: Exception) {
Log.e(TAG, "InputStream exception: - $e")
}

View File

@ -55,6 +55,12 @@ import androidx.lifecycle.Lifecycle
import androidx.lifecycle.ProcessLifecycleOwner
import androidx.navigation.NavController
import com.tutpro.baresip.Call.Companion.inCall
import kotlinx.serialization.KSerializer
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import java.io.BufferedInputStream
import java.io.BufferedOutputStream
import java.io.File
@ -1579,4 +1585,14 @@ object Utils {
if (p1.routes != p2.routes) return false
return true
}
object GregorianCalendarSerializer : KSerializer<GregorianCalendar> {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("GregorianCalendar", PrimitiveKind.LONG)
override fun serialize(encoder: Encoder, value: GregorianCalendar) = encoder.encodeLong(value.timeInMillis)
override fun deserialize(decoder: Decoder): GregorianCalendar {
val calendar = GregorianCalendar()
calendar.timeInMillis = decoder.decodeLong()
return calendar
}
}
}