refactor: init optimization
This commit is contained in:
@@ -26,12 +26,12 @@ import me.rhunk.snapenhance.e2ee.E2EEImplementation
|
||||
import me.rhunk.snapenhance.messaging.ModDatabase
|
||||
import me.rhunk.snapenhance.messaging.StreaksReminder
|
||||
import me.rhunk.snapenhance.scripting.RemoteScriptManager
|
||||
import me.rhunk.snapenhance.ui.overlay.SettingsOverlay
|
||||
import me.rhunk.snapenhance.ui.manager.MainActivity
|
||||
import me.rhunk.snapenhance.ui.manager.data.InstallationSummary
|
||||
import me.rhunk.snapenhance.ui.manager.data.ModInfo
|
||||
import me.rhunk.snapenhance.ui.manager.data.PlatformInfo
|
||||
import me.rhunk.snapenhance.ui.manager.data.SnapchatAppInfo
|
||||
import me.rhunk.snapenhance.ui.overlay.SettingsOverlay
|
||||
import me.rhunk.snapenhance.ui.setup.Requirements
|
||||
import me.rhunk.snapenhance.ui.setup.SetupActivity
|
||||
import java.io.ByteArrayInputStream
|
||||
@@ -43,6 +43,8 @@ import java.security.cert.X509Certificate
|
||||
class RemoteSideContext(
|
||||
val androidContext: Context
|
||||
) {
|
||||
val coroutineScope = CoroutineScope(Dispatchers.IO)
|
||||
|
||||
private var _activity: WeakReference<ComponentActivity>? = null
|
||||
lateinit var bridgeService: BridgeService
|
||||
|
||||
@@ -78,7 +80,6 @@ class RemoteSideContext(
|
||||
}
|
||||
.components { add(VideoFrameDecoder.Factory()) }.build()
|
||||
}
|
||||
val coroutineScope = CoroutineScope(Dispatchers.IO)
|
||||
|
||||
fun reload() {
|
||||
log.verbose("Loading RemoteSideContext")
|
||||
|
||||
@@ -11,6 +11,9 @@ import android.os.Process
|
||||
import android.widget.Toast
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import me.rhunk.snapenhance.core.Logger
|
||||
import me.rhunk.snapenhance.core.bridge.BridgeClient
|
||||
import me.rhunk.snapenhance.core.bridge.wrapper.LocaleWrapper
|
||||
@@ -27,13 +30,11 @@ import me.rhunk.snapenhance.manager.impl.FeatureManager
|
||||
import me.rhunk.snapenhance.nativelib.NativeConfig
|
||||
import me.rhunk.snapenhance.nativelib.NativeLib
|
||||
import me.rhunk.snapenhance.scripting.core.CoreScriptRuntime
|
||||
import java.util.concurrent.ExecutorService
|
||||
import java.util.concurrent.Executors
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
class ModContext {
|
||||
private val executorService: ExecutorService = Executors.newCachedThreadPool()
|
||||
val coroutineScope = CoroutineScope(Dispatchers.IO)
|
||||
|
||||
lateinit var androidContext: Context
|
||||
lateinit var bridgeClient: BridgeClient
|
||||
@@ -73,13 +74,13 @@ class ModContext {
|
||||
}
|
||||
}
|
||||
|
||||
fun executeAsync(runnable: ModContext.() -> Unit) {
|
||||
executorService.submit {
|
||||
fun executeAsync(runnable: suspend ModContext.() -> Unit) {
|
||||
coroutineScope.launch {
|
||||
runCatching {
|
||||
runnable()
|
||||
}.onFailure {
|
||||
longToast("Async task failed " + it.message)
|
||||
Logger.xposedLog("Async task failed", it)
|
||||
log.error("Async task failed", it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,10 @@ package me.rhunk.snapenhance
|
||||
import android.app.Activity
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import me.rhunk.snapenhance.bridge.SyncCallback
|
||||
import me.rhunk.snapenhance.core.Logger
|
||||
import me.rhunk.snapenhance.core.bridge.BridgeClient
|
||||
@@ -13,8 +17,7 @@ import me.rhunk.snapenhance.core.messaging.MessagingGroupInfo
|
||||
import me.rhunk.snapenhance.data.SnapClassCache
|
||||
import me.rhunk.snapenhance.hook.HookStage
|
||||
import me.rhunk.snapenhance.hook.hook
|
||||
import kotlin.time.ExperimentalTime
|
||||
import kotlin.time.measureTime
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
|
||||
class SnapEnhance {
|
||||
@@ -55,7 +58,13 @@ class SnapEnhance {
|
||||
return@connect
|
||||
}
|
||||
runCatching {
|
||||
init()
|
||||
measureTimeMillis {
|
||||
runBlocking {
|
||||
init(this)
|
||||
}
|
||||
}.also {
|
||||
appContext.log.verbose("init took ${it}ms")
|
||||
}
|
||||
}.onSuccess {
|
||||
isBridgeInitialized = true
|
||||
}.onFailure {
|
||||
@@ -92,34 +101,28 @@ class SnapEnhance {
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalTime::class)
|
||||
private fun init() {
|
||||
measureTime {
|
||||
with(appContext) {
|
||||
reloadConfig()
|
||||
private fun init(scope: CoroutineScope) {
|
||||
with(appContext) {
|
||||
reloadConfig()
|
||||
scope.launch(Dispatchers.IO) {
|
||||
initNative()
|
||||
executeAsync {
|
||||
translation.userLocale = getConfigLocale()
|
||||
translation.loadFromBridge(bridgeClient)
|
||||
}
|
||||
|
||||
mappings.loadFromBridge(bridgeClient)
|
||||
mappings.init(androidContext)
|
||||
eventDispatcher.init()
|
||||
//if mappings aren't loaded, we can't initialize features
|
||||
if (!mappings.isMappingsLoaded()) return
|
||||
features.init()
|
||||
syncRemote()
|
||||
scriptRuntime.connect(bridgeClient.getScriptingInterface())
|
||||
translation.userLocale = getConfigLocale()
|
||||
translation.loadFromBridge(bridgeClient)
|
||||
}
|
||||
}.also { time ->
|
||||
appContext.log.verbose("init took $time")
|
||||
|
||||
mappings.loadFromBridge(bridgeClient)
|
||||
mappings.init(androidContext)
|
||||
eventDispatcher.init()
|
||||
//if mappings aren't loaded, we can't initialize features
|
||||
if (!mappings.isMappingsLoaded()) return
|
||||
features.init()
|
||||
scriptRuntime.connect(bridgeClient.getScriptingInterface())
|
||||
syncRemote()
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalTime::class)
|
||||
private fun onActivityCreate() {
|
||||
measureTime {
|
||||
measureTimeMillis {
|
||||
with(appContext) {
|
||||
features.onActivityCreate()
|
||||
actionManager.init()
|
||||
|
||||
@@ -5,7 +5,6 @@ import android.content.DialogInterface
|
||||
import android.os.Environment
|
||||
import android.text.InputType
|
||||
import android.widget.EditText
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.joinAll
|
||||
@@ -44,8 +43,6 @@ class ExportChatMessages : AbstractAction() {
|
||||
context.feature(Messaging::class).conversationManager
|
||||
}
|
||||
|
||||
private val coroutineScope = CoroutineScope(Dispatchers.Default)
|
||||
|
||||
private val dialogLogs = mutableListOf<String>()
|
||||
private var currentActionDialog: AlertDialog? = null
|
||||
|
||||
@@ -83,7 +80,7 @@ class ExportChatMessages : AbstractAction() {
|
||||
}
|
||||
|
||||
private suspend fun askAmountOfMessages() = suspendCancellableCoroutine { cont ->
|
||||
coroutineScope.launch(Dispatchers.Main) {
|
||||
context.coroutineScope.launch(Dispatchers.Main) {
|
||||
val input = EditText(context.mainActivity)
|
||||
input.inputType = InputType.TYPE_CLASS_NUMBER
|
||||
input.setSingleLine()
|
||||
@@ -132,7 +129,7 @@ class ExportChatMessages : AbstractAction() {
|
||||
}
|
||||
|
||||
override fun run() {
|
||||
coroutineScope.launch(Dispatchers.Main) {
|
||||
context.coroutineScope.launch(Dispatchers.Main) {
|
||||
exportType = askExportType() ?: return@launch
|
||||
mediaToDownload = if (exportType == ExportFormat.HTML) askMediaToDownload() else null
|
||||
amountOfMessages = askAmountOfMessages()
|
||||
@@ -289,7 +286,7 @@ class ExportChatMessages : AbstractAction() {
|
||||
|
||||
logDialog(conversationSize)
|
||||
|
||||
coroutineScope.launch {
|
||||
context.coroutineScope.launch {
|
||||
conversations.forEach { conversation ->
|
||||
launch {
|
||||
runCatching {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package me.rhunk.snapenhance.features.impl
|
||||
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import me.rhunk.snapenhance.core.event.events.impl.SendMessageWithContentEvent
|
||||
import me.rhunk.snapenhance.core.messaging.SocialScope
|
||||
import me.rhunk.snapenhance.data.ContentType
|
||||
@@ -13,7 +15,6 @@ class ScopeSync : Feature("Scope Sync", loadParams = FeatureLoadParams.INIT_SYNC
|
||||
}
|
||||
|
||||
private val updateJobs = mutableMapOf<String, Job>()
|
||||
private val coroutineScope = CoroutineScope(Dispatchers.Main)
|
||||
|
||||
private fun sync(conversationId: String) {
|
||||
context.database.getDMOtherParticipant(conversationId)?.also { participant ->
|
||||
@@ -31,7 +32,7 @@ class ScopeSync : Feature("Scope Sync", loadParams = FeatureLoadParams.INIT_SYNC
|
||||
event.destinations.conversations.map { it.toString() }.forEach { conversationId ->
|
||||
updateJobs[conversationId]?.also { it.cancel() }
|
||||
|
||||
updateJobs[conversationId] = (coroutineScope.launch {
|
||||
updateJobs[conversationId] = (context.coroutineScope.launch {
|
||||
delay(DELAY_BEFORE_SYNC)
|
||||
sync(conversationId)
|
||||
})
|
||||
|
||||
@@ -18,8 +18,7 @@ import me.rhunk.snapenhance.features.FeatureLoadParams
|
||||
import me.rhunk.snapenhance.ui.addForegroundDrawable
|
||||
import me.rhunk.snapenhance.ui.removeForegroundDrawable
|
||||
import java.util.concurrent.Executors
|
||||
import kotlin.time.ExperimentalTime
|
||||
import kotlin.time.measureTime
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
private fun Any.longHashCode(): Long {
|
||||
var h = 1125899906842597L
|
||||
@@ -91,17 +90,16 @@ class MessageLogger : Feature("MessageLogger",
|
||||
return computeMessageIdentifier(conversationId, serverMessageId)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalTime::class)
|
||||
override fun asyncOnActivityCreate() {
|
||||
if (!isEnabled || !context.database.hasArroyo()) {
|
||||
return
|
||||
}
|
||||
|
||||
measureTime {
|
||||
measureTimeMillis {
|
||||
val conversationIds = context.database.getFeedEntries(PREFETCH_FEED_COUNT).map { it.key!! }
|
||||
if (conversationIds.isEmpty()) return@measureTime
|
||||
if (conversationIds.isEmpty()) return@measureTimeMillis
|
||||
fetchedMessages.addAll(messageLoggerInterface.getLoggedIds(conversationIds.toTypedArray(), PREFETCH_MESSAGE_COUNT).toList())
|
||||
}.also { context.log.verbose("Loaded ${fetchedMessages.size} cached messages in $it") }
|
||||
}.also { context.log.verbose("Loaded ${fetchedMessages.size} cached messages in ${it}ms") }
|
||||
}
|
||||
|
||||
override fun init() {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package me.rhunk.snapenhance.manager.impl
|
||||
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import me.rhunk.snapenhance.ModContext
|
||||
import me.rhunk.snapenhance.core.Logger
|
||||
import me.rhunk.snapenhance.features.Feature
|
||||
@@ -24,22 +26,31 @@ import me.rhunk.snapenhance.features.impl.ui.PinConversations
|
||||
import me.rhunk.snapenhance.features.impl.ui.UITweaks
|
||||
import me.rhunk.snapenhance.manager.Manager
|
||||
import me.rhunk.snapenhance.ui.menu.impl.MenuViewInjector
|
||||
import java.util.concurrent.Executors
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
class FeatureManager(private val context: ModContext) : Manager {
|
||||
private val asyncLoadExecutorService = Executors.newFixedThreadPool(5)
|
||||
class FeatureManager(
|
||||
private val context: ModContext
|
||||
) : Manager {
|
||||
private val features = mutableListOf<Feature>()
|
||||
|
||||
private fun register(vararg featureClasses: KClass<out Feature>) {
|
||||
featureClasses.forEach { clazz ->
|
||||
runCatching {
|
||||
clazz.constructors.first().call().also { feature ->
|
||||
feature.context = context
|
||||
features.add(feature)
|
||||
runBlocking {
|
||||
featureClasses.forEach { clazz ->
|
||||
context.coroutineScope.launch {
|
||||
runCatching {
|
||||
clazz.java.constructors.first().newInstance()
|
||||
.let { it as Feature }
|
||||
.also {
|
||||
it.context = context
|
||||
synchronized(features) {
|
||||
features.add(it)
|
||||
}
|
||||
}
|
||||
}.onFailure {
|
||||
Logger.xposedLog("Failed to register feature ${clazz.simpleName}", it)
|
||||
}
|
||||
}
|
||||
}.onFailure {
|
||||
Logger.xposedLog("Failed to register feature ${clazz.simpleName}", it)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -95,34 +106,61 @@ class FeatureManager(private val context: ModContext) : Manager {
|
||||
initializeFeatures()
|
||||
}
|
||||
|
||||
private fun featureInitializer(isAsync: Boolean, param: Int, action: (Feature) -> Unit) {
|
||||
features.filter { it.loadParams and param != 0 }.forEach { feature ->
|
||||
val callback = {
|
||||
runCatching {
|
||||
action(feature)
|
||||
}.onFailure {
|
||||
context.log.error("Failed to init feature ${feature.featureKey}", it)
|
||||
context.longToast("Failed to load feature ${feature.featureKey}! Check logcat for more details.")
|
||||
private fun initFeatures(
|
||||
syncParam: Int,
|
||||
asyncParam: Int,
|
||||
syncAction: (Feature) -> Unit,
|
||||
asyncAction: (Feature) -> Unit
|
||||
) {
|
||||
fun tryInit(feature: Feature, block: () -> Unit) {
|
||||
runCatching {
|
||||
block()
|
||||
}.onFailure {
|
||||
context.log.error("Failed to init feature ${feature.featureKey}", it)
|
||||
context.longToast("Failed to init feature ${feature.featureKey}! Check logcat for more details.")
|
||||
}
|
||||
}
|
||||
|
||||
features.toList().forEach { feature ->
|
||||
if (feature.loadParams and syncParam != 0) {
|
||||
tryInit(feature) {
|
||||
syncAction(feature)
|
||||
}
|
||||
}
|
||||
if (!isAsync) {
|
||||
callback()
|
||||
return@forEach
|
||||
}
|
||||
asyncLoadExecutorService.submit {
|
||||
callback()
|
||||
if (feature.loadParams and asyncParam != 0) {
|
||||
context.coroutineScope.launch {
|
||||
tryInit(feature) {
|
||||
asyncAction(feature)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun initializeFeatures() {
|
||||
//TODO: async called when all features are initiated ?
|
||||
featureInitializer(false, FeatureLoadParams.INIT_SYNC) { it.init() }
|
||||
featureInitializer(true, FeatureLoadParams.INIT_ASYNC) { it.asyncInit() }
|
||||
measureTimeMillis {
|
||||
initFeatures(
|
||||
FeatureLoadParams.INIT_SYNC,
|
||||
FeatureLoadParams.INIT_ASYNC,
|
||||
Feature::init,
|
||||
Feature::asyncInit
|
||||
)
|
||||
}.also {
|
||||
context.log.verbose("feature manager init took $it ms")
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityCreate() {
|
||||
featureInitializer(false, FeatureLoadParams.ACTIVITY_CREATE_SYNC) { it.onActivityCreate() }
|
||||
featureInitializer(true, FeatureLoadParams.ACTIVITY_CREATE_ASYNC) { it.asyncOnActivityCreate() }
|
||||
measureTimeMillis {
|
||||
initFeatures(
|
||||
FeatureLoadParams.ACTIVITY_CREATE_SYNC,
|
||||
FeatureLoadParams.ACTIVITY_CREATE_ASYNC,
|
||||
Feature::onActivityCreate,
|
||||
Feature::asyncOnActivityCreate
|
||||
)
|
||||
}.also {
|
||||
context.log.verbose("feature manager onActivityCreate took $it ms")
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user