Skip to content

Commit

Permalink
Plugin support was broken. Fixed.
Browse files Browse the repository at this point in the history
  • Loading branch information
amankgo committed Feb 10, 2022
1 parent cd13e4d commit 3cac9b3
Show file tree
Hide file tree
Showing 10 changed files with 195 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import com.voxfinite.logvue.utils.Either

class AndroidLogStreamer {

fun stream(packageName: String): Flow<Either<LogCatErrors, ArrayList<LogCatMessage2>>> {
return AdbHelper.monitorLogs(packageName)
fun stream(packageName: String, filters: List<String>): Flow<Either<LogCatErrors, ArrayList<LogCatMessage2>>> {
return AdbHelper.monitorLogs(packageName, filters)
}

fun stop() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ object AdbHelper {
@OptIn(ExperimentalCoroutinesApi::class)
fun monitorLogs(
packageName: String,
filters: Array<String> = arrayOf("FA", "FA-SVC", "PDTLogging")
filters: List<String>
) = callbackFlow {
stopLogs = false
val currentSelectedDevice = Devices.currentDevice?.device
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import javax.annotation.concurrent.GuardedBy
class LogCatRunner(
val mDevice: IDevice,
pid: Long,
filters: Array<String> = arrayOf("FA", "FA-SVC")
filters: List<String>
) {

companion object {
Expand Down
1 change: 1 addition & 0 deletions app/src/main/kotlin/com/voxfinite/logvue/app/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import com.voxfinite.logvue.ui.components.SideNavigation
import com.voxfinite.logvue.ui.components.dialogs.CrashDialog
import com.voxfinite.logvue.ui.components.dialogs.IntroDialog
import com.voxfinite.logvue.utils.*
import com.voxfinite.logvue.utils.plugins.PluginsHelper

@Composable
@Preview
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.voxfinite.logvue.processor

import com.voxfinite.logvue.api.models.LogLevel2
import com.voxfinite.logvue.adb.AndroidLogStreamer
import com.voxfinite.logvue.adb.LogCatErrors
import com.voxfinite.logvue.adb.LogErrorNoSession
Expand All @@ -17,6 +16,7 @@ import com.voxfinite.logvue.api.models.LogItem
import com.voxfinite.logvue.models.SessionInfo
import com.voxfinite.logvue.storage.Db
import com.voxfinite.logvue.utils.*
import com.voxfinite.logvue.utils.plugins.PluginsHelper

class MainProcessor {

Expand Down Expand Up @@ -82,8 +82,9 @@ class MainProcessor {
return@withContext
}
val packageName = sessionInfo.appPackage
val stream = streamer.stream(packageName)
val parsers = PluginsHelper.parsers()
val filters = parsers.map { it.filters() }.flatten()
val stream = streamer.stream(packageName, filters)
launch {
val successStream = stream.filter { it.isSuccess }.map { it.getOrNull() }
.filterNotNull()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.voxfinite.logvue.storage.serializer

import com.voxfinite.logvue.utils.plugins.PluginsHelper
import org.mapdb.CC
import org.mapdb.DataInput2
import org.mapdb.DataOutput2
Expand Down Expand Up @@ -53,16 +54,16 @@ class ObjectSerializer<T>(val classLoader: ClassLoader = Thread.currentThread().
/**
* Loader must be non-null;
*/
(`in`: InputStream?) : ObjectInputStream(`in`) {
(inputStream: InputStream?) : ObjectInputStream(inputStream) {
/**
* Use the given ClassLoader rather than using the system class
*/
@Throws(IOException::class, ClassNotFoundException::class)
override fun resolveClass(desc: ObjectStreamClass): Class<*> {
val name = desc.name
return try {
Class.forName(name, false, classLoader)
} catch (ex: ClassNotFoundException) {
PluginsHelper.tryResolveClass(name)
} catch (ignore: ClassNotFoundException) {
super.resolveClass(desc)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import androidx.compose.ui.unit.sp
import com.voxfinite.logvue.models.EventTypeNotSure
import com.voxfinite.logvue.api.models.LogItem
import com.voxfinite.logvue.ui.CustomTheme
import com.voxfinite.logvue.ui.components.common.CustomImage
import com.voxfinite.logvue.ui.components.common.NetworkImage
import com.voxfinite.logvue.ui.views.flow.FlowRow
import com.voxfinite.logvue.utils.Helpers
import com.voxfinite.logvue.utils.predictedEventType
Expand Down Expand Up @@ -94,8 +96,7 @@ fun LogTitle(logItem: LogItem, modifier: Modifier = Modifier) {
fun LogIcon(logItem: LogItem, modifier: Modifier = Modifier) {
Box(modifier.size(48.dp)) {
val sourceIcon = logItem.source.icon
val sourceIconPainter = painterResource(sourceIcon)
Image(sourceIconPainter, logItem.source.type, Modifier.size(36.dp))
CustomImage(sourceIcon, logItem.source.type, Modifier.size(36.dp))
val predictedEventType = logItem.predictedEventType()
if (predictedEventType != EventTypeNotSure) {
val typePainter = painterResource(predictedEventType.iconResource)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package com.voxfinite.logvue.ui.components.common

import androidx.compose.foundation.Image
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.produceState
import androidx.compose.runtime.remember
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.painter.BitmapPainter
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.loadImageBitmap
import androidx.compose.ui.res.loadSvgPainter
import androidx.compose.ui.res.loadXmlImageVector
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.Density
import com.voxfinite.logvue.utils.plugins.PluginsResourceLoader
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.xml.sax.InputSource
import java.io.File
import java.io.IOException
import java.net.URL

@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun CustomImage(
url: String?,
contentDescription: String,
modifier: Modifier = Modifier,
contentScale: ContentScale = ContentScale.Fit
) {
if (url.isNullOrBlank()) return
if (url.startsWith("http://") || url.startsWith("https://")) {
NetworkImage(url, contentDescription, modifier, contentScale)
} else {
Image(painterResource(url, PluginsResourceLoader()), contentDescription, modifier, contentScale = contentScale)
}
}

@Composable
fun NetworkImage(
url: String?,
contentDescription: String,
modifier: Modifier = Modifier,
contentScale: ContentScale = ContentScale.Fit
) {
if (url.isNullOrBlank()) return
AsyncImage(
load = { loadImageBitmap(url) },
painterFor = { remember { BitmapPainter(it) } },
contentDescription, modifier, contentScale
)
}

@Composable
fun <T> AsyncImage(
load: suspend () -> T,
painterFor: @Composable (T) -> Painter,
contentDescription: String,
modifier: Modifier = Modifier,
contentScale: ContentScale = ContentScale.Fit,
) {
// should cache image
val image: T? by produceState<T?>(null) {
value = withContext(Dispatchers.IO) {
try {
load()
} catch (e: IOException) {
// instead of printing to console, you can also write this to log,
// or show some error placeholder
e.printStackTrace()
null
}
}
}

if (image != null) {
Image(
painter = painterFor(image!!),
contentDescription = contentDescription,
contentScale = contentScale,
modifier = modifier
)
}
}


/* Loading from file with java.io API */

fun loadImageBitmap(file: File): ImageBitmap =
file.inputStream().buffered().use(::loadImageBitmap)

fun loadSvgPainter(file: File, density: Density): Painter =
file.inputStream().buffered().use { loadSvgPainter(it, density) }

fun loadXmlImageVector(file: File, density: Density): ImageVector =
file.inputStream().buffered().use { loadXmlImageVector(InputSource(it), density) }

/* Loading from network with java.net API */

fun loadImageBitmap(url: String): ImageBitmap =
URL(url).openStream().buffered().use(::loadImageBitmap)

fun loadSvgPainter(url: String, density: Density): Painter =
URL(url).openStream().buffered().use { loadSvgPainter(it, density) }

fun loadXmlImageVector(url: String, density: Density): ImageVector =
URL(url).openStream().buffered().use { loadXmlImageVector(InputSource(it), density) }

/* Loading from network with Ktor client API (https://ktor.io/docs/client.html). */

/*
suspend fun loadImageBitmap(url: String): ImageBitmap =
urlStream(url).use(::loadImageBitmap)
suspend fun loadSvgPainter(url: String, density: Density): Painter =
urlStream(url).use { loadSvgPainter(it, density) }
suspend fun loadXmlImageVector(url: String, density: Density): ImageVector =
urlStream(url).use { loadXmlImageVector(InputSource(it), density) }
@OptIn(KtorExperimentalAPI::class)
private suspend fun urlStream(url: String) = HttpClient(CIO).use {
ByteArrayInputStream(it.get(url))
}
*/
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
package com.voxfinite.logvue.utils
package com.voxfinite.logvue.utils.plugins

import com.voxfinite.logvue.api.LogEventParser
import com.voxfinite.logvue.parsers.FirebaseParser
import com.voxfinite.logvue.storage.StorageHelper
import com.voxfinite.logvue.utils.AppLog
import org.pf4j.CompoundPluginDescriptorFinder
import org.pf4j.DefaultPluginManager
import org.pf4j.ManifestPluginDescriptorFinder
import org.pf4j.PropertiesPluginDescriptorFinder
import java.nio.file.Path
import kotlin.jvm.Throws

object PluginsHelper {

private class PluginManager(importPaths: List<Path>) : DefaultPluginManager(importPaths) {
internal class PluginManager(importPaths: List<Path>) : DefaultPluginManager(importPaths) {
override fun createPluginDescriptorFinder(): CompoundPluginDescriptorFinder {
return CompoundPluginDescriptorFinder() // Demo is using the Manifest file
// PropertiesPluginDescriptorFinder is commented out just to avoid error log
Expand All @@ -20,7 +22,7 @@ object PluginsHelper {
}
}

private val pluginManager by lazy {
internal val pluginManager by lazy {
val pluginsPath = StorageHelper.getPluginsPath()
AppLog.d(pluginsPath.toString())
PluginManager(listOf(pluginsPath))
Expand All @@ -33,7 +35,6 @@ object PluginsHelper {
fun load() {
// load the plugins
pluginManager.loadPlugins()

// enable a disabled plugin
// pluginManager.enablePlugin("welcome-plugin")

Expand All @@ -49,6 +50,21 @@ object PluginsHelper {
return allParsers
}

@Throws(ClassCastException::class)
fun tryResolveClass(className : String) : Class<*> {
pluginManager.resolvedPlugins.forEach {
val classLoader = it.pluginClassLoader
val resolvedClass: Class<*>?
try {
resolvedClass = Class.forName(className, false, classLoader)
return resolvedClass
} catch (ignore : ClassNotFoundException) {
// ignore
}
}
return Class.forName(className, false, Thread.currentThread().contextClassLoader)
}

private fun getDefaultParsers(): MutableList<LogEventParser> = arrayListOf(FirebaseParser())

fun stop() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.voxfinite.logvue.utils.plugins

import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.res.ResourceLoader
import java.io.InputStream

@OptIn(ExperimentalComposeUiApi::class)
class PluginsResourceLoader : ResourceLoader {
override fun load(resourcePath: String): InputStream {
PluginsHelper.pluginManager.resolvedPlugins.forEach {
val classLoader = it.pluginClassLoader
val resource = try {
classLoader.getResourceAsStream(resourcePath)
} catch (ignore : Exception) {
null
}
if (resource != null) {
return resource
}
}
// TODO(https://github.com/JetBrains/compose-jb/issues/618): probably we shouldn't use
// contextClassLoader here, as it is not defined in threads created by non-JVM
val contextClassLoader = Thread.currentThread().contextClassLoader!!
val resource = contextClassLoader.getResourceAsStream(resourcePath)
?: (::PluginsResourceLoader.javaClass).getResourceAsStream(resourcePath)
return requireNotNull(resource) { "Resource $resourcePath not found" }
}
}

0 comments on commit 3cac9b3

Please sign in to comment.