2021-12-29 20:33:17 +01:00
|
|
|
package io.heckel.ntfy.up
|
|
|
|
|
|
|
|
import android.content.Context
|
|
|
|
import android.content.Intent
|
|
|
|
import io.heckel.ntfy.R
|
|
|
|
import io.heckel.ntfy.app.Application
|
|
|
|
import io.heckel.ntfy.data.Subscription
|
2022-01-17 06:19:05 +01:00
|
|
|
import io.heckel.ntfy.log.Log
|
2021-12-30 17:00:27 +01:00
|
|
|
import io.heckel.ntfy.service.SubscriberServiceManager
|
2021-12-30 01:05:32 +01:00
|
|
|
import io.heckel.ntfy.util.randomString
|
|
|
|
import io.heckel.ntfy.util.topicUrlUp
|
2021-12-29 20:33:17 +01:00
|
|
|
import kotlinx.coroutines.Dispatchers
|
|
|
|
import kotlinx.coroutines.GlobalScope
|
|
|
|
import kotlinx.coroutines.launch
|
|
|
|
import java.util.*
|
|
|
|
import kotlin.random.Random
|
|
|
|
|
2021-12-31 15:30:49 +01:00
|
|
|
/**
|
|
|
|
* This is the UnifiedPush broadcast receiver to handle the distributor actions REGISTER and UNREGISTER.
|
|
|
|
* See https://unifiedpush.org/spec/android/ for details.
|
|
|
|
*/
|
2021-12-29 20:33:17 +01:00
|
|
|
class BroadcastReceiver : android.content.BroadcastReceiver() {
|
|
|
|
override fun onReceive(context: Context?, intent: Intent?) {
|
2021-12-30 14:23:47 +01:00
|
|
|
if (context == null || intent == null) {
|
|
|
|
return
|
|
|
|
}
|
2022-01-17 06:19:05 +01:00
|
|
|
Log.init(context) // Init in all entrypoints
|
2021-12-30 14:23:47 +01:00
|
|
|
when (intent.action) {
|
|
|
|
ACTION_REGISTER -> register(context, intent)
|
|
|
|
ACTION_UNREGISTER -> unregister(context, intent)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun register(context: Context, intent: Intent) {
|
|
|
|
val appId = intent.getStringExtra(EXTRA_APPLICATION) ?: return
|
|
|
|
val connectorToken = intent.getStringExtra(EXTRA_TOKEN) ?: return
|
|
|
|
val app = context.applicationContext as Application
|
|
|
|
val repository = app.repository
|
|
|
|
val distributor = Distributor(app)
|
|
|
|
Log.d(TAG, "REGISTER received for app $appId (connectorToken=$connectorToken)")
|
2021-12-31 01:34:25 +01:00
|
|
|
if (!repository.getUnifiedPushEnabled() || appId.isBlank()) {
|
|
|
|
Log.w(TAG, "Refusing registration: UnifiedPush disabled or empty application")
|
2021-12-30 14:23:47 +01:00
|
|
|
distributor.sendRegistrationRefused(appId, connectorToken)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
GlobalScope.launch(Dispatchers.IO) {
|
|
|
|
val existingSubscription = repository.getSubscriptionByConnectorToken(connectorToken)
|
|
|
|
if (existingSubscription != null) {
|
|
|
|
if (existingSubscription.upAppId == appId) {
|
|
|
|
val endpoint = topicUrlUp(existingSubscription.baseUrl, existingSubscription.topic)
|
|
|
|
Log.d(TAG, "Subscription with connectorToken $connectorToken exists. Sending endpoint $endpoint.")
|
2021-12-30 01:05:32 +01:00
|
|
|
distributor.sendEndpoint(appId, connectorToken, endpoint)
|
2021-12-30 14:23:47 +01:00
|
|
|
} else {
|
|
|
|
Log.d(TAG, "Subscription with connectorToken $connectorToken exists for a different app. Refusing registration.")
|
|
|
|
distributor.sendRegistrationRefused(appId, connectorToken)
|
2021-12-29 20:33:17 +01:00
|
|
|
}
|
2021-12-30 14:23:47 +01:00
|
|
|
return@launch
|
2021-12-29 20:33:17 +01:00
|
|
|
}
|
2021-12-30 17:00:27 +01:00
|
|
|
|
|
|
|
// Add subscription
|
2021-12-31 01:34:25 +01:00
|
|
|
val baseUrl = repository.getUnifiedPushBaseUrl() ?: context.getString(R.string.app_base_url)
|
|
|
|
val topic = UP_PREFIX + randomString(TOPIC_RANDOM_ID_LENGTH)
|
2021-12-30 14:23:47 +01:00
|
|
|
val endpoint = topicUrlUp(baseUrl, topic)
|
|
|
|
val subscription = Subscription(
|
|
|
|
id = Random.nextLong(),
|
|
|
|
baseUrl = baseUrl,
|
|
|
|
topic = topic,
|
|
|
|
instant = true, // No Firebase, always instant!
|
|
|
|
mutedUntil = 0,
|
|
|
|
upAppId = appId,
|
|
|
|
upConnectorToken = connectorToken,
|
|
|
|
totalCount = 0,
|
|
|
|
newCount = 0,
|
|
|
|
lastActive = Date().time/1000
|
|
|
|
)
|
|
|
|
Log.d(TAG, "Adding subscription with for app $appId (connectorToken $connectorToken): $subscription")
|
|
|
|
repository.addSubscription(subscription)
|
|
|
|
distributor.sendEndpoint(appId, connectorToken, endpoint)
|
|
|
|
|
|
|
|
// Refresh (and maybe start) foreground service
|
2021-12-30 17:00:27 +01:00
|
|
|
SubscriberServiceManager.refresh(app)
|
2021-12-30 14:23:47 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun unregister(context: Context, intent: Intent) {
|
|
|
|
val connectorToken = intent.getStringExtra(EXTRA_TOKEN) ?: return
|
|
|
|
val app = context.applicationContext as Application
|
|
|
|
val repository = app.repository
|
|
|
|
val distributor = Distributor(app)
|
|
|
|
Log.d(TAG, "UNREGISTER received (connectorToken=$connectorToken)")
|
|
|
|
GlobalScope.launch(Dispatchers.IO) {
|
|
|
|
val existingSubscription = repository.getSubscriptionByConnectorToken(connectorToken)
|
|
|
|
if (existingSubscription == null) {
|
|
|
|
Log.d(TAG, "Subscription with connectorToken $connectorToken does not exist. Ignoring.")
|
|
|
|
return@launch
|
2021-12-29 20:33:17 +01:00
|
|
|
}
|
2021-12-30 14:23:47 +01:00
|
|
|
|
|
|
|
// Remove subscription
|
|
|
|
Log.d(TAG, "Removing subscription ${existingSubscription.id} with connectorToken $connectorToken")
|
|
|
|
repository.removeSubscription(existingSubscription.id)
|
|
|
|
existingSubscription.upAppId?.let { appId -> distributor.sendUnregistered(appId, connectorToken) }
|
|
|
|
|
|
|
|
// Refresh (and maybe stop) foreground service
|
2021-12-30 17:00:27 +01:00
|
|
|
SubscriberServiceManager.refresh(context)
|
2021-12-29 20:33:17 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
companion object {
|
|
|
|
private const val TAG = "NtfyUpBroadcastRecv"
|
2021-12-30 14:23:47 +01:00
|
|
|
private const val UP_PREFIX = "up"
|
2021-12-31 01:34:25 +01:00
|
|
|
private const val TOPIC_RANDOM_ID_LENGTH = 12
|
2021-12-29 20:33:17 +01:00
|
|
|
}
|
|
|
|
}
|