Add Sygnal API implementation to test is Push are correctly received

This commit is contained in:
Benoit Marty 2020-10-02 12:06:06 +02:00 committed by Benoit Marty
parent 3133cbcc3e
commit 7d53dfeca4
16 changed files with 331 additions and 8 deletions

View File

@ -29,6 +29,7 @@
<w>signout</w> <w>signout</w>
<w>signup</w> <w>signup</w>
<w>ssss</w> <w>ssss</w>
<w>sygnal</w>
<w>threepid</w> <w>threepid</w>
<w>unwedging</w> <w>unwedging</w>
</words> </words>

View File

@ -16,6 +16,7 @@ Improvements 🙌:
- Drawer: move settings access and add sign out action (#2171) - Drawer: move settings access and add sign out action (#2171)
- Filter room member (and banned users) by name (#2184) - Filter room member (and banned users) by name (#2184)
- Implement "Jump to read receipt" and "Mention" actions on the room member profile screen - Implement "Jump to read receipt" and "Mention" actions on the room member profile screen
- Add Sygnal API implementation to test is Push are correctly received
Bugfix 🐛: Bugfix 🐛:
- Improve support for image/audio/video/file selection with intent changes (#1376) - Improve support for image/audio/video/file selection with intent changes (#1376)

View File

@ -66,6 +66,19 @@ interface PushersService {
append: Boolean, append: Boolean,
withEventIdOnly: Boolean): UUID withEventIdOnly: Boolean): UUID
/**
* Directly ask Sygnal to send a push to this device
* @param url the Sygnal url (full path)
* @param appId the application id
* @param pushkey the FCM token
* @param callback callback to know if Sygnal has accepted the request. In this case, the app should receive a Push with the provided data (TODO)
*
*/
fun testPush(url: String,
appId: String,
pushkey: String,
callback: MatrixCallback<Unit>)
/** /**
* Remove the http pusher * Remove the http pusher
*/ */

View File

@ -17,7 +17,7 @@
package org.matrix.android.sdk.internal.network package org.matrix.android.sdk.internal.network
internal object NetworkConstants { internal object NetworkConstants {
// Homeserver
private const val URI_API_PREFIX_PATH = "_matrix/client" private const val URI_API_PREFIX_PATH = "_matrix/client"
const val URI_API_PREFIX_PATH_ = "$URI_API_PREFIX_PATH/" const val URI_API_PREFIX_PATH_ = "$URI_API_PREFIX_PATH/"
const val URI_API_PREFIX_PATH_R0 = "$URI_API_PREFIX_PATH/r0/" const val URI_API_PREFIX_PATH_R0 = "$URI_API_PREFIX_PATH/r0/"
@ -31,5 +31,9 @@ internal object NetworkConstants {
const val URI_IDENTITY_PREFIX_PATH = "_matrix/identity/v2" const val URI_IDENTITY_PREFIX_PATH = "_matrix/identity/v2"
const val URI_IDENTITY_PATH_V2 = "$URI_IDENTITY_PREFIX_PATH/" const val URI_IDENTITY_PATH_V2 = "$URI_IDENTITY_PREFIX_PATH/"
// Sygnal
const val URI_SYGNAL_PREFIX_PATH = "_matrix/push/v1/"
// Integration
const val URI_INTEGRATION_MANAGER_PATH = "_matrix/integrations/v1/" const val URI_INTEGRATION_MANAGER_PATH = "_matrix/integrations/v1/"
} }

View File

@ -28,6 +28,7 @@ import org.matrix.android.sdk.internal.database.query.where
import org.matrix.android.sdk.internal.di.SessionDatabase import org.matrix.android.sdk.internal.di.SessionDatabase
import org.matrix.android.sdk.internal.di.SessionId import org.matrix.android.sdk.internal.di.SessionId
import org.matrix.android.sdk.internal.di.WorkManagerProvider import org.matrix.android.sdk.internal.di.WorkManagerProvider
import org.matrix.android.sdk.internal.session.pushers.sygnal.SygnalNotifyTask
import org.matrix.android.sdk.internal.task.TaskExecutor import org.matrix.android.sdk.internal.task.TaskExecutor
import org.matrix.android.sdk.internal.task.configureWith import org.matrix.android.sdk.internal.task.configureWith
import org.matrix.android.sdk.internal.worker.WorkerParamsFactory import org.matrix.android.sdk.internal.worker.WorkerParamsFactory
@ -41,10 +42,22 @@ internal class DefaultPushersService @Inject constructor(
@SessionDatabase private val monarchy: Monarchy, @SessionDatabase private val monarchy: Monarchy,
@SessionId private val sessionId: String, @SessionId private val sessionId: String,
private val getPusherTask: GetPushersTask, private val getPusherTask: GetPushersTask,
private val sygnalNotifyTask: SygnalNotifyTask,
private val removePusherTask: RemovePusherTask, private val removePusherTask: RemovePusherTask,
private val taskExecutor: TaskExecutor private val taskExecutor: TaskExecutor
) : PushersService { ) : PushersService {
override fun testPush(url: String,
appId: String,
pushkey: String,
callback: MatrixCallback<Unit>) {
sygnalNotifyTask
.configureWith(SygnalNotifyTask.Params(url, appId, pushkey)) {
this.callback = callback
}
.executeBy(taskExecutor)
}
override fun refreshPushers() { override fun refreshPushers() {
getPusherTask getPusherTask
.configureWith() .configureWith()

View File

@ -25,6 +25,8 @@ import org.matrix.android.sdk.api.session.pushers.PushersService
import org.matrix.android.sdk.internal.session.notification.DefaultProcessEventForPushTask import org.matrix.android.sdk.internal.session.notification.DefaultProcessEventForPushTask
import org.matrix.android.sdk.internal.session.notification.DefaultPushRuleService import org.matrix.android.sdk.internal.session.notification.DefaultPushRuleService
import org.matrix.android.sdk.internal.session.notification.ProcessEventForPushTask import org.matrix.android.sdk.internal.session.notification.ProcessEventForPushTask
import org.matrix.android.sdk.internal.session.pushers.sygnal.DefaultSygnalNotifyTask
import org.matrix.android.sdk.internal.session.pushers.sygnal.SygnalNotifyTask
import org.matrix.android.sdk.internal.session.room.notification.DefaultSetRoomNotificationStateTask import org.matrix.android.sdk.internal.session.room.notification.DefaultSetRoomNotificationStateTask
import org.matrix.android.sdk.internal.session.room.notification.SetRoomNotificationStateTask import org.matrix.android.sdk.internal.session.room.notification.SetRoomNotificationStateTask
import retrofit2.Retrofit import retrofit2.Retrofit
@ -86,4 +88,7 @@ internal abstract class PushersModule {
@Binds @Binds
abstract fun bindProcessEventForPushTask(task: DefaultProcessEventForPushTask): ProcessEventForPushTask abstract fun bindProcessEventForPushTask(task: DefaultProcessEventForPushTask): ProcessEventForPushTask
@Binds
abstract fun bindSygnalNotifyTask(task: DefaultSygnalNotifyTask): SygnalNotifyTask
} }

View File

@ -0,0 +1,32 @@
/*
* Copyright (c) 2020 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.session.pushers.sygnal
import org.matrix.android.sdk.internal.network.NetworkConstants
import retrofit2.Call
import retrofit2.http.Body
import retrofit2.http.POST
internal interface SygnalAPI {
/**
* Ask Sygnal to send a push to the current device.
*
* Ref: https://matrix.org/docs/spec/push_gateway/r0.1.1#post-matrix-push-v1-notify
*/
@POST(NetworkConstants.URI_SYGNAL_PREFIX_PATH + "notify")
fun notify(@Body body: SygnalNotifyBody): Call<SygnalNotifyResponse>
}

View File

@ -0,0 +1,34 @@
/*
* Copyright (c) 2020 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.session.pushers.sygnal
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
internal data class SygnalDevice(
/**
* Required. The app_id given when the pusher was created.
*/
@Json(name = "app_id")
val appId: String,
/**
* Required. The pushkey given when the pusher was created.
*/
@Json(name = "pushkey")
val pushKey: String
)

View File

@ -0,0 +1,29 @@
/*
* Copyright (c) 2020 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.session.pushers.sygnal
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
internal data class SygnalNotification(
/**
* Required. This is an array of devices that the notification should be sent to.
*/
@Json(name = "devices")
val devices: List<SygnalDevice>
)

View File

@ -0,0 +1,29 @@
/*
* Copyright (c) 2020 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.session.pushers.sygnal
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
internal data class SygnalNotifyBody(
/**
* Required. Information about the push notification
*/
@Json(name = "notification")
val notification: SygnalNotification
)

View File

@ -0,0 +1,26 @@
/*
* Copyright (c) 2020 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.session.pushers.sygnal
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
internal data class SygnalNotifyResponse(
@Json(name = "rejected")
val rejectedPushKey: List<String>
)

View File

@ -0,0 +1,65 @@
/*
* Copyright (c) 2020 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.session.pushers.sygnal
import okhttp3.OkHttpClient
import org.matrix.android.sdk.internal.di.Unauthenticated
import org.matrix.android.sdk.internal.network.NetworkConstants
import org.matrix.android.sdk.internal.network.RetrofitFactory
import org.matrix.android.sdk.internal.network.executeRequest
import org.matrix.android.sdk.internal.task.Task
import javax.inject.Inject
internal interface SygnalNotifyTask : Task<SygnalNotifyTask.Params, Unit> {
data class Params(
val url: String,
val appId: String,
val pushKey: String
)
}
internal class DefaultSygnalNotifyTask @Inject constructor(
private val retrofitFactory: RetrofitFactory,
@Unauthenticated private val unauthenticatedOkHttpClient: OkHttpClient
) : SygnalNotifyTask {
override suspend fun execute(params: SygnalNotifyTask.Params) {
val sygnalApi = retrofitFactory.create(
unauthenticatedOkHttpClient,
params.url.substringBefore(NetworkConstants.URI_SYGNAL_PREFIX_PATH)
)
.create(SygnalAPI::class.java)
val response = executeRequest<SygnalNotifyResponse>(null) {
apiCall = sygnalApi.notify(
SygnalNotifyBody(
SygnalNotification(
devices = listOf(
SygnalDevice(
params.appId,
params.pushKey
)
)
)
)
)
}
if (response.rejectedPushKey.contains(params.pushKey)) {
throw IllegalStateException("Failure")
}
}
}

View File

@ -0,0 +1,52 @@
/*
* Copyright 2020 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.app.gplay.features.settings.troubleshoot
import androidx.appcompat.app.AppCompatActivity
import im.vector.app.R
import im.vector.app.core.pushers.PushersManager
import im.vector.app.core.resources.StringProvider
import im.vector.app.features.settings.troubleshoot.TroubleshootTest
import im.vector.app.push.fcm.FcmHelper
import org.matrix.android.sdk.api.MatrixCallback
import javax.inject.Inject
/**
* Test Push by asking Sygnal to send a Push back
*/
class TestPushFromSygnal @Inject constructor(private val context: AppCompatActivity,
private val stringProvider: StringProvider,
private val pushersManager: PushersManager)
: TroubleshootTest(R.string.settings_troubleshoot_test_push_loop_title) {
override fun perform() {
val fcmToken = FcmHelper.getFcmToken(context) ?: run {
status = TestStatus.FAILED
return
}
pushersManager.testPush(fcmToken, object : MatrixCallback<Unit> {
override fun onFailure(failure: Throwable) {
description = stringProvider.getString(R.string.settings_troubleshoot_test_push_loop_failed)
status = TestStatus.FAILED
}
override fun onSuccess(data: Unit) {
description = stringProvider.getString(R.string.settings_troubleshoot_test_push_loop_success)
status = TestStatus.SUCCESS
}
})
}
}

View File

@ -23,16 +23,20 @@ import im.vector.app.features.settings.troubleshoot.TestPushRulesSettings
import im.vector.app.features.settings.troubleshoot.TestSystemSettings import im.vector.app.features.settings.troubleshoot.TestSystemSettings
import im.vector.app.gplay.features.settings.troubleshoot.TestFirebaseToken import im.vector.app.gplay.features.settings.troubleshoot.TestFirebaseToken
import im.vector.app.gplay.features.settings.troubleshoot.TestPlayServices import im.vector.app.gplay.features.settings.troubleshoot.TestPlayServices
import im.vector.app.gplay.features.settings.troubleshoot.TestPushFromSygnal
import im.vector.app.gplay.features.settings.troubleshoot.TestTokenRegistration import im.vector.app.gplay.features.settings.troubleshoot.TestTokenRegistration
import javax.inject.Inject import javax.inject.Inject
class NotificationTroubleshootTestManagerFactory @Inject constructor(private val testSystemSettings: TestSystemSettings, class NotificationTroubleshootTestManagerFactory @Inject constructor(
private val testAccountSettings: TestAccountSettings, private val testSystemSettings: TestSystemSettings,
private val testDeviceSettings: TestDeviceSettings, private val testAccountSettings: TestAccountSettings,
private val testBingRulesSettings: TestPushRulesSettings, private val testDeviceSettings: TestDeviceSettings,
private val testPlayServices: TestPlayServices, private val testBingRulesSettings: TestPushRulesSettings,
private val testFirebaseToken: TestFirebaseToken, private val testPlayServices: TestPlayServices,
private val testTokenRegistration: TestTokenRegistration) { private val testFirebaseToken: TestFirebaseToken,
private val testTokenRegistration: TestTokenRegistration,
private val testPushFromSygnal: TestPushFromSygnal
) {
fun create(fragment: Fragment): NotificationTroubleshootTestManager { fun create(fragment: Fragment): NotificationTroubleshootTestManager {
val mgr = NotificationTroubleshootTestManager(fragment) val mgr = NotificationTroubleshootTestManager(fragment)
@ -43,6 +47,7 @@ class NotificationTroubleshootTestManagerFactory @Inject constructor(private val
mgr.addTest(testPlayServices) mgr.addTest(testPlayServices)
mgr.addTest(testFirebaseToken) mgr.addTest(testFirebaseToken)
mgr.addTest(testTokenRegistration) mgr.addTest(testTokenRegistration)
mgr.addTest(testPushFromSygnal)
return mgr return mgr
} }
} }

View File

@ -34,6 +34,16 @@ class PushersManager @Inject constructor(
private val stringProvider: StringProvider, private val stringProvider: StringProvider,
private val appNameProvider: AppNameProvider private val appNameProvider: AppNameProvider
) { ) {
fun testPush(pushKey: String, callback: MatrixCallback<Unit>) {
val currentSession = activeSessionHolder.getActiveSession()
currentSession.testPush(
stringProvider.getString(R.string.pusher_http_url),
stringProvider.getString(R.string.pusher_app_id),
pushKey,
callback
)
}
fun registerPusherWithFcmKey(pushKey: String): UUID { fun registerPusherWithFcmKey(pushKey: String): UUID {
val currentSession = activeSessionHolder.getActiveSession() val currentSession = activeSessionHolder.getActiveSession()

View File

@ -749,6 +749,10 @@
<string name="settings_troubleshoot_test_token_registration_success">FCM token successfully registered to HomeServer.</string> <string name="settings_troubleshoot_test_token_registration_success">FCM token successfully registered to HomeServer.</string>
<string name="settings_troubleshoot_test_token_registration_failed">Failed to register FCM token to HomeServer:\n%1$s</string> <string name="settings_troubleshoot_test_token_registration_failed">Failed to register FCM token to HomeServer:\n%1$s</string>
<string name="settings_troubleshoot_test_push_loop_title">Test Push</string>
<string name="settings_troubleshoot_test_push_loop_success">The application is receiving PUSH, you should see a notification.</string>
<string name="settings_troubleshoot_test_push_loop_failed">Failed to receive push. Solution could be to reinstall the application.</string>
<string name="settings_troubleshoot_test_foreground_service_started_title">Notifications Service</string> <string name="settings_troubleshoot_test_foreground_service_started_title">Notifications Service</string>
<string name="settings_troubleshoot_test_foreground_service_startedt_success">Notifications Service is running.</string> <string name="settings_troubleshoot_test_foreground_service_startedt_success">Notifications Service is running.</string>
<string name="settings_troubleshoot_test_foreground_service_started_failed">Notifications Service is not running.\nTry to restart the application.</string> <string name="settings_troubleshoot_test_foreground_service_started_failed">Notifications Service is not running.\nTry to restart the application.</string>