Message Dupe Features

pull/369/head
Mike 2024-12-18 16:45:47 -08:00
rodzic ec0e3224da
commit ab221cc679
5 zmienionych plików z 71 dodań i 17 usunięć

Wyświetl plik

@ -240,6 +240,7 @@
<string name="p_aprsis_udp">UDP (send only)</string>
<!-- array of TNC link types -->
<string name="p_link_bt">Bluetooth SPP</string>
<string name="p_link_ble">Bluetooth Low Energy</string>
<string name="p_link_tcpip">TCP/IP</string>
<string name="p_link_usb">USB Serial</string>
<!-- array of location sources -->
@ -360,7 +361,7 @@
<string name="status_linkon">Connected: %s</string>
<string name="p_messaging">Messaging Preferences</string>
<string name="p_messaging_preferences">Set Messaging Retry &amp; Ack Options</string>
<string name="p_messaging_preferences">Advanced Messaging Options</string>
<string name="p_message_retry">Message Retries</string>
<string name="p_message_retry_entry">Number of messages to retry</string>
<string name="p_message_retry_summary">Message retry limit</string>
@ -369,13 +370,19 @@
<string name="p_retry_interval_entry">Retry interval start rate</string>
<string name="p_retry_interval_summary">Rate doubles each retry</string>
<string name="p_ackdupe_interval">Ack Dupe Timeout</string>
<string name="p_ackdupe_interval">Ack Dupe Timeout or Disable</string>
<string name="p_ackdupe_interval_entry">Ack dupe timeout (0 = ack disabled)</string>
<string name="p_ackdupe_interval_summary">Dupe timeout</string>
<string name="p_ackdupe_interval_summary">Dupe acks allowed after timeout</string>
<string name="p_ackdupetoggle">Ack Dupe Timeout</string>
<string name="p_ackdupetoggle_summary">Enable</string>
<string name="p_ackdupetoggle_summary">Sends dupe acks after the timeout period</string>
<string name="p_msgdupetoggle">Duplicate Messages</string>
<string name="p_msgdupetoggle_summary">Allows dupe messages after timeout period</string>
<string name="p_msgdupetime_summary">Duplicate messages allowed after timeout</string>
<string name="p_msgdupetime_entry">Dupe message timeout (0 = disabled)</string>
<string name="p_msgdupetime_title">Dupe Message Timeout</string>
<!-- AFSK settings -->
<string name="p_aprs_path">APRS digi path</string>

Wyświetl plik

@ -34,5 +34,20 @@
android:summary="@string/p_ackdupe_interval_summary"
android:dialogTitle="@string/p_ackdupe_interval_entry" />
<CheckBoxPreference
android:key="p.msgdupetoggle"
android:title="@string/p_msgdupetoggle"
android:summary="@string/p_msgdupetoggle_summary"
android:defaultValue="false" />
<de.duenndns.EditTextPreferenceWithValue
android:key="p.msgdupetime"
android:defaultValue="30"
android:hint="30"
android:inputType="number"
android:title="@string/p_msgdupetime_title"
android:summary="@string/p_msgdupetime_summary"
android:dialogTitle="@string/p_msgdupetime_entry" />
</PreferenceScreen>

Wyświetl plik

@ -30,7 +30,7 @@ class MessagingPrefs extends PreferenceActivity with OnSharedPreferenceChangeLis
// Called when a shared preference is changed
override def onSharedPreferenceChanged(sp: SharedPreferences, key: String): Unit = {
key match {
case "p.messaging" | "p.retry" | "p.ackdupetoggle" | "p.ackdupe" =>
case "p.messaging" | "p.retry" | "p.ackdupetoggle" | "p.ackdupe" | "p.msgdupetoggle" | "p.msgdupetime" =>
setPreferenceScreen(null) // Clear the current preference screen
loadXml() // Reload the preferences to reflect any changes
case _ => // Ignore other keys

Wyświetl plik

@ -21,6 +21,9 @@ class PrefsWrapper(val context : Context) {
def isAckDupeEnabled(): Boolean = {
prefs.getBoolean("p.ackdupetoggle", false)
}
def isMsgDupeEnabled(): Boolean = {
prefs.getBoolean("p.msgdupetoggle", false)
}
def isMetric(): Boolean = {
prefs.getString("p.units", "1") == "1" // "1" for metric, "2" for imperial
}

Wyświetl plik

@ -7,6 +7,7 @@ import _root_.android.database.sqlite.SQLiteDatabase
import _root_.android.database.Cursor
import _root_.android.util.Log
import _root_.android.widget.FilterQueryProvider
import _root_.android.preference.PreferenceManager
import _root_.net.ab0oo.aprs.parser._
@ -183,6 +184,8 @@ class StorageDatabase(context : Context) extends
null, StorageDatabase.DB_VERSION) {
import StorageDatabase._
lazy val prefs = new PrefsWrapper(context)
override def onCreate(db: SQLiteDatabase) {
Log.d(TAG, "onCreate(): creating new database " + DB_NAME);
db.execSQL(Post.TABLE_CREATE);
@ -259,21 +262,47 @@ class StorageDatabase(context : Context) extends
getWritableDatabase().replaceOrThrow(TABLE, CALL, cv)
}
def isMessageDuplicate(call : String, msgid : String, text : String) : Boolean = {
val c = getReadableDatabase().query(Message.TABLE, Message.COLUMNS,
"type = 1 AND call = ? AND msgid = ? AND text = ?",
Array(call, msgid, text),
null, null,
null, null)
val result = (c.getCount() > 0)
c.close()
result
def isMessageDuplicate(call: String, msgid: String, text: String, currentTs: Long): Boolean = {
// Prepare the base query conditions
val selection = "type = 1 AND call = ? AND msgid = ? AND text = ?"
val selectionArgs = Array(call, msgid, text)
var query: String = selection
var args: Array[String] = selectionArgs
// If message duplication is enabled, add the time threshold condition
if (prefs.isMsgDupeEnabled) {
val msgDupetime = prefs.getStringInt("p.msgdupetime", 30)
val timeThreshold = currentTs - (msgDupetime * 1000)
// If msgDupetime is 0, return false immediately (no duplication check)
if (msgDupetime == 0) {
return false
}
query += " AND ts >= ?"
args = args :+ timeThreshold.toString
}
// Perform the database query with the constructed query and args
val cursor = getReadableDatabase().query(
Message.TABLE,
Message.COLUMNS,
query,
args,
null, null, null, null
)
// Check if there are any results (cursor.getCount() could be replaced with cursor.moveToFirst())
val result = cursor.moveToFirst() // Checks if at least one record is found
cursor.close()
result
}
// add an incoming message, returns false if duplicate
def addMessage(ts : Long, srccall : String, msg : MessagePacket) : Boolean = {
// Add an incoming message, returns false if duplicate
def addMessage(ts: Long, srccall: String, msg: MessagePacket): Boolean = {
import Message._
if (isMessageDuplicate(srccall, msg.getMessageNumber(), msg.getMessageBody())) {
// Check if the message is a duplicate considering timestamp
if (isMessageDuplicate(srccall, msg.getMessageNumber(), msg.getMessageBody(), ts)) {
Log.i(TAG, "received duplicate message from %s: %s".format(srccall, msg))
return false
}