mirror of
https://github.com/vector-im/riotX-android
synced 2025-10-06 00:02:48 +02:00
Compare commits
9 Commits
michaelk/c
...
feature/pe
Author | SHA1 | Date | |
---|---|---|---|
|
192b0ed3fb | ||
|
c909fc50a2 | ||
|
5cf1175d7f | ||
|
7be93e03ba | ||
|
98b86e977f | ||
|
3cb2873f93 | ||
|
bb7cd409e6 | ||
|
cef191f1a5 | ||
|
2ab2c5c94b |
@@ -56,11 +56,19 @@ android {
|
||||
buildConfigField "boolean", "LOG_PRIVATE_DATA", project.property("vector.debugPrivateData")
|
||||
// Set to BODY instead of NONE to enable logging
|
||||
buildConfigField "okhttp3.logging.HttpLoggingInterceptor.Level", "OKHTTP_LOGGING_LEVEL", "okhttp3.logging.HttpLoggingInterceptor.Level." + project.property("vector.httpLogLevel")
|
||||
|
||||
buildConfigField "String", "PERF_TRACING_SERVER", project.property("vector.perfTracingServer")
|
||||
buildConfigField "String", "PERF_TRACING_SERVER_TOKEN", project.property("vector.perfTracingServerToken")
|
||||
buildConfigField "String", "PERF_TRACING_SERVER_USER", project.property("vector.perfTracingServerUser")
|
||||
}
|
||||
|
||||
release {
|
||||
buildConfigField "boolean", "LOG_PRIVATE_DATA", "false"
|
||||
buildConfigField "okhttp3.logging.HttpLoggingInterceptor.Level", "OKHTTP_LOGGING_LEVEL", "okhttp3.logging.HttpLoggingInterceptor.Level.NONE"
|
||||
|
||||
buildConfigField "String", "PERF_TRACING_SERVER", ""
|
||||
buildConfigField "String", "PERF_TRACING_SERVER_TOKEN", ""
|
||||
buildConfigField "String", "PERF_TRACING_SERVER_USER", ""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,6 +177,9 @@ dependencies {
|
||||
implementation 'com.jakewharton.timber:timber:4.7.1'
|
||||
implementation 'com.facebook.stetho:stetho-okhttp3:1.5.1'
|
||||
|
||||
debugImplementation 'com.nikitakozlov.pury:pury:1.1.0'
|
||||
releaseImplementation 'com.nikitakozlov.pury:pury-no-op:1.1.0'
|
||||
|
||||
// Bus
|
||||
implementation 'org.greenrobot:eventbus:3.1.1'
|
||||
|
||||
|
@@ -21,11 +21,13 @@ import android.content.Context
|
||||
import androidx.lifecycle.ProcessLifecycleOwner
|
||||
import androidx.work.Configuration
|
||||
import androidx.work.WorkManager
|
||||
import com.nikitakozlov.pury.Pury
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import org.matrix.android.sdk.BuildConfig
|
||||
import org.matrix.android.sdk.api.auth.AuthenticationService
|
||||
import org.matrix.android.sdk.api.legacy.LegacySessionImporter
|
||||
import org.matrix.android.sdk.api.raw.RawService
|
||||
import org.matrix.android.sdk.api.util.profiling.PerfServerPlugin
|
||||
import org.matrix.android.sdk.internal.SessionManager
|
||||
import org.matrix.android.sdk.internal.di.DaggerMatrixComponent
|
||||
import org.matrix.android.sdk.internal.network.UserAgentHolder
|
||||
@@ -48,6 +50,7 @@ class Matrix private constructor(context: Context, matrixConfiguration: MatrixCo
|
||||
@Inject internal lateinit var backgroundDetectionObserver: BackgroundDetectionObserver
|
||||
@Inject internal lateinit var olmManager: OlmManager
|
||||
@Inject internal lateinit var sessionManager: SessionManager
|
||||
@Inject internal lateinit var perfServerPlugin: PerfServerPlugin
|
||||
|
||||
init {
|
||||
Monarchy.init(context)
|
||||
@@ -56,6 +59,10 @@ class Matrix private constructor(context: Context, matrixConfiguration: MatrixCo
|
||||
WorkManager.initialize(context, Configuration.Builder().setExecutor(Executors.newCachedThreadPool()).build())
|
||||
}
|
||||
ProcessLifecycleOwner.get().lifecycle.addObserver(backgroundDetectionObserver)
|
||||
|
||||
if (!BuildConfig.PERF_TRACING_SERVER.isNullOrEmpty()) {
|
||||
Pury.addPlugin("per-server", perfServerPlugin)
|
||||
}
|
||||
}
|
||||
|
||||
fun getUserAgent() = userAgentHolder.userAgent
|
||||
|
@@ -112,7 +112,8 @@ interface CryptoService {
|
||||
|
||||
fun isRoomEncrypted(roomId: String): Boolean
|
||||
|
||||
fun encryptEventContent(eventContent: Content,
|
||||
fun encryptEventContent(eventId: String,
|
||||
eventContent: Content,
|
||||
eventType: String,
|
||||
roomId: String,
|
||||
callback: MatrixCallback<MXEncryptEventContentResult>)
|
||||
|
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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.api.session.room.send
|
||||
|
||||
import org.matrix.android.sdk.api.util.profiling.BaseProfiler
|
||||
|
||||
object SendPerformanceProfiler: BaseProfiler<SendPerformanceProfiler.Stages>() {
|
||||
|
||||
enum class Stages() {
|
||||
// LOCAL_ECHO,
|
||||
ENCRYPT_WORKER,
|
||||
ENCRYPT_GET_USERS,
|
||||
ENCRYPT_SET_ROOM_ENCRYPTION,
|
||||
ENCRYPT_MEGOLM_SHARE_KEYS,
|
||||
ENCRYPT_MEGOLM_ENCRYPT,
|
||||
SEND_WORKER,
|
||||
GET_UP_TO_DATE_ECHO,
|
||||
SEND_REQUEST,
|
||||
RECEIVED_IN_SYNC
|
||||
}
|
||||
|
||||
override val name = "SEND_PROFILER"
|
||||
}
|
@@ -34,9 +34,10 @@ interface SendService {
|
||||
* Method to send a generic event asynchronously. If you want to send a state event, please use [StateService] instead.
|
||||
* @param eventType the type of the event
|
||||
* @param content the optional body as a json dict.
|
||||
* @param onBuiltEvent lambda to react to the event creation
|
||||
* @return a [Cancelable]
|
||||
*/
|
||||
fun sendEvent(eventType: String, content: Content?): Cancelable
|
||||
fun sendEvent(eventType: String, content: Content?, onBuiltEvent: ((Event) -> Unit)? = null): Cancelable
|
||||
|
||||
/**
|
||||
* Method to send a text message asynchronously.
|
||||
@@ -47,7 +48,12 @@ interface SendService {
|
||||
* @param autoMarkdown If true, the SDK will generate a formatted HTML message from the body text if markdown syntax is present
|
||||
* @return a [Cancelable]
|
||||
*/
|
||||
fun sendTextMessage(text: CharSequence, msgType: String = MessageType.MSGTYPE_TEXT, autoMarkdown: Boolean = false): Cancelable
|
||||
fun sendTextMessage(
|
||||
text: CharSequence,
|
||||
msgType: String = MessageType.MSGTYPE_TEXT,
|
||||
autoMarkdown: Boolean = false,
|
||||
onBuiltEvent: ((Event) -> Unit)? = null
|
||||
): Cancelable
|
||||
|
||||
/**
|
||||
* Method to send a text message with a formatted body.
|
||||
@@ -56,7 +62,12 @@ interface SendService {
|
||||
* @param msgType the message type: MessageType.MSGTYPE_TEXT (default) or MessageType.MSGTYPE_EMOTE
|
||||
* @return a [Cancelable]
|
||||
*/
|
||||
fun sendFormattedTextMessage(text: String, formattedText: String, msgType: String = MessageType.MSGTYPE_TEXT): Cancelable
|
||||
fun sendFormattedTextMessage(
|
||||
text: String,
|
||||
formattedText: String,
|
||||
msgType: String = MessageType.MSGTYPE_TEXT,
|
||||
onBuiltEvent: ((Event) -> Unit)? = null
|
||||
): Cancelable
|
||||
|
||||
/**
|
||||
* Method to send a media asynchronously.
|
||||
|
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* 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.api.util.profiling
|
||||
|
||||
import com.nikitakozlov.pury.Pury
|
||||
|
||||
private const val ROOT_STAGE = "ROOT_STAGE"
|
||||
|
||||
/**
|
||||
* Base class for profilers, it's implementing Pury start and stop profiling.
|
||||
* Order of STAGE in enum matters.
|
||||
*/
|
||||
abstract class BaseProfiler<STAGE : Enum<STAGE>> {
|
||||
|
||||
private val currentProfilers = ArrayList<String>()
|
||||
|
||||
abstract val name: String
|
||||
|
||||
/**
|
||||
* Use to start the profiling process. It's necessary to call this method before any other method.
|
||||
* You should always call stop profiling with the same key param when you want to stop profiling.
|
||||
*
|
||||
* @param key unique identifier of the profiling.
|
||||
*/
|
||||
fun startProfiling(key: String) {
|
||||
if (currentProfilers.contains(key)) {
|
||||
return
|
||||
}
|
||||
currentProfilers.add(key)
|
||||
Pury.startProfiling(profilerName(key), ROOT_STAGE, 0, 1)
|
||||
}
|
||||
|
||||
/**
|
||||
* Use to stop the profiling process. This will dispatch information to the configured pury plugins.
|
||||
*
|
||||
* @param key unique identifier of the profiling.
|
||||
*/
|
||||
fun stopProfiling(key: String) {
|
||||
if (!currentProfilers.contains(key)) {
|
||||
return
|
||||
}
|
||||
Pury.stopProfiling(profilerName(key), ROOT_STAGE, 1)
|
||||
currentProfilers.remove(key)
|
||||
}
|
||||
|
||||
/**
|
||||
* Use to profile a block of code. Internally it will call start and stop stage.
|
||||
*
|
||||
* @param key unique identifier of the profiling.
|
||||
* @param stage the current stage to mark
|
||||
*/
|
||||
fun profileBlock(key: String, stage: STAGE, block: (() -> Unit)? = null) {
|
||||
startStage(key, stage)
|
||||
block?.invoke()
|
||||
stopStage(key, stage)
|
||||
}
|
||||
|
||||
/**
|
||||
* Use to add a new stage to profile inside the root profiling.
|
||||
* You should have called startProfiling with the same key before.
|
||||
* You should also call stopStage with same key and same stage to mark the end of this stage.
|
||||
*
|
||||
* @param key unique identifier of the profiling.
|
||||
* @param stage the current stage to profile
|
||||
*/
|
||||
fun startStage(key: String, stage: STAGE) {
|
||||
if (!currentProfilers.contains(key)) return
|
||||
Pury.startProfiling(profilerName(key), stage.name, stage.ordinal + 1, 1)
|
||||
}
|
||||
|
||||
/**
|
||||
* Use to finish the profiling of a stage.
|
||||
* You should have called startStage with the same key and same stage before.
|
||||
*
|
||||
* @param key unique identifier of the profiling.
|
||||
* @param stage the current stage to profile
|
||||
*/
|
||||
fun stopStage(key: String, stage: STAGE) {
|
||||
if (!currentProfilers.contains(key)) return
|
||||
Pury.stopProfiling(profilerName(key), stage.name, 1)
|
||||
}
|
||||
|
||||
private fun profilerName(key: String) = "${name}_$key"
|
||||
}
|
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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.api.util.profiling
|
||||
|
||||
import retrofit2.Call
|
||||
import retrofit2.http.Body
|
||||
import retrofit2.http.POST
|
||||
|
||||
interface PerServerAPI {
|
||||
|
||||
@POST("api/result")
|
||||
fun postReport(@Body profileResult: ProfileReport): Call<Unit>
|
||||
}
|
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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.api.util.profiling
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
interface ProfileResult {
|
||||
val name: String?
|
||||
val depth: Int?
|
||||
val nestedResults: List<ProfileResult>?
|
||||
}
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class SingleProfileResultRest(
|
||||
override val name: String? = null,
|
||||
override val depth: Int? = 0,
|
||||
override val nestedResults: List<SingleProfileResultRest>? = null,
|
||||
val startTime: Long? = 0L,
|
||||
val execTime: Long? = 0L
|
||||
) : ProfileResult
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class ProfileReport(
|
||||
@Json(name = "user")
|
||||
val user: String? = null,
|
||||
@Json(name = "device")
|
||||
val device: String? = null,
|
||||
@Json(name = "id")
|
||||
val id: String? = null,
|
||||
@Json(name = "rootProfileResults")
|
||||
val rootProfileResult: SingleProfileResultRest? = null,
|
||||
@Json(name = "tag")
|
||||
val tag: String? = null
|
||||
)
|
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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.api.util.profiling
|
||||
|
||||
import dagger.Binds
|
||||
import dagger.Lazy
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.internal.tls.OkHostnameVerifier
|
||||
import org.matrix.android.sdk.BuildConfig
|
||||
import org.matrix.android.sdk.internal.di.Unauthenticated
|
||||
import org.matrix.android.sdk.internal.network.HttpHeaders
|
||||
import org.matrix.android.sdk.internal.network.RetrofitFactory
|
||||
|
||||
@Module
|
||||
internal abstract class PerfModule {
|
||||
|
||||
@Module
|
||||
companion object {
|
||||
|
||||
@Provides
|
||||
@JvmStatic
|
||||
fun providesPrefServerAPI(@Unauthenticated okHttpClient: Lazy<OkHttpClient>,
|
||||
retrofitFactory: RetrofitFactory): PerServerAPI {
|
||||
val client = okHttpClient.get().newBuilder()
|
||||
.addInterceptor { chain ->
|
||||
var request = chain.request()
|
||||
val token = BuildConfig.PERF_TRACING_SERVER_TOKEN
|
||||
val newRequestBuilder = request.newBuilder()
|
||||
newRequestBuilder.header(HttpHeaders.Authorization, "Bearer $token")
|
||||
request = newRequestBuilder.build()
|
||||
chain.proceed(request)
|
||||
}
|
||||
.hostnameVerifier(OkHostnameVerifier)
|
||||
.build()
|
||||
return retrofitFactory.create(client, BuildConfig.PERF_TRACING_SERVER).create(PerServerAPI::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
@Binds
|
||||
abstract fun bindPublishTask(task: DefaultPublishPerfTask): PublishPerfTask
|
||||
}
|
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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.api.util.profiling
|
||||
|
||||
import android.os.Build
|
||||
import com.nikitakozlov.pury.Plugin
|
||||
import com.nikitakozlov.pury.profile.ProfilerId
|
||||
import com.nikitakozlov.pury.result.model.ProfileResult
|
||||
import com.nikitakozlov.pury.result.model.SingleProfileResult
|
||||
import org.matrix.android.sdk.BuildConfig
|
||||
import org.matrix.android.sdk.internal.task.TaskExecutor
|
||||
import org.matrix.android.sdk.internal.task.configureWith
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class PerfServerPlugin @Inject constructor(
|
||||
private val publishPerfTask: PublishPerfTask,
|
||||
private val taskExecutor: TaskExecutor
|
||||
) : Plugin {
|
||||
override fun handleResult(result: ProfileResult?, profilerId: ProfilerId?) {
|
||||
val report = ProfileReport(
|
||||
user = BuildConfig.PERF_TRACING_SERVER_USER,
|
||||
device = Build.DEVICE,
|
||||
id = profilerId?.profilerName,
|
||||
rootProfileResult = (result as? SingleProfileResult)?.let { ResultMapper.map(it) },
|
||||
tag = "original"
|
||||
)
|
||||
|
||||
publishPerfTask.configureWith(PublishPerfTask.Params(report))
|
||||
.executeBy(taskExecutor)
|
||||
}
|
||||
|
||||
object ResultMapper {
|
||||
|
||||
private const val MS_TO_NS = 1000000
|
||||
|
||||
fun map(singleProfileResult: SingleProfileResult): SingleProfileResultRest {
|
||||
return SingleProfileResultRest(
|
||||
name = singleProfileResult.stageName,
|
||||
depth = singleProfileResult.depth,
|
||||
execTime = singleProfileResult.execTime / MS_TO_NS,
|
||||
startTime = singleProfileResult.startTime / MS_TO_NS,
|
||||
nestedResults = singleProfileResult.nestedResults.filterIsInstance<SingleProfileResult>().map {
|
||||
map(it)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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.api.util.profiling
|
||||
|
||||
import com.nikitakozlov.pury.Logger
|
||||
import com.nikitakozlov.pury.Pury
|
||||
import timber.log.Timber
|
||||
|
||||
object ProfilingConfiguration {
|
||||
|
||||
init {
|
||||
Pury.setLogger(object : Logger {
|
||||
override fun result(tag: String, message: String) {
|
||||
Timber.tag(tag)
|
||||
Timber.v(message)
|
||||
}
|
||||
|
||||
override fun warning(tag: String, message: String) {
|
||||
Timber.tag(tag)
|
||||
Timber.w(message)
|
||||
}
|
||||
|
||||
override fun error(tag: String, message: String) {
|
||||
Timber.tag(tag)
|
||||
Timber.e(message)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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.api.util.profiling
|
||||
|
||||
import org.matrix.android.sdk.internal.network.executeRequest
|
||||
import org.matrix.android.sdk.internal.task.Task
|
||||
import javax.inject.Inject
|
||||
|
||||
internal interface PublishPerfTask : Task<PublishPerfTask.Params, Unit> {
|
||||
data class Params(
|
||||
val report: ProfileReport
|
||||
)
|
||||
}
|
||||
|
||||
internal class DefaultPublishPerfTask @Inject constructor(
|
||||
private val perfAPI: PerServerAPI
|
||||
) : PublishPerfTask {
|
||||
|
||||
override suspend fun execute(params: PublishPerfTask.Params) {
|
||||
return executeRequest(null) {
|
||||
apiCall = perfAPI.postReport(params.report)
|
||||
}
|
||||
}
|
||||
}
|
@@ -54,6 +54,7 @@ import org.matrix.android.sdk.api.session.room.model.Membership
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibilityContent
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary
|
||||
import org.matrix.android.sdk.api.session.room.send.SendPerformanceProfiler
|
||||
import org.matrix.android.sdk.internal.crypto.actions.EnsureOlmSessionsForDevicesAction
|
||||
import org.matrix.android.sdk.internal.crypto.actions.MegolmSessionDataImporter
|
||||
import org.matrix.android.sdk.internal.crypto.actions.MessageEncrypter
|
||||
@@ -653,12 +654,14 @@ internal class DefaultCryptoService @Inject constructor(
|
||||
/**
|
||||
* Encrypt an event content according to the configuration of the room.
|
||||
*
|
||||
* @param eventId the identifier of the event
|
||||
* @param eventContent the content of the event.
|
||||
* @param eventType the type of the event.
|
||||
* @param roomId the room identifier the event will be sent.
|
||||
* @param callback the asynchronous callback
|
||||
*/
|
||||
override fun encryptEventContent(eventContent: Content,
|
||||
override fun encryptEventContent(eventId: String,
|
||||
eventContent: Content,
|
||||
eventType: String,
|
||||
roomId: String,
|
||||
callback: MatrixCallback<MXEncryptEventContentResult>) {
|
||||
@@ -667,7 +670,12 @@ internal class DefaultCryptoService @Inject constructor(
|
||||
// Timber.v("## CRYPTO | encryptEventContent() : wait after e2e init")
|
||||
// internalStart(false)
|
||||
// }
|
||||
val userIds = getRoomUserIds(roomId)
|
||||
|
||||
SendPerformanceProfiler.startStage(eventId, SendPerformanceProfiler.Stages.ENCRYPT_GET_USERS)
|
||||
val userIds = getRoomUserIds(roomId)
|
||||
SendPerformanceProfiler.stopStage(eventId, SendPerformanceProfiler.Stages.ENCRYPT_GET_USERS)
|
||||
|
||||
SendPerformanceProfiler.startStage(eventId, SendPerformanceProfiler.Stages.ENCRYPT_SET_ROOM_ENCRYPTION)
|
||||
var alg = roomEncryptorsStore.get(roomId)
|
||||
if (alg == null) {
|
||||
val algorithm = getEncryptionAlgorithm(roomId)
|
||||
@@ -677,12 +685,13 @@ internal class DefaultCryptoService @Inject constructor(
|
||||
}
|
||||
}
|
||||
}
|
||||
SendPerformanceProfiler.stopStage(eventId, SendPerformanceProfiler.Stages.ENCRYPT_SET_ROOM_ENCRYPTION)
|
||||
val safeAlgorithm = alg
|
||||
if (safeAlgorithm != null) {
|
||||
val t0 = System.currentTimeMillis()
|
||||
Timber.v("## CRYPTO | encryptEventContent() starts")
|
||||
runCatching {
|
||||
val content = safeAlgorithm.encryptEventContent(eventContent, eventType, userIds)
|
||||
val content = safeAlgorithm.encryptEventContent(eventId, eventContent, eventType, userIds)
|
||||
Timber.v("## CRYPTO | encryptEventContent() : succeeds after ${System.currentTimeMillis() - t0} ms")
|
||||
MXEncryptEventContentResult(content, EventType.ENCRYPTED)
|
||||
}.foldToCallback(callback)
|
||||
@@ -803,17 +812,17 @@ internal class DefaultCryptoService @Inject constructor(
|
||||
onRoomKeyEvent(event)
|
||||
}
|
||||
EventType.REQUEST_SECRET,
|
||||
EventType.ROOM_KEY_REQUEST -> {
|
||||
EventType.ROOM_KEY_REQUEST -> {
|
||||
// save audit trail
|
||||
cryptoStore.saveGossipingEvent(event)
|
||||
// Requests are stacked, and will be handled one by one at the end of the sync (onSyncComplete)
|
||||
incomingGossipingRequestManager.onGossipingRequestEvent(event)
|
||||
}
|
||||
EventType.SEND_SECRET -> {
|
||||
EventType.SEND_SECRET -> {
|
||||
cryptoStore.saveGossipingEvent(event)
|
||||
onSecretSendReceived(event)
|
||||
}
|
||||
EventType.ROOM_KEY_WITHHELD -> {
|
||||
EventType.ROOM_KEY_WITHHELD -> {
|
||||
onKeyWithHeldReceived(event)
|
||||
}
|
||||
else -> {
|
||||
@@ -892,7 +901,7 @@ internal class DefaultCryptoService @Inject constructor(
|
||||
*/
|
||||
private fun handleSDKLevelGossip(secretName: String?, secretValue: String): Boolean {
|
||||
return when (secretName) {
|
||||
MASTER_KEY_SSSS_NAME -> {
|
||||
MASTER_KEY_SSSS_NAME -> {
|
||||
crossSigningService.onSecretMSKGossip(secretValue)
|
||||
true
|
||||
}
|
||||
@@ -1351,9 +1360,9 @@ internal class DefaultCryptoService @Inject constructor(
|
||||
override fun getWithHeldMegolmSession(roomId: String, sessionId: String): RoomKeyWithHeldContent? {
|
||||
return cryptoStore.getWithHeldMegolmSession(roomId, sessionId)
|
||||
}
|
||||
/* ==========================================================================================
|
||||
* For test only
|
||||
* ========================================================================================== */
|
||||
/* ==========================================================================================
|
||||
* For test only
|
||||
* ========================================================================================== */
|
||||
|
||||
@VisibleForTesting
|
||||
val cryptoStoreForTesting = cryptoStore
|
||||
|
@@ -33,7 +33,7 @@ internal interface IMXEncrypting {
|
||||
* @param userIds the room members the event will be sent to.
|
||||
* @return the encrypted content
|
||||
*/
|
||||
suspend fun encryptEventContent(eventContent: Content, eventType: String, userIds: List<String>): Content
|
||||
suspend fun encryptEventContent(eventId: String, eventContent: Content, eventType: String, userIds: List<String>): Content
|
||||
|
||||
/**
|
||||
* In Megolm, each recipient maintains a record of the ratchet value which allows
|
||||
|
@@ -24,6 +24,7 @@ import org.matrix.android.sdk.api.auth.data.Credentials
|
||||
import org.matrix.android.sdk.api.session.crypto.MXCryptoError
|
||||
import org.matrix.android.sdk.api.session.events.model.Content
|
||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||
import org.matrix.android.sdk.api.session.room.send.SendPerformanceProfiler
|
||||
import org.matrix.android.sdk.internal.crypto.DeviceListManager
|
||||
import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM
|
||||
import org.matrix.android.sdk.internal.crypto.MXOlmDevice
|
||||
@@ -71,17 +72,20 @@ internal class MXMegolmEncryption(
|
||||
private var sessionRotationPeriodMsgs: Int = 100
|
||||
private var sessionRotationPeriodMs: Int = 7 * 24 * 3600 * 1000
|
||||
|
||||
override suspend fun encryptEventContent(eventContent: Content,
|
||||
override suspend fun encryptEventContent(eventId: String,
|
||||
eventContent: Content,
|
||||
eventType: String,
|
||||
userIds: List<String>): Content {
|
||||
val ts = System.currentTimeMillis()
|
||||
Timber.v("## CRYPTO | encryptEventContent : getDevicesInRoom")
|
||||
val devices = getDevicesInRoom(userIds)
|
||||
Timber.v("## CRYPTO | encryptEventContent ${System.currentTimeMillis() - ts}: getDevicesInRoom ${devices.allowedDevices.map}")
|
||||
val outboundSession = ensureOutboundSession(devices.allowedDevices)
|
||||
val outboundSession = ensureOutboundSession(eventId, devices.allowedDevices)
|
||||
|
||||
SendPerformanceProfiler.startStage(eventId, SendPerformanceProfiler.Stages.ENCRYPT_MEGOLM_ENCRYPT)
|
||||
return encryptContent(outboundSession, eventType, eventContent)
|
||||
.also {
|
||||
SendPerformanceProfiler.stopStage(eventId, SendPerformanceProfiler.Stages.ENCRYPT_MEGOLM_ENCRYPT)
|
||||
notifyWithheldForSession(devices.withHeldDevices, outboundSession)
|
||||
}
|
||||
}
|
||||
@@ -128,7 +132,7 @@ internal class MXMegolmEncryption(
|
||||
*
|
||||
* @param devicesInRoom the devices list
|
||||
*/
|
||||
private suspend fun ensureOutboundSession(devicesInRoom: MXUsersDevicesMap<CryptoDeviceInfo>): MXOutboundSessionInfo {
|
||||
private suspend fun ensureOutboundSession(eventId: String, devicesInRoom: MXUsersDevicesMap<CryptoDeviceInfo>): MXOutboundSessionInfo {
|
||||
Timber.v("## CRYPTO | ensureOutboundSession start")
|
||||
var session = outboundSession
|
||||
if (session == null
|
||||
@@ -152,7 +156,9 @@ internal class MXMegolmEncryption(
|
||||
}
|
||||
}
|
||||
}
|
||||
SendPerformanceProfiler.startStage(eventId, SendPerformanceProfiler.Stages.ENCRYPT_MEGOLM_SHARE_KEYS)
|
||||
shareKey(safeSession, shareMap)
|
||||
SendPerformanceProfiler.stopStage(eventId, SendPerformanceProfiler.Stages.ENCRYPT_MEGOLM_SHARE_KEYS)
|
||||
return safeSession
|
||||
}
|
||||
|
||||
@@ -307,6 +313,7 @@ internal class MXMegolmEncryption(
|
||||
// Get canonical Json from
|
||||
|
||||
val payloadString = convertToUTF8(JsonCanonicalizer.getCanonicalJson(Map::class.java, payloadJson))
|
||||
|
||||
val ciphertext = olmDevice.encryptGroupMessage(session.sessionId, payloadString)
|
||||
|
||||
val map = HashMap<String, Any>()
|
||||
|
@@ -38,7 +38,7 @@ internal class MXOlmEncryption(
|
||||
private val ensureOlmSessionsForUsersAction: EnsureOlmSessionsForUsersAction)
|
||||
: IMXEncrypting {
|
||||
|
||||
override suspend fun encryptEventContent(eventContent: Content, eventType: String, userIds: List<String>): Content {
|
||||
override suspend fun encryptEventContent(eventId: String, eventContent: Content, eventType: String, userIds: List<String>): Content {
|
||||
// pick the list of recipients based on the membership list.
|
||||
//
|
||||
// TODO: there is a race condition here! What if a new user turns up
|
||||
|
@@ -54,7 +54,7 @@ internal class DefaultEncryptEventTask @Inject constructor(
|
||||
|
||||
// try {
|
||||
awaitCallback<MXEncryptEventContentResult> {
|
||||
params.crypto.encryptEventContent(localMutableContent, localEvent.type, params.roomId, it)
|
||||
params.crypto.encryptEventContent(localEvent.eventId, localMutableContent, localEvent.type, params.roomId, it)
|
||||
}.let { result ->
|
||||
val modifiedContent = HashMap(result.eventContent)
|
||||
params.keepKeys?.forEach { toKeep ->
|
||||
|
@@ -27,6 +27,7 @@ import org.matrix.android.sdk.api.Matrix
|
||||
import org.matrix.android.sdk.api.MatrixConfiguration
|
||||
import org.matrix.android.sdk.api.auth.AuthenticationService
|
||||
import org.matrix.android.sdk.api.raw.RawService
|
||||
import org.matrix.android.sdk.api.util.profiling.PerfModule
|
||||
import org.matrix.android.sdk.internal.SessionManager
|
||||
import org.matrix.android.sdk.internal.auth.AuthModule
|
||||
import org.matrix.android.sdk.internal.auth.SessionParamsStore
|
||||
@@ -44,6 +45,7 @@ import java.io.File
|
||||
NetworkModule::class,
|
||||
AuthModule::class,
|
||||
RawModule::class,
|
||||
PerfModule::class,
|
||||
NoOpTestModule::class
|
||||
])
|
||||
@MatrixScope
|
||||
|
@@ -21,11 +21,11 @@ import android.content.Context
|
||||
import android.content.res.Resources
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers
|
||||
import org.matrix.android.sdk.internal.util.createBackgroundHandler
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.android.asCoroutineDispatcher
|
||||
import kotlinx.coroutines.asCoroutineDispatcher
|
||||
import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers
|
||||
import org.matrix.android.sdk.internal.util.createBackgroundHandler
|
||||
import org.matrix.olm.OlmManager
|
||||
import java.io.File
|
||||
import java.util.concurrent.Executors
|
||||
|
@@ -22,11 +22,13 @@ import androidx.work.BackoffPolicy
|
||||
import androidx.work.ExistingWorkPolicy
|
||||
import androidx.work.OneTimeWorkRequest
|
||||
import androidx.work.Operation
|
||||
import com.nikitakozlov.pury.annotations.StartProfiling
|
||||
import com.squareup.inject.assisted.Assisted
|
||||
import com.squareup.inject.assisted.AssistedInject
|
||||
import kotlinx.coroutines.launch
|
||||
import org.matrix.android.sdk.api.session.content.ContentAttachmentData
|
||||
import org.matrix.android.sdk.api.session.crypto.CryptoService
|
||||
import org.matrix.android.sdk.api.session.events.model.Content
|
||||
import org.matrix.android.sdk.api.session.events.model.Event
|
||||
import org.matrix.android.sdk.api.session.events.model.isAttachmentMessage
|
||||
import org.matrix.android.sdk.api.session.events.model.isTextMessage
|
||||
@@ -44,7 +46,6 @@ import org.matrix.android.sdk.api.session.room.send.SendState
|
||||
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
|
||||
import org.matrix.android.sdk.api.util.Cancelable
|
||||
import org.matrix.android.sdk.api.util.CancelableBag
|
||||
import org.matrix.android.sdk.api.util.JsonDict
|
||||
import org.matrix.android.sdk.api.util.NoOpCancellable
|
||||
import org.matrix.android.sdk.internal.di.SessionId
|
||||
import org.matrix.android.sdk.internal.di.WorkManagerProvider
|
||||
@@ -81,14 +82,21 @@ internal class DefaultSendService @AssistedInject constructor(
|
||||
|
||||
private val workerFutureListenerExecutor = Executors.newSingleThreadExecutor()
|
||||
|
||||
override fun sendEvent(eventType: String, content: JsonDict?): Cancelable {
|
||||
override fun sendEvent(eventType: String, content: Content?, onBuiltEvent: ((Event) -> Unit)?): Cancelable {
|
||||
return localEchoEventFactory.createEvent(roomId, eventType, content)
|
||||
.also { onBuiltEvent?.invoke(it) }
|
||||
.also { createLocalEcho(it) }
|
||||
.let { sendEvent(it) }
|
||||
}
|
||||
|
||||
override fun sendTextMessage(text: CharSequence, msgType: String, autoMarkdown: Boolean): Cancelable {
|
||||
override fun sendTextMessage(
|
||||
text: CharSequence,
|
||||
msgType: String,
|
||||
autoMarkdown: Boolean,
|
||||
onBuiltEvent: ((Event) -> Unit)?
|
||||
): Cancelable {
|
||||
return localEchoEventFactory.createTextEvent(roomId, msgType, text, autoMarkdown)
|
||||
.also { onBuiltEvent?.invoke(it) }
|
||||
.also { createLocalEcho(it) }
|
||||
.let { sendEvent(it) }
|
||||
}
|
||||
@@ -106,8 +114,14 @@ internal class DefaultSendService @AssistedInject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
override fun sendFormattedTextMessage(text: String, formattedText: String, msgType: String): Cancelable {
|
||||
override fun sendFormattedTextMessage(
|
||||
text: String,
|
||||
formattedText: String,
|
||||
msgType: String,
|
||||
onBuiltEvent: ((Event) -> Unit)?
|
||||
): Cancelable {
|
||||
return localEchoEventFactory.createFormattedTextEvent(roomId, TextContent(text, formattedText), msgType)
|
||||
.also { onBuiltEvent?.invoke(it) }
|
||||
.also { createLocalEcho(it) }
|
||||
.let { sendEvent(it) }
|
||||
}
|
||||
@@ -138,6 +152,7 @@ internal class DefaultSendService @AssistedInject constructor(
|
||||
.let { timelineSendEventWorkCommon.postWork(roomId, it) }
|
||||
}
|
||||
|
||||
@StartProfiling(profilerName = "Sending", stageName = "Send service", stageOrder = 0)
|
||||
override fun resendTextMessage(localEcho: TimelineEvent): Cancelable {
|
||||
if (localEcho.root.isTextMessage() && localEcho.root.sendState.hasFailed()) {
|
||||
localEchoRepository.updateSendState(localEcho.eventId, SendState.UNSENT)
|
||||
|
@@ -25,6 +25,7 @@ import org.matrix.android.sdk.api.session.crypto.CryptoService
|
||||
import org.matrix.android.sdk.api.session.events.model.Event
|
||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||
import org.matrix.android.sdk.api.session.events.model.toContent
|
||||
import org.matrix.android.sdk.api.session.room.send.SendPerformanceProfiler
|
||||
import org.matrix.android.sdk.api.session.room.send.SendState
|
||||
import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM
|
||||
import org.matrix.android.sdk.internal.crypto.MXEventDecryptionResult
|
||||
@@ -65,7 +66,11 @@ internal class EncryptEventWorker(context: Context, params: WorkerParameters)
|
||||
override suspend fun doSafeWork(params: Params): Result {
|
||||
Timber.v("## SendEvent: Start Encrypt work for event ${params.eventId}")
|
||||
|
||||
SendPerformanceProfiler.startStage(params.eventId, SendPerformanceProfiler.Stages.GET_UP_TO_DATE_ECHO)
|
||||
val localEvent = localEchoRepository.getUpToDateEcho(params.eventId)
|
||||
SendPerformanceProfiler.stopStage(params.eventId, SendPerformanceProfiler.Stages.GET_UP_TO_DATE_ECHO)
|
||||
|
||||
SendPerformanceProfiler.startStage(params.eventId, SendPerformanceProfiler.Stages.ENCRYPT_WORKER)
|
||||
if (localEvent?.eventId == null) {
|
||||
return Result.success()
|
||||
}
|
||||
@@ -86,7 +91,7 @@ internal class EncryptEventWorker(context: Context, params: WorkerParameters)
|
||||
var result: MXEncryptEventContentResult? = null
|
||||
try {
|
||||
result = awaitCallback {
|
||||
crypto.encryptEventContent(localMutableContent, localEvent.type, localEvent.roomId!!, it)
|
||||
crypto.encryptEventContent(localEvent.eventId, localMutableContent, localEvent.type, localEvent.roomId!!, it)
|
||||
}
|
||||
} catch (throwable: Throwable) {
|
||||
error = throwable
|
||||
@@ -122,7 +127,7 @@ internal class EncryptEventWorker(context: Context, params: WorkerParameters)
|
||||
localEcho.setDecryptionResult(it)
|
||||
}
|
||||
}
|
||||
|
||||
SendPerformanceProfiler.stopStage(params.eventId, SendPerformanceProfiler.Stages.ENCRYPT_WORKER)
|
||||
val nextWorkerParams = SendEventWorker.Params(sessionId = params.sessionId, eventId = params.eventId)
|
||||
return Result.success(WorkerParamsFactory.toData(nextWorkerParams))
|
||||
} else {
|
||||
|
@@ -53,6 +53,7 @@ import org.matrix.android.sdk.api.session.room.model.relation.ReactionContent
|
||||
import org.matrix.android.sdk.api.session.room.model.relation.ReactionInfo
|
||||
import org.matrix.android.sdk.api.session.room.model.relation.RelationDefaultContent
|
||||
import org.matrix.android.sdk.api.session.room.model.relation.ReplyToContent
|
||||
import org.matrix.android.sdk.api.session.room.send.SendPerformanceProfiler
|
||||
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
|
||||
import org.matrix.android.sdk.api.session.room.timeline.getLastMessageContent
|
||||
import org.matrix.android.sdk.api.session.room.timeline.isReply
|
||||
@@ -325,6 +326,7 @@ internal class LocalEchoEventFactory @Inject constructor(
|
||||
|
||||
fun createEvent(roomId: String, type: String, content: Content?): Event {
|
||||
val localId = LocalEcho.createLocalEchoId()
|
||||
SendPerformanceProfiler.startProfiling(localId)
|
||||
return Event(
|
||||
roomId = roomId,
|
||||
originServerTs = dummyOriginServerTs(),
|
||||
@@ -433,10 +435,10 @@ internal class LocalEchoEventFactory @Inject constructor(
|
||||
TextContent(content.body, formattedText)
|
||||
}
|
||||
}
|
||||
MessageType.MSGTYPE_FILE -> return TextContent("sent a file.")
|
||||
MessageType.MSGTYPE_AUDIO -> return TextContent("sent an audio file.")
|
||||
MessageType.MSGTYPE_IMAGE -> return TextContent("sent an image.")
|
||||
MessageType.MSGTYPE_VIDEO -> return TextContent("sent a video.")
|
||||
MessageType.MSGTYPE_FILE -> return TextContent("sent a file.")
|
||||
MessageType.MSGTYPE_AUDIO -> return TextContent("sent an audio file.")
|
||||
MessageType.MSGTYPE_IMAGE -> return TextContent("sent an image.")
|
||||
MessageType.MSGTYPE_VIDEO -> return TextContent("sent a video.")
|
||||
else -> return TextContent(content?.body ?: "")
|
||||
}
|
||||
}
|
||||
|
@@ -25,6 +25,7 @@ import org.matrix.android.sdk.api.session.events.model.EventType
|
||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageContent
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageType
|
||||
import org.matrix.android.sdk.api.session.room.send.SendPerformanceProfiler
|
||||
import org.matrix.android.sdk.api.session.room.send.SendState
|
||||
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
|
||||
import org.matrix.android.sdk.internal.database.RealmSessionProvider
|
||||
@@ -62,6 +63,7 @@ internal class LocalEchoRepository @Inject constructor(@SessionDatabase private
|
||||
if (event.eventId == null) {
|
||||
throw IllegalStateException("You should have set an eventId for your event")
|
||||
}
|
||||
// SendPerformanceProfiler.startStage(event.eventId, SendPerformanceProfiler.Stages.LOCAL_ECHO)
|
||||
val timelineEventEntity = realmSessionProvider.withRealm { realm ->
|
||||
val eventEntity = event.toEntity(roomId, SendState.UNSENT, System.currentTimeMillis())
|
||||
val roomMemberHelper = RoomMemberHelper(realm, roomId)
|
||||
@@ -86,6 +88,7 @@ internal class LocalEchoRepository @Inject constructor(@SessionDatabase private
|
||||
val roomEntity = RoomEntity.where(realm, roomId = roomId).findFirst() ?: return@asyncTransaction
|
||||
roomEntity.sendingTimelineEvents.add(0, timelineEventEntity)
|
||||
roomSummaryUpdater.updateSendingInformation(realm, roomId)
|
||||
//SendPerformanceProfiler.stopStage(event.eventId, SendPerformanceProfiler.Stages.LOCAL_ECHO)
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -37,6 +37,7 @@ internal class RoomEventSender @Inject constructor(
|
||||
@SessionId private val sessionId: String,
|
||||
private val cryptoService: CryptoService
|
||||
) {
|
||||
|
||||
fun sendEvent(event: Event): Cancelable {
|
||||
// Encrypted room handling
|
||||
return if (cryptoService.isRoomEncrypted(event.roomId ?: "")
|
||||
|
@@ -24,6 +24,7 @@ import io.realm.RealmConfiguration
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.matrix.android.sdk.api.failure.shouldBeRetried
|
||||
import org.matrix.android.sdk.api.session.events.model.Content
|
||||
import org.matrix.android.sdk.api.session.room.send.SendPerformanceProfiler
|
||||
import org.matrix.android.sdk.api.session.room.send.SendState
|
||||
import org.matrix.android.sdk.internal.di.SessionDatabase
|
||||
import org.matrix.android.sdk.internal.network.executeRequest
|
||||
@@ -62,6 +63,7 @@ internal class SendEventWorker(context: Context,
|
||||
}
|
||||
|
||||
override suspend fun doSafeWork(params: Params): Result {
|
||||
SendPerformanceProfiler.startStage(params.eventId, SendPerformanceProfiler.Stages.SEND_WORKER)
|
||||
val event = localEchoRepository.getUpToDateEcho(params.eventId)
|
||||
if (event?.eventId == null || event.roomId == null) {
|
||||
localEchoRepository.updateSendState(params.eventId, SendState.UNDELIVERED)
|
||||
@@ -87,6 +89,7 @@ internal class SendEventWorker(context: Context,
|
||||
Timber.v("## SendEvent: [${System.currentTimeMillis()}] Send event ${params.eventId}")
|
||||
return try {
|
||||
sendEvent(event.eventId, event.roomId, event.type, event.content)
|
||||
SendPerformanceProfiler.stopStage(event.eventId, SendPerformanceProfiler.Stages.SEND_WORKER)
|
||||
Result.success()
|
||||
} catch (exception: Throwable) {
|
||||
if (/*currentAttemptCount >= MAX_NUMBER_OF_RETRY_BEFORE_FAILING ||**/ !exception.shouldBeRetried()) {
|
||||
@@ -106,9 +109,11 @@ internal class SendEventWorker(context: Context,
|
||||
|
||||
private suspend fun sendEvent(eventId: String, roomId: String, type: String, content: Content?) {
|
||||
localEchoRepository.updateSendState(eventId, SendState.SENDING)
|
||||
SendPerformanceProfiler.startStage(eventId, SendPerformanceProfiler.Stages.SEND_REQUEST)
|
||||
executeRequest<SendResponse>(eventBus) {
|
||||
apiCall = roomAPI.send(eventId, roomId, type, content)
|
||||
}
|
||||
SendPerformanceProfiler.stopStage(eventId, SendPerformanceProfiler.Stages.SEND_REQUEST)
|
||||
localEchoRepository.updateSendState(eventId, SendState.SENT)
|
||||
}
|
||||
}
|
||||
|
@@ -65,6 +65,7 @@ import org.matrix.android.sdk.internal.session.sync.model.RoomsSyncResponse
|
||||
import io.realm.Realm
|
||||
import io.realm.kotlin.createObject
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.matrix.android.sdk.api.session.room.send.SendPerformanceProfiler
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
@@ -333,6 +334,7 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
|
||||
event.unsignedData?.transactionId?.also {
|
||||
val sendingEventEntity = roomEntity.sendingTimelineEvents.find(it)
|
||||
if (sendingEventEntity != null) {
|
||||
SendPerformanceProfiler.profileBlock(it, SendPerformanceProfiler.Stages.RECEIVED_IN_SYNC)
|
||||
Timber.v("Remove local echo for tx:$it")
|
||||
roomEntity.sendingTimelineEvents.remove(sendingEventEntity)
|
||||
if (event.isEncrypted() && event.content?.get("algorithm") as? String == MXCRYPTO_ALGORITHM_MEGOLM) {
|
||||
|
@@ -32,8 +32,6 @@
|
||||
import static
|
||||
|
||||
### Rubbish from merge. Please delete those lines (sometimes in comment)
|
||||
<<<<<<<
|
||||
>>>>>>>
|
||||
|
||||
### carry return before "}". Please remove empty lines.
|
||||
\n\s*\n\s*\}
|
||||
@@ -164,7 +162,7 @@ Formatter\.formatShortFileSize===1
|
||||
# android\.text\.TextUtils
|
||||
|
||||
### This is not a rule, but a warning: the number of "enum class" has changed. For Json classes, it is mandatory that they have `@JsonClass(generateAdapter = false)`. If it is ok, change the value in file forbidden_strings_in_code.txt
|
||||
enum class===80
|
||||
enum class===81
|
||||
|
||||
### Do not import temporary legacy classes
|
||||
import org.matrix.android.sdk.internal.legacy.riot===3
|
||||
|
@@ -334,6 +334,9 @@ dependencies {
|
||||
// Phone number https://github.com/google/libphonenumber
|
||||
implementation 'com.googlecode.libphonenumber:libphonenumber:8.10.23'
|
||||
|
||||
debugImplementation 'com.nikitakozlov.pury:pury:1.1.0'
|
||||
releaseImplementation 'com.nikitakozlov.pury:pury-no-op:1.1.0'
|
||||
|
||||
// rx
|
||||
implementation 'io.reactivex.rxjava2:rxkotlin:2.3.0'
|
||||
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
|
||||
|
@@ -94,6 +94,7 @@ import org.matrix.android.sdk.api.util.toOptional
|
||||
import org.matrix.android.sdk.internal.crypto.attachments.toElementToDecrypt
|
||||
import org.matrix.android.sdk.internal.crypto.model.event.EncryptedEventContent
|
||||
import org.matrix.android.sdk.internal.crypto.model.event.WithHeldCode
|
||||
import org.matrix.android.sdk.api.session.room.send.SendPerformanceProfiler
|
||||
import org.matrix.android.sdk.internal.util.awaitCallback
|
||||
import org.matrix.android.sdk.rx.rx
|
||||
import org.matrix.android.sdk.rx.unwrap
|
||||
@@ -551,7 +552,9 @@ class RoomDetailViewModel @AssistedInject constructor(
|
||||
when (val slashCommandResult = CommandParser.parseSplashCommand(action.text)) {
|
||||
is ParsedCommand.ErrorNotACommand -> {
|
||||
// Send the text message to the room
|
||||
room.sendTextMessage(action.text, autoMarkdown = action.autoMarkdown)
|
||||
room.sendTextMessage(action.text, autoMarkdown = action.autoMarkdown) {
|
||||
SendPerformanceProfiler.startProfiling(it.eventId!!)
|
||||
}
|
||||
_viewEvents.post(RoomDetailViewEvents.MessageSent)
|
||||
popDraft()
|
||||
}
|
||||
@@ -890,6 +893,9 @@ class RoomDetailViewModel @AssistedInject constructor(
|
||||
private fun handleEventVisible(action: RoomDetailAction.TimelineEventTurnsVisible) {
|
||||
viewModelScope.launch(Dispatchers.Default) {
|
||||
if (action.event.root.sendState.isSent()) { // ignore pending/local events
|
||||
action.event.root.unsignedData?.transactionId?.also {
|
||||
SendPerformanceProfiler.stopProfiling(it)
|
||||
}
|
||||
visibleEventsObservable.accept(action)
|
||||
}
|
||||
// We need to update this with the related m.replace also (to move read receipt)
|
||||
|
@@ -25,6 +25,7 @@ import androidx.recyclerview.widget.RecyclerView
|
||||
import com.airbnb.epoxy.EpoxyController
|
||||
import com.airbnb.epoxy.EpoxyModel
|
||||
import com.airbnb.epoxy.VisibilityState
|
||||
import im.vector.app.BuildConfig
|
||||
import im.vector.app.core.date.DateFormatKind
|
||||
import im.vector.app.core.date.VectorDateFormatter
|
||||
import im.vector.app.core.epoxy.LoadingItem_
|
||||
@@ -176,6 +177,7 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec
|
||||
}
|
||||
|
||||
init {
|
||||
isDebugLoggingEnabled = BuildConfig.DEBUG
|
||||
addInterceptor(this)
|
||||
requestModelBuild()
|
||||
}
|
||||
|
Reference in New Issue
Block a user