Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 14 additions & 15 deletions Common/src/main/java/tk/glucodata/TelegramStaleCheckWork.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@ import java.util.concurrent.ConcurrentHashMap
*
* The producer ([OutboundApi.sendTelegram]) calls [schedule] right after a
* successful send. We queue a single [Runnable] per destination in a static
* [Handler]; when it fires, we call the Telegram editMessageText endpoint to
* rewrite the existing bubble to "⚠️ Stale." (at the stale threshold) or
* "βšͺ Missed reading." (at the missed threshold). The edit is best-effort:
* if the bubble was deleted, the API returns an error and we give up.
* [Handler]; when it fires, we post a **new** Telegram message ("⚠️ Stale" at
* the stale threshold, "βšͺ Missed reading" at the missed threshold) rather than
* editing the bubble. This preserves the last valid reading in the bubble and
* leaves stale/missed events as distinct, timestamped messages in the chat
* history for easy retrospective review.
*
* Limitation: this is in-process only. If the app process is killed between
* sends, the stale check is lost until the next CGM reading arrives and
Expand Down Expand Up @@ -78,11 +79,11 @@ object TelegramStaleCheckWork {
}
val lastStaleMs = destination.lastStaleAtMsByRecipient[recipient] ?: 0L
if (lastStaleMs > 0L && now - lastStaleMs < 30_000L) continue // throttle
val messageId = destination.lastMessageIdByRecipient[recipient] ?: 0L
if (messageId <= 0L) continue
val hasActiveBubble = (destination.lastMessageIdByRecipient[recipient] ?: 0L) > 0L
if (!hasActiveBubble) continue

val text = renderStaleText(status, now)
val result = postEdit(destination, recipient, messageId, text)
val result = postSend(destination, recipient, text)
when (result) {
true -> {
OutboundApiSettings.recordStaleAt(context, destinationId, recipient, now)
Expand All @@ -92,8 +93,8 @@ object TelegramStaleCheckWork {
}
}
false -> {
// Definitive Telegram rejection (bubble deleted) β€” clear state
// so next reading starts a fresh bubble.
// Definitive Telegram rejection (bot blocked, wrong chat_id, etc.) β€” clear
// state so next reading starts a fresh bubble.
OutboundApiSettings.clearRecipientState(
context = context,
destinationId = destinationId,
Expand Down Expand Up @@ -122,25 +123,23 @@ object TelegramStaleCheckWork {
}

/**
* Posts a new stale/missed message to the chat (does not edit the existing bubble).
* Returns true on 2xx, false on a definitive API rejection (4xx),
* null on transient network failure (caller should leave state intact).
*/
private fun postEdit(
private fun postSend(
destination: OutboundApiSettings.Destination,
recipient: String,
messageId: Long,
text: String
): Boolean? {
val editUrl = destination.resolvedUrl()
.replace(Regex("/sendMessage$"), "/editMessageText")
val sendUrl = destination.resolvedUrl()
val body = JSONObject()
.put("chat_id", recipient)
.put("message_id", messageId)
.put("text", text)
.toString()
.toByteArray(Charsets.UTF_8)
return try {
val connection = (URL(editUrl).openConnection() as HttpURLConnection).apply {
val connection = (URL(sendUrl).openConnection() as HttpURLConnection).apply {
requestMethod = "POST"
connectTimeout = 20_000
readTimeout = 30_000
Expand Down
Loading