From 9f0f77c007cda70312f5c25c0a36b1e49eaf8d0c Mon Sep 17 00:00:00 2001 From: Aleksandr Soloshenko Date: Fri, 19 Jun 2026 08:21:44 +0700 Subject: [PATCH] [incoming] cleanup incoming messages periodically --- .../incoming/IncomingMessagesService.kt | 15 +++++ .../incoming/IncomingMessagesSettings.kt | 43 ++++++++++++++ .../incoming/db/IncomingMessagesDao.kt | 2 +- .../IncomingMessagesRepository.kt | 2 +- .../workers/IncomingLogTruncateWorker.kt | 57 +++++++++++++++++++ .../orchestrator/OrchestratorService.kt | 4 ++ .../smsgateway/modules/settings/Module.kt | 6 ++ .../modules/settings/SettingsService.kt | 3 + .../ui/settings/InboxSettingsFragment.kt | 27 +++++++++ .../ui/settings/ReceiverSettingsFragment.kt | 10 ---- app/src/main/res/drawable/ic_inbox.xml | 5 ++ app/src/main/res/values-ar/strings.xml | 5 +- app/src/main/res/values-ru/strings.xml | 5 +- app/src/main/res/values-zh/strings.xml | 5 +- app/src/main/res/values/strings.xml | 10 ++-- ..._preferences.xml => inbox_preferences.xml} | 8 ++- app/src/main/res/xml/root_preferences.xml | 8 +-- 17 files changed, 180 insertions(+), 35 deletions(-) create mode 100644 app/src/main/java/me/capcom/smsgateway/modules/incoming/IncomingMessagesSettings.kt create mode 100644 app/src/main/java/me/capcom/smsgateway/modules/incoming/workers/IncomingLogTruncateWorker.kt create mode 100644 app/src/main/java/me/capcom/smsgateway/ui/settings/InboxSettingsFragment.kt delete mode 100644 app/src/main/java/me/capcom/smsgateway/ui/settings/ReceiverSettingsFragment.kt create mode 100644 app/src/main/res/drawable/ic_inbox.xml rename app/src/main/res/xml/{receiver_preferences.xml => inbox_preferences.xml} (68%) diff --git a/app/src/main/java/me/capcom/smsgateway/modules/incoming/IncomingMessagesService.kt b/app/src/main/java/me/capcom/smsgateway/modules/incoming/IncomingMessagesService.kt index a8803b0b5..6c413a5e0 100644 --- a/app/src/main/java/me/capcom/smsgateway/modules/incoming/IncomingMessagesService.kt +++ b/app/src/main/java/me/capcom/smsgateway/modules/incoming/IncomingMessagesService.kt @@ -6,6 +6,7 @@ import me.capcom.smsgateway.helpers.SubscriptionsHelper import me.capcom.smsgateway.modules.incoming.db.IncomingMessage import me.capcom.smsgateway.modules.incoming.db.IncomingMessageType import me.capcom.smsgateway.modules.incoming.repositories.IncomingMessagesRepository +import me.capcom.smsgateway.modules.incoming.workers.IncomingLogTruncateWorker import me.capcom.smsgateway.modules.logs.LogsService import me.capcom.smsgateway.modules.logs.db.LogEntry import me.capcom.smsgateway.modules.mms.MmsAttachmentStorage @@ -13,6 +14,7 @@ import me.capcom.smsgateway.modules.receiver.data.InboxMessage class IncomingMessagesService( private val context: Context, + private val settings: IncomingMessagesSettings, private val repository: IncomingMessagesRepository, private val attachmentStorage: MmsAttachmentStorage, private val logsService: LogsService, @@ -128,6 +130,19 @@ class IncomingMessagesService( return getById(buildId(message)) != null } + fun start(context: Context) { + IncomingLogTruncateWorker.start(context) + } + + fun stop(context: Context) { + IncomingLogTruncateWorker.stop(context) + } + + suspend fun truncateLog() { + val lifetime = settings.lifetimeDays ?: return + repository.truncate(System.currentTimeMillis() - lifetime * 86400000L) + } + private fun buildId(message: InboxMessage): String { val prefix = when (message) { is InboxMessage.Data -> "data:" diff --git a/app/src/main/java/me/capcom/smsgateway/modules/incoming/IncomingMessagesSettings.kt b/app/src/main/java/me/capcom/smsgateway/modules/incoming/IncomingMessagesSettings.kt new file mode 100644 index 000000000..04c74610e --- /dev/null +++ b/app/src/main/java/me/capcom/smsgateway/modules/incoming/IncomingMessagesSettings.kt @@ -0,0 +1,43 @@ +package me.capcom.smsgateway.modules.incoming + +import me.capcom.smsgateway.modules.settings.Exporter +import me.capcom.smsgateway.modules.settings.Importer +import me.capcom.smsgateway.modules.settings.KeyValueStorage +import me.capcom.smsgateway.modules.settings.get + +class IncomingMessagesSettings( + private val storage: KeyValueStorage, +) : Exporter, Importer { + val lifetimeDays: Int? + get() = storage.get(LIFETIME_DAYS)?.takeIf { it > 0 } + + override fun export(): Map { + return mapOf( + LIFETIME_DAYS to lifetimeDays, + ) + } + + override fun import(data: Map): Boolean { + return data.map { (key, value) -> + when (key) { + LIFETIME_DAYS -> { + val lifetimeDays = value?.toString()?.toFloat()?.toInt() + if (lifetimeDays != null && lifetimeDays < 1) { + throw IllegalArgumentException("Log lifetime days must be >= 1") + } + + val changed = this.lifetimeDays != lifetimeDays + storage.set(key, lifetimeDays?.toString()) + + changed + } + + else -> false + } + }.any { it } + } + + companion object { + private const val LIFETIME_DAYS = "lifetime_days" + } +} diff --git a/app/src/main/java/me/capcom/smsgateway/modules/incoming/db/IncomingMessagesDao.kt b/app/src/main/java/me/capcom/smsgateway/modules/incoming/db/IncomingMessagesDao.kt index e54cd07a3..e56bb72c7 100644 --- a/app/src/main/java/me/capcom/smsgateway/modules/incoming/db/IncomingMessagesDao.kt +++ b/app/src/main/java/me/capcom/smsgateway/modules/incoming/db/IncomingMessagesDao.kt @@ -66,5 +66,5 @@ interface IncomingMessagesDao { fun delete(from: Long, to: Long, types: Set) @Query("DELETE FROM incoming_messages WHERE createdAt < :until") - fun truncate(until: Long) + suspend fun truncate(until: Long) } diff --git a/app/src/main/java/me/capcom/smsgateway/modules/incoming/repositories/IncomingMessagesRepository.kt b/app/src/main/java/me/capcom/smsgateway/modules/incoming/repositories/IncomingMessagesRepository.kt index b98aa1346..e241cbe89 100644 --- a/app/src/main/java/me/capcom/smsgateway/modules/incoming/repositories/IncomingMessagesRepository.kt +++ b/app/src/main/java/me/capcom/smsgateway/modules/incoming/repositories/IncomingMessagesRepository.kt @@ -30,5 +30,5 @@ class IncomingMessagesRepository(private val dao: IncomingMessagesDao) { fun insert(message: IncomingMessage) = dao.insert(message) fun delete(from: Long, to: Long, types: Set) = dao.delete(from, to, types) - fun truncate(until: Long) = dao.truncate(until) + suspend fun truncate(until: Long) = dao.truncate(until) } diff --git a/app/src/main/java/me/capcom/smsgateway/modules/incoming/workers/IncomingLogTruncateWorker.kt b/app/src/main/java/me/capcom/smsgateway/modules/incoming/workers/IncomingLogTruncateWorker.kt new file mode 100644 index 000000000..3126714f6 --- /dev/null +++ b/app/src/main/java/me/capcom/smsgateway/modules/incoming/workers/IncomingLogTruncateWorker.kt @@ -0,0 +1,57 @@ +package me.capcom.smsgateway.modules.incoming.workers + +import android.content.Context +import androidx.work.Constraints +import androidx.work.CoroutineWorker +import androidx.work.ExistingPeriodicWorkPolicy +import androidx.work.PeriodicWorkRequestBuilder +import androidx.work.WorkManager +import androidx.work.WorkerParameters +import kotlinx.coroutines.CancellationException +import me.capcom.smsgateway.modules.incoming.IncomingMessagesService +import org.koin.core.component.KoinComponent +import org.koin.core.component.inject +import java.util.concurrent.TimeUnit + +class IncomingLogTruncateWorker(appContext: Context, params: WorkerParameters) : CoroutineWorker( + appContext, + params +), KoinComponent { + private val incomingSvc: IncomingMessagesService by inject() + + override suspend fun doWork(): Result = try { + incomingSvc.truncateLog() + Result.success() + } catch (e: CancellationException) { + throw e + } catch (e: Throwable) { + e.printStackTrace() + Result.retry() + } + + companion object { + private const val NAME = "IncomingLogTruncateWorker" + + fun start(context: Context) { + val work = PeriodicWorkRequestBuilder(1L, TimeUnit.DAYS) + .setConstraints( + Constraints.Builder() + .setRequiresBatteryNotLow(true) + .build() + ) + .build() + + WorkManager.getInstance(context) + .enqueueUniquePeriodicWork( + NAME, + ExistingPeriodicWorkPolicy.KEEP, + work + ) + } + + fun stop(context: Context) { + WorkManager.getInstance(context) + .cancelUniqueWork(NAME) + } + } +} diff --git a/app/src/main/java/me/capcom/smsgateway/modules/orchestrator/OrchestratorService.kt b/app/src/main/java/me/capcom/smsgateway/modules/orchestrator/OrchestratorService.kt index c2c2006c6..13006ac8a 100644 --- a/app/src/main/java/me/capcom/smsgateway/modules/orchestrator/OrchestratorService.kt +++ b/app/src/main/java/me/capcom/smsgateway/modules/orchestrator/OrchestratorService.kt @@ -4,6 +4,7 @@ import android.content.Context import me.capcom.smsgateway.helpers.SettingsHelper import me.capcom.smsgateway.helpers.SubscriptionsHelper import me.capcom.smsgateway.modules.gateway.GatewayService +import me.capcom.smsgateway.modules.incoming.IncomingMessagesService import me.capcom.smsgateway.modules.localserver.LocalServerService import me.capcom.smsgateway.modules.logs.LogsService import me.capcom.smsgateway.modules.logs.db.LogEntry @@ -16,6 +17,7 @@ import me.capcom.smsgateway.modules.webhooks.payload.AppStartedPayload class OrchestratorService( private val messagesSvc: MessagesService, + private val incomingSvc: IncomingMessagesService, private val gatewaySvc: GatewayService, private val localServerSvc: LocalServerService, private val webHooksSvc: WebHooksService, @@ -31,6 +33,7 @@ class OrchestratorService( logsSvc.start(context) messagesSvc.start(context) + incomingSvc.start(context) webHooksSvc.start(context) gatewaySvc.start(context) @@ -71,6 +74,7 @@ class OrchestratorService( gatewaySvc.stop(context) webHooksSvc.stop(context) messagesSvc.stop(context) + incomingSvc.stop(context) logsSvc.stop(context) } } \ No newline at end of file diff --git a/app/src/main/java/me/capcom/smsgateway/modules/settings/Module.kt b/app/src/main/java/me/capcom/smsgateway/modules/settings/Module.kt index 71aef8691..4a62df7f4 100644 --- a/app/src/main/java/me/capcom/smsgateway/modules/settings/Module.kt +++ b/app/src/main/java/me/capcom/smsgateway/modules/settings/Module.kt @@ -4,6 +4,7 @@ import androidx.preference.PreferenceManager import me.capcom.smsgateway.helpers.SettingsHelper import me.capcom.smsgateway.modules.encryption.EncryptionSettings import me.capcom.smsgateway.modules.gateway.GatewaySettings +import me.capcom.smsgateway.modules.incoming.IncomingMessagesSettings import me.capcom.smsgateway.modules.localserver.LocalServerSettings import me.capcom.smsgateway.modules.logs.LogsSettings import me.capcom.smsgateway.modules.messages.MessagesSettings @@ -46,6 +47,11 @@ val settingsModule = module { PreferencesStorage(get(), "ping") ) } + factory { + IncomingMessagesSettings( + PreferencesStorage(get(), "incoming") + ) + } factory { LogsSettings( PreferencesStorage(get(), "logs") diff --git a/app/src/main/java/me/capcom/smsgateway/modules/settings/SettingsService.kt b/app/src/main/java/me/capcom/smsgateway/modules/settings/SettingsService.kt index 34c9999be..b793e519f 100644 --- a/app/src/main/java/me/capcom/smsgateway/modules/settings/SettingsService.kt +++ b/app/src/main/java/me/capcom/smsgateway/modules/settings/SettingsService.kt @@ -4,6 +4,7 @@ import android.content.Context import me.capcom.smsgateway.R import me.capcom.smsgateway.modules.encryption.EncryptionSettings import me.capcom.smsgateway.modules.gateway.GatewaySettings +import me.capcom.smsgateway.modules.incoming.IncomingMessagesSettings import me.capcom.smsgateway.modules.logs.LogsSettings import me.capcom.smsgateway.modules.messages.MessagesSettings import me.capcom.smsgateway.modules.notifications.NotificationsService @@ -15,6 +16,7 @@ class SettingsService( private val notificationsService: NotificationsService, encryptionSettings: EncryptionSettings, gatewaySettings: GatewaySettings, + incomingMessagesSettings: IncomingMessagesSettings, messagesSettings: MessagesSettings, pingSettings: PingSettings, logsSettings: LogsSettings, @@ -23,6 +25,7 @@ class SettingsService( private val settings = mapOf( "encryption" to encryptionSettings, "gateway" to gatewaySettings, + "incoming" to incomingMessagesSettings, "messages" to messagesSettings, "ping" to pingSettings, "logs" to logsSettings, diff --git a/app/src/main/java/me/capcom/smsgateway/ui/settings/InboxSettingsFragment.kt b/app/src/main/java/me/capcom/smsgateway/ui/settings/InboxSettingsFragment.kt new file mode 100644 index 000000000..ec3965488 --- /dev/null +++ b/app/src/main/java/me/capcom/smsgateway/ui/settings/InboxSettingsFragment.kt @@ -0,0 +1,27 @@ +package me.capcom.smsgateway.ui.settings + +import android.os.Bundle +import android.text.InputType +import androidx.preference.EditTextPreference +import androidx.preference.Preference +import me.capcom.smsgateway.R + +class InboxSettingsFragment : BasePreferenceFragment() { + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { + setPreferencesFromResource(R.xml.inbox_preferences, rootKey) + } + + override fun onDisplayPreferenceDialog(preference: Preference) { + when (preference.key) { + "incoming.lifetime_days" -> { + (preference as EditTextPreference).setOnBindEditTextListener { + it.inputType = InputType.TYPE_CLASS_NUMBER + it.setSelectAllOnFocus(true) + it.selectAll() + } + } + } + + super.onDisplayPreferenceDialog(preference) + } +} diff --git a/app/src/main/java/me/capcom/smsgateway/ui/settings/ReceiverSettingsFragment.kt b/app/src/main/java/me/capcom/smsgateway/ui/settings/ReceiverSettingsFragment.kt deleted file mode 100644 index 0956ff38d..000000000 --- a/app/src/main/java/me/capcom/smsgateway/ui/settings/ReceiverSettingsFragment.kt +++ /dev/null @@ -1,10 +0,0 @@ -package me.capcom.smsgateway.ui.settings - -import android.os.Bundle -import me.capcom.smsgateway.R - -class ReceiverSettingsFragment : BasePreferenceFragment() { - override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { - setPreferencesFromResource(R.xml.receiver_preferences, rootKey) - } -} diff --git a/app/src/main/res/drawable/ic_inbox.xml b/app/src/main/res/drawable/ic_inbox.xml new file mode 100644 index 000000000..43e408d4f --- /dev/null +++ b/app/src/main/res/drawable/ic_inbox.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index dff9e4ecd..35296b84d 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -12,8 +12,7 @@ استمرار بواسطة الكود يمكن أن يؤثر على عمر البطارية - انقر + انقر فوق استمرار لإنشاء حساب. لا يلزم تقديم معلومات شخصية.\nمن خلال الاستمرار، فإنك توافق على سياسة الخصوصية الخاصة بنا على https://docs.sms-gate.app/privacy/policy/ خادم السحاب… @@ -60,7 +59,6 @@ الرسائل الرسائل… الحد الأدنى - مزيد من الإعدادات… غير متاح تم تسجيل ويب هوك جديد للرسائل المستلمة لم يتم تكوين ويب هوك @@ -68,7 +66,6 @@ لم يحدد SMSGate قناة الإشعارات - الإشعارات حالة الاتصال بالإنترنت على حساب عمر البطارية كلمة السر diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 92f600bc9..52b70bd34 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -12,8 +12,7 @@ Продолжить По коду может влиять на время работы батареи - Нажмите + Нажмите \"Продолжить\", чтобы создать аккаунт. Личная информация не требуется.\nПродолжая, вы соглашаетесь с Политикой конфиденциальности по адресу https://docs.sms-gate.app/privacy/policy/ @@ -61,7 +60,6 @@ Сообщения Сообщения… Минимум - Другие настройки… н/д Зарегистрирован новый вебхук для входящих сообщений @@ -70,7 +68,6 @@ Не задано SMSGate Канал уведомлений - Уведомления Время автономной работы может быть снижено Ключ шифрования diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index 968206c16..c6b0bd646 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -10,8 +10,7 @@ 继续 通过验证码 可能影响电池寿命 - 点击"继续"创建账户,无需提供个人信息。\n继续即表示您同意我们的隐私政策,详情见 + 点击"继续"创建账户,无需提供个人信息。\n继续即表示您同意我们的隐私政策,详情见 https://docs.sms-gate.app/privacy/policy/ 云服务器… 云服务器 @@ -56,7 +55,6 @@ 消息 消息… 最小值 - 更多设置… 无数据 已注册新短信接收 Webhook 未配置 Webhook @@ -64,7 +62,6 @@ 未设置 短信网关 通知渠道 - 通知 保持在线状态(可能消耗更多电量) 密码短语 密码修改成功 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 72adfc8f7..f6606c1ae 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -12,8 +12,7 @@ Continue By Code can affect battery life - Click + Click Continue to create an account. No personal information is required.\nBy continuing, you agree to our Privacy Policy at https://docs.sms-gate.app/privacy/policy/ Cloud server… @@ -61,7 +60,6 @@ Messages Messages… Minimum - More settings… n/a New SMS Received Webhooks registered No webhooks configured @@ -69,7 +67,6 @@ Not set SMSGate Notification channel - Notifications Online status at the cost of battery life Passphrase @@ -146,8 +143,6 @@ Processing Processing order - Receiver - Content provider monitoring, fallback, etc. Content Provider Monitoring Also detect incoming SMS via content provider @@ -181,4 +176,7 @@ Language System default Password must not be empty + Inbox… + Content provider monitoring, retention, etc. + Inbox \ No newline at end of file diff --git a/app/src/main/res/xml/receiver_preferences.xml b/app/src/main/res/xml/inbox_preferences.xml similarity index 68% rename from app/src/main/res/xml/receiver_preferences.xml rename to app/src/main/res/xml/inbox_preferences.xml index d578afd92..5e6a70573 100644 --- a/app/src/main/res/xml/receiver_preferences.xml +++ b/app/src/main/res/xml/inbox_preferences.xml @@ -1,12 +1,18 @@ - + + + diff --git a/app/src/main/res/xml/root_preferences.xml b/app/src/main/res/xml/root_preferences.xml index a1aa966e1..760d763ee 100644 --- a/app/src/main/res/xml/root_preferences.xml +++ b/app/src/main/res/xml/root_preferences.xml @@ -18,10 +18,10 @@ app:summary="@string/delays_limits_etc" /> + android:icon="@drawable/ic_inbox" + app:fragment="me.capcom.smsgateway.ui.settings.InboxSettingsFragment" + app:summary="@string/inbox_settings_summary" + app:title="@string/inbox_dotdotdot" />