Implement poll_request for Firebase to account for protected topics
This commit is contained in:
parent
28bfd087c7
commit
82177253a7
8 changed files with 89 additions and 53 deletions
|
@ -422,9 +422,9 @@ class Repository(private val sharedPrefs: SharedPreferences, private val databas
|
||||||
private const val TAG = "NtfyRepository"
|
private const val TAG = "NtfyRepository"
|
||||||
private var instance: Repository? = null
|
private var instance: Repository? = null
|
||||||
|
|
||||||
fun getInstance(activity: Activity): Repository {
|
fun getInstance(context: Context): Repository {
|
||||||
val database = Database.getInstance(activity.applicationContext)
|
val database = Database.getInstance(context.applicationContext)
|
||||||
val sharedPrefs = activity.getSharedPreferences(SHARED_PREFS_ID, Context.MODE_PRIVATE)
|
val sharedPrefs = context.getSharedPreferences(SHARED_PREFS_ID, Context.MODE_PRIVATE)
|
||||||
return getInstance(sharedPrefs, database)
|
return getInstance(sharedPrefs, database)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,6 @@ import java.nio.charset.StandardCharsets.UTF_8
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
|
|
||||||
class ApiService {
|
class ApiService {
|
||||||
private val client = OkHttpClient.Builder()
|
private val client = OkHttpClient.Builder()
|
||||||
.callTimeout(15, TimeUnit.SECONDS) // Total timeout for entire request
|
.callTimeout(15, TimeUnit.SECONDS) // Total timeout for entire request
|
||||||
|
@ -29,27 +28,23 @@ class ApiService {
|
||||||
.build()
|
.build()
|
||||||
private val parser = NotificationParser()
|
private val parser = NotificationParser()
|
||||||
|
|
||||||
fun publish(baseUrl: String, topic: String, message: String, title: String, priority: Int, tags: List<String>, delay: String) {
|
fun publish(baseUrl: String, topic: String, user: User?, message: String, title: String, priority: Int, tags: List<String>, delay: String) {
|
||||||
val url = topicUrl(baseUrl, topic)
|
val url = topicUrl(baseUrl, topic)
|
||||||
Log.d(TAG, "Publishing to $url")
|
Log.d(TAG, "Publishing to $url")
|
||||||
|
|
||||||
// XXXXXXXXXXXx
|
val builder = builder(url, user)
|
||||||
|
|
||||||
var builder = Request.Builder()
|
|
||||||
.url(url)
|
|
||||||
.put(message.toRequestBody())
|
.put(message.toRequestBody())
|
||||||
.addHeader("User-Agent", USER_AGENT)
|
|
||||||
if (priority in 1..5) {
|
if (priority in 1..5) {
|
||||||
builder = builder.addHeader("X-Priority", priority.toString())
|
builder.addHeader("X-Priority", priority.toString())
|
||||||
}
|
}
|
||||||
if (tags.isNotEmpty()) {
|
if (tags.isNotEmpty()) {
|
||||||
builder = builder.addHeader("X-Tags", tags.joinToString(","))
|
builder.addHeader("X-Tags", tags.joinToString(","))
|
||||||
}
|
}
|
||||||
if (title.isNotEmpty()) {
|
if (title.isNotEmpty()) {
|
||||||
builder = builder.addHeader("X-Title", title)
|
builder.addHeader("X-Title", title)
|
||||||
}
|
}
|
||||||
if (delay.isNotEmpty()) {
|
if (delay.isNotEmpty()) {
|
||||||
builder = builder.addHeader("X-Delay", delay)
|
builder.addHeader("X-Delay", delay)
|
||||||
}
|
}
|
||||||
client.newCall(builder.build()).execute().use { response ->
|
client.newCall(builder.build()).execute().use { response ->
|
||||||
if (!response.isSuccessful) {
|
if (!response.isSuccessful) {
|
||||||
|
@ -59,18 +54,12 @@ class ApiService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun poll(subscriptionId: Long, baseUrl: String, topic: String, since: Long = 0L): List<Notification> {
|
fun poll(subscriptionId: Long, baseUrl: String, topic: String, user: User?, since: Long = 0L): List<Notification> {
|
||||||
val sinceVal = if (since == 0L) "all" else since.toString()
|
val sinceVal = if (since == 0L) "all" else since.toString()
|
||||||
val url = topicUrlJsonPoll(baseUrl, topic, sinceVal)
|
val url = topicUrlJsonPoll(baseUrl, topic, sinceVal)
|
||||||
Log.d(TAG, "Polling topic $url")
|
Log.d(TAG, "Polling topic $url")
|
||||||
|
|
||||||
val request = Request.Builder()
|
val request = builder(url, user).build()
|
||||||
.url(url)
|
|
||||||
.addHeader("User-Agent", USER_AGENT)
|
|
||||||
.build()
|
|
||||||
|
|
||||||
// XXXXXXXXXXXx
|
|
||||||
|
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (!response.isSuccessful) {
|
if (!response.isSuccessful) {
|
||||||
throw Exception("Unexpected response ${response.code} when polling topic $url")
|
throw Exception("Unexpected response ${response.code} when polling topic $url")
|
||||||
|
@ -97,14 +86,7 @@ class ApiService {
|
||||||
val sinceVal = if (since == 0L) "all" else since.toString()
|
val sinceVal = if (since == 0L) "all" else since.toString()
|
||||||
val url = topicUrlJson(baseUrl, topics, sinceVal)
|
val url = topicUrlJson(baseUrl, topics, sinceVal)
|
||||||
Log.d(TAG, "Opening subscription connection to $url")
|
Log.d(TAG, "Opening subscription connection to $url")
|
||||||
val builder = Request.Builder()
|
val request = builder(url, user).build()
|
||||||
.get()
|
|
||||||
.url(url)
|
|
||||||
.addHeader("User-Agent", USER_AGENT)
|
|
||||||
if (user != null) {
|
|
||||||
builder.addHeader("Authorization", Credentials.basic(user.username, user.password, UTF_8))
|
|
||||||
}
|
|
||||||
val request = builder.build()
|
|
||||||
val call = subscriberClient.newCall(request)
|
val call = subscriberClient.newCall(request)
|
||||||
call.enqueue(object : Callback {
|
call.enqueue(object : Callback {
|
||||||
override fun onResponse(call: Call, response: Response) {
|
override fun onResponse(call: Call, response: Response) {
|
||||||
|
@ -140,14 +122,7 @@ class ApiService {
|
||||||
Log.d(TAG, "Checking read access for user ${user.username} against ${topicUrl(baseUrl, topic)}")
|
Log.d(TAG, "Checking read access for user ${user.username} against ${topicUrl(baseUrl, topic)}")
|
||||||
}
|
}
|
||||||
val url = topicUrlAuth(baseUrl, topic)
|
val url = topicUrlAuth(baseUrl, topic)
|
||||||
val builder = Request.Builder()
|
val request = builder(url, user).build()
|
||||||
.get()
|
|
||||||
.url(url)
|
|
||||||
.addHeader("User-Agent", USER_AGENT)
|
|
||||||
if (user != null) {
|
|
||||||
builder.addHeader("Authorization", Credentials.basic(user.username, user.password, UTF_8))
|
|
||||||
}
|
|
||||||
val request = builder.build()
|
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
return if (user == null) {
|
return if (user == null) {
|
||||||
response.isSuccessful || response.code == 404 // Treat 404 as success (old server; to be removed in future versions)
|
response.isSuccessful || response.code == 404 // Treat 404 as success (old server; to be removed in future versions)
|
||||||
|
@ -157,6 +132,16 @@ class ApiService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun builder(url: String, user: User?): Request.Builder {
|
||||||
|
val builder = Request.Builder()
|
||||||
|
.url(url)
|
||||||
|
.addHeader("User-Agent", USER_AGENT)
|
||||||
|
if (user != null) {
|
||||||
|
builder.addHeader("Authorization", Credentials.basic(user.username, user.password, UTF_8))
|
||||||
|
}
|
||||||
|
return builder
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val USER_AGENT = "ntfy/${BuildConfig.VERSION_NAME} (${BuildConfig.FLAVOR}; Android ${Build.VERSION.RELEASE}; SDK ${Build.VERSION.SDK_INT})"
|
val USER_AGENT = "ntfy/${BuildConfig.VERSION_NAME} (${BuildConfig.FLAVOR}; Android ${Build.VERSION.RELEASE}; SDK ${Build.VERSION.SDK_INT})"
|
||||||
private const val TAG = "NtfyApiService"
|
private const val TAG = "NtfyApiService"
|
||||||
|
@ -165,5 +150,6 @@ class ApiService {
|
||||||
const val CONTROL_TOPIC = "~control"
|
const val CONTROL_TOPIC = "~control"
|
||||||
const val EVENT_MESSAGE = "message"
|
const val EVENT_MESSAGE = "message"
|
||||||
const val EVENT_KEEPALIVE = "keepalive"
|
const val EVENT_KEEPALIVE = "keepalive"
|
||||||
|
const val EVENT_POLL_REQUEST = "poll_request"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import io.heckel.ntfy.R
|
import io.heckel.ntfy.R
|
||||||
import io.heckel.ntfy.db.Notification
|
import io.heckel.ntfy.db.Notification
|
||||||
|
import io.heckel.ntfy.db.Repository
|
||||||
import io.heckel.ntfy.db.Subscription
|
import io.heckel.ntfy.db.Subscription
|
||||||
import io.heckel.ntfy.log.Log
|
import io.heckel.ntfy.log.Log
|
||||||
import io.heckel.ntfy.util.joinTagsMap
|
import io.heckel.ntfy.util.joinTagsMap
|
||||||
|
@ -65,9 +66,12 @@ class BroadcastService(private val ctx: Context) {
|
||||||
}
|
}
|
||||||
val delay = getStringExtra(intent,"delay") ?: ""
|
val delay = getStringExtra(intent,"delay") ?: ""
|
||||||
GlobalScope.launch(Dispatchers.IO) {
|
GlobalScope.launch(Dispatchers.IO) {
|
||||||
|
val repository = Repository.getInstance(ctx)
|
||||||
|
val user = repository.getUser(baseUrl) // May be null
|
||||||
api.publish(
|
api.publish(
|
||||||
baseUrl = baseUrl,
|
baseUrl = baseUrl,
|
||||||
topic = topic,
|
topic = topic,
|
||||||
|
user = user,
|
||||||
message = message,
|
message = message,
|
||||||
title = title,
|
title = title,
|
||||||
priority = priority,
|
priority = priority,
|
||||||
|
@ -94,8 +98,10 @@ class BroadcastService(private val ctx: Context) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "NtfyBroadcastService"
|
private const val TAG = "NtfyBroadcastService"
|
||||||
private const val MESSAGE_RECEIVED_ACTION = "io.heckel.ntfy.MESSAGE_RECEIVED"
|
|
||||||
private const val MESSAGE_SEND_ACTION = "io.heckel.ntfy.SEND_MESSAGE" // If changed, change in manifest too!
|
|
||||||
private const val DOES_NOT_EXIST = -2586000
|
private const val DOES_NOT_EXIST = -2586000
|
||||||
|
|
||||||
|
// These constants cannot be changed without breaking the contract; also see manifest
|
||||||
|
private const val MESSAGE_RECEIVED_ACTION = "io.heckel.ntfy.MESSAGE_RECEIVED"
|
||||||
|
private const val MESSAGE_SEND_ACTION = "io.heckel.ntfy.SEND_MESSAGE"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -269,6 +269,7 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
|
||||||
|
|
||||||
lifecycleScope.launch(Dispatchers.IO) {
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
try {
|
try {
|
||||||
|
val user = repository.getUser(subscriptionBaseUrl) // May be null
|
||||||
val possibleTags = listOf(
|
val possibleTags = listOf(
|
||||||
"warning", "skull", "success", "triangular_flag_on_post", "de", "dog", "rotating_light", "cat", "bike", // Emojis
|
"warning", "skull", "success", "triangular_flag_on_post", "de", "dog", "rotating_light", "cat", "bike", // Emojis
|
||||||
"backup", "rsync", "de-server1", "this-is-a-tag"
|
"backup", "rsync", "de-server1", "this-is-a-tag"
|
||||||
|
@ -277,7 +278,7 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
|
||||||
val tags = possibleTags.shuffled().take(Random.nextInt(0, 4))
|
val tags = possibleTags.shuffled().take(Random.nextInt(0, 4))
|
||||||
val title = if (Random.nextBoolean()) getString(R.string.detail_test_title) else ""
|
val title = if (Random.nextBoolean()) getString(R.string.detail_test_title) else ""
|
||||||
val message = getString(R.string.detail_test_message, priority)
|
val message = getString(R.string.detail_test_message, priority)
|
||||||
api.publish(subscriptionBaseUrl, subscriptionTopic, message, title, priority, tags, delay = "")
|
api.publish(subscriptionBaseUrl, subscriptionTopic, user, message, title, priority, tags, delay = "")
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
runOnUiThread {
|
runOnUiThread {
|
||||||
Toast
|
Toast
|
||||||
|
@ -339,7 +340,8 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
|
||||||
|
|
||||||
lifecycleScope.launch(Dispatchers.IO) {
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
try {
|
try {
|
||||||
val notifications = api.poll(subscriptionId, subscriptionBaseUrl, subscriptionTopic)
|
val user = repository.getUser(subscriptionBaseUrl) // May be null
|
||||||
|
val notifications = api.poll(subscriptionId, subscriptionBaseUrl, subscriptionTopic, user)
|
||||||
val newNotifications = repository.onlyNewNotifications(subscriptionId, notifications)
|
val newNotifications = repository.onlyNewNotifications(subscriptionId, notifications)
|
||||||
val toastMessage = if (newNotifications.isEmpty()) {
|
val toastMessage = if (newNotifications.isEmpty()) {
|
||||||
getString(R.string.refresh_message_no_results)
|
getString(R.string.refresh_message_no_results)
|
||||||
|
|
|
@ -193,10 +193,10 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
|
||||||
val work = PeriodicWorkRequestBuilder<PollWorker>(POLL_WORKER_INTERVAL_MINUTES, TimeUnit.MINUTES)
|
val work = PeriodicWorkRequestBuilder<PollWorker>(POLL_WORKER_INTERVAL_MINUTES, TimeUnit.MINUTES)
|
||||||
.setConstraints(constraints)
|
.setConstraints(constraints)
|
||||||
.addTag(PollWorker.TAG)
|
.addTag(PollWorker.TAG)
|
||||||
.addTag(PollWorker.WORK_NAME_PERIODIC)
|
.addTag(PollWorker.WORK_NAME_PERIODIC_ALL)
|
||||||
.build()
|
.build()
|
||||||
Log.d(TAG, "Poll worker: Scheduling period work every $POLL_WORKER_INTERVAL_MINUTES minutes")
|
Log.d(TAG, "Poll worker: Scheduling period work every $POLL_WORKER_INTERVAL_MINUTES minutes")
|
||||||
workManager!!.enqueueUniquePeriodicWork(PollWorker.WORK_NAME_PERIODIC, workPolicy, work)
|
workManager!!.enqueueUniquePeriodicWork(PollWorker.WORK_NAME_PERIODIC_ALL, workPolicy, work)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun startPeriodicServiceRestartWorker() {
|
private fun startPeriodicServiceRestartWorker() {
|
||||||
|
@ -375,7 +375,8 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
|
||||||
// Fetch cached messages
|
// Fetch cached messages
|
||||||
lifecycleScope.launch(Dispatchers.IO) {
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
try {
|
try {
|
||||||
val notifications = api.poll(subscription.id, subscription.baseUrl, subscription.topic)
|
val user = repository.getUser(subscription.baseUrl) // May be null
|
||||||
|
val notifications = api.poll(subscription.id, subscription.baseUrl, subscription.topic, user)
|
||||||
notifications.forEach { notification -> repository.addNotification(notification) }
|
notifications.forEach { notification -> repository.addNotification(notification) }
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(TAG, "Unable to fetch notifications: ${e.stackTrace}")
|
Log.e(TAG, "Unable to fetch notifications: ${e.stackTrace}")
|
||||||
|
@ -418,7 +419,8 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
|
||||||
var newNotificationsCount = 0
|
var newNotificationsCount = 0
|
||||||
repository.getSubscriptions().forEach { subscription ->
|
repository.getSubscriptions().forEach { subscription ->
|
||||||
try {
|
try {
|
||||||
val notifications = api.poll(subscription.id, subscription.baseUrl, subscription.topic)
|
val user = repository.getUser(subscription.baseUrl) // May be null
|
||||||
|
val notifications = api.poll(subscription.id, subscription.baseUrl, subscription.topic, user)
|
||||||
val newNotifications = repository.onlyNewNotifications(subscription.id, notifications)
|
val newNotifications = repository.onlyNewNotifications(subscription.id, notifications)
|
||||||
newNotifications.forEach { notification ->
|
newNotifications.forEach { notification ->
|
||||||
newNotificationsCount++
|
newNotificationsCount++
|
||||||
|
|
|
@ -23,7 +23,6 @@ class PollWorker(ctx: Context, params: WorkerParameters) : CoroutineWorker(ctx,
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun doWork(): Result {
|
override suspend fun doWork(): Result {
|
||||||
|
|
||||||
return withContext(Dispatchers.IO) {
|
return withContext(Dispatchers.IO) {
|
||||||
Log.d(TAG, "Polling for new notifications")
|
Log.d(TAG, "Polling for new notifications")
|
||||||
val database = Database.getInstance(applicationContext)
|
val database = Database.getInstance(applicationContext)
|
||||||
|
@ -32,9 +31,25 @@ class PollWorker(ctx: Context, params: WorkerParameters) : CoroutineWorker(ctx,
|
||||||
val dispatcher = NotificationDispatcher(applicationContext, repository)
|
val dispatcher = NotificationDispatcher(applicationContext, repository)
|
||||||
val api = ApiService()
|
val api = ApiService()
|
||||||
|
|
||||||
repository.getSubscriptions().forEach{ subscription ->
|
val baseUrl = inputData.getString(INPUT_DATA_BASE_URL)
|
||||||
|
val topic = inputData.getString(INPUT_DATA_TOPIC)
|
||||||
|
val subscriptions = if (baseUrl != null && topic != null) {
|
||||||
|
val subscription = repository.getSubscription(baseUrl, topic) ?: return@withContext Result.success()
|
||||||
|
listOf(subscription)
|
||||||
|
} else {
|
||||||
|
repository.getSubscriptions()
|
||||||
|
}
|
||||||
|
|
||||||
|
subscriptions.forEach{ subscription ->
|
||||||
try {
|
try {
|
||||||
val notifications = api.poll(subscription.id, subscription.baseUrl, subscription.topic, since = subscription.lastActive)
|
val user = repository.getUser(subscription.baseUrl)
|
||||||
|
val notifications = api.poll(
|
||||||
|
subscriptionId = subscription.id,
|
||||||
|
baseUrl = subscription.baseUrl,
|
||||||
|
topic = subscription.topic,
|
||||||
|
user = user,
|
||||||
|
since = subscription.lastActive
|
||||||
|
)
|
||||||
val newNotifications = repository
|
val newNotifications = repository
|
||||||
.onlyNewNotifications(subscription.id, notifications)
|
.onlyNewNotifications(subscription.id, notifications)
|
||||||
.map { it.copy(notificationId = Random.nextInt()) }
|
.map { it.copy(notificationId = Random.nextInt()) }
|
||||||
|
@ -55,6 +70,9 @@ class PollWorker(ctx: Context, params: WorkerParameters) : CoroutineWorker(ctx,
|
||||||
companion object {
|
companion object {
|
||||||
const val VERSION = BuildConfig.VERSION_CODE
|
const val VERSION = BuildConfig.VERSION_CODE
|
||||||
const val TAG = "NtfyPollWorker"
|
const val TAG = "NtfyPollWorker"
|
||||||
const val WORK_NAME_PERIODIC = "NtfyPollWorkerPeriodic" // Do not change
|
const val WORK_NAME_PERIODIC_ALL = "NtfyPollWorkerPeriodic" // Do not change
|
||||||
|
const val WORK_NAME_ONCE_SINGE_PREFIX = "NtfyPollWorkerSingle" // e.g. NtfyPollWorkerSingle_https://ntfy.sh_mytopic
|
||||||
|
const val INPUT_DATA_BASE_URL = "baseUrl"
|
||||||
|
const val INPUT_DATA_TOPIC = "topic"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
<!-- Main app-->
|
<!-- Main app-->
|
||||||
<string name="app_name">Ntfy</string>
|
<string name="app_name">Ntfy</string>
|
||||||
<string name="app_base_url">https://ntfy.sh</string> <!-- If changed, you must also change google-services.json! -->
|
<string name="app_base_url">https://ntfy.sh</string> <!-- If changed, you must also change google-services.json! -->
|
||||||
<string name="app_base_scheme">https</string> <!-- If changed, you must also change google-services.json! -->
|
|
||||||
<string name="app_base_host">ntfy.sh</string> <!-- If changed, you must also change google-services.json! -->
|
|
||||||
|
|
||||||
<!-- Notification channels -->
|
<!-- Notification channels -->
|
||||||
<string name="channel_notifications_min_name">Notifications (Min Priority)</string>
|
<string name="channel_notifications_min_name">Notifications (Min Priority)</string>
|
||||||
|
|
|
@ -2,6 +2,7 @@ package io.heckel.ntfy.firebase
|
||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.util.Base64
|
import android.util.Base64
|
||||||
|
import androidx.work.*
|
||||||
import com.google.firebase.messaging.FirebaseMessagingService
|
import com.google.firebase.messaging.FirebaseMessagingService
|
||||||
import com.google.firebase.messaging.RemoteMessage
|
import com.google.firebase.messaging.RemoteMessage
|
||||||
import io.heckel.ntfy.R
|
import io.heckel.ntfy.R
|
||||||
|
@ -14,6 +15,8 @@ import io.heckel.ntfy.msg.MESSAGE_ENCODING_BASE64
|
||||||
import io.heckel.ntfy.msg.NotificationDispatcher
|
import io.heckel.ntfy.msg.NotificationDispatcher
|
||||||
import io.heckel.ntfy.service.SubscriberService
|
import io.heckel.ntfy.service.SubscriberService
|
||||||
import io.heckel.ntfy.util.toPriority
|
import io.heckel.ntfy.util.toPriority
|
||||||
|
import io.heckel.ntfy.util.topicShortUrl
|
||||||
|
import io.heckel.ntfy.work.PollWorker
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.SupervisorJob
|
import kotlinx.coroutines.SupervisorJob
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
@ -38,8 +41,9 @@ class FirebaseService : FirebaseMessagingService() {
|
||||||
// Dispatch event
|
// Dispatch event
|
||||||
val data = remoteMessage.data
|
val data = remoteMessage.data
|
||||||
when (data["event"]) {
|
when (data["event"]) {
|
||||||
ApiService.EVENT_KEEPALIVE -> handleKeepalive(remoteMessage)
|
|
||||||
ApiService.EVENT_MESSAGE -> handleMessage(remoteMessage)
|
ApiService.EVENT_MESSAGE -> handleMessage(remoteMessage)
|
||||||
|
ApiService.EVENT_KEEPALIVE -> handleKeepalive(remoteMessage)
|
||||||
|
ApiService.EVENT_POLL_REQUEST -> handlePollRequest(remoteMessage)
|
||||||
else -> Log.d(TAG, "Discarding unexpected message (2): from=${remoteMessage.from}, data=${data}")
|
else -> Log.d(TAG, "Discarding unexpected message (2): from=${remoteMessage.from}, data=${data}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,6 +58,26 @@ class FirebaseService : FirebaseMessagingService() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun handlePollRequest(remoteMessage: RemoteMessage) {
|
||||||
|
val baseUrl = getString(R.string.app_base_url) // Everything from Firebase comes from main service URL!
|
||||||
|
val topic = remoteMessage.data["topic"] ?: return
|
||||||
|
val constraints = Constraints.Builder()
|
||||||
|
.setRequiredNetworkType(NetworkType.CONNECTED)
|
||||||
|
.build()
|
||||||
|
val workName = "${PollWorker.WORK_NAME_ONCE_SINGE_PREFIX}_${baseUrl}_${topic}"
|
||||||
|
val workManager = WorkManager.getInstance(this)
|
||||||
|
val workRequest = OneTimeWorkRequest.Builder(PollWorker::class.java)
|
||||||
|
.setInputData(workDataOf(
|
||||||
|
PollWorker.INPUT_DATA_BASE_URL to baseUrl,
|
||||||
|
PollWorker.INPUT_DATA_TOPIC to topic
|
||||||
|
))
|
||||||
|
.setConstraints(constraints)
|
||||||
|
.build()
|
||||||
|
Log.d(TAG, "Poll request for ${topicShortUrl(baseUrl, topic)} received, scheduling unique poll worker with name $workName")
|
||||||
|
|
||||||
|
workManager.enqueueUniqueWork(workName, ExistingWorkPolicy.REPLACE, workRequest)
|
||||||
|
}
|
||||||
|
|
||||||
private fun handleMessage(remoteMessage: RemoteMessage) {
|
private fun handleMessage(remoteMessage: RemoteMessage) {
|
||||||
val data = remoteMessage.data
|
val data = remoteMessage.data
|
||||||
val id = data["id"]
|
val id = data["id"]
|
||||||
|
|
Loading…
Add table
Reference in a new issue