make things slightly nicer?

This commit is contained in:
Karmanyaah Malhotra 2023-12-16 22:45:26 -06:00
parent 9d38118dcb
commit eb1c8300ab
6 changed files with 33 additions and 36 deletions

View file

@ -11,7 +11,6 @@ import java.io.IOException
import java.net.URLEncoder import java.net.URLEncoder
import java.nio.charset.StandardCharsets.UTF_8 import java.nio.charset.StandardCharsets.UTF_8
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import kotlin.random.Random
class ApiService { class ApiService {
private val client = OkHttpClient.Builder() private val client = OkHttpClient.Builder()
@ -97,7 +96,7 @@ class ApiService {
val body = response.body?.string()?.trim() val body = response.body?.string()?.trim()
if (body.isNullOrEmpty()) return emptyList() if (body.isNullOrEmpty()) return emptyList()
val notifications = body.lines().mapNotNull { line -> val notifications = body.lines().mapNotNull { line ->
parser.parse(line, subscriptionId = subscriptionId, notificationId = 0) // No notification when we poll parser.parseNotification(line, subscriptionId = subscriptionId, notificationId = 0) // No notification when we poll
} }
Log.d(TAG, "Notifications: $notifications") Log.d(TAG, "Notifications: $notifications")

View file

@ -6,7 +6,6 @@ import io.heckel.ntfy.db.Action
import io.heckel.ntfy.db.Attachment import io.heckel.ntfy.db.Attachment
import io.heckel.ntfy.db.Icon import io.heckel.ntfy.db.Icon
import io.heckel.ntfy.db.Notification import io.heckel.ntfy.db.Notification
import io.heckel.ntfy.util.Log
import io.heckel.ntfy.util.joinTags import io.heckel.ntfy.util.joinTags
import io.heckel.ntfy.util.toPriority import io.heckel.ntfy.util.toPriority
import java.lang.reflect.Type import java.lang.reflect.Type
@ -15,19 +14,16 @@ class NotificationParser {
private val gson = Gson() private val gson = Gson()
fun parseMessage(s: String) : Message? { fun parseMessage(s: String) : Message? {
return gson.fromJson(s, Message::class.java)
val message= gson.fromJson(s, Message::class.java)
Log.d("HITAGME", message.toString())
return message
} }
fun parse(s: String, subscriptionId: Long = 0, notificationId: Int = 0): Notification? { fun parseNotification(s: String, subscriptionId: Long = 0, notificationId: Int = 0): Notification? {
val message = parseMessage(s) ?: return null val message = parseMessage(s) ?: return null
val notificationWithTopic = parseWithTopic(message, subscriptionId = subscriptionId, notificationId = notificationId) val notificationWithTopic = parseNotificationWithTopic(message, subscriptionId = subscriptionId, notificationId = notificationId)
return notificationWithTopic?.notification return notificationWithTopic?.notification
} }
fun parseWithTopic(message: Message, subscriptionId: Long = 0, notificationId: Int = 0): NotificationWithTopic? { fun parseNotificationWithTopic(message: Message, subscriptionId: Long = 0, notificationId: Int = 0): NotificationWithTopic? {
if (message.event != ApiService.EVENT_MESSAGE) { if (message.event != ApiService.EVENT_MESSAGE) {
return null return null
} }

View file

@ -43,7 +43,7 @@ class JsonConnection(
while (isActive && serviceActive()) { while (isActive && serviceActive()) {
Log.d(TAG, "[$url] (Re-)starting connection for subscriptions: $topicsToSubscriptionIds") Log.d(TAG, "[$url] (Re-)starting connection for subscriptions: $topicsToSubscriptionIds")
val startTime = System.currentTimeMillis() val startTime = System.currentTimeMillis()
val notify = notify@ { message : Message -> val notify = { message : Message ->
since = notificationListener(ConnectionId(baseUrl, topicsToSubscriptionIds, topicIsUnifiedPush), message)?: since since = notificationListener(ConnectionId(baseUrl, topicsToSubscriptionIds, topicIsUnifiedPush), message)?: since
} }
val failed = AtomicBoolean(false) val failed = AtomicBoolean(false)

View file

@ -15,7 +15,6 @@ import io.heckel.ntfy.R
import io.heckel.ntfy.app.Application import io.heckel.ntfy.app.Application
import io.heckel.ntfy.db.ConnectionState import io.heckel.ntfy.db.ConnectionState
import io.heckel.ntfy.db.Repository import io.heckel.ntfy.db.Repository
import io.heckel.ntfy.db.Subscription
import io.heckel.ntfy.msg.ApiService import io.heckel.ntfy.msg.ApiService
import io.heckel.ntfy.msg.Message import io.heckel.ntfy.msg.Message
import io.heckel.ntfy.msg.NotificationDispatcher import io.heckel.ntfy.msg.NotificationDispatcher
@ -252,18 +251,18 @@ class SubscriberService : Service() {
} }
private fun onConnectionOpen(connectionId: ConnectionId, message: String?) { private fun onConnectionOpen(connectionId: ConnectionId, message: String?) {
Log.d(TAG, "Received open from connection to ${connectionId.baseUrl} with message: $message") Log.d(TAG, "Received open from connection ${connectionId.baseUrl} with message: $message")
// TODO extract constant // this check is sufficient for now, and the message can be upgraded to include other parameters in the future
if (message?.contains(ApiService.EVENT_OPEN_PARAM_NEW_TOPIC) == true) { if (message?.contains(ApiService.EVENT_OPEN_PARAM_NEW_TOPIC) == true) {
val connectionId = connectionId.copy() // TODO does this deep copy
GlobalScope.launch(Dispatchers.IO) { GlobalScope.launch(Dispatchers.IO) {
for (topic in connectionId.topicsToSubscriptionIds.keys) for (topic in connectionId.topicsToSubscriptionIds.keys) {
if (connectionId.topicIsUnifiedPush[topic] == true){ if (connectionId.topicIsUnifiedPush[topic] == true) {
io.heckel.ntfy.up.BroadcastReceiver.sendRegistration(baseContext, connectionId.baseUrl, topic) io.heckel.ntfy.up.BroadcastReceiver.sendRegistration(baseContext, connectionId.baseUrl, topic)
// TODO is that the right context
// looks like it works???
Log.d(TAG, "Attempting to re-register ${connectionId.baseUrl}/$topic") Log.d(TAG, "Attempting to re-register ${connectionId.baseUrl}/$topic")
} }
// TODO is that the right context }
// looks like it works???
} }
} }
} }
@ -271,21 +270,19 @@ class SubscriberService : Service() {
repository.updateState(subscriptionIds, state) repository.updateState(subscriptionIds, state)
} }
// return successfully processed ID, else null // Process messages received from the server, and dispatch a notification if required.
// Return the ID of the notification if successfully processed, else null.
private fun onNotificationReceived(connectionId: ConnectionId, message: Message) : String? { private fun onNotificationReceived(connectionId: ConnectionId, message: Message) : String? {
if (message.event == ApiService.EVENT_OPEN) { if (message.event == ApiService.EVENT_OPEN) {
onConnectionOpen(connectionId, message.message) onConnectionOpen(connectionId, message.message)
return null return null
} }
val notificationWithTopic = parser.parseWithTopic(message, notificationId = Random.nextInt(), subscriptionId = 0
) ?: return null// subscriptionId to be set downstream
val (topic, notificationWoId) = notificationWithTopic val (topic, notificationWithoutId) = parser.parseNotificationWithTopic(message, notificationId = Random.nextInt(), subscriptionId = 0)
?: return null // subscriptionId to be set downstream
val subscriptionId = connectionId.topicsToSubscriptionIds[topic] ?: return null val subscriptionId = connectionId.topicsToSubscriptionIds[topic] ?: return null
val subscription = val subscription = repository.getSubscription(subscriptionId) ?: return null
repository.getSubscription(subscriptionId) ?: return null val notification = notificationWithoutId.copy(subscriptionId = subscription.id)
val notification =
notificationWoId.copy(subscriptionId = subscription.id)
// Wakelock while notifications are being dispatched // Wakelock while notifications are being dispatched
// Wakelocks are reference counted by default so that should work neatly here // Wakelocks are reference counted by default so that should work neatly here

View file

@ -61,8 +61,8 @@ class WsConnection(
private val topicIsUnifiedPush = connectionId.topicIsUnifiedPush private val topicIsUnifiedPush = connectionId.topicIsUnifiedPush
private val subscriptionIds = topicsToSubscriptionIds.values private val subscriptionIds = topicsToSubscriptionIds.values
private val topicsStr = topicsToSubscriptionIds.keys.joinToString(separator = ",") private val topicsStr = topicsToSubscriptionIds.keys.joinToString(separator = ",")
private val unifiedPushTopicsStr = private val unifiedPushTopicsStr = topicIsUnifiedPush.filter { entry -> entry.value
topicIsUnifiedPush.filter { entry -> entry.value }.keys.joinToString(separator = ",") }.keys.joinToString(separator = ",")
private val shortUrl = topicShortUrl(baseUrl, topicsStr) private val shortUrl = topicShortUrl(baseUrl, topicsStr)
init { init {

View file

@ -93,10 +93,13 @@ class BroadcastReceiver : android.content.BroadcastReceiver() {
try { try {
// Note, this may fail due to a SQL constraint exception, see https://github.com/binwiederhier/ntfy/issues/185 // Note, this may fail due to a SQL constraint exception, see https://github.com/binwiederhier/ntfy/issues/185
repository.addSubscription(subscription) repository.addSubscription(subscription)
//distributor.sendEndpoint(appId, connectorToken, endpoint) /* We don't send the endpoint here anymore, the foreground service will do that after
//lets wait to subscribe, THEN, send registering with the push server. This avoids a race condition where the application server
is rejected before ntfy even establishes that this topic exists.
This is fine from an application perspective, because other distributors can't even register
without a connection to the push server. */
// Refresh (and maybe start) foreground service //Refresh (and maybe start) foreground service
SubscriberServiceManager.refresh(app) SubscriberServiceManager.refresh(app)
} catch (e: Exception) { } catch (e: Exception) {
Log.w(TAG, "Failed to add subscription", e) Log.w(TAG, "Failed to add subscription", e)
@ -144,7 +147,11 @@ class BroadcastReceiver : android.content.BroadcastReceiver() {
private const val TOPIC_RANDOM_ID_LENGTH = 12 private const val TOPIC_RANDOM_ID_LENGTH = 12
val mutex = Mutex() // https://github.com/binwiederhier/ntfy/issues/230 val mutex = Mutex() // https://github.com/binwiederhier/ntfy/issues/230
public fun sendRegistration(context: Context, baseUrl : String, topic : String) : Boolean {
// TODO Where's the best place to put this function? This seems to be the only place
// with the access to the locks, but also globally accessible
// but also, broadcast receiver is for *receiving Android broadcasts*
public fun sendRegistration(context: Context, baseUrl : String, topic : String) {
val app = context.applicationContext as Application val app = context.applicationContext as Application
val repository = app.repository val repository = app.repository
val distributor = Distributor(app) val distributor = Distributor(app)
@ -161,8 +168,6 @@ class BroadcastReceiver : android.content.BroadcastReceiver() {
distributor.sendEndpoint(appId, connectorToken, endpoint) distributor.sendEndpoint(appId, connectorToken, endpoint)
} }
} }
return false // todo return result async somehow
} }
} }
} }