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

View File

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

View File

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

View File

@ -55,6 +55,12 @@ import androidx.lifecycle.Lifecycle
import androidx.lifecycle.ProcessLifecycleOwner import androidx.lifecycle.ProcessLifecycleOwner
import androidx.navigation.NavController import androidx.navigation.NavController
import com.tutpro.baresip.Call.Companion.inCall 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.BufferedInputStream
import java.io.BufferedOutputStream import java.io.BufferedOutputStream
import java.io.File import java.io.File
@ -1579,4 +1585,14 @@ object Utils {
if (p1.routes != p2.routes) return false if (p1.routes != p2.routes) return false
return true 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
}
}
} }