diff --git a/.idea/runConfigurations/logvue__run_.xml b/.idea/runConfigurations/logvue__run_.xml deleted file mode 100644 index 2727d01..0000000 --- a/.idea/runConfigurations/logvue__run_.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - true - true - false - - - \ No newline at end of file diff --git a/api/build.gradle.kts b/api/build.gradle.kts new file mode 100644 index 0000000..8446bd0 --- /dev/null +++ b/api/build.gradle.kts @@ -0,0 +1,30 @@ +val pf4jVersion: String by project + + +plugins { + kotlin("jvm") +} + +dependencies { + implementation(kotlin("stdlib")) + // https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-slf4j-impl + implementation("org.apache.logging.log4j:log4j-slf4j-impl:2.17.0") + implementation("org.apache.logging.log4j:log4j-api:2.17.0") + implementation("org.apache.logging.log4j:log4j-core:2.17.0") + + compileOnly("org.pf4j:pf4j:${pf4jVersion}") + // types parser for object to map conversion + implementation("com.github.drapostolos:type-parser:0.7.0") + implementation("com.google.code.gson:gson:2.8.9") + // https://mvnrepository.com/artifact/com.google.guava/guava + api("com.google.guava:guava:31.0.1-jre") + testImplementation(platform("org.junit:junit-bom:5.8.2")) + testImplementation("org.junit.jupiter:junit-jupiter") +} + +tasks.test { + useJUnitPlatform() + testLogging { + events("passed", "skipped", "failed") + } +} \ No newline at end of file diff --git a/api/src/main/kotlin/com/voxfinite/logvue/api/LogEventParser.kt b/api/src/main/kotlin/com/voxfinite/logvue/api/LogEventParser.kt new file mode 100644 index 0000000..76550a1 --- /dev/null +++ b/api/src/main/kotlin/com/voxfinite/logvue/api/LogEventParser.kt @@ -0,0 +1,29 @@ +package com.voxfinite.logvue.api + +import com.voxfinite.logvue.api.models.LogCatMessage2 +import com.voxfinite.logvue.api.models.LogItem +import org.pf4j.ExtensionPoint + +/** + * Plugin extension point + * All plugins must extend with interface and annotate with @Extension + */ +interface LogEventParser : ExtensionPoint { + + /** + * Filters for tags + */ + fun filters() : List + + /** + * Validate and return whether to process this message + */ + fun validate(logCatMessage2: LogCatMessage2) : Boolean + + /** + * Parse item which is validated before to [LogItem] + * + */ + fun parse(logCatMessage2: LogCatMessage2) : LogItem + +} \ No newline at end of file diff --git a/src/main/kotlin/models/InternalContent.kt b/api/src/main/kotlin/com/voxfinite/logvue/api/models/InternalContent.kt similarity index 82% rename from src/main/kotlin/models/InternalContent.kt rename to api/src/main/kotlin/com/voxfinite/logvue/api/models/InternalContent.kt index 4921de3..a6eee2e 100644 --- a/src/main/kotlin/models/InternalContent.kt +++ b/api/src/main/kotlin/com/voxfinite/logvue/api/models/InternalContent.kt @@ -1,4 +1,4 @@ -package models +package com.voxfinite.logvue.api.models sealed interface InternalContent diff --git a/src/main/kotlin/models/ItemSource.kt b/api/src/main/kotlin/com/voxfinite/logvue/api/models/ItemSource.kt similarity index 61% rename from src/main/kotlin/models/ItemSource.kt rename to api/src/main/kotlin/com/voxfinite/logvue/api/models/ItemSource.kt index feb8420..e7cf051 100644 --- a/src/main/kotlin/models/ItemSource.kt +++ b/api/src/main/kotlin/com/voxfinite/logvue/api/models/ItemSource.kt @@ -1,12 +1,12 @@ -package models +package com.voxfinite.logvue.api.models import java.io.Serializable -sealed class ItemSource(val type: String, val icon: String) : Serializable { +abstract class ItemSource(val type: String, val icon: String) : Serializable { companion object { private const val serialVersionUID = 1L } } -object SourceFA : ItemSource("Firebase", "icons/firebaseLogo.webp") +object SourceFA : ItemSource("Firebase", "icons/firebaseLogo.webp") // TODO: Move to url object SourceInternalContent : ItemSource("Content", "") diff --git a/src/main/kotlin/models/LogCatHeader2.kt b/api/src/main/kotlin/com/voxfinite/logvue/api/models/LogCatHeader2.kt similarity index 73% rename from src/main/kotlin/models/LogCatHeader2.kt rename to api/src/main/kotlin/com/voxfinite/logvue/api/models/LogCatHeader2.kt index 89a70af..d755237 100644 --- a/src/main/kotlin/models/LogCatHeader2.kt +++ b/api/src/main/kotlin/com/voxfinite/logvue/api/models/LogCatHeader2.kt @@ -1,7 +1,5 @@ -package models +package com.voxfinite.logvue.api.models -import com.android.ddmlib.Log.LogLevel -import com.android.ddmlib.logcat.LogCatHeader import java.time.Instant import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatterBuilder @@ -14,15 +12,13 @@ private val EPOCH_TIME_FORMATTER: DateTimeFormatter = DateTimeFormatterBuilder() .toFormatter(Locale.ROOT) data class LogCatHeader2( - val logLevel: LogLevel, + val logLevel: LogLevel2, val pid: Int, val tid: Int, val appName: String, val tag: String, val timestamp: Instant, ) { - constructor(header: LogCatHeader) : this( - header.logLevel, header.pid, header.tid, header.appName, header.tag, header.timestamp) override fun toString(): String { val epoch = EPOCH_TIME_FORMATTER.format(timestamp) diff --git a/src/main/kotlin/models/LogCatMessage2.kt b/api/src/main/kotlin/com/voxfinite/logvue/api/models/LogCatMessage2.kt similarity index 65% rename from src/main/kotlin/models/LogCatMessage2.kt rename to api/src/main/kotlin/com/voxfinite/logvue/api/models/LogCatMessage2.kt index 6c8dfc3..e3e6ca1 100644 --- a/src/main/kotlin/models/LogCatMessage2.kt +++ b/api/src/main/kotlin/com/voxfinite/logvue/api/models/LogCatMessage2.kt @@ -1,12 +1,9 @@ -package models +package com.voxfinite.logvue.api.models -import com.android.ddmlib.logcat.LogCatMessage import java.io.Serializable data class LogCatMessage2(val header: LogCatHeader2, val message: String) : Serializable { - constructor(log: LogCatMessage) : this(LogCatHeader2(log.header), log.message) - companion object { private const val serialVersionUID = 1L } diff --git a/api/src/main/kotlin/com/voxfinite/logvue/api/models/LogItem.kt b/api/src/main/kotlin/com/voxfinite/logvue/api/models/LogItem.kt new file mode 100644 index 0000000..9126208 --- /dev/null +++ b/api/src/main/kotlin/com/voxfinite/logvue/api/models/LogItem.kt @@ -0,0 +1,36 @@ +package com.voxfinite.logvue.api.models + +import com.voxfinite.logvue.api.utils.HashMapEntity +import com.voxfinite.logvue.api.utils.hashMapEntityOf +import java.io.Serializable +import java.util.* + +/** + * Base class for holding analytics data + * Every plugin can extend [ItemSource] and add here along with event name and other details. + * Do not add anything to [internalContent] + */ +data class LogItem @JvmOverloads constructor( + val source: ItemSource, + val eventName: String, + val properties: HashMapEntity = hashMapEntityOf(hashMapOf()), + val localTime: Long = System.currentTimeMillis(), + val internalContent: InternalContent? = null, +) : Serializable { + companion object { + private const val serialVersionUID = 1L + } + + private val id: String = buildKey() + + @Transient + var isSelected: Boolean = false + + private fun buildKey() = "${iKey()}_$localTime" + fun key() = id + + private fun iKey(): String { + val k = "${source.type}_${eventName}_${properties.hashCode()}" + return k + UUID.randomUUID().toString() + } +} diff --git a/api/src/main/kotlin/com/voxfinite/logvue/api/models/LogLevel2.kt b/api/src/main/kotlin/com/voxfinite/logvue/api/models/LogLevel2.kt new file mode 100644 index 0000000..772a497 --- /dev/null +++ b/api/src/main/kotlin/com/voxfinite/logvue/api/models/LogLevel2.kt @@ -0,0 +1,69 @@ +package com.voxfinite.logvue.api.models + +/** + * Log Level enum. + */ +enum class LogLevel2( + /** + * Returns the numerical value of the priority. + */ + //$NON-NLS-1$ + val priority: Int, + /** + * Returns a non translated string representing the LogLevel. + */ + val stringValue: String, + /** + * Returns the letter identifying the priority of the [LogLevel2]. + */ + val priorityLetter: Char +) { + VERBOSE(2, "verbose", 'V'), //$NON-NLS-1$ + DEBUG(3, "debug", 'D'), //$NON-NLS-1$ + INFO(4, "info", 'I'), //$NON-NLS-1$ + WARN(5, "warn", 'W'), //$NON-NLS-1$ + ERROR(6, "error", 'E'), //$NON-NLS-1$ + ASSERT(7, "assert", 'A'); + + companion object { + fun getByString(value: String): LogLevel2? { + for (mode in values()) { + if (mode.stringValue == value) { + return mode + } + } + return null + } + + /** + * Returns the [LogLevel2] enum matching the specified letter. + * + * @param letter the letter matching a `LogLevel` enum + * @return a `LogLevel` object or `null` if no match were found. + */ + fun getByLetter(letter: Char): LogLevel2? { + for (mode in values()) { + if (mode.priorityLetter == letter) { + return mode + } + } + return null + } + + /** + * Returns the [LogLevel2] enum matching the specified letter. + * + * + * The letter is passed as a [String] argument, but only the first character + * is used. + * + * @param letter the letter matching a `LogLevel` enum + * @return a `LogLevel` object or `null` if no match were found. + */ + fun getByLetterString(letter: String): LogLevel2? { + return if (letter.isNotEmpty()) { + getByLetter(letter[0]) + } else null + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/utils/HashMapEntity.kt b/api/src/main/kotlin/com/voxfinite/logvue/api/utils/HashMapEntity.kt similarity index 98% rename from src/main/kotlin/utils/HashMapEntity.kt rename to api/src/main/kotlin/com/voxfinite/logvue/api/utils/HashMapEntity.kt index d2be4d7..17af2af 100644 --- a/src/main/kotlin/utils/HashMapEntity.kt +++ b/api/src/main/kotlin/com/voxfinite/logvue/api/utils/HashMapEntity.kt @@ -1,4 +1,4 @@ -package utils +package com.voxfinite.logvue.api.utils import java.io.Serializable diff --git a/api/src/main/kotlin/com/voxfinite/logvue/api/utils/LogVueExtensions.kt b/api/src/main/kotlin/com/voxfinite/logvue/api/utils/LogVueExtensions.kt new file mode 100644 index 0000000..c45f723 --- /dev/null +++ b/api/src/main/kotlin/com/voxfinite/logvue/api/utils/LogVueExtensions.kt @@ -0,0 +1,3 @@ +package com.voxfinite.logvue.api.utils + +fun hashMapEntityOf(mapToWrap: MutableMap): HashMapEntity = HashMapEntity(mapToWrap) \ No newline at end of file diff --git a/api/src/main/kotlin/com/voxfinite/logvue/api/utils/deserializers/EventDeserializers.kt b/api/src/main/kotlin/com/voxfinite/logvue/api/utils/deserializers/EventDeserializers.kt new file mode 100644 index 0000000..d48c36e --- /dev/null +++ b/api/src/main/kotlin/com/voxfinite/logvue/api/utils/deserializers/EventDeserializers.kt @@ -0,0 +1,11 @@ +package com.voxfinite.logvue.api.utils.deserializers + +import com.voxfinite.logvue.api.utils.deserializers.`object`.ObjectDeserializer +import com.voxfinite.logvue.api.utils.deserializers.json.JsonDeserializer + +object EventDeserializers { + + fun fromObject(message: String?) = ObjectDeserializer.map(message) + fun fromJson(message: String?) = JsonDeserializer.map(message) + +} \ No newline at end of file diff --git a/api/src/main/kotlin/com/voxfinite/logvue/api/utils/deserializers/json/JsonDeserializer.kt b/api/src/main/kotlin/com/voxfinite/logvue/api/utils/deserializers/json/JsonDeserializer.kt new file mode 100644 index 0000000..93ceb1c --- /dev/null +++ b/api/src/main/kotlin/com/voxfinite/logvue/api/utils/deserializers/json/JsonDeserializer.kt @@ -0,0 +1,35 @@ +package com.voxfinite.logvue.api.utils.deserializers.json + +import com.google.gson.GsonBuilder +import com.google.gson.JsonParseException +import com.google.gson.JsonSyntaxException +import com.google.gson.ToNumberPolicy +import com.google.gson.reflect.TypeToken +import com.voxfinite.logvue.api.utils.HashMapEntity +import com.voxfinite.logvue.api.utils.hashMapEntityOf + +object JsonDeserializer { + + private val gson by lazy { + val gsonBuilder = GsonBuilder().setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE) + gsonBuilder.setPrettyPrinting() + gsonBuilder.create() + } + + fun createJsonString(src: Any): String { + return gson.toJson(src) + } + + fun map(message: String?): HashMapEntity { + val type = object : TypeToken>() {}.type + val map = try { + gson.fromJson>(message, type) + } catch (e: JsonParseException) { + hashMapOf() + } catch (e: JsonSyntaxException) { + hashMapOf() + } + return hashMapEntityOf(map) + } + +} \ No newline at end of file diff --git a/src/main/kotlin/utils/Item.kt b/api/src/main/kotlin/com/voxfinite/logvue/api/utils/deserializers/object/Item.kt similarity index 57% rename from src/main/kotlin/utils/Item.kt rename to api/src/main/kotlin/com/voxfinite/logvue/api/utils/deserializers/object/Item.kt index 0712d1d..6ee242f 100644 --- a/src/main/kotlin/utils/Item.kt +++ b/api/src/main/kotlin/com/voxfinite/logvue/api/utils/deserializers/object/Item.kt @@ -1,8 +1,10 @@ -package utils +package com.voxfinite.logvue.api.utils.deserializers.`object` import com.google.common.base.Joiner import com.google.common.base.Splitter import org.slf4j.LoggerFactory +import java.io.StreamTokenizer +import java.io.StringReader import java.util.* import java.util.regex.Pattern @@ -14,6 +16,16 @@ import java.util.regex.Pattern * * @author dschreiber */ + +internal val objectPattern = Pattern.compile( + "(^[A-Z]\\S*)[ ]?(\\((.*)\\)$)|(\\[(.*)]$)", + Pattern.DOTALL +) +internal val mapPattern = Pattern.compile( + "\\{.*=.*}", + Pattern.DOTALL +) + sealed class Item(val stringRepresentation: String?) { class ValueItem(stringRepresentation: String?) : Item(stringRepresentation) @@ -22,8 +34,7 @@ sealed class Item(val stringRepresentation: String?) { private val attributes: MutableMap = HashMap() init { - val typePattern = Pattern.compile("(^[A-Z]\\S*)\\[(.*)]$", Pattern.DOTALL) - val typeMatcher = typePattern.matcher(stringRepresentation) + val typeMatcher = objectPattern.matcher(stringRepresentation) if (typeMatcher.matches()) { type = typeMatcher.group(1) val onFirstLevelCommaRespectEqualSign = @@ -53,7 +64,37 @@ sealed class Item(val stringRepresentation: String?) { type + "\n " + Joiner.on("\n ").withKeyValueSeparator(" = ") - .join(attributes)) + .join(attributes)) + } + } + + class MapItem(stringRepresentation: String) : Item(stringRepresentation) { + private val attributes: MutableMap = hashMapOf() + + init { + val typeMatcher = mapPattern.matcher(stringRepresentation) + if (!typeMatcher.matches()) { + throw IllegalArgumentException("Cannot create map from string: $stringRepresentation") + } + val onFirstLevelCommaRespectEqualSign = + splitOnFirstLevelCommaRespectEqualSignInMap(stringRepresentation.removePrefix("{").removeSuffix("}")) + for (attributeValue: String in onFirstLevelCommaRespectEqualSign) { + val split: Iterator = Splitter.on("=").trimResults() + .limit(2).split(attributeValue).iterator() + val attributeName = split.next() + val attributeValueString = split.next() + attributes[attributeName] = parseString(attributeValueString) + } + } + + fun getAttributes(): Map { + return attributes + } + + override fun toString(): String { + return (super.toString() + + Joiner.on("\n ").withKeyValueSeparator(" = ") + .join(attributes)) } } @@ -118,13 +159,15 @@ sealed class Item(val stringRepresentation: String?) { result.add(current) } else { if (result.isEmpty()) { - throw IllegalStateException( - ("first comma must not occur before first equal sign! (" + - string + ")") - ) +// throw IllegalStateException( +// ("first comma must not occur before first equal sign! (" + +// string + ")") +// ) + result.add(current) + } else { + result[result.size - 1] = (result[result.size - 1] + + ", " + current) } - result[result.size - 1] = (result[result.size - 1] + - ", " + current) } } return result @@ -136,6 +179,7 @@ sealed class Item(val stringRepresentation: String?) { * @param string */ fun splitOnFirstLevelComma(string: String?): List { + if (string.isNullOrBlank()) return emptyList() val scanner = Scanner(string) scanner.useDelimiter(", ") val result: MutableList = ArrayList() @@ -160,19 +204,78 @@ sealed class Item(val stringRepresentation: String?) { return result } + /** + * only the first comma before an equal sign ('=') is used for split. (So + * that strings that contain a comma are not split.) + * + * @param string + * @return + */ + fun splitOnFirstLevelCommaRespectEqualSignInMap( + string: String + ): List { + val allSplits = splitOnFirstLevelCommaInMap(string) + val result: MutableList = ArrayList(allSplits.size) + for (current: String in allSplits) { + if (current.contains("=")) { + result.add(current) + } else { + if (result.isEmpty()) { + throw IllegalStateException( + ("first comma must not occur before first equal sign! (" + + string + ")") + ) + } + result[result.size - 1] = (result[result.size - 1] + + ", " + current) + } + } + return result + } + + /** + * ignores commas nested in square brackets ("{", "}") + * + * @param string + */ + fun splitOnFirstLevelCommaInMap(string: String?): List { + if (string.isNullOrBlank()) return emptyList() + val scanner = Scanner(string) + scanner.useDelimiter(", ") + val result = arrayListOf() + + var openBrackets = 0 + while (scanner.hasNext()) { + val next = scanner.next() + val open = contains(next, '{') + val close = contains(next, '}') + println( + ("openBrackets: " + openBrackets + ", open: " + open + + ", close: " + close + ", next: " + next) + ) + if (openBrackets > 0) { + result[result.size - 1] = (result[result.size - 1] + + ", " + next) + } else { + result.add(next) + } + openBrackets = openBrackets + open - close + } + scanner.close() + return result + } + fun parseString(stringRaw: String?): Item { if (stringRaw.isNullOrBlank()) { return ValueItem(stringRaw) } - val objectPattern = Pattern.compile( - "^[A-Z][^ ]* \\[.*", - Pattern.DOTALL - ) val string = stringRaw.trim { it <= ' ' } return if (string.startsWith("[")) { ListItem(string) - } else if (objectPattern.matcher(string).matches()) { + } else if (objectPattern.matcher(string).matches() && string.contains("=")) { ObjectItem(string) + } else if (mapPattern.matcher(string).matches() && string.contains("=")) { + MapItem(string) } else { ValueItem(string) } diff --git a/api/src/main/kotlin/com/voxfinite/logvue/api/utils/deserializers/object/ItemObjectMapper.kt b/api/src/main/kotlin/com/voxfinite/logvue/api/utils/deserializers/object/ItemObjectMapper.kt new file mode 100644 index 0000000..8b65793 --- /dev/null +++ b/api/src/main/kotlin/com/voxfinite/logvue/api/utils/deserializers/object/ItemObjectMapper.kt @@ -0,0 +1,69 @@ +package com.voxfinite.logvue.api.utils.deserializers.`object` + +import com.voxfinite.logvue.api.utils.deserializers.`object`.Item.ObjectItem + +/** + * Creates object/instance from toString()-Model. + */ +class ItemObjectMapper { + + fun parse(item: Item): Any? { + return try { + when (item) { + is ObjectItem -> { + parseObject(item) + } + is Item.MapItem -> { + parseMap(item) + } + else -> { + ObjectDeserializer.tryParseToType(item.stringRepresentation) + } + } + } catch (e: Exception) { +// Exception("Item mapping failed for item=$item", e).reportException() + item.stringRepresentation + } + } + + private fun parseObject(item: ObjectItem): HashMap { + val map = hashMapOf() + item.getAttributes().forEach { entry -> + val stringRepresentation = entry.value.stringRepresentation ?: "" + val key = entry.key.removePrefix("{").removeSuffix("}") + if (mapPattern.matcher(stringRepresentation).matches() && stringRepresentation.contains("=")) { + // this is a map + map[key] = parse(Item.MapItem(stringRepresentation)) + } else if (objectPattern.matcher(stringRepresentation).matches() && stringRepresentation.contains("=")) { + // this is a map + map[key] = parse(ObjectItem(stringRepresentation.removePrefix("{").removeSuffix("}"))) + } else { + map[key] = parse(Item.ValueItem(stringRepresentation.removePrefix("{").removeSuffix("}"))) + } + } + return map + } + + private fun parseMap(item: Item.MapItem): HashMap { + val map = hashMapOf() + item.getAttributes().forEach { entry -> + val stringRepresentation = entry.value.stringRepresentation ?: "" + val key = entry.key.removePrefix("{").removeSuffix("}") + if (mapPattern.matcher(stringRepresentation).matches() && stringRepresentation.contains("=")) { + // this is a map + map[key] = parse(Item.MapItem(stringRepresentation)) + } else if (objectPattern.matcher(stringRepresentation).matches() && stringRepresentation.contains("=")) { + // this is a map + map[key] = parse(ObjectItem(stringRepresentation.removePrefix("{").removeSuffix("}"))) + } else { + map[key] = parse(Item.ValueItem(stringRepresentation.removePrefix("{").removeSuffix("}"))) + } + } + return map + } + +// companion object { +// private val LOGGER: Logger = LoggerFactory +// .getLogger(ItemObjectMapper::class.java) +// } +} diff --git a/api/src/main/kotlin/com/voxfinite/logvue/api/utils/deserializers/object/ObjectDeserializer.kt b/api/src/main/kotlin/com/voxfinite/logvue/api/utils/deserializers/object/ObjectDeserializer.kt new file mode 100644 index 0000000..3bf37f4 --- /dev/null +++ b/api/src/main/kotlin/com/voxfinite/logvue/api/utils/deserializers/object/ObjectDeserializer.kt @@ -0,0 +1,136 @@ +package com.voxfinite.logvue.api.utils.deserializers.`object` + +import com.github.drapostolos.typeparser.GenericType +import com.github.drapostolos.typeparser.TypeParser +import com.voxfinite.logvue.api.utils.HashMapEntity +import com.voxfinite.logvue.api.utils.hashMapEntityOf +import java.util.HashMap + +object ObjectDeserializer { + + private val objectMapper by lazy { + ItemObjectMapper() + } + + private val parser = TypeParser.newBuilder().build() + + fun map(message: String?): HashMapEntity { + val properties = hashMapOf() + if (!message.isNullOrBlank()) { + val mMsg = message.trim() + if (mMsg.startsWith("{") && mMsg.endsWith("}")) { + val item = Item.MapItem(mMsg) + properties.putAll(item.getAttributes()) + } else { + val item = Item.ObjectItem(mMsg) + properties.putAll(item.getAttributes()) + } + } + return hashMapEntityOf(properties) + } + + internal fun tryParseToType(str: String?): Any? { + return try { + tryParseInternal(str) + } catch (ve: ValueException) { + ve.value + } + } + + @Throws(ValueException::class) + private fun tryParseInternal(str: String?): Any? { + if (str == null) return null + if (str.isBlank()) return str + var parsed: Boolean + parsed = tryParseType(str, Boolean::class.java) + if (!parsed) { + parsed = tryParseType(str, Long::class.java) + } + if (!parsed) { + parsed = tryParseType(str, Int::class.java) + } + if (!parsed) { + parsed = tryParseType(str, Double::class.java) + } + if (!parsed) { + parsed = tryParseType(str, Float::class.java) + } + if (!parsed) { + parsed = tryParseType(str, Double::class.java) + } + if (!parsed) { + parsed = tryParseType(str, object : GenericType>() {}) + } + if (!parsed) { + parsed = tryParseType(str, object : GenericType>() {}) + } + if (!parsed) { + parsed = tryParseType(str, object : GenericType>() {}) + } + if (!parsed) { + parsed = tryParseType(str, object : GenericType>() {}) + } + if (!parsed) { + parsed = tryParseType(str, object : GenericType>() {}) + } + if (!parsed) { + parsed = tryParseType(str, object : GenericType>() {}) + } + if (!parsed) { + parsed = tryParseType(str, object : GenericType>() {}) + } + if (!parsed) { + parsed = tryParseType(str, object : GenericType>() {}) + } + if (!parsed) { + parsed = tryParseType(str, object : GenericType>() {}) + } + if (!parsed) { + parsed = tryParseType(str, object : GenericType>() {}) + } + if (!parsed) { + parsed = tryParseType(str, object : GenericType>() {}) + } + if (!parsed) { + parsed = tryParseType(str, object : GenericType>() {}) + } + if (!parsed) { + parsed = tryParseType(str, object : GenericType>() {}) + } + if (!parsed) { + parsed = tryParseType(str, object : GenericType>() {}) + } + if (!parsed) { + parsed = tryParseType(str, object : GenericType>() {}) + } + return str + } + + @Throws(ValueException::class) + private fun tryParseType(str: String, clazz: Class): Boolean { + return tryOp { + val value = parser.parse(str, clazz) + throw ValueException(value) // anti-pattern ki **** + } + } + + @Throws(ValueException::class) + private fun tryParseType(str: String, genericType: GenericType): Boolean { + return tryOp { + val value = parser.parse(str, genericType) + throw ValueException(value) + } + } + + private fun tryOp(op: () -> Unit): Boolean { + return try { + op() + true + } catch (e: ValueException) { + throw e + } catch (e: Exception) { + false + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/utils/ValueException.kt b/api/src/main/kotlin/com/voxfinite/logvue/api/utils/deserializers/object/ValueException.kt similarity index 53% rename from src/main/kotlin/utils/ValueException.kt rename to api/src/main/kotlin/com/voxfinite/logvue/api/utils/deserializers/object/ValueException.kt index a97100d..4114abc 100644 --- a/src/main/kotlin/utils/ValueException.kt +++ b/api/src/main/kotlin/com/voxfinite/logvue/api/utils/deserializers/object/ValueException.kt @@ -1,3 +1,3 @@ -package utils +package com.voxfinite.logvue.api.utils.deserializers.`object` class ValueException(val value: Any?) : Exception("Value is $value") diff --git a/api/src/test/kotlin/com/voxfinite/logvue/api/utils/deserializers/object/ItemTest.kt b/api/src/test/kotlin/com/voxfinite/logvue/api/utils/deserializers/object/ItemTest.kt new file mode 100644 index 0000000..69545e5 --- /dev/null +++ b/api/src/test/kotlin/com/voxfinite/logvue/api/utils/deserializers/object/ItemTest.kt @@ -0,0 +1,43 @@ +package com.voxfinite.logvue.api.utils.deserializers.`object` + +import org.junit.jupiter.api.Test + +class ItemTest { + + @Test + fun splitOnFirstLevelCommaRespectEqualSignTest() { + val string = """ + {context={session_visit_number=16, client_timestamp=1643621396141, client_timezone=IST, + correlationId=, template_id=26355}, + event_details={item_selected=lobMatrix, action=itemSelected, event=home}, user=User(is_logged_in=true, + loyalty=Loyalty(tier=1, gcp_balance=0.0, tier_start_date=15 Sep'20, tier_end_date=15 Mar'22))} + """.trimIndent() + val items = Item.splitOnFirstLevelCommaRespectEqualSign(string) + println(items) + } + + @Test + fun splitOnFirstLevelCommaRespectEqualSignInMap() { + val string = """ + {context={session_visit_number=16, client_timestamp=1643621396141, client_timezone=IST, + correlationId=, template_id=26355}, + event_details={item_selected=lobMatrix, action=itemSelected, event=home}, user=User(is_logged_in=true, + loyalty=Loyalty(tier=1, gcp_balance=0.0, tier_start_date=15 Sep'20, tier_end_date=15 Mar'22))} + """.trimIndent() + val items = Item.splitOnFirstLevelCommaRespectEqualSignInMap(string.removePrefix("{").removeSuffix("}")) + println(items) + } + + @Test + fun splitOnFirstLevelComma() { + val string = """ + {context={session_visit_number=16, client_timestamp=1643621396141, client_timezone=IST, + correlationId=, template_id=26355}, + event_details={item_selected=lobMatrix, action=itemSelected, event=home}, user=User(is_logged_in=true, + loyalty=Loyalty(tier=1, gcp_balance=0.0, tier_start_date=15 Sep'20, tier_end_date=15 Mar'22))} + """.trimIndent() + val items = Item.splitOnFirstLevelCommaInMap(string) + println(items) + } + +} \ No newline at end of file diff --git a/api/src/test/kotlin/com/voxfinite/logvue/api/utils/deserializers/object/ObjectDeserializerTest.kt b/api/src/test/kotlin/com/voxfinite/logvue/api/utils/deserializers/object/ObjectDeserializerTest.kt new file mode 100644 index 0000000..0bd2f29 --- /dev/null +++ b/api/src/test/kotlin/com/voxfinite/logvue/api/utils/deserializers/object/ObjectDeserializerTest.kt @@ -0,0 +1,39 @@ +package com.voxfinite.logvue.api.utils.deserializers.`object` + +import org.junit.jupiter.api.Test + +class ObjectDeserializerTest { + + @Test + fun mapTest() { + val string = """ + {context={session_visit_number=16, client_timestamp=1643621396141, client_timezone=IST, topic_name=gi_client_common_logging, session_id=ad2F03AA3EF57F097E1E0432D9626B4429115BDD821643619576931, correlationId=, template_id=26355}, event_details={item_selected=lobMatrix, item_position=2, screen_name=home, ab_experiment=Newhomepage2021, action=itemSelected, custom1=1, tag=Flights, event=home, lob=flight}, user=User(is_logged_in=true, uuid=g9ln3qkjpdyn5xw5v, loyalty=Loyalty(tier=1, tribe_coin_balance=66.0, gcp_balance=0.0, tier_start_date=15 Sep'20, tier_end_date=15 Mar'22)), device=Device(app_version=1957, device_id=20bc9bc86c8ea600, googleAdId=4872c655-ff0b-4eed-bfdf-e3c933a3c5df, device_resolution=1080x2250, flavour=android, geo_city=, geo_state=, geo_latitude=-1, geo_longitude=-1, manufacturer=OnePlus, model=LE2111, os_version=12, traffic_country=india, traffic_currency=inr, traffic_language=en, traffic_medium=(none), traffic_source=(direct), user_agent=Goibibo/14.5.0.debug (Android 12; LE2111 Build/SKQ1.210216.001), network_type=WIFI, carrier=airtel, ram=11805249536)} + """.trimIndent() + val map = ObjectDeserializer.map(string) + val events = map["event_details"] + assert(events is HashMap<*,*>) + @Suppress("UNCHECKED_CAST") + assert((events as HashMap)["event"] == "home") + } + + @Test + fun simpleMapTest() { + val inputMap = hashMapOf() + inputMap["demo"] = "added" + inputMap["title"] = "test" + val string = "$inputMap" + val map = ObjectDeserializer.map(string) + assert(map["title"] == "test") + } + + @Test + fun wrappedMapTest() { + val inputMap = hashMapOf() + inputMap["demo"] = "added" + inputMap["title"] = "test" + val string = "D[$inputMap]" + val map = ObjectDeserializer.map(string) + assert(map["title"] == "test") + } + +} \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 0000000..7ce3062 --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,194 @@ +import org.jetbrains.compose.compose +import org.jetbrains.compose.desktop.application.dsl.TargetFormat +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +val pf4jVersion: String by project +val pluginsDir: File by rootProject.extra + +plugins { + kotlin("jvm") + id("org.jetbrains.compose") version "1.0.1" + id("com.github.gmazzo.buildconfig") version "3.0.3" +} + +val r8: Configuration by configurations.creating + +group = "com.voxfinite" +version = appVersion() +val appName = "logvue" +val appMainClass = "com.voxfinite.logvue.app.MainKt" + +dependencies { + implementation(kotlin("stdlib")) + testImplementation(kotlin("test")) + implementation(project(":api")) + implementation(compose.desktop.currentOs) + // https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-slf4j-impl + implementation("org.apache.logging.log4j:log4j-slf4j-impl:2.17.0") + implementation("org.apache.logging.log4j:log4j-api:2.17.0") + implementation("org.apache.logging.log4j:log4j-core:2.17.0") + // embedded database + implementation("org.mapdb:mapdb:3.0.8") + implementation("org.snakeyaml:snakeyaml-engine:2.3") +// runtimeOnly("io.netty:netty-resolver-dns-native-macos:4.1.72.Final") // not sure if needed now + implementation("com.android.tools.ddms:ddmlib:30.2.0-alpha06") + implementation("com.google.code.gson:gson:2.8.9") + // https://mvnrepository.com/artifact/com.googlecode.cqengine/cqengine + implementation("com.googlecode.cqengine:cqengine:3.6.0") + implementation("org.jetbrains.kotlin:kotlin-reflect:1.6.10") + + implementation("io.sentry:sentry-log4j2:5.6.0") + // https://mvnrepository.com/artifact/net.harawata/appdirs + implementation("net.harawata:appdirs:1.2.1") + implementation ("org.pf4j:pf4j:${pf4jVersion}") + + r8("com.android.tools:r8:3.0.73") +} + +tasks.test { + useJUnit() +} + +compose.desktop { + application { + mainClass = appMainClass + nativeDistributions { + modules( + "java.compiler", "java.instrument", "java.management", + "java.naming", "java.rmi", "java.scripting", "java.sql", "jdk.attach", + "jdk.jdi", "jdk.unsupported", "jdk.crypto.ec" + ) +// includeAllModules = true + targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb) + packageName = project.rootProject.name + packageVersion = "${project.version}" + description = "Local Analytics" + linux { + debMaintainer = "kapoor.aman22@gmail.com" + iconFile.set(project.file("logo_icon.png")) + } + macOS { + bundleID = "${project.group}.${project.rootProject.name}" + setDockNameSameAsPackageName = true + iconFile.set(project.file("logo_icon.icns")) +// notarization { +// appleID.set("test.app@example.com") +// password.set("@keychain:NOTARIZATION_PASSWORD") +// } + } + windows { + upgradeUuid = "8AEBC8BF-9C94-4D02-ACA8-AF543E0CEB98" + iconFile.set(project.file("logo_icon.ico")) + } + } + } +} + +buildConfig { + className("AppBuildConfig") + useKotlinOutput { topLevelConstants = true } + buildConfigField("String", "APP_NAME", "\"${project.rootProject.name}\"") + buildConfigField("String", "APP_VERSION", "\"${project.version}\"") + val sentryEndpoint = if (project.hasProperty("SENTRY_ENDPOINT")) { + project.property("SENTRY_ENDPOINT").toString() + } else { + "" + } + buildConfigField("String", "SENTRY_ENDPOINT", "\"${sentryEndpoint}\"") + val pluginsPath = if (project.hasProperty("PLUGINS_PATH")) { + project.property("PLUGINS_PATH").toString() + } else { + "" + } + buildConfigField("String", "PLUGINS_PATH", "\"${pluginsPath}\"") +} + +// Define task to obfuscate the JAR and output to .min.jar +tasks.register("r8") { + val packageUberJarForCurrentOS = tasks.getByName("packageUberJarForCurrentOS") + dependsOn(packageUberJarForCurrentOS) + val file = packageUberJarForCurrentOS.outputs.files.first() + val rules = file("src/main/shrink-rules.pro") + val output = File(file.parentFile, "${file.nameWithoutExtension}.min.jar") + inputs.files(file, rules) + outputs.file(output) + classpath(r8) + mainClass.set("com.android.tools.r8.R8") + args = listOf( + "--release", + "--classfile", + "--output", output.toString(), + "--pg-conf", rules.toString(), + "--lib", System.getProperty("java.home") + ) + doFirst { + args?.add(file.absolutePath) + } +} + +tasks.register("repackageUberJar") { + val packageUberJarForCurrentOS = tasks.getByName("packageUberJarForCurrentOS") + dependsOn(packageUberJarForCurrentOS) + val file = packageUberJarForCurrentOS.outputs.files.first() + val output = File(file.parentFile, "${file.nameWithoutExtension}-repacked.jar") + archiveFileName.set(output.absolutePath) + destinationDirectory.set(file.parentFile.absoluteFile) + exclude("META-INF/*.SF") + exclude("META-INF/*.RSA") + exclude("META-INF/*.DSA") + from(project.zipTree(file)) + doLast { + delete(file) + output.renameTo(file) + logger.lifecycle("The repackaged jar is written to ${archiveFile.get().asFile.canonicalPath}") + } +} + +/** + * Sets the Github Action output as package name and path to use in other steps. + */ +gradle.buildFinished { + val pkgFormat = + compose.desktop.application.nativeDistributions.targetFormats.firstOrNull { it.isCompatibleWithCurrentOS } + val nativePkg = buildDir.resolve("compose/binaries").findPkg(pkgFormat?.fileExt) + val jarPkg = buildDir.resolve("compose/jars").findPkg(".jar") + nativePkg.ghActionOutput("app_pkg") + jarPkg.ghActionOutput("uber_jar") +} + +fun File.findPkg(format: String?) = when (format != null) { + true -> walk().firstOrNull { it.isFile && it.name.endsWith(format, ignoreCase = true) } + else -> null +} + +fun File?.ghActionOutput(prefix: String) = this?.let { + when (System.getenv("GITHUB_ACTIONS").toBoolean()) { + true -> println( + """ + ::set-output name=${prefix}_name::${it.name} + ::set-output name=${prefix}_path::${it.absolutePath} + """.trimIndent() + ) + else -> println("$prefix: $this") + } +} + +fun appVersion() : String { + val key = "APP_VERSION" + return if (project.hasProperty(key)) { + val version = project.property("APP_VERSION").toString() + println("Version = $version") + if (version.isBlank()) { + return "1.0.0" + } + if (version.matches(Regex("^[\\d]{1,3}.[\\d]{1,3}.[\\d]{1,4}"))) { + return version + } + if (version.matches(Regex("^v[\\d]{1,3}.[\\d]{1,3}.[\\d]{1,4}"))) { + return version.removePrefix("v") + } + "1.0.0" + } else { + "1.0.0" + } +} diff --git a/src/main/kotlin/inputs/adb/AndroidLogStreamer.kt b/app/src/main/kotlin/com/voxfinite/logvue/adb/AndroidLogStreamer.kt similarity index 60% rename from src/main/kotlin/inputs/adb/AndroidLogStreamer.kt rename to app/src/main/kotlin/com/voxfinite/logvue/adb/AndroidLogStreamer.kt index 7d8d183..3f3c251 100644 --- a/src/main/kotlin/inputs/adb/AndroidLogStreamer.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/adb/AndroidLogStreamer.kt @@ -1,9 +1,9 @@ -package inputs.adb +package com.voxfinite.logvue.adb -import inputs.adb.ddmlib.AdbHelper +import com.voxfinite.logvue.adb.ddmlib.AdbHelper import kotlinx.coroutines.flow.Flow -import models.LogCatMessage2 -import utils.Either +import com.voxfinite.logvue.api.models.LogCatMessage2 +import com.voxfinite.logvue.utils.Either class AndroidLogStreamer { diff --git a/src/main/kotlin/inputs/adb/LogCatErrors.kt b/app/src/main/kotlin/com/voxfinite/logvue/adb/LogCatErrors.kt similarity index 97% rename from src/main/kotlin/inputs/adb/LogCatErrors.kt rename to app/src/main/kotlin/com/voxfinite/logvue/adb/LogCatErrors.kt index 0a6598b..c5f74da 100644 --- a/src/main/kotlin/inputs/adb/LogCatErrors.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/adb/LogCatErrors.kt @@ -1,4 +1,4 @@ -package inputs.adb +package com.voxfinite.logvue.adb import java.io.Serializable diff --git a/src/main/kotlin/inputs/adb/ddmlib/AdbHelper.kt b/app/src/main/kotlin/com/voxfinite/logvue/adb/ddmlib/AdbHelper.kt similarity index 92% rename from src/main/kotlin/inputs/adb/ddmlib/AdbHelper.kt rename to app/src/main/kotlin/com/voxfinite/logvue/adb/ddmlib/AdbHelper.kt index fa2b6d9..7a4fad1 100644 --- a/src/main/kotlin/inputs/adb/ddmlib/AdbHelper.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/adb/ddmlib/AdbHelper.kt @@ -1,11 +1,11 @@ -package inputs.adb.ddmlib +package com.voxfinite.logvue.adb.ddmlib import com.android.ddmlib.AdbInitOptions import com.android.ddmlib.AndroidDebugBridge import com.android.ddmlib.IDevice import com.android.ddmlib.Log -import inputs.adb.LogErrorDeviceNotConnected -import inputs.adb.LogErrorPackageIssue +import com.voxfinite.logvue.adb.LogErrorDeviceNotConnected +import com.voxfinite.logvue.adb.LogErrorPackageIssue import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.channels.Channel @@ -15,9 +15,9 @@ import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.cancellable import kotlinx.coroutines.isActive import kotlinx.coroutines.withContext -import models.LogCatMessage2 -import utils.Either -import utils.reportException +import com.voxfinite.logvue.api.models.LogCatMessage2 +import com.voxfinite.logvue.utils.Either +import com.voxfinite.logvue.utils.reportException import java.io.File import java.util.* import java.util.concurrent.TimeUnit @@ -62,7 +62,7 @@ object AdbHelper { @OptIn(ExperimentalCoroutinesApi::class) fun monitorLogs( packageName: String, - filters: Array = arrayOf("FA", "FA-SVC") + filters: Array = arrayOf("FA", "FA-SVC", "PDTLogging") ) = callbackFlow { stopLogs = false val currentSelectedDevice = Devices.currentDevice?.device diff --git a/src/main/kotlin/inputs/adb/ddmlib/Devices.kt b/app/src/main/kotlin/com/voxfinite/logvue/adb/ddmlib/Devices.kt similarity index 94% rename from src/main/kotlin/inputs/adb/ddmlib/Devices.kt rename to app/src/main/kotlin/com/voxfinite/logvue/adb/ddmlib/Devices.kt index bb11d3b..2adaac2 100644 --- a/src/main/kotlin/inputs/adb/ddmlib/Devices.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/adb/ddmlib/Devices.kt @@ -1,9 +1,9 @@ -package inputs.adb.ddmlib +package com.voxfinite.logvue.adb.ddmlib import com.android.ddmlib.AndroidDebugBridge import com.android.ddmlib.IDevice import kotlinx.coroutines.flow.MutableStateFlow -import models.DeviceDetails2 +import com.voxfinite.logvue.models.DeviceDetails2 class Devices : AndroidDebugBridge.IDeviceChangeListener { diff --git a/src/main/kotlin/inputs/adb/ddmlib/EmptyReceiver.kt b/app/src/main/kotlin/com/voxfinite/logvue/adb/ddmlib/EmptyReceiver.kt similarity index 52% rename from src/main/kotlin/inputs/adb/ddmlib/EmptyReceiver.kt rename to app/src/main/kotlin/com/voxfinite/logvue/adb/ddmlib/EmptyReceiver.kt index 63ff263..db42d9a 100644 --- a/src/main/kotlin/inputs/adb/ddmlib/EmptyReceiver.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/adb/ddmlib/EmptyReceiver.kt @@ -1,3 +1,3 @@ -package inputs.adb.ddmlib +package com.voxfinite.logvue.adb.ddmlib val EmptyReceiver = SingleValueReceiver {} diff --git a/app/src/main/kotlin/com/voxfinite/logvue/adb/ddmlib/LogCatListener2.kt b/app/src/main/kotlin/com/voxfinite/logvue/adb/ddmlib/LogCatListener2.kt new file mode 100644 index 0000000..f9cc8ea --- /dev/null +++ b/app/src/main/kotlin/com/voxfinite/logvue/adb/ddmlib/LogCatListener2.kt @@ -0,0 +1,7 @@ +package com.voxfinite.logvue.adb.ddmlib + +import com.voxfinite.logvue.api.models.LogCatMessage2 + +fun interface LogCatListener2 { + fun log(msgList: ArrayList) +} diff --git a/src/main/kotlin/inputs/adb/ddmlib/LogCatRunner.kt b/app/src/main/kotlin/com/voxfinite/logvue/adb/ddmlib/LogCatRunner.kt similarity index 90% rename from src/main/kotlin/inputs/adb/ddmlib/LogCatRunner.kt rename to app/src/main/kotlin/com/voxfinite/logvue/adb/ddmlib/LogCatRunner.kt index a4370a9..c86d133 100644 --- a/src/main/kotlin/inputs/adb/ddmlib/LogCatRunner.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/adb/ddmlib/LogCatRunner.kt @@ -1,10 +1,12 @@ -package inputs.adb.ddmlib +package com.voxfinite.logvue.adb.ddmlib import com.android.ddmlib.* import com.android.ddmlib.logcat.LogCatMessageParser -import models.LogCatHeader2 -import models.LogCatMessage2 -import utils.reportException +import com.voxfinite.logvue.api.models.LogCatHeader2 +import com.voxfinite.logvue.api.models.LogCatMessage2 +import com.voxfinite.logvue.api.models.LogLevel2 +import com.voxfinite.logvue.utils.reportException +import com.voxfinite.logvue.utils.to2 import java.io.IOException import java.time.Instant import java.util.concurrent.TimeUnit @@ -29,7 +31,7 @@ class LogCatRunner( private fun newLogCatMessage(message: String): LogCatMessage2 { return LogCatMessage2( LogCatHeader2( - Log.LogLevel.ERROR, -1, -1, "", "", + LogLevel2.ERROR, -1, -1, "", "", Instant.EPOCH ), message ) @@ -93,7 +95,7 @@ class LogCatRunner( } private fun processLogLines(lines: Array) { - val newMessages: List = mParser.processLogLines(lines, mDevice).map { LogCatMessage2(it) } + val newMessages: List = mParser.processLogLines(lines, mDevice).map { it.to2() } if (newMessages.isNotEmpty()) { notifyListeners(arrayListOf().also { logCatMessage2s -> logCatMessage2s.addAll( diff --git a/src/main/kotlin/inputs/adb/ddmlib/PackagesReceiver.kt b/app/src/main/kotlin/com/voxfinite/logvue/adb/ddmlib/PackagesReceiver.kt similarity index 92% rename from src/main/kotlin/inputs/adb/ddmlib/PackagesReceiver.kt rename to app/src/main/kotlin/com/voxfinite/logvue/adb/ddmlib/PackagesReceiver.kt index 679df8c..274a33c 100644 --- a/src/main/kotlin/inputs/adb/ddmlib/PackagesReceiver.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/adb/ddmlib/PackagesReceiver.kt @@ -1,4 +1,4 @@ -package inputs.adb.ddmlib +package com.voxfinite.logvue.adb.ddmlib import com.android.ddmlib.MultiLineReceiver diff --git a/src/main/kotlin/inputs/adb/ddmlib/SingleValueReceiver.kt b/app/src/main/kotlin/com/voxfinite/logvue/adb/ddmlib/SingleValueReceiver.kt similarity index 91% rename from src/main/kotlin/inputs/adb/ddmlib/SingleValueReceiver.kt rename to app/src/main/kotlin/com/voxfinite/logvue/adb/ddmlib/SingleValueReceiver.kt index fcf607c..d3c2938 100644 --- a/src/main/kotlin/inputs/adb/ddmlib/SingleValueReceiver.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/adb/ddmlib/SingleValueReceiver.kt @@ -1,4 +1,4 @@ -package inputs.adb.ddmlib +package com.voxfinite.logvue.adb.ddmlib import com.android.ddmlib.MultiLineReceiver diff --git a/src/main/kotlin/app/App.kt b/app/src/main/kotlin/com/voxfinite/logvue/app/App.kt similarity index 76% rename from src/main/kotlin/app/App.kt rename to app/src/main/kotlin/com/voxfinite/logvue/app/App.kt index 19dae35..3c67d3e 100644 --- a/src/main/kotlin/app/App.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/app/App.kt @@ -1,4 +1,4 @@ -package app +package com.voxfinite.logvue.app import androidx.compose.desktop.ui.tooling.preview.Preview import androidx.compose.foundation.background @@ -11,24 +11,25 @@ import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp -import inputs.adb.ddmlib.AdbHelper -import processor.MainProcessor -import storage.Db -import ui.AppTheme -import ui.CustomTheme -import ui.components.BodyPanel -import ui.components.SideNavigation -import ui.components.dialogs.CrashDialog -import ui.components.dialogs.IntroDialog -import utils.AppSettings -import utils.CustomExceptionHandler -import utils.Helpers +import com.voxfinite.logvue.adb.ddmlib.AdbHelper +import com.voxfinite.logvue.processor.MainProcessor +import com.voxfinite.logvue.storage.Db +import com.voxfinite.logvue.ui.AppTheme +import com.voxfinite.logvue.ui.CustomTheme +import com.voxfinite.logvue.ui.components.BodyPanel +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.* @Composable @Preview fun App() { val processor = remember { MainProcessor() } val isLightTheme by Helpers.isThemeLightMode.collectAsState() + LaunchedEffect(Unit) { + PluginsHelper.load() + } AppTheme(isLightTheme) { Row(Modifier.fillMaxSize().background(CustomTheme.colors.background)) { var sessionId by remember { mutableStateOf(Db.sessionId()) } diff --git a/src/main/kotlin/app/Main.kt b/app/src/main/kotlin/com/voxfinite/logvue/app/Main.kt similarity index 89% rename from src/main/kotlin/app/Main.kt rename to app/src/main/kotlin/com/voxfinite/logvue/app/Main.kt index 6e6c4a5..2535520 100644 --- a/src/main/kotlin/app/Main.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/app/Main.kt @@ -1,4 +1,4 @@ -package app +package com.voxfinite.logvue.app import androidx.compose.ui.window.application diff --git a/src/main/kotlin/app/MainWindow.kt b/app/src/main/kotlin/com/voxfinite/logvue/app/MainWindow.kt similarity index 77% rename from src/main/kotlin/app/MainWindow.kt rename to app/src/main/kotlin/com/voxfinite/logvue/app/MainWindow.kt index 8d6ed8a..e51b15c 100644 --- a/src/main/kotlin/app/MainWindow.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/app/MainWindow.kt @@ -1,16 +1,16 @@ -package app +package com.voxfinite.logvue.app import androidx.compose.runtime.Composable import androidx.compose.ui.window.ApplicationScope import androidx.compose.ui.window.Window import androidx.compose.ui.window.WindowPlacement import androidx.compose.ui.window.rememberWindowState -import inputs.adb.ddmlib.AdbHelper -import storage.Db -import ui.CustomTheme -import utils.AppLog -import utils.CustomExceptionHandler -import utils.SentryHelper +import com.voxfinite.logvue.adb.ddmlib.AdbHelper +import com.voxfinite.logvue.storage.Db +import com.voxfinite.logvue.ui.CustomTheme +import com.voxfinite.logvue.utils.AppLog +import com.voxfinite.logvue.utils.CustomExceptionHandler +import com.voxfinite.logvue.utils.SentryHelper import java.awt.Desktop @Composable diff --git a/src/main/kotlin/models/DeviceDetails2.kt b/app/src/main/kotlin/com/voxfinite/logvue/models/DeviceDetails2.kt similarity index 95% rename from src/main/kotlin/models/DeviceDetails2.kt rename to app/src/main/kotlin/com/voxfinite/logvue/models/DeviceDetails2.kt index 3d122a7..1b45255 100644 --- a/src/main/kotlin/models/DeviceDetails2.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/models/DeviceDetails2.kt @@ -1,4 +1,4 @@ -package models +package com.voxfinite.logvue.models import com.android.ddmlib.IDevice diff --git a/src/main/kotlin/models/Faq.kt b/app/src/main/kotlin/com/voxfinite/logvue/models/Faq.kt similarity index 85% rename from src/main/kotlin/models/Faq.kt rename to app/src/main/kotlin/com/voxfinite/logvue/models/Faq.kt index 14a5bf6..d561bba 100644 --- a/src/main/kotlin/models/Faq.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/models/Faq.kt @@ -1,4 +1,4 @@ -package models +package com.voxfinite.logvue.models data class Faq(val question: MarkupText, val answer: MarkupText) { constructor(question: String, answer: String) : this(MarkupText(question), MarkupText(answer)) diff --git a/src/main/kotlin/models/ParameterFormats.kt b/app/src/main/kotlin/com/voxfinite/logvue/models/ParameterFormats.kt similarity index 94% rename from src/main/kotlin/models/ParameterFormats.kt rename to app/src/main/kotlin/com/voxfinite/logvue/models/ParameterFormats.kt index 0b6ed35..50fae1e 100644 --- a/src/main/kotlin/models/ParameterFormats.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/models/ParameterFormats.kt @@ -1,4 +1,4 @@ -package models +package com.voxfinite.logvue.models sealed class ParameterFormats(val key: String, val text: String, val subText: String) object FormatJsonPretty : diff --git a/src/main/kotlin/models/PredictedEventType.kt b/app/src/main/kotlin/com/voxfinite/logvue/models/PredictedEventType.kt similarity index 98% rename from src/main/kotlin/models/PredictedEventType.kt rename to app/src/main/kotlin/com/voxfinite/logvue/models/PredictedEventType.kt index 6f5fa59..a8450a7 100644 --- a/src/main/kotlin/models/PredictedEventType.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/models/PredictedEventType.kt @@ -1,4 +1,4 @@ -package models +package com.voxfinite.logvue.models import java.io.Serializable diff --git a/src/main/kotlin/models/SessionInfo.kt b/app/src/main/kotlin/com/voxfinite/logvue/models/SessionInfo.kt similarity index 92% rename from src/main/kotlin/models/SessionInfo.kt rename to app/src/main/kotlin/com/voxfinite/logvue/models/SessionInfo.kt index 4f2bf3e..16e63d2 100644 --- a/src/main/kotlin/models/SessionInfo.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/models/SessionInfo.kt @@ -1,4 +1,4 @@ -package models +package com.voxfinite.logvue.models import java.io.Serializable diff --git a/src/main/kotlin/models/SocialIcons.kt b/app/src/main/kotlin/com/voxfinite/logvue/models/SocialIcons.kt similarity index 95% rename from src/main/kotlin/models/SocialIcons.kt rename to app/src/main/kotlin/com/voxfinite/logvue/models/SocialIcons.kt index 68ed183..e774fd1 100644 --- a/src/main/kotlin/models/SocialIcons.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/models/SocialIcons.kt @@ -1,4 +1,4 @@ -package models +package com.voxfinite.logvue.models enum class SocialIcons(val icon: String, val url: String) { Twitter( diff --git a/app/src/main/kotlin/com/voxfinite/logvue/parsers/FirebaseParser.kt b/app/src/main/kotlin/com/voxfinite/logvue/parsers/FirebaseParser.kt new file mode 100644 index 0000000..d45275e --- /dev/null +++ b/app/src/main/kotlin/com/voxfinite/logvue/parsers/FirebaseParser.kt @@ -0,0 +1,21 @@ +package com.voxfinite.logvue.parsers + +import com.voxfinite.logvue.api.LogEventParser +import com.voxfinite.logvue.api.models.LogCatMessage2 +import com.voxfinite.logvue.api.models.LogItem +import com.voxfinite.logvue.api.models.LogLevel2 +import com.voxfinite.logvue.utils.Helpers + +class FirebaseParser : LogEventParser { + + override fun filters(): List { + return arrayListOf("FA", "FA-SVC") + } + + override fun validate(logCatMessage2: LogCatMessage2): Boolean { + return Helpers.validateFALogString(logCatMessage2.message) && + logCatMessage2.header.logLevel != LogLevel2.ERROR + } + + override fun parse(logCatMessage2: LogCatMessage2): LogItem = Helpers.parseFALogs(logCatMessage2) +} \ No newline at end of file diff --git a/src/main/kotlin/processor/DbSink.kt b/app/src/main/kotlin/com/voxfinite/logvue/processor/DbSink.kt similarity index 78% rename from src/main/kotlin/processor/DbSink.kt rename to app/src/main/kotlin/com/voxfinite/logvue/processor/DbSink.kt index 189d666..b54d457 100644 --- a/src/main/kotlin/processor/DbSink.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/processor/DbSink.kt @@ -1,8 +1,8 @@ -package processor +package com.voxfinite.logvue.processor -import models.LogItem -import models.SourceInternalContent -import storage.Db +import com.voxfinite.logvue.api.models.LogItem +import com.voxfinite.logvue.api.models.SourceInternalContent +import com.voxfinite.logvue.storage.Db object DbSink { diff --git a/src/main/kotlin/processor/Exporter.kt b/app/src/main/kotlin/com/voxfinite/logvue/processor/Exporter.kt similarity index 90% rename from src/main/kotlin/processor/Exporter.kt rename to app/src/main/kotlin/com/voxfinite/logvue/processor/Exporter.kt index 23dedad..41b9fc3 100644 --- a/src/main/kotlin/processor/Exporter.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/processor/Exporter.kt @@ -1,11 +1,13 @@ -package processor +package com.voxfinite.logvue.processor import com.google.gson.GsonBuilder import com.google.gson.ToNumberPolicy +import com.voxfinite.logvue.api.models.LogItem +import com.voxfinite.logvue.api.models.SourceInternalContent import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext -import models.* -import utils.Helpers +import com.voxfinite.logvue.models.* +import com.voxfinite.logvue.utils.Helpers import java.io.PrintWriter import java.nio.file.Path import java.nio.file.StandardOpenOption diff --git a/src/main/kotlin/processor/MainProcessor.kt b/app/src/main/kotlin/com/voxfinite/logvue/processor/MainProcessor.kt similarity index 70% rename from src/main/kotlin/processor/MainProcessor.kt rename to app/src/main/kotlin/com/voxfinite/logvue/processor/MainProcessor.kt index d2a447a..d708d4a 100644 --- a/src/main/kotlin/processor/MainProcessor.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/processor/MainProcessor.kt @@ -1,23 +1,22 @@ -package processor +package com.voxfinite.logvue.processor -import com.android.ddmlib.Log -import inputs.adb.AndroidLogStreamer -import inputs.adb.LogCatErrors -import inputs.adb.LogErrorNoSession +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 +import com.voxfinite.logvue.api.LogEventParser import io.sentry.Sentry import io.sentry.SpanStatus import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import models.ErrorContent -import models.LogItem -import models.SessionInfo -import storage.Db -import utils.Helpers -import utils.failureOrNull -import utils.getOrNull -import utils.reportException +import com.voxfinite.logvue.api.models.ErrorContent +import com.voxfinite.logvue.api.models.LogCatMessage2 +import com.voxfinite.logvue.api.models.LogItem +import com.voxfinite.logvue.models.SessionInfo +import com.voxfinite.logvue.storage.Db +import com.voxfinite.logvue.utils.* class MainProcessor { @@ -36,12 +35,14 @@ class MainProcessor { pause() filterQuery = null Db.changeSession(session) + EventTypePredictor.clear() } fun createNewSession(sessionInfo: SessionInfo) { pause() filterQuery = null Db.createNewSession(sessionInfo) + EventTypePredictor.clear() } fun deleteSession(sessionId: String) { @@ -62,7 +63,7 @@ class MainProcessor { if (!lastItems.isNullOrEmpty()) { uiFlowSink(flowOf(lastItems), false, onMessage) } else { - onMessage(listOf(LogItem.noContent("Record logs using the start button above"))) + onMessage(listOf(EventCompanion.noContent("Record logs using the start button above"))) } } @@ -82,16 +83,12 @@ class MainProcessor { } val packageName = sessionInfo.appPackage val stream = streamer.stream(packageName) + val parsers = PluginsHelper.parsers() launch { val successStream = stream.filter { it.isSuccess }.map { it.getOrNull() } .filterNotNull() .mapNotNull { logCatMessage2s -> - logCatMessage2s.filter { - Helpers.validateFALogString(it.message) && - it.header.logLevel != Log.LogLevel.ERROR - }.map { - Helpers.parseFALogs(it) - } + generateLogItems(logCatMessage2s, parsers) }.buffer() launch { uiFlowSink(successStream, true, onMessage) @@ -110,6 +107,28 @@ class MainProcessor { } } + private fun generateLogItems( + logCatMessage2s: ArrayList, + parsers: MutableList + ): ArrayList { + val localList = arrayListOf() + logCatMessage2s.forEach { message -> + parsers.forEach inner@ { parser -> + val filters = parser.filters() + val mFilter = message.header.tag + if (!filters.contains(mFilter) || !parser.validate(message)) { + return@inner + } + try { + localList.add(parser.parse(message)) + } catch (e: Exception) { + e.reportException() + } + } + } + return localList + } + private suspend fun uiFlowSink( logItemStream: Flow>, isNewStream: Boolean, @@ -137,13 +156,13 @@ class MainProcessor { e.reportException() sentryTransaction.throwable = e sentryTransaction.status = SpanStatus.INTERNAL_ERROR - listOf(LogItem.errorContent(ErrorContent("Unable to filter current query", e))) + listOf(EventCompanion.errorContent(ErrorContent("Unable to filter current query", e))) } finally { sentryTransaction.finish() } } if (filterResult.isEmpty() && !isNewStream) { - onMessage(listOf(LogItem.noContent("No results found for this query"))) + onMessage(listOf(EventCompanion.noContent("No results found for this query"))) } else { onMessage(filterResult) } diff --git a/src/main/kotlin/processor/ParameterizedAttribute.kt b/app/src/main/kotlin/com/voxfinite/logvue/processor/ParameterizedAttribute.kt similarity index 93% rename from src/main/kotlin/processor/ParameterizedAttribute.kt rename to app/src/main/kotlin/com/voxfinite/logvue/processor/ParameterizedAttribute.kt index 7f55473..c71d287 100644 --- a/src/main/kotlin/processor/ParameterizedAttribute.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/processor/ParameterizedAttribute.kt @@ -1,11 +1,11 @@ -package processor +package com.voxfinite.logvue.processor import com.googlecode.cqengine.attribute.SimpleNullableAttribute import com.googlecode.cqengine.query.option.QueryOptions import javassist.NotFoundException -import models.LogItem -import utils.WarningException -import utils.reportException +import com.voxfinite.logvue.api.models.LogItem +import com.voxfinite.logvue.utils.WarningException +import com.voxfinite.logvue.utils.reportException class ParameterizedAttribute(private val mapKey: String, private val clazz: Class) : SimpleNullableAttribute(LogItem::class.java, clazz, mapKey) { diff --git a/src/main/kotlin/processor/QueryHelper.kt b/app/src/main/kotlin/com/voxfinite/logvue/processor/QueryHelper.kt similarity index 86% rename from src/main/kotlin/processor/QueryHelper.kt rename to app/src/main/kotlin/com/voxfinite/logvue/processor/QueryHelper.kt index fa7d323..a42287d 100644 --- a/src/main/kotlin/processor/QueryHelper.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/processor/QueryHelper.kt @@ -1,4 +1,4 @@ -package processor +package com.voxfinite.logvue.processor import com.googlecode.cqengine.ConcurrentIndexedCollection import com.googlecode.cqengine.ObjectLockingIndexedCollection @@ -9,11 +9,12 @@ import com.googlecode.cqengine.index.radix.RadixTreeIndex import com.googlecode.cqengine.index.radixinverted.InvertedRadixTreeIndex import com.googlecode.cqengine.index.radixreversed.ReversedRadixTreeIndex import com.googlecode.cqengine.query.parser.sql.SQLParser -import models.LogItem -import storage.SessionConfig -import utils.AppLog -import utils.ConfigConstants -import utils.reportException +import com.voxfinite.logvue.api.models.LogItem +import com.voxfinite.logvue.storage.SessionConfig +import com.voxfinite.logvue.utils.AppLog +import com.voxfinite.logvue.utils.ConfigConstants +import com.voxfinite.logvue.utils.EventCompanion +import com.voxfinite.logvue.utils.reportException import kotlin.reflect.KProperty1 import kotlin.time.ExperimentalTime import kotlin.time.measureTimedValue @@ -26,19 +27,19 @@ inline fun attribute(name: String, accessor: KProperty1 { return ObjectLockingIndexedCollection().apply { - addIndex(HashIndex.onAttribute(LogItem.EVENT_NAME)) - addIndex(RadixTreeIndex.onAttribute(LogItem.EVENT_NAME)) - addIndex(InvertedRadixTreeIndex.onAttribute(LogItem.EVENT_NAME)) - addIndex(ReversedRadixTreeIndex.onAttribute(LogItem.EVENT_NAME)) - addIndex(HashIndex.onAttribute(LogItem.ATTR_TIME)) - addIndex(NavigableIndex.onAttribute(LogItem.ATTR_TIME)) + addIndex(HashIndex.onAttribute(EventCompanion.EVENT_NAME)) + addIndex(RadixTreeIndex.onAttribute(EventCompanion.EVENT_NAME)) + addIndex(InvertedRadixTreeIndex.onAttribute(EventCompanion.EVENT_NAME)) + addIndex(ReversedRadixTreeIndex.onAttribute(EventCompanion.EVENT_NAME)) + addIndex(HashIndex.onAttribute(EventCompanion.ATTR_TIME)) + addIndex(NavigableIndex.onAttribute(EventCompanion.ATTR_TIME)) } } fun sqlParser(): SQLParser { return SQLParser.forPojo(LogItem::class.java).apply { - registerAttribute(LogItem.EVENT_NAME) - registerAttribute(LogItem.ATTR_TIME) + registerAttribute(EventCompanion.EVENT_NAME) + registerAttribute(EventCompanion.ATTR_TIME) } } diff --git a/src/main/kotlin/processor/YamlWriter.kt b/app/src/main/kotlin/com/voxfinite/logvue/processor/YamlWriter.kt similarity index 91% rename from src/main/kotlin/processor/YamlWriter.kt rename to app/src/main/kotlin/com/voxfinite/logvue/processor/YamlWriter.kt index 9ca0986..c97db1f 100644 --- a/src/main/kotlin/processor/YamlWriter.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/processor/YamlWriter.kt @@ -1,4 +1,4 @@ -package processor +package com.voxfinite.logvue.processor import org.snakeyaml.engine.v2.api.StreamDataWriter import java.io.PrintWriter diff --git a/src/main/kotlin/storage/Db.kt b/app/src/main/kotlin/com/voxfinite/logvue/storage/Db.kt similarity index 96% rename from src/main/kotlin/storage/Db.kt rename to app/src/main/kotlin/com/voxfinite/logvue/storage/Db.kt index 30d09ad..933fdf3 100644 --- a/src/main/kotlin/storage/Db.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/storage/Db.kt @@ -1,10 +1,10 @@ -package storage +package com.voxfinite.logvue.storage -import models.LogItem -import models.SessionInfo +import com.voxfinite.logvue.api.models.LogItem +import com.voxfinite.logvue.models.SessionInfo import org.mapdb.HTreeMap import org.mapdb.Serializer -import storage.serializer.ObjectSerializer +import com.voxfinite.logvue.storage.serializer.ObjectSerializer object Db { diff --git a/src/main/kotlin/storage/SessionConfig.kt b/app/src/main/kotlin/com/voxfinite/logvue/storage/SessionConfig.kt similarity index 96% rename from src/main/kotlin/storage/SessionConfig.kt rename to app/src/main/kotlin/com/voxfinite/logvue/storage/SessionConfig.kt index 288bd3b..f2968dc 100644 --- a/src/main/kotlin/storage/SessionConfig.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/storage/SessionConfig.kt @@ -1,6 +1,6 @@ -package storage +package com.voxfinite.logvue.storage -import models.SessionInfo +import com.voxfinite.logvue.models.SessionInfo /** * Operations for config related to session. diff --git a/app/src/main/kotlin/com/voxfinite/logvue/storage/StorageHelper.kt b/app/src/main/kotlin/com/voxfinite/logvue/storage/StorageHelper.kt new file mode 100644 index 0000000..2c14814 --- /dev/null +++ b/app/src/main/kotlin/com/voxfinite/logvue/storage/StorageHelper.kt @@ -0,0 +1,83 @@ +package com.voxfinite.logvue.storage + +import com.voxfinite.app.APP_NAME +import com.voxfinite.app.PLUGINS_PATH +import net.harawata.appdirs.AppDirsFactory +import org.mapdb.DB +import org.mapdb.DBException +import org.mapdb.DBMaker +import com.voxfinite.logvue.utils.DbCreationException +import com.voxfinite.logvue.utils.reportException +import java.io.File +import java.io.IOException +import java.nio.file.FileSystems +import java.nio.file.Files +import java.nio.file.Path +import java.nio.file.Paths +import java.nio.file.attribute.PosixFilePermissions + + +object StorageHelper { + + internal fun createDiskDb(): DB { + val dbFile = getDbFile() + return try { + DBMaker.fileDB(dbFile).fileMmapEnableIfSupported().checksumHeaderBypass().make() + } catch (e: DBException.VolumeIOError) { + DbCreationException("Mmap enabled db could not be created", e).reportException() + try { + DBMaker.fileDB(dbFile).fileChannelEnable().checksumHeaderBypass().make() + } catch (ee: DBException.VolumeIOError) { + DbCreationException("file channel enabled db could not be created", ee).reportException() + DBMaker.fileDB(dbFile).checksumHeaderBypass().make() + } + } + } + + fun getPluginsPath() : Path { + val appDir = appDir() + val pluginDir = File(appDir, "plugins") + createDir(pluginDir) + var pluginPath = PLUGINS_PATH + if (pluginPath.isBlank()) { + pluginPath = pluginDir.absolutePath + } + return Paths.get(pluginPath) + } + + @Throws(IOException::class) + private fun getDbFile(): File { + val dataDir = appDir() + val dbName = "sessions.db" + return File(dataDir, dbName) + } + + private fun appDir(): File { + val appDirs = AppDirsFactory.getInstance() + val dataDir = appDirs.getUserDataDir(APP_NAME, null, APP_NAME) + val folder = File(dataDir) + createDir(folder) + return folder + } + + private fun createDir(folder: File) { + if (folder.exists() && folder.isDirectory) return + if (folder.exists()) { + folder.delete() + } + try { + val isPosix = FileSystems.getDefault().supportedFileAttributeViews().contains("posix") + if (isPosix) { + val posixAttribute = PosixFilePermissions.asFileAttribute( + PosixFilePermissions.fromString("rwxr-x---") + ) + Files.createDirectories(folder.toPath(), posixAttribute) + } else { + Files.createDirectories(folder.toPath()) + } + } catch (e: IOException) { + throw IOException("Cannot create app folder at path ${folder.canonicalPath}", e) + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/storage/serializer/ObjectSerializer.kt b/app/src/main/kotlin/com/voxfinite/logvue/storage/serializer/ObjectSerializer.kt similarity index 97% rename from src/main/kotlin/storage/serializer/ObjectSerializer.kt rename to app/src/main/kotlin/com/voxfinite/logvue/storage/serializer/ObjectSerializer.kt index c95e9fc..5ac8f0f 100644 --- a/src/main/kotlin/storage/serializer/ObjectSerializer.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/storage/serializer/ObjectSerializer.kt @@ -1,4 +1,4 @@ -package storage.serializer +package com.voxfinite.logvue.storage.serializer import org.mapdb.CC import org.mapdb.DataInput2 diff --git a/src/main/kotlin/ui/CustomHeading.kt b/app/src/main/kotlin/com/voxfinite/logvue/ui/CustomHeading.kt similarity index 97% rename from src/main/kotlin/ui/CustomHeading.kt rename to app/src/main/kotlin/com/voxfinite/logvue/ui/CustomHeading.kt index 2b73da3..3f1bafd 100644 --- a/src/main/kotlin/ui/CustomHeading.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/ui/CustomHeading.kt @@ -1,4 +1,4 @@ -package ui +package com.voxfinite.logvue.ui import androidx.compose.runtime.Immutable import androidx.compose.ui.text.TextStyle diff --git a/src/main/kotlin/ui/Theme.kt b/app/src/main/kotlin/com/voxfinite/logvue/ui/Theme.kt similarity index 98% rename from src/main/kotlin/ui/Theme.kt rename to app/src/main/kotlin/com/voxfinite/logvue/ui/Theme.kt index 21af999..b1aeed5 100644 --- a/src/main/kotlin/ui/Theme.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/ui/Theme.kt @@ -1,4 +1,4 @@ -package ui +package com.voxfinite.logvue.ui import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.* @@ -14,8 +14,8 @@ import androidx.compose.ui.text.platform.Font import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import utils.EnglishStringRes -import utils.StringRes +import com.voxfinite.logvue.utils.EnglishStringRes +import com.voxfinite.logvue.utils.StringRes @Composable fun AppTheme(isLightTheme: Boolean = true, content: @Composable () -> Unit) = diff --git a/src/main/kotlin/ui/components/ActionBar.kt b/app/src/main/kotlin/com/voxfinite/logvue/ui/components/ActionBar.kt similarity index 96% rename from src/main/kotlin/ui/components/ActionBar.kt rename to app/src/main/kotlin/com/voxfinite/logvue/ui/components/ActionBar.kt index 4647a22..f95354c 100644 --- a/src/main/kotlin/ui/components/ActionBar.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/ui/components/ActionBar.kt @@ -1,4 +1,4 @@ -package ui.components +package com.voxfinite.logvue.ui.components import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size @@ -9,7 +9,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp -import ui.views.flow.FlowRow +import com.voxfinite.logvue.ui.views.flow.FlowRow @Composable fun ActionBar( diff --git a/src/main/kotlin/ui/components/BodyHeader.kt b/app/src/main/kotlin/com/voxfinite/logvue/ui/components/BodyHeader.kt similarity index 95% rename from src/main/kotlin/ui/components/BodyHeader.kt rename to app/src/main/kotlin/com/voxfinite/logvue/ui/components/BodyHeader.kt index 6133299..e540d30 100644 --- a/src/main/kotlin/ui/components/BodyHeader.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/ui/components/BodyHeader.kt @@ -1,4 +1,4 @@ -package ui.components +package com.voxfinite.logvue.ui.components import androidx.compose.foundation.background import androidx.compose.foundation.layout.* @@ -15,10 +15,10 @@ import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.unit.dp -import processor.QUERY_PREFIX -import ui.CustomTheme -import ui.components.dialogs.FilterFaqDialog -import ui.components.dialogs.SettingsDialog +import com.voxfinite.logvue.processor.QUERY_PREFIX +import com.voxfinite.logvue.ui.CustomTheme +import com.voxfinite.logvue.ui.components.dialogs.FilterFaqDialog +import com.voxfinite.logvue.ui.components.dialogs.SettingsDialog @Composable fun BodyHeader( diff --git a/src/main/kotlin/ui/components/BodyPanel.kt b/app/src/main/kotlin/com/voxfinite/logvue/ui/components/BodyPanel.kt similarity index 94% rename from src/main/kotlin/ui/components/BodyPanel.kt rename to app/src/main/kotlin/com/voxfinite/logvue/ui/components/BodyPanel.kt index 0201691..bc11a1e 100644 --- a/src/main/kotlin/ui/components/BodyPanel.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/ui/components/BodyPanel.kt @@ -1,4 +1,4 @@ -package ui.components +package com.voxfinite.logvue.ui.components import androidx.compose.animation.* import androidx.compose.foundation.* @@ -20,16 +20,17 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp -import inputs.adb.LogCatErrors -import inputs.adb.ddmlib.Devices -import inputs.adb.logcatErrorString +import com.voxfinite.logvue.adb.LogCatErrors +import com.voxfinite.logvue.adb.ddmlib.Devices +import com.voxfinite.logvue.adb.logcatErrorString import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch -import models.LogItem -import models.SourceInternalContent -import processor.MainProcessor -import ui.CustomTheme -import utils.AppSettings +import com.voxfinite.logvue.api.models.LogItem +import com.voxfinite.logvue.api.models.SourceInternalContent +import com.voxfinite.logvue.processor.MainProcessor +import com.voxfinite.logvue.ui.CustomTheme +import com.voxfinite.logvue.ui.components.dialogs.ExportDialog +import com.voxfinite.logvue.utils.AppSettings @Composable fun BodyPanel( @@ -94,7 +95,7 @@ fun BodyPanel( if (isOpen) { val sessionInfo = processor.getSessionInfo(sessionId.orEmpty()) if (sessionInfo != null) { - ui.components.dialogs.ExportDialog(sessionInfo, logItems) { + ExportDialog(sessionInfo, logItems) { isOpen = false } } diff --git a/src/main/kotlin/ui/components/Chip.kt b/app/src/main/kotlin/com/voxfinite/logvue/ui/components/Chip.kt similarity index 88% rename from src/main/kotlin/ui/components/Chip.kt rename to app/src/main/kotlin/com/voxfinite/logvue/ui/components/Chip.kt index 8f4c662..779479d 100644 --- a/src/main/kotlin/ui/components/Chip.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/ui/components/Chip.kt @@ -1,4 +1,4 @@ -package ui.components +package com.voxfinite.logvue.ui.components import androidx.compose.foundation.background import androidx.compose.foundation.border @@ -11,9 +11,9 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp -import ui.CustomTheme -import ui.LocalCustomColors -import ui.LocalCustomTypography +import com.voxfinite.logvue.ui.CustomTheme +import com.voxfinite.logvue.ui.LocalCustomColors +import com.voxfinite.logvue.ui.LocalCustomTypography @Composable fun Chip( diff --git a/src/main/kotlin/ui/components/DetailCard.kt b/app/src/main/kotlin/com/voxfinite/logvue/ui/components/DetailCard.kt similarity index 96% rename from src/main/kotlin/ui/components/DetailCard.kt rename to app/src/main/kotlin/com/voxfinite/logvue/ui/components/DetailCard.kt index 40c1e05..9e44225 100644 --- a/src/main/kotlin/ui/components/DetailCard.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/ui/components/DetailCard.kt @@ -1,4 +1,4 @@ -package ui.components +package com.voxfinite.logvue.ui.components import androidx.compose.foundation.Image import androidx.compose.foundation.horizontalScroll @@ -21,9 +21,9 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import kotlinx.coroutines.launch -import models.LogItem -import ui.CustomTheme -import utils.Helpers +import com.voxfinite.logvue.api.models.LogItem +import com.voxfinite.logvue.ui.CustomTheme +import com.voxfinite.logvue.utils.Helpers @Composable fun DetailCard(logItem: LogItem, modifier: Modifier = Modifier, onCloseClick: () -> Unit) { diff --git a/src/main/kotlin/ui/components/DeviceList.kt b/app/src/main/kotlin/com/voxfinite/logvue/ui/components/DeviceList.kt similarity index 92% rename from src/main/kotlin/ui/components/DeviceList.kt rename to app/src/main/kotlin/com/voxfinite/logvue/ui/components/DeviceList.kt index 253713e..8dc01da 100644 --- a/src/main/kotlin/ui/components/DeviceList.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/ui/components/DeviceList.kt @@ -1,4 +1,4 @@ -package ui.components +package com.voxfinite.logvue.ui.components import androidx.compose.foundation.background import androidx.compose.foundation.clickable @@ -17,11 +17,11 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.unit.dp -import inputs.adb.ddmlib.Devices +import com.voxfinite.logvue.adb.ddmlib.Devices import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch -import models.DeviceDetails2 -import ui.CustomTheme +import com.voxfinite.logvue.models.DeviceDetails2 +import com.voxfinite.logvue.ui.CustomTheme @Composable fun DeviceList(devices: List, modifier: Modifier = Modifier) { diff --git a/src/main/kotlin/ui/components/ListItemInternalContent.kt b/app/src/main/kotlin/com/voxfinite/logvue/ui/components/ListItemInternalContent.kt similarity index 91% rename from src/main/kotlin/ui/components/ListItemInternalContent.kt rename to app/src/main/kotlin/com/voxfinite/logvue/ui/components/ListItemInternalContent.kt index af26f8d..119e357 100644 --- a/src/main/kotlin/ui/components/ListItemInternalContent.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/ui/components/ListItemInternalContent.kt @@ -1,4 +1,4 @@ -package ui.components +package com.voxfinite.logvue.ui.components import androidx.compose.desktop.ui.tooling.preview.Preview import androidx.compose.foundation.Image @@ -17,13 +17,13 @@ import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.unit.dp -import models.ErrorContent -import models.InternalContent -import models.NoLogsContent -import storage.Db -import storage.SessionConfig -import ui.CustomTheme -import utils.ConfigConstants +import com.voxfinite.logvue.api.models.ErrorContent +import com.voxfinite.logvue.api.models.InternalContent +import com.voxfinite.logvue.api.models.NoLogsContent +import com.voxfinite.logvue.storage.Db +import com.voxfinite.logvue.storage.SessionConfig +import com.voxfinite.logvue.ui.CustomTheme +import com.voxfinite.logvue.utils.ConfigConstants @Composable fun ListItemInternalContent(internalContent: InternalContent?, modifier: Modifier = Modifier) { diff --git a/src/main/kotlin/ui/components/LogCard.kt b/app/src/main/kotlin/com/voxfinite/logvue/ui/components/LogCard.kt similarity index 93% rename from src/main/kotlin/ui/components/LogCard.kt rename to app/src/main/kotlin/com/voxfinite/logvue/ui/components/LogCard.kt index 031a202..654f303 100644 --- a/src/main/kotlin/ui/components/LogCard.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/ui/components/LogCard.kt @@ -1,4 +1,4 @@ -package ui.components +package com.voxfinite.logvue.ui.components import androidx.compose.foundation.Image import androidx.compose.foundation.background @@ -17,11 +17,12 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import models.EventTypeNotSure -import models.LogItem -import ui.CustomTheme -import ui.views.flow.FlowRow -import utils.Helpers +import com.voxfinite.logvue.models.EventTypeNotSure +import com.voxfinite.logvue.api.models.LogItem +import com.voxfinite.logvue.ui.CustomTheme +import com.voxfinite.logvue.ui.views.flow.FlowRow +import com.voxfinite.logvue.utils.Helpers +import com.voxfinite.logvue.utils.predictedEventType import java.text.SimpleDateFormat @OptIn(ExperimentalMaterialApi::class) diff --git a/src/main/kotlin/ui/components/LogList.kt b/app/src/main/kotlin/com/voxfinite/logvue/ui/components/LogList.kt similarity index 90% rename from src/main/kotlin/ui/components/LogList.kt rename to app/src/main/kotlin/com/voxfinite/logvue/ui/components/LogList.kt index 91fa6a6..deedec0 100644 --- a/src/main/kotlin/ui/components/LogList.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/ui/components/LogList.kt @@ -1,4 +1,4 @@ -package ui.components +package com.voxfinite.logvue.ui.components import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.PaddingValues @@ -12,8 +12,8 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp -import models.LogItem -import models.SourceInternalContent +import com.voxfinite.logvue.api.models.LogItem +import com.voxfinite.logvue.api.models.SourceInternalContent @OptIn(ExperimentalMaterialApi::class, ExperimentalComposeUiApi::class) @Composable diff --git a/src/main/kotlin/ui/components/NewSessionBox.kt b/app/src/main/kotlin/com/voxfinite/logvue/ui/components/NewSessionBox.kt similarity index 93% rename from src/main/kotlin/ui/components/NewSessionBox.kt rename to app/src/main/kotlin/com/voxfinite/logvue/ui/components/NewSessionBox.kt index 08a00ac..8281339 100644 --- a/src/main/kotlin/ui/components/NewSessionBox.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/ui/components/NewSessionBox.kt @@ -1,4 +1,4 @@ -package ui.components +package com.voxfinite.logvue.ui.components import androidx.compose.foundation.background import androidx.compose.foundation.clickable @@ -16,12 +16,12 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.TextRange import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.unit.dp -import inputs.adb.ddmlib.AdbHelper -import inputs.adb.ddmlib.Devices -import models.DeviceDetails2 -import models.SessionInfo -import ui.CustomTheme -import ui.components.dialogs.StyledCustomVerticalDialog +import com.voxfinite.logvue.adb.ddmlib.AdbHelper +import com.voxfinite.logvue.adb.ddmlib.Devices +import com.voxfinite.logvue.models.DeviceDetails2 +import com.voxfinite.logvue.models.SessionInfo +import com.voxfinite.logvue.ui.CustomTheme +import com.voxfinite.logvue.ui.components.dialogs.StyledCustomVerticalDialog @OptIn(ExperimentalMaterialApi::class, ExperimentalComposeUiApi::class) @Composable diff --git a/src/main/kotlin/ui/components/SessionComponents.kt b/app/src/main/kotlin/com/voxfinite/logvue/ui/components/SessionComponents.kt similarity index 96% rename from src/main/kotlin/ui/components/SessionComponents.kt rename to app/src/main/kotlin/com/voxfinite/logvue/ui/components/SessionComponents.kt index 3723d39..bf4da02 100644 --- a/src/main/kotlin/ui/components/SessionComponents.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/ui/components/SessionComponents.kt @@ -1,4 +1,4 @@ -package ui.components +package com.voxfinite.logvue.ui.components import androidx.compose.foundation.Image import androidx.compose.foundation.background @@ -17,8 +17,8 @@ import androidx.compose.ui.input.pointer.pointerMoveFilter import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp -import processor.MainProcessor -import ui.CustomTheme +import com.voxfinite.logvue.processor.MainProcessor +import com.voxfinite.logvue.ui.CustomTheme @Composable fun CreateSessionButton(onClick: () -> Unit) { diff --git a/src/main/kotlin/ui/components/SideNavigation.kt b/app/src/main/kotlin/com/voxfinite/logvue/ui/components/SideNavigation.kt similarity index 90% rename from src/main/kotlin/ui/components/SideNavigation.kt rename to app/src/main/kotlin/com/voxfinite/logvue/ui/components/SideNavigation.kt index f3a875a..557036e 100644 --- a/src/main/kotlin/ui/components/SideNavigation.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/ui/components/SideNavigation.kt @@ -1,4 +1,4 @@ -package ui.components +package com.voxfinite.logvue.ui.components import androidx.compose.foundation.background import androidx.compose.foundation.layout.* @@ -8,11 +8,11 @@ import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp -import inputs.adb.ddmlib.Devices +import com.voxfinite.logvue.adb.ddmlib.Devices import kotlinx.coroutines.launch -import processor.MainProcessor -import ui.CustomTheme -import ui.components.common.AppLogo +import com.voxfinite.logvue.processor.MainProcessor +import com.voxfinite.logvue.ui.CustomTheme +import com.voxfinite.logvue.ui.components.common.AppLogo @Composable fun SideNavigation( diff --git a/src/main/kotlin/ui/components/Texts.kt b/app/src/main/kotlin/com/voxfinite/logvue/ui/components/Texts.kt similarity index 75% rename from src/main/kotlin/ui/components/Texts.kt rename to app/src/main/kotlin/com/voxfinite/logvue/ui/components/Texts.kt index 784cf26..e632cba 100644 --- a/src/main/kotlin/ui/components/Texts.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/ui/components/Texts.kt @@ -1,9 +1,9 @@ -package ui.components +package com.voxfinite.logvue.ui.components import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import ui.CustomTheme +import com.voxfinite.logvue.ui.CustomTheme @Composable fun ItemHeader(text: String, modifier: Modifier = Modifier) { diff --git a/src/main/kotlin/ui/components/common/BasicComponents.kt b/app/src/main/kotlin/com/voxfinite/logvue/ui/components/common/BasicComponents.kt similarity index 96% rename from src/main/kotlin/ui/components/common/BasicComponents.kt rename to app/src/main/kotlin/com/voxfinite/logvue/ui/components/common/BasicComponents.kt index 5ef31c3..3f0e70a 100644 --- a/src/main/kotlin/ui/components/common/BasicComponents.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/ui/components/common/BasicComponents.kt @@ -1,4 +1,4 @@ -package ui.components.common +package com.voxfinite.logvue.ui.components.common import androidx.compose.foundation.Image import androidx.compose.foundation.clickable @@ -17,11 +17,11 @@ import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import models.MarkupText -import models.SocialIcons -import ui.CustomTheme -import ui.components.dialogs.openBrowser -import ui.views.DarkToggleButton +import com.voxfinite.logvue.models.MarkupText +import com.voxfinite.logvue.models.SocialIcons +import com.voxfinite.logvue.ui.CustomTheme +import com.voxfinite.logvue.ui.components.dialogs.openBrowser +import com.voxfinite.logvue.ui.views.DarkToggleButton @Composable fun AppLogo(modifier: Modifier = Modifier) { diff --git a/src/main/kotlin/ui/components/dialogs/CrashDialog.kt b/app/src/main/kotlin/com/voxfinite/logvue/ui/components/dialogs/CrashDialog.kt similarity index 81% rename from src/main/kotlin/ui/components/dialogs/CrashDialog.kt rename to app/src/main/kotlin/com/voxfinite/logvue/ui/components/dialogs/CrashDialog.kt index 695d3f9..6a63532 100644 --- a/src/main/kotlin/ui/components/dialogs/CrashDialog.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/ui/components/dialogs/CrashDialog.kt @@ -1,4 +1,4 @@ -package ui.components.dialogs +package com.voxfinite.logvue.ui.components.dialogs import androidx.compose.foundation.Image import androidx.compose.foundation.layout.* @@ -9,10 +9,10 @@ import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp -import models.SocialIcons -import ui.CustomTheme -import ui.components.common.WebLinkButtonFilled -import utils.CustomExceptionHandler +import com.voxfinite.logvue.models.SocialIcons +import com.voxfinite.logvue.ui.CustomTheme +import com.voxfinite.logvue.ui.components.common.WebLinkButtonFilled +import com.voxfinite.logvue.utils.CustomExceptionHandler @Composable fun CrashDialog(onDismissRequest: () -> Unit) { diff --git a/src/main/kotlin/ui/components/dialogs/CustomDialog.kt b/app/src/main/kotlin/com/voxfinite/logvue/ui/components/dialogs/CustomDialog.kt similarity index 97% rename from src/main/kotlin/ui/components/dialogs/CustomDialog.kt rename to app/src/main/kotlin/com/voxfinite/logvue/ui/components/dialogs/CustomDialog.kt index 8f15a5d..9902b5f 100644 --- a/src/main/kotlin/ui/components/dialogs/CustomDialog.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/ui/components/dialogs/CustomDialog.kt @@ -1,4 +1,4 @@ -package ui.components.dialogs +package com.voxfinite.logvue.ui.components.dialogs import androidx.compose.foundation.Image import androidx.compose.foundation.background @@ -22,7 +22,7 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.rememberDialogState import com.google.common.primitives.Floats -import ui.CustomTheme +import com.voxfinite.logvue.ui.CustomTheme @Composable fun StyledCustomVerticalDialog(onDismissRequest: () -> Unit, content: @Composable BoxScope.() -> Unit) { diff --git a/src/main/kotlin/ui/components/dialogs/ExportDialog.kt b/app/src/main/kotlin/com/voxfinite/logvue/ui/components/dialogs/ExportDialog.kt similarity index 90% rename from src/main/kotlin/ui/components/dialogs/ExportDialog.kt rename to app/src/main/kotlin/com/voxfinite/logvue/ui/components/dialogs/ExportDialog.kt index 2e167e0..2b6c6ad 100644 --- a/src/main/kotlin/ui/components/dialogs/ExportDialog.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/ui/components/dialogs/ExportDialog.kt @@ -1,4 +1,4 @@ -package ui.components.dialogs +package com.voxfinite.logvue.ui.components.dialogs import androidx.compose.foundation.layout.* import androidx.compose.material.Button @@ -10,14 +10,15 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.capitalize import androidx.compose.ui.text.intl.Locale import androidx.compose.ui.unit.dp +import com.voxfinite.logvue.api.models.LogItem import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch -import models.* -import processor.Exporter -import storage.Db -import ui.components.common.MultiLineRadioButton -import ui.components.common.SwitchItem -import utils.Helpers +import com.voxfinite.logvue.models.* +import com.voxfinite.logvue.processor.Exporter +import com.voxfinite.logvue.storage.Db +import com.voxfinite.logvue.ui.components.common.MultiLineRadioButton +import com.voxfinite.logvue.ui.components.common.SwitchItem +import com.voxfinite.logvue.utils.Helpers import java.nio.file.Path import kotlin.io.path.absolutePathString diff --git a/src/main/kotlin/ui/components/dialogs/FaqDialog.kt b/app/src/main/kotlin/com/voxfinite/logvue/ui/components/dialogs/FaqDialog.kt similarity index 93% rename from src/main/kotlin/ui/components/dialogs/FaqDialog.kt rename to app/src/main/kotlin/com/voxfinite/logvue/ui/components/dialogs/FaqDialog.kt index 664ebf2..1d944dc 100644 --- a/src/main/kotlin/ui/components/dialogs/FaqDialog.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/ui/components/dialogs/FaqDialog.kt @@ -1,4 +1,4 @@ -package ui.components.dialogs +package com.voxfinite.logvue.ui.components.dialogs import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement @@ -11,9 +11,9 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp -import models.Faq -import ui.CustomTheme -import ui.components.common.SimpleListItem +import com.voxfinite.logvue.models.Faq +import com.voxfinite.logvue.ui.CustomTheme +import com.voxfinite.logvue.ui.components.common.SimpleListItem @Composable fun FaqDialog( diff --git a/src/main/kotlin/ui/components/dialogs/FileDialog.kt b/app/src/main/kotlin/com/voxfinite/logvue/ui/components/dialogs/FileDialog.kt similarity index 92% rename from src/main/kotlin/ui/components/dialogs/FileDialog.kt rename to app/src/main/kotlin/com/voxfinite/logvue/ui/components/dialogs/FileDialog.kt index f8f5227..ecf0bb0 100644 --- a/src/main/kotlin/ui/components/dialogs/FileDialog.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/ui/components/dialogs/FileDialog.kt @@ -1,8 +1,8 @@ -package ui.components.dialogs +package com.voxfinite.logvue.ui.components.dialogs import androidx.compose.runtime.Composable import androidx.compose.ui.window.AwtWindow -import storage.Db +import com.voxfinite.logvue.storage.Db import java.awt.FileDialog import java.awt.Frame import java.io.File diff --git a/src/main/kotlin/ui/components/dialogs/IntroDialog.kt b/app/src/main/kotlin/com/voxfinite/logvue/ui/components/dialogs/IntroDialog.kt similarity index 93% rename from src/main/kotlin/ui/components/dialogs/IntroDialog.kt rename to app/src/main/kotlin/com/voxfinite/logvue/ui/components/dialogs/IntroDialog.kt index 05e0b51..fbcf29c 100644 --- a/src/main/kotlin/ui/components/dialogs/IntroDialog.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/ui/components/dialogs/IntroDialog.kt @@ -1,4 +1,4 @@ -package ui.components.dialogs +package com.voxfinite.logvue.ui.components.dialogs import androidx.compose.foundation.background import androidx.compose.foundation.layout.* @@ -12,8 +12,8 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp -import ui.CustomTheme -import ui.components.common.AppLogo +import com.voxfinite.logvue.ui.CustomTheme +import com.voxfinite.logvue.ui.components.common.AppLogo @Composable fun IntroDialog(onDismissRequest: () -> Unit) { diff --git a/src/main/kotlin/ui/components/dialogs/SettingsDialog.kt b/app/src/main/kotlin/com/voxfinite/logvue/ui/components/dialogs/SettingsDialog.kt similarity index 92% rename from src/main/kotlin/ui/components/dialogs/SettingsDialog.kt rename to app/src/main/kotlin/com/voxfinite/logvue/ui/components/dialogs/SettingsDialog.kt index b6092fd..e8471c0 100644 --- a/src/main/kotlin/ui/components/dialogs/SettingsDialog.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/ui/components/dialogs/SettingsDialog.kt @@ -1,4 +1,4 @@ -package ui.components.dialogs +package com.voxfinite.logvue.ui.components.dialogs import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background @@ -18,14 +18,14 @@ import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.text.withStyle import androidx.compose.ui.unit.dp -import com.voxfinite.logvue.APP_VERSION -import models.SocialIcons -import ui.CustomTheme -import ui.components.ItemHeader -import ui.components.common.* -import utils.AppSettings -import utils.Helpers -import utils.SentryHelper +import com.voxfinite.app.APP_VERSION +import com.voxfinite.logvue.models.SocialIcons +import com.voxfinite.logvue.ui.CustomTheme +import com.voxfinite.logvue.ui.components.ItemHeader +import com.voxfinite.logvue.ui.components.common.* +import com.voxfinite.logvue.utils.AppSettings +import com.voxfinite.logvue.utils.Helpers +import com.voxfinite.logvue.utils.SentryHelper @OptIn(ExperimentalFoundationApi::class) @Composable diff --git a/src/main/kotlin/ui/views/DarkToggleButton.kt b/app/src/main/kotlin/com/voxfinite/logvue/ui/views/DarkToggleButton.kt similarity index 99% rename from src/main/kotlin/ui/views/DarkToggleButton.kt rename to app/src/main/kotlin/com/voxfinite/logvue/ui/views/DarkToggleButton.kt index 8c99897..d0e8d1c 100644 --- a/src/main/kotlin/ui/views/DarkToggleButton.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/ui/views/DarkToggleButton.kt @@ -1,4 +1,4 @@ -package ui.views +package com.voxfinite.logvue.ui.views import androidx.compose.animation.core.* import androidx.compose.foundation.Canvas diff --git a/src/main/kotlin/ui/views/flow/Flow.kt b/app/src/main/kotlin/com/voxfinite/logvue/ui/views/flow/Flow.kt similarity index 99% rename from src/main/kotlin/ui/views/flow/Flow.kt rename to app/src/main/kotlin/com/voxfinite/logvue/ui/views/flow/Flow.kt index 4475e2c..34bab10 100644 --- a/src/main/kotlin/ui/views/flow/Flow.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/ui/views/flow/Flow.kt @@ -1,4 +1,4 @@ -package ui.views.flow +package com.voxfinite.logvue.ui.views.flow /* * Copyright 2021 The Android Open Source Project diff --git a/src/main/kotlin/ui/views/flow/Layout.kt b/app/src/main/kotlin/com/voxfinite/logvue/ui/views/flow/Layout.kt similarity index 94% rename from src/main/kotlin/ui/views/flow/Layout.kt rename to app/src/main/kotlin/com/voxfinite/logvue/ui/views/flow/Layout.kt index 500114f..c697557 100644 --- a/src/main/kotlin/ui/views/flow/Layout.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/ui/views/flow/Layout.kt @@ -1,4 +1,4 @@ -package ui.views.flow +package com.voxfinite.logvue.ui.views.flow import androidx.compose.ui.unit.Constraints diff --git a/app/src/main/kotlin/com/voxfinite/logvue/ui/views/init.kt b/app/src/main/kotlin/com/voxfinite/logvue/ui/views/init.kt new file mode 100644 index 0000000..dfac9ff --- /dev/null +++ b/app/src/main/kotlin/com/voxfinite/logvue/ui/views/init.kt @@ -0,0 +1 @@ +package com.voxfinite.logvue.ui.views diff --git a/src/main/kotlin/utils/AppLog.kt b/app/src/main/kotlin/com/voxfinite/logvue/utils/AppLog.kt similarity index 81% rename from src/main/kotlin/utils/AppLog.kt rename to app/src/main/kotlin/com/voxfinite/logvue/utils/AppLog.kt index 5b03f1f..5674747 100644 --- a/src/main/kotlin/utils/AppLog.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/utils/AppLog.kt @@ -1,4 +1,4 @@ -package utils +package com.voxfinite.logvue.utils import io.sentry.Sentry import java.util.logging.Level @@ -11,8 +11,8 @@ object AppLog { private val formatter = SimpleFormatter() fun d(tag: String, msg: String) { - val s = formatter.format(LogRecord(Level.FINER, "$tag : $msg")) - Logger.getGlobal().log(Level.FINE, s) + val s = formatter.format(LogRecord(Level.INFO, "$tag : $msg")) + Logger.getGlobal().log(Level.INFO, s) } fun d(msg: String) { diff --git a/src/main/kotlin/utils/AppResources.kt b/app/src/main/kotlin/com/voxfinite/logvue/utils/AppResources.kt similarity index 95% rename from src/main/kotlin/utils/AppResources.kt rename to app/src/main/kotlin/com/voxfinite/logvue/utils/AppResources.kt index b1aa956..2cab9f9 100644 --- a/src/main/kotlin/utils/AppResources.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/utils/AppResources.kt @@ -1,4 +1,4 @@ -package utils +package com.voxfinite.logvue.utils //TODO: Move all strings here to support languages in future interface StringRes { diff --git a/src/main/kotlin/utils/AppSettings.kt b/app/src/main/kotlin/com/voxfinite/logvue/utils/AppSettings.kt similarity index 83% rename from src/main/kotlin/utils/AppSettings.kt rename to app/src/main/kotlin/com/voxfinite/logvue/utils/AppSettings.kt index b5c3a79..b6d7a76 100644 --- a/src/main/kotlin/utils/AppSettings.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/utils/AppSettings.kt @@ -1,6 +1,6 @@ -package utils +package com.voxfinite.logvue.utils -import storage.Db +import com.voxfinite.logvue.storage.Db object AppSettings { diff --git a/src/main/kotlin/utils/ConfigConstants.kt b/app/src/main/kotlin/com/voxfinite/logvue/utils/ConfigConstants.kt similarity index 68% rename from src/main/kotlin/utils/ConfigConstants.kt rename to app/src/main/kotlin/com/voxfinite/logvue/utils/ConfigConstants.kt index 3381d72..4126032 100644 --- a/src/main/kotlin/utils/ConfigConstants.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/utils/ConfigConstants.kt @@ -1,4 +1,4 @@ -package utils +package com.voxfinite.logvue.utils object ConfigConstants { diff --git a/src/main/kotlin/utils/CustomExceptionHandler.kt b/app/src/main/kotlin/com/voxfinite/logvue/utils/CustomExceptionHandler.kt similarity index 93% rename from src/main/kotlin/utils/CustomExceptionHandler.kt rename to app/src/main/kotlin/com/voxfinite/logvue/utils/CustomExceptionHandler.kt index 998b3b3..4a1ff31 100644 --- a/src/main/kotlin/utils/CustomExceptionHandler.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/utils/CustomExceptionHandler.kt @@ -1,4 +1,4 @@ -package utils +package com.voxfinite.logvue.utils class CustomExceptionHandler : Thread.UncaughtExceptionHandler { diff --git a/src/main/kotlin/utils/DbCreationException.kt b/app/src/main/kotlin/com/voxfinite/logvue/utils/DbCreationException.kt similarity index 87% rename from src/main/kotlin/utils/DbCreationException.kt rename to app/src/main/kotlin/com/voxfinite/logvue/utils/DbCreationException.kt index 8007da9..4b155e2 100644 --- a/src/main/kotlin/utils/DbCreationException.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/utils/DbCreationException.kt @@ -1,4 +1,4 @@ -package utils +package com.voxfinite.logvue.utils class DbCreationException : Exception { constructor() : super() diff --git a/src/main/kotlin/utils/Either.kt b/app/src/main/kotlin/com/voxfinite/logvue/utils/Either.kt similarity index 97% rename from src/main/kotlin/utils/Either.kt rename to app/src/main/kotlin/com/voxfinite/logvue/utils/Either.kt index a854fc2..ec4e122 100644 --- a/src/main/kotlin/utils/Either.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/utils/Either.kt @@ -1,7 +1,7 @@ -package utils +package com.voxfinite.logvue.utils -import utils.Either.Left -import utils.Either.Right +import com.voxfinite.logvue.utils.Either.Left +import com.voxfinite.logvue.utils.Either.Right import java.io.Serializable /** diff --git a/app/src/main/kotlin/com/voxfinite/logvue/utils/EventCompanion.kt b/app/src/main/kotlin/com/voxfinite/logvue/utils/EventCompanion.kt new file mode 100644 index 0000000..016261a --- /dev/null +++ b/app/src/main/kotlin/com/voxfinite/logvue/utils/EventCompanion.kt @@ -0,0 +1,17 @@ +package com.voxfinite.logvue.utils + +import com.voxfinite.logvue.api.models.LogItem +import com.voxfinite.logvue.api.models.ErrorContent +import com.voxfinite.logvue.api.models.NoLogsContent +import com.voxfinite.logvue.api.models.SourceInternalContent +import com.voxfinite.logvue.processor.attribute + +object EventCompanion { + + val EVENT_NAME = attribute("eventName", LogItem::eventName) + val ATTR_TIME = attribute("localTime", LogItem::localTime) + + fun noContent(msg: String) = LogItem(SourceInternalContent, "No Logs", internalContent = NoLogsContent(msg)) + fun errorContent(error: ErrorContent) = LogItem(SourceInternalContent, "Error", internalContent = error) + +} \ No newline at end of file diff --git a/app/src/main/kotlin/com/voxfinite/logvue/utils/EventTypePredictor.kt b/app/src/main/kotlin/com/voxfinite/logvue/utils/EventTypePredictor.kt new file mode 100644 index 0000000..ddab896 --- /dev/null +++ b/app/src/main/kotlin/com/voxfinite/logvue/utils/EventTypePredictor.kt @@ -0,0 +1,20 @@ +package com.voxfinite.logvue.utils + +import com.voxfinite.logvue.api.models.LogItem +import com.voxfinite.logvue.models.PredictedEventType + +object EventTypePredictor { + + private val predictionMap = hashMapOf() + + fun predict(logItem: LogItem) : PredictedEventType { + return predictionMap.getOrPut(logItem.key()) { + Helpers.predictEventType(logItem) + } + } + + fun clear() = predictionMap.clear() + +} + +fun LogItem.predictedEventType() = EventTypePredictor.predict(this) \ No newline at end of file diff --git a/src/main/kotlin/utils/Helpers.kt b/app/src/main/kotlin/com/voxfinite/logvue/utils/Helpers.kt similarity index 60% rename from src/main/kotlin/utils/Helpers.kt rename to app/src/main/kotlin/com/voxfinite/logvue/utils/Helpers.kt index 3823ab7..6cbaf23 100644 --- a/src/main/kotlin/utils/Helpers.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/utils/Helpers.kt @@ -1,21 +1,27 @@ -package utils +package com.voxfinite.logvue.utils import androidx.compose.ui.text.* import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.sp -import com.github.drapostolos.typeparser.GenericType -import com.github.drapostolos.typeparser.TypeParser +import com.android.ddmlib.Log +import com.android.ddmlib.logcat.LogCatHeader +import com.android.ddmlib.logcat.LogCatMessage import com.google.gson.GsonBuilder import com.google.gson.ToNumberPolicy +import com.voxfinite.logvue.api.models.* +import com.voxfinite.logvue.api.utils.deserializers.`object`.ObjectDeserializer +import com.voxfinite.logvue.models.EventTypeNotSure +import com.voxfinite.logvue.models.PredictedEventType +import com.voxfinite.logvue.models.predictionEventNameMap +import com.voxfinite.logvue.models.predictionPropertiesMap +import com.voxfinite.logvue.processor.YamlWriter +import com.voxfinite.logvue.storage.Db import kotlinx.coroutines.flow.MutableStateFlow -import models.* import org.snakeyaml.engine.v2.api.Dump import org.snakeyaml.engine.v2.api.DumpSettings import org.snakeyaml.engine.v2.api.StreamDataWriter import org.snakeyaml.engine.v2.common.FlowStyle import org.snakeyaml.engine.v2.common.ScalarStyle -import processor.YamlWriter -import storage.Db import java.awt.Desktop import java.io.PrintWriter import java.net.URI @@ -25,14 +31,8 @@ import kotlin.io.path.absolutePathString object Helpers { - private val objectMapper by lazy { - ItemObjectMapper() - } - private const val faPrefix = "Passing event to registered event handler (FE): " - private val parser = TypeParser.newBuilder().build() - private val settings by lazy { DumpSettings.builder().setDefaultScalarStyle(ScalarStyle.PLAIN) .setBestLineBreak(System.lineSeparator()) @@ -62,130 +62,23 @@ object Helpers { } /* - * Sample: Passing event to registered event handler (FE): lumos_home, Bundle[{analytics={request_id=a85e6056-448b-4bb3-beaf-14c2550d7499}, templateName=vaccination, screenName=home_notloggedin, utm_campaign=GI_VACCINATION_V2_LOW_B2C_IN_DEF, cardName=GI_VACCINATION_V2_LOW_B2C_IN_DEF, ga_screen_class(_sc)=HomeActivity, ga_screen_id(_si)=5665805600968775538, home=skywalker_v1, type=cardViewed, request_id=a85e6056-448b-4bb3-beaf-14c2550d7499}] + * Sample: Passing event to registered event handler (FE): home, + * Bundle[{analytics={request_id=a85e6056-448b-4bb3-beaf-14c2550d7499}, + * ga_screen_class(_sc)=HomeActivity, type=cardViewed}] */ fun parseFALogs(msg: LogCatMessage2): LogItem { val rawText = msg.message val cut1 = rawText.removePrefix(faPrefix) val eventParamsCutter = cut1.split(Regex(","), 2) val eventName = eventParamsCutter[0].trim() - val properties = hashMapOf() - eventParamsCutter.getOrNull(1)?.trim()?.let { - val objectItem = Item.ObjectItem(it.trim()) - val something = objectMapper.parse(objectItem) as HashMap - properties.putAll(something) - } + val properties = ObjectDeserializer.map(eventParamsCutter.getOrNull(1)) val time = msg.header.timestamp.toEpochMilli() return LogItem( source = SourceFA, eventName = eventName, - properties = hashMapEntityOf(properties), localTime = time + properties = properties, localTime = time ) } - fun tryParseToType(str: String?): Any? { - return try { - tryParseInternal(str) - } catch (ve: ValueException) { - ve.value - } - } - - @Throws(ValueException::class) - private fun tryParseInternal(str: String?): Any? { - if (str == null) return null - if (str.isBlank()) return str - var parsed: Boolean - parsed = tryParseType(str, Boolean::class.java) - if (!parsed) { - parsed = tryParseType(str, Long::class.java) - } - if (!parsed) { - parsed = tryParseType(str, Int::class.java) - } - if (!parsed) { - parsed = tryParseType(str, Double::class.java) - } - if (!parsed) { - parsed = tryParseType(str, Float::class.java) - } - if (!parsed) { - parsed = tryParseType(str, Double::class.java) - } - if (!parsed) { - parsed = tryParseType(str, object : GenericType>() {}) - } - if (!parsed) { - parsed = tryParseType(str, object : GenericType>() {}) - } - if (!parsed) { - parsed = tryParseType(str, object : GenericType>() {}) - } - if (!parsed) { - parsed = tryParseType(str, object : GenericType>() {}) - } - if (!parsed) { - parsed = tryParseType(str, object : GenericType>() {}) - } - if (!parsed) { - parsed = tryParseType(str, object : GenericType>() {}) - } - if (!parsed) { - parsed = tryParseType(str, object : GenericType>() {}) - } - if (!parsed) { - parsed = tryParseType(str, object : GenericType>() {}) - } - if (!parsed) { - parsed = tryParseType(str, object : GenericType>() {}) - } - if (!parsed) { - parsed = tryParseType(str, object : GenericType>() {}) - } - if (!parsed) { - parsed = tryParseType(str, object : GenericType>() {}) - } - if (!parsed) { - parsed = tryParseType(str, object : GenericType>() {}) - } - if (!parsed) { - parsed = tryParseType(str, object : GenericType>() {}) - } - if (!parsed) { - parsed = tryParseType(str, object : GenericType>() {}) - } - if (!parsed) { - parsed = tryParseType(str, object : GenericType>() {}) - } - return str - } - - @Throws(ValueException::class) - private fun tryParseType(str: String, clazz: Class): Boolean { - return tryOp { - val value = parser.parse(str, clazz) - throw ValueException(value) // anti-pattern ki **** - } - } - - @Throws(ValueException::class) - private fun tryParseType(str: String, genericType: GenericType): Boolean { - return tryOp { - val value = parser.parse(str, genericType) - throw ValueException(value) - } - } - - private fun tryOp(op: () -> Unit): Boolean { - return try { - op() - true - } catch (e: ValueException) { - throw e - } catch (e: Exception) { - false - } - } - fun convertToYamlString(properties: Map): String? { return try { val dump = Dump(settings) @@ -235,11 +128,6 @@ object Helpers { } } - @Suppress("UNCHECKED_CAST") - fun createJsonString(properties: Map): String { - return gson.toJson(properties) - } - /** * Get string for any object with a [maxLength]. * It will add ellipsize dots (...) at the end to clip length to maxLength if [addEllipsize] is true else @@ -340,4 +228,6 @@ object Helpers { } } -fun hashMapEntityOf(mapToWrap: MutableMap): HashMapEntity = HashMapEntity(mapToWrap) +fun Log.LogLevel.to2() = LogLevel2.getByLetter(priorityLetter) ?: LogLevel2.VERBOSE +fun LogCatHeader.to2() = LogCatHeader2(logLevel.to2(), pid, tid, appName, tag, timestamp) +fun LogCatMessage.to2() = LogCatMessage2(header.to2(), message) diff --git a/app/src/main/kotlin/com/voxfinite/logvue/utils/PluginsHelper.kt b/app/src/main/kotlin/com/voxfinite/logvue/utils/PluginsHelper.kt new file mode 100644 index 0000000..98dea29 --- /dev/null +++ b/app/src/main/kotlin/com/voxfinite/logvue/utils/PluginsHelper.kt @@ -0,0 +1,59 @@ +package com.voxfinite.logvue.utils + +import com.voxfinite.logvue.api.LogEventParser +import com.voxfinite.logvue.parsers.FirebaseParser +import com.voxfinite.logvue.storage.StorageHelper +import org.pf4j.CompoundPluginDescriptorFinder +import org.pf4j.DefaultPluginManager +import org.pf4j.ManifestPluginDescriptorFinder +import org.pf4j.PropertiesPluginDescriptorFinder +import java.nio.file.Path + +object PluginsHelper { + + private class PluginManager(importPaths: List) : DefaultPluginManager(importPaths) { + override fun createPluginDescriptorFinder(): CompoundPluginDescriptorFinder { + return CompoundPluginDescriptorFinder() // Demo is using the Manifest file + // PropertiesPluginDescriptorFinder is commented out just to avoid error log + .add(PropertiesPluginDescriptorFinder()) + .add(ManifestPluginDescriptorFinder()); + } + } + + private val pluginManager by lazy { + val pluginsPath = StorageHelper.getPluginsPath() + AppLog.d(pluginsPath.toString()) + PluginManager(listOf(pluginsPath)) + } + + private val parsers by lazy { + pluginManager.getExtensions(LogEventParser::class.java) + } + + fun load() { + // load the plugins + pluginManager.loadPlugins() + + // enable a disabled plugin + // pluginManager.enablePlugin("welcome-plugin") + + // start (active/resolved) the plugins + pluginManager.startPlugins() + parsers + } + + fun parsers(): MutableList { + val allParsers = mutableListOf() + allParsers.addAll(getDefaultParsers()) + allParsers.addAll(parsers) + return allParsers + } + + private fun getDefaultParsers(): MutableList = arrayListOf(FirebaseParser()) + + fun stop() { + // stop the plugins + pluginManager.stopPlugins() + } + +} \ No newline at end of file diff --git a/src/main/kotlin/utils/Renderer.kt b/app/src/main/kotlin/com/voxfinite/logvue/utils/Renderer.kt similarity index 97% rename from src/main/kotlin/utils/Renderer.kt rename to app/src/main/kotlin/com/voxfinite/logvue/utils/Renderer.kt index ced6e42..bab21ca 100644 --- a/src/main/kotlin/utils/Renderer.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/utils/Renderer.kt @@ -1,4 +1,4 @@ -package utils +package com.voxfinite.logvue.utils import org.jetbrains.skiko.GraphicsApi import org.jetbrains.skiko.OS diff --git a/src/main/kotlin/utils/SentryHelper.kt b/app/src/main/kotlin/com/voxfinite/logvue/utils/SentryHelper.kt similarity index 91% rename from src/main/kotlin/utils/SentryHelper.kt rename to app/src/main/kotlin/com/voxfinite/logvue/utils/SentryHelper.kt index 0382201..c67c54e 100644 --- a/src/main/kotlin/utils/SentryHelper.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/utils/SentryHelper.kt @@ -1,7 +1,7 @@ -package utils +package com.voxfinite.logvue.utils -import com.voxfinite.logvue.APP_VERSION -import com.voxfinite.logvue.SENTRY_ENDPOINT +import com.voxfinite.app.APP_VERSION +import com.voxfinite.app.SENTRY_ENDPOINT import io.sentry.Breadcrumb import io.sentry.Sentry import io.sentry.SentryOptions diff --git a/src/main/kotlin/utils/SystemTools.kt b/app/src/main/kotlin/com/voxfinite/logvue/utils/SystemTools.kt similarity index 94% rename from src/main/kotlin/utils/SystemTools.kt rename to app/src/main/kotlin/com/voxfinite/logvue/utils/SystemTools.kt index 8189001..c10d958 100644 --- a/src/main/kotlin/utils/SystemTools.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/utils/SystemTools.kt @@ -1,4 +1,4 @@ -package utils +package com.voxfinite.logvue.utils import java.util.* diff --git a/src/main/kotlin/utils/WarningException.kt b/app/src/main/kotlin/com/voxfinite/logvue/utils/WarningException.kt similarity index 60% rename from src/main/kotlin/utils/WarningException.kt rename to app/src/main/kotlin/com/voxfinite/logvue/utils/WarningException.kt index 7e61eac..ccb096d 100644 --- a/src/main/kotlin/utils/WarningException.kt +++ b/app/src/main/kotlin/com/voxfinite/logvue/utils/WarningException.kt @@ -1,3 +1,3 @@ -package utils +package com.voxfinite.logvue.utils class WarningException(msg: String) : Exception(msg) diff --git a/src/main/resources/WorkSans-Bold.ttf b/app/src/main/resources/WorkSans-Bold.ttf similarity index 100% rename from src/main/resources/WorkSans-Bold.ttf rename to app/src/main/resources/WorkSans-Bold.ttf diff --git a/src/main/resources/WorkSans-Medium.ttf b/app/src/main/resources/WorkSans-Medium.ttf similarity index 100% rename from src/main/resources/WorkSans-Medium.ttf rename to app/src/main/resources/WorkSans-Medium.ttf diff --git a/src/main/resources/WorkSans-Regular.ttf b/app/src/main/resources/WorkSans-Regular.ttf similarity index 100% rename from src/main/resources/WorkSans-Regular.ttf rename to app/src/main/resources/WorkSans-Regular.ttf diff --git a/src/main/resources/WorkSans-SemiBold.ttf b/app/src/main/resources/WorkSans-SemiBold.ttf similarity index 100% rename from src/main/resources/WorkSans-SemiBold.ttf rename to app/src/main/resources/WorkSans-SemiBold.ttf diff --git a/src/main/resources/icons/DarkMode.svg b/app/src/main/resources/icons/DarkMode.svg similarity index 100% rename from src/main/resources/icons/DarkMode.svg rename to app/src/main/resources/icons/DarkMode.svg diff --git a/src/main/resources/icons/Info.svg b/app/src/main/resources/icons/Info.svg similarity index 100% rename from src/main/resources/icons/Info.svg rename to app/src/main/resources/icons/Info.svg diff --git a/src/main/resources/icons/Share1.svg b/app/src/main/resources/icons/Share1.svg similarity index 100% rename from src/main/resources/icons/Share1.svg rename to app/src/main/resources/icons/Share1.svg diff --git a/src/main/resources/icons/Share2.svg b/app/src/main/resources/icons/Share2.svg similarity index 100% rename from src/main/resources/icons/Share2.svg rename to app/src/main/resources/icons/Share2.svg diff --git a/src/main/resources/icons/Tornado.svg b/app/src/main/resources/icons/Tornado.svg similarity index 100% rename from src/main/resources/icons/Tornado.svg rename to app/src/main/resources/icons/Tornado.svg diff --git a/src/main/resources/icons/activity.svg b/app/src/main/resources/icons/activity.svg similarity index 100% rename from src/main/resources/icons/activity.svg rename to app/src/main/resources/icons/activity.svg diff --git a/src/main/resources/icons/bell.svg b/app/src/main/resources/icons/bell.svg similarity index 100% rename from src/main/resources/icons/bell.svg rename to app/src/main/resources/icons/bell.svg diff --git a/src/main/resources/icons/bug.svg b/app/src/main/resources/icons/bug.svg similarity index 100% rename from src/main/resources/icons/bug.svg rename to app/src/main/resources/icons/bug.svg diff --git a/src/main/resources/icons/crash_illustration.xml b/app/src/main/resources/icons/crash_illustration.xml similarity index 100% rename from src/main/resources/icons/crash_illustration.xml rename to app/src/main/resources/icons/crash_illustration.xml diff --git a/src/main/resources/icons/empty_state.svg b/app/src/main/resources/icons/empty_state.svg similarity index 100% rename from src/main/resources/icons/empty_state.svg rename to app/src/main/resources/icons/empty_state.svg diff --git a/src/main/resources/icons/eventType_activity.svg b/app/src/main/resources/icons/eventType_activity.svg similarity index 100% rename from src/main/resources/icons/eventType_activity.svg rename to app/src/main/resources/icons/eventType_activity.svg diff --git a/src/main/resources/icons/eventType_click.svg b/app/src/main/resources/icons/eventType_click.svg similarity index 100% rename from src/main/resources/icons/eventType_click.svg rename to app/src/main/resources/icons/eventType_click.svg diff --git a/src/main/resources/icons/eventType_view.svg b/app/src/main/resources/icons/eventType_view.svg similarity index 100% rename from src/main/resources/icons/eventType_view.svg rename to app/src/main/resources/icons/eventType_view.svg diff --git a/src/main/resources/icons/eye.svg b/app/src/main/resources/icons/eye.svg similarity index 100% rename from src/main/resources/icons/eye.svg rename to app/src/main/resources/icons/eye.svg diff --git a/src/main/resources/icons/firebaseLogo.webp b/app/src/main/resources/icons/firebaseLogo.webp similarity index 100% rename from src/main/resources/icons/firebaseLogo.webp rename to app/src/main/resources/icons/firebaseLogo.webp diff --git a/src/main/resources/icons/gift.svg b/app/src/main/resources/icons/gift.svg similarity index 100% rename from src/main/resources/icons/gift.svg rename to app/src/main/resources/icons/gift.svg diff --git a/src/main/resources/icons/ic_illustration_new_session.xml b/app/src/main/resources/icons/ic_illustration_new_session.xml similarity index 100% rename from src/main/resources/icons/ic_illustration_new_session.xml rename to app/src/main/resources/icons/ic_illustration_new_session.xml diff --git a/src/main/resources/icons/ico-alert.svg b/app/src/main/resources/icons/ico-alert.svg similarity index 100% rename from src/main/resources/icons/ico-alert.svg rename to app/src/main/resources/icons/ico-alert.svg diff --git a/src/main/resources/icons/ico-carrot-right.svg b/app/src/main/resources/icons/ico-carrot-right.svg similarity index 100% rename from src/main/resources/icons/ico-carrot-right.svg rename to app/src/main/resources/icons/ico-carrot-right.svg diff --git a/src/main/resources/icons/ico-email.svg b/app/src/main/resources/icons/ico-email.svg similarity index 100% rename from src/main/resources/icons/ico-email.svg rename to app/src/main/resources/icons/ico-email.svg diff --git a/src/main/resources/icons/ico-help.svg b/app/src/main/resources/icons/ico-help.svg similarity index 100% rename from src/main/resources/icons/ico-help.svg rename to app/src/main/resources/icons/ico-help.svg diff --git a/src/main/resources/icons/ico-plus.svg b/app/src/main/resources/icons/ico-plus.svg similarity index 100% rename from src/main/resources/icons/ico-plus.svg rename to app/src/main/resources/icons/ico-plus.svg diff --git a/src/main/resources/icons/ico-search.svg b/app/src/main/resources/icons/ico-search.svg similarity index 100% rename from src/main/resources/icons/ico-search.svg rename to app/src/main/resources/icons/ico-search.svg diff --git a/src/main/resources/icons/ico-settings.svg b/app/src/main/resources/icons/ico-settings.svg similarity index 100% rename from src/main/resources/icons/ico-settings.svg rename to app/src/main/resources/icons/ico-settings.svg diff --git a/src/main/resources/icons/ico-share.svg b/app/src/main/resources/icons/ico-share.svg similarity index 100% rename from src/main/resources/icons/ico-share.svg rename to app/src/main/resources/icons/ico-share.svg diff --git a/src/main/resources/icons/ico-trashcan.svg b/app/src/main/resources/icons/ico-trashcan.svg similarity index 100% rename from src/main/resources/icons/ico-trashcan.svg rename to app/src/main/resources/icons/ico-trashcan.svg diff --git a/src/main/resources/icons/ico_close.xml b/app/src/main/resources/icons/ico_close.xml similarity index 100% rename from src/main/resources/icons/ico_close.xml rename to app/src/main/resources/icons/ico_close.xml diff --git a/src/main/resources/icons/ico_copy.svg b/app/src/main/resources/icons/ico_copy.svg similarity index 100% rename from src/main/resources/icons/ico_copy.svg rename to app/src/main/resources/icons/ico_copy.svg diff --git a/src/main/resources/icons/ico_filter.svg b/app/src/main/resources/icons/ico_filter.svg similarity index 100% rename from src/main/resources/icons/ico_filter.svg rename to app/src/main/resources/icons/ico_filter.svg diff --git a/src/main/resources/icons/ico_info.svg b/app/src/main/resources/icons/ico_info.svg similarity index 100% rename from src/main/resources/icons/ico_info.svg rename to app/src/main/resources/icons/ico_info.svg diff --git a/src/main/resources/icons/ico_pause.svg b/app/src/main/resources/icons/ico_pause.svg similarity index 100% rename from src/main/resources/icons/ico_pause.svg rename to app/src/main/resources/icons/ico_pause.svg diff --git a/src/main/resources/icons/ico_play.svg b/app/src/main/resources/icons/ico_play.svg similarity index 100% rename from src/main/resources/icons/ico_play.svg rename to app/src/main/resources/icons/ico_play.svg diff --git a/src/main/resources/icons/ico_view.svg b/app/src/main/resources/icons/ico_view.svg similarity index 100% rename from src/main/resources/icons/ico_view.svg rename to app/src/main/resources/icons/ico_view.svg diff --git a/src/main/resources/icons/layered_waves.svg b/app/src/main/resources/icons/layered_waves.svg similarity index 100% rename from src/main/resources/icons/layered_waves.svg rename to app/src/main/resources/icons/layered_waves.svg diff --git a/src/main/resources/icons/loader.svg b/app/src/main/resources/icons/loader.svg similarity index 100% rename from src/main/resources/icons/loader.svg rename to app/src/main/resources/icons/loader.svg diff --git a/src/main/resources/icons/log-in.svg b/app/src/main/resources/icons/log-in.svg similarity index 100% rename from src/main/resources/icons/log-in.svg rename to app/src/main/resources/icons/log-in.svg diff --git a/src/main/resources/icons/log-out.svg b/app/src/main/resources/icons/log-out.svg similarity index 100% rename from src/main/resources/icons/log-out.svg rename to app/src/main/resources/icons/log-out.svg diff --git a/src/main/resources/icons/logo.svg b/app/src/main/resources/icons/logo.svg similarity index 100% rename from src/main/resources/icons/logo.svg rename to app/src/main/resources/icons/logo.svg diff --git a/src/main/resources/icons/mouse-pointer-click.svg b/app/src/main/resources/icons/mouse-pointer-click.svg similarity index 100% rename from src/main/resources/icons/mouse-pointer-click.svg rename to app/src/main/resources/icons/mouse-pointer-click.svg diff --git a/src/main/resources/icons/shopping-bag.svg b/app/src/main/resources/icons/shopping-bag.svg similarity index 100% rename from src/main/resources/icons/shopping-bag.svg rename to app/src/main/resources/icons/shopping-bag.svg diff --git a/src/main/resources/icons/shopping-cart.svg b/app/src/main/resources/icons/shopping-cart.svg similarity index 100% rename from src/main/resources/icons/shopping-cart.svg rename to app/src/main/resources/icons/shopping-cart.svg diff --git a/src/main/resources/icons/social/social_facebook.svg b/app/src/main/resources/icons/social/social_facebook.svg similarity index 100% rename from src/main/resources/icons/social/social_facebook.svg rename to app/src/main/resources/icons/social/social_facebook.svg diff --git a/src/main/resources/icons/social/social_github.svg b/app/src/main/resources/icons/social/social_github.svg similarity index 100% rename from src/main/resources/icons/social/social_github.svg rename to app/src/main/resources/icons/social/social_github.svg diff --git a/src/main/resources/icons/social/social_instagram.svg b/app/src/main/resources/icons/social/social_instagram.svg similarity index 100% rename from src/main/resources/icons/social/social_instagram.svg rename to app/src/main/resources/icons/social/social_instagram.svg diff --git a/src/main/resources/icons/social/social_linkedIn.svg b/app/src/main/resources/icons/social/social_linkedIn.svg similarity index 100% rename from src/main/resources/icons/social/social_linkedIn.svg rename to app/src/main/resources/icons/social/social_linkedIn.svg diff --git a/src/main/resources/icons/social/social_twitter.svg b/app/src/main/resources/icons/social/social_twitter.svg similarity index 100% rename from src/main/resources/icons/social/social_twitter.svg rename to app/src/main/resources/icons/social/social_twitter.svg diff --git a/src/main/resources/icons/trash-2.svg b/app/src/main/resources/icons/trash-2.svg similarity index 100% rename from src/main/resources/icons/trash-2.svg rename to app/src/main/resources/icons/trash-2.svg diff --git a/src/main/resources/icons/waiting.svg b/app/src/main/resources/icons/waiting.svg similarity index 100% rename from src/main/resources/icons/waiting.svg rename to app/src/main/resources/icons/waiting.svg diff --git a/src/main/resources/log4j2.xml b/app/src/main/resources/log4j2.xml similarity index 100% rename from src/main/resources/log4j2.xml rename to app/src/main/resources/log4j2.xml diff --git a/src/main/shrink-rules.pro b/app/src/main/shrink-rules.pro similarity index 100% rename from src/main/shrink-rules.pro rename to app/src/main/shrink-rules.pro diff --git a/build.gradle.kts b/build.gradle.kts index ef19dd1..ff256a6 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,197 +1,36 @@ -import org.jetbrains.compose.compose -import org.jetbrains.compose.desktop.application.dsl.TargetFormat import org.jetbrains.kotlin.gradle.tasks.KotlinCompile -plugins { - kotlin("jvm") version "1.6.10" - id("org.jetbrains.compose") version "1.0.1" - id("com.github.gmazzo.buildconfig") version "3.0.3" -} - -val r8: Configuration by configurations.creating -fun appVersion() : String { - val key = "APP_VERSION" - return if (project.hasProperty(key)) { - val version = project.property("APP_VERSION").toString() - println("Version = $version") - if (version.isBlank()) { - return "1.0.0" - } - if (version.matches(Regex("^[\\d]{1,3}.[\\d]{1,3}.[\\d]{1,4}"))) { - return version - } - if (version.matches(Regex("^v[\\d]{1,3}.[\\d]{1,3}.[\\d]{1,4}"))) { - return version.removePrefix("v") - } - "1.0.0" - } else { - "1.0.0" - } -} - -group = "com.voxfinite" -version = appVersion() - -repositories { - google() - mavenCentral() - maven("https://maven.pkg.jetbrains.space/public/p/compose/dev") -} - -dependencies { - testImplementation(kotlin("test")) - implementation(compose.desktop.currentOs) - // https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-slf4j-impl - implementation("org.apache.logging.log4j:log4j-slf4j-impl:2.17.0") - implementation("org.apache.logging.log4j:log4j-api:2.17.0") - implementation("org.apache.logging.log4j:log4j-core:2.17.0") - // types parser for object to map conversion - implementation("com.github.drapostolos:type-parser:0.7.0") - // embedded database - implementation("org.mapdb:mapdb:3.0.8") - implementation("org.snakeyaml:snakeyaml-engine:2.3") -// runtimeOnly("io.netty:netty-resolver-dns-native-macos:4.1.72.Final") // not sure if needed now - implementation("com.android.tools.ddms:ddmlib:30.2.0-alpha06") - implementation("com.google.code.gson:gson:2.8.9") - // https://mvnrepository.com/artifact/com.googlecode.cqengine/cqengine - implementation("com.googlecode.cqengine:cqengine:3.6.0") - implementation("org.jetbrains.kotlin:kotlin-reflect:1.6.10") - - implementation("io.sentry:sentry-log4j2:5.5.2") - // https://mvnrepository.com/artifact/net.harawata/appdirs - implementation("net.harawata:appdirs:1.2.1") - - r8("com.android.tools:r8:3.0.73") -} +val pluginsDir by extra { file("$buildDir/plugins") } -tasks.test { - useJUnit() -} - -tasks.withType().configureEach { - kotlinOptions.jvmTarget = "16" - kotlinOptions.freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn" -} - -compose.desktop { - application { - mainClass = "app.MainKt" - nativeDistributions { - modules( - "java.compiler", "java.instrument", "java.management", - "java.naming", "java.rmi", "java.scripting", "java.sql", "jdk.attach", - "jdk.jdi", "jdk.unsupported", "jdk.crypto.ec" - ) -// includeAllModules = true - targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb) - packageName = project.name - packageVersion = "${project.version}" - description = "Local Analytics" - linux { - debMaintainer = "kapoor.aman22@gmail.com" - iconFile.set(project.file("logo_icon.png")) - } - macOS { - bundleID = "${project.group}.${project.name}" - setDockNameSameAsPackageName = true - iconFile.set(project.file("logo_icon.icns")) -// notarization { -// appleID.set("test.app@example.com") -// password.set("@keychain:NOTARIZATION_PASSWORD") -// } - } - windows { - upgradeUuid = "8AEBC8BF-9C94-4D02-ACA8-AF543E0CEB98" - iconFile.set(project.file("logo_icon.ico")) - } - } +buildscript { + repositories { + google() + mavenCentral() + maven("https://maven.pkg.jetbrains.space/public/p/compose/dev") } -} - -//tasks.withType().configureEach { -// println("excluding meta") -// exclude("META-INF/*.RSA", "META-INF/*.SF","META-INF/*.DSA") -//} -buildConfig { - className("AppBuildConfig") - useKotlinOutput { topLevelConstants = true } - buildConfigField("String", "APP_NAME", "\"${project.name}\"") - buildConfigField("String", "APP_VERSION", "\"${project.version}\"") - val sentryEndpoint = if (project.hasProperty("SENTRY_ENDPOINT")) { - project.property("SENTRY_ENDPOINT").toString() - } else { - "" + dependencies { + classpath(kotlin("gradle-plugin", version = "1.6.10")) } - buildConfigField("String", "SENTRY_ENDPOINT", "\"${sentryEndpoint}\"") } -// Define task to obfuscate the JAR and output to .min.jar -tasks.register("r8") { - val packageUberJarForCurrentOS = tasks.getByName("packageUberJarForCurrentOS") - dependsOn(packageUberJarForCurrentOS) - val file = packageUberJarForCurrentOS.outputs.files.first() - val rules = file("src/main/shrink-rules.pro") - val output = File(file.parentFile, "${file.nameWithoutExtension}.min.jar") - inputs.files(file, rules) - outputs.file(output) - classpath(r8) - mainClass.set("com.android.tools.r8.R8") - args = listOf( - "--release", - "--classfile", - "--output", output.toString(), - "--pg-conf", rules.toString(), - "--lib", System.getProperty("java.home") - ) - doFirst { - args?.add(file.absolutePath) - } +plugins { + kotlin("jvm") version "1.6.10" } -tasks.register("repackageUberJar") { - val packageUberJarForCurrentOS = tasks.getByName("packageUberJarForCurrentOS") - dependsOn(packageUberJarForCurrentOS) - val file = packageUberJarForCurrentOS.outputs.files.first() - val output = File(file.parentFile, "${file.nameWithoutExtension}-repacked.jar") - archiveFileName.set(output.absolutePath) - destinationDirectory.set(file.parentFile.absoluteFile) - exclude("META-INF/*.SF") - exclude("META-INF/*.RSA") - exclude("META-INF/*.DSA") - from(project.zipTree(file)) - doLast { - delete(file) - output.renameTo(file) - logger.lifecycle("The repackaged jar is written to ${archiveFile.get().asFile.canonicalPath}") +allprojects { + repositories { + google() + mavenCentral() + maven("https://maven.pkg.jetbrains.space/public/p/compose/dev") } } -/** - * Sets the Github Action output as package name and path to use in other steps. - */ -gradle.buildFinished { - val pkgFormat = - compose.desktop.application.nativeDistributions.targetFormats.firstOrNull { it.isCompatibleWithCurrentOS } - val nativePkg = buildDir.resolve("compose/binaries").findPkg(pkgFormat?.fileExt) - val jarPkg = buildDir.resolve("compose/jars").findPkg(".jar") - nativePkg.ghActionOutput("app_pkg") - jarPkg.ghActionOutput("uber_jar") -} - -fun File.findPkg(format: String?) = when (format != null) { - true -> walk().firstOrNull { it.isFile && it.name.endsWith(format, ignoreCase = true) } - else -> null -} - -fun File?.ghActionOutput(prefix: String) = this?.let { - when (System.getenv("GITHUB_ACTIONS").toBoolean()) { - true -> println( - """ - ::set-output name=${prefix}_name::${it.name} - ::set-output name=${prefix}_path::${it.absolutePath} - """.trimIndent() - ) - else -> println("$prefix: $this") +subprojects { + tasks.withType().configureEach { + kotlinOptions.languageVersion = "1.6" + kotlinOptions.apiVersion = "1.6" + kotlinOptions.jvmTarget = "16" + kotlinOptions.freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn" } } diff --git a/gradle.properties b/gradle.properties index 9930c09..3183a8e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,5 @@ kotlin.code.style=official #kotlin.native.binary.memoryModel=experimental + +# PF4J +pf4jVersion=3.6.0 diff --git a/plugins/build.gradle.kts b/plugins/build.gradle.kts new file mode 100644 index 0000000..fc20aeb --- /dev/null +++ b/plugins/build.gradle.kts @@ -0,0 +1,68 @@ +val pluginsDir: File by rootProject.extra + + +plugins { + kotlin("jvm") // need to apply kotlin plugin here as it provides 'build' task +} + +// here we define the tasks which will build the plugins in the subprojects +subprojects { + // if the variable definitions are put here they are resolved for each subproject + val pluginId: String by project + val pluginClass: String by project + val pluginProvider: String by project + val pluginDescription: String by project + + val project = this + // we have to apply the gradle jvm plugin, because it provides the jar and build tasks + apply(plugin = "org.jetbrains.kotlin.jvm") + + // the plugin task will put the files into a zip file + tasks.register("plugin") { + archiveBaseName.set("plugin-${pluginId}") + + // first taking the classes generated by the jar task + into("classes") { + with(tasks.named("jar").get()) + } + // and then we also need to include any libraries that are needed by the plugin + dependsOn(configurations.runtimeClasspath) + into("lib") { + from({ + configurations.runtimeClasspath.get().filter { it.name.endsWith("jar") } + }) + } + archiveExtension.set("zip") + } + + // the assemblePlugin will copy the zip file into the common plugins directory + tasks.register("assemblePlugin") { + from(project.tasks.named("plugin")) + into(pluginsDir) + } + + // for the jar task we have to set the plugin properties, so they can be written to the manifest + tasks.named("jar") { + manifest { + attributes["Plugin-Class"] = pluginClass + attributes["Plugin-Id"] = pluginId + attributes["Plugin-Version"] = archiveVersion + attributes["Plugin-Provider"] = pluginProvider + attributes["Plugin-Description"] = pluginDescription + } + } + + tasks.named("build") { + dependsOn(tasks.named("plugin")) + } +} + +tasks.register("assemblePlugins") { + dependsOn(subprojects.map { it.tasks.named("assemblePlugin") }) +} + +tasks { + "build" { + dependsOn(named("assemblePlugins")) + } +} \ No newline at end of file diff --git a/plugins/pdt/build.gradle.kts b/plugins/pdt/build.gradle.kts new file mode 100644 index 0000000..91966a6 --- /dev/null +++ b/plugins/pdt/build.gradle.kts @@ -0,0 +1,14 @@ +plugins { + kotlin("kapt") +} + +val pf4jVersion: String by project + +dependencies { + compileOnly(project(":api")) + compileOnly(kotlin("stdlib")) + + compileOnly("org.pf4j:pf4j:${pf4jVersion}") + kapt("org.pf4j:pf4j:${pf4jVersion}") +// implementation("org.apache.commons:commons-lang3:3.5") // this is an example for an external library included +} \ No newline at end of file diff --git a/plugins/pdt/gradle.properties b/plugins/pdt/gradle.properties new file mode 100644 index 0000000..89acd61 --- /dev/null +++ b/plugins/pdt/gradle.properties @@ -0,0 +1,7 @@ +version=0.0.1 + +pluginId=goMmtPdt +pluginClass=com.voxfinite.plugin.pdt.GoMmtPdtPlugin +pluginProvider=voxfinite +pluginDependencies= +pluginDescription=LogVue plugin for go-mmt pdt events \ No newline at end of file diff --git a/plugins/pdt/src/main/kotlin/com/voxfinite/plugin/pdt/GoMmtPdtPlugin.kt b/plugins/pdt/src/main/kotlin/com/voxfinite/plugin/pdt/GoMmtPdtPlugin.kt new file mode 100644 index 0000000..71354dd --- /dev/null +++ b/plugins/pdt/src/main/kotlin/com/voxfinite/plugin/pdt/GoMmtPdtPlugin.kt @@ -0,0 +1,19 @@ +package com.voxfinite.plugin.pdt + +import org.pf4j.Plugin +import org.pf4j.PluginWrapper + +class GoMmtPdtPlugin(wrapper: PluginWrapper) : Plugin(wrapper) { + + override fun start() { + super.start() + } + + override fun stop() { + super.stop() + } + + override fun delete() { + super.delete() + } +} \ No newline at end of file diff --git a/plugins/pdt/src/main/kotlin/com/voxfinite/plugin/pdt/PdtEventParser.kt b/plugins/pdt/src/main/kotlin/com/voxfinite/plugin/pdt/PdtEventParser.kt new file mode 100644 index 0000000..6f3f521 --- /dev/null +++ b/plugins/pdt/src/main/kotlin/com/voxfinite/plugin/pdt/PdtEventParser.kt @@ -0,0 +1,30 @@ +package com.voxfinite.plugin.pdt + +import com.voxfinite.logvue.api.LogEventParser +import com.voxfinite.logvue.api.models.LogCatMessage2 +import com.voxfinite.logvue.api.models.LogItem +import com.voxfinite.logvue.api.models.LogLevel2 +import org.pf4j.Extension + +@Extension +class PdtEventParser : LogEventParser { + + companion object { + private const val ADB_TAG = "PDTLogging" + private const val PREFIX = "Saved Event ID" + } + + override fun filters(): List { + return arrayListOf(ADB_TAG) + } + + override fun validate(logCatMessage2: LogCatMessage2): Boolean { + val header = logCatMessage2.header + return header.logLevel == LogLevel2.DEBUG && header.tag == ADB_TAG + && logCatMessage2.message.startsWith(PREFIX) + } + + override fun parse(logCatMessage2: LogCatMessage2): LogItem { + TODO("Not yet implemented") + } +} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 15b19d3..4a82728 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -6,3 +6,8 @@ pluginManagement { } } rootProject.name = "logvue" + +include("api") +include("app") +include("plugins") +include("plugins:pdt") diff --git a/src/main/kotlin/inputs/adb/ddmlib/LogCatListener2.kt b/src/main/kotlin/inputs/adb/ddmlib/LogCatListener2.kt deleted file mode 100644 index 6c8053f..0000000 --- a/src/main/kotlin/inputs/adb/ddmlib/LogCatListener2.kt +++ /dev/null @@ -1,7 +0,0 @@ -package inputs.adb.ddmlib - -import models.LogCatMessage2 - -fun interface LogCatListener2 { - fun log(msgList: ArrayList) -} diff --git a/src/main/kotlin/models/LogItem.kt b/src/main/kotlin/models/LogItem.kt deleted file mode 100644 index 048dc0c..0000000 --- a/src/main/kotlin/models/LogItem.kt +++ /dev/null @@ -1,58 +0,0 @@ -package models - -import processor.attribute -import utils.HashMapEntity -import utils.Helpers -import utils.hashMapEntityOf -import java.io.Serializable -import java.util.* - -data class LogItem( - val source: ItemSource, - val eventName: String, - val properties: HashMapEntity = hashMapEntityOf(hashMapOf()), - val localTime: Long = System.currentTimeMillis(), - val internalContent: InternalContent? = null, -) : Serializable { - companion object { - private const val serialVersionUID = 1L - val EVENT_NAME = attribute("eventName", LogItem::eventName) - val ATTR_TIME = attribute("localTime", LogItem::localTime) - - fun noContent(msg: String) = LogItem(SourceInternalContent, "No Logs", internalContent = NoLogsContent(msg)) - fun errorContent(error: ErrorContent) = LogItem(SourceInternalContent, "Error", internalContent = error) - } - - private val id: String = buildKey() - - @Transient - var _predictedEventType: PredictedEventType? = null - - /** - * This is a predicted event type and there is no guarantee of it's accuracy - */ - fun predictedEventType(): PredictedEventType { - if (_predictedEventType == null) { - synchronized(lock) { - if (_predictedEventType == null) { - _predictedEventType = Helpers.predictEventType(this) - } - } - } - return _predictedEventType!! - } - - @Transient - private val lock = true - - @Transient - var isSelected: Boolean = false - - private fun buildKey() = "${iKey()}_$localTime" - fun key() = id - - private fun iKey(): String { - val k = "${source.type}_${eventName}_${properties.hashCode()}" - return k + UUID.randomUUID().toString() - } -} diff --git a/src/main/kotlin/storage/StorageHelper.kt b/src/main/kotlin/storage/StorageHelper.kt deleted file mode 100644 index baf9983..0000000 --- a/src/main/kotlin/storage/StorageHelper.kt +++ /dev/null @@ -1,61 +0,0 @@ -package storage - -import com.voxfinite.logvue.APP_NAME -import net.harawata.appdirs.AppDirsFactory -import org.mapdb.DB -import org.mapdb.DBException -import org.mapdb.DBMaker -import utils.DbCreationException -import utils.reportException -import java.io.File -import java.io.IOException -import java.nio.file.FileSystems -import java.nio.file.Files -import java.nio.file.attribute.PosixFilePermissions - - -object StorageHelper { - - internal fun createDiskDb(): DB { - val dbFile = getDbFile() - return try { - DBMaker.fileDB(dbFile).fileMmapEnableIfSupported().checksumHeaderBypass().make() - } catch (e: DBException.VolumeIOError) { - DbCreationException("Mmap enabled db could not be created", e).reportException() - try { - DBMaker.fileDB(dbFile).fileChannelEnable().checksumHeaderBypass().make() - } catch (ee: DBException.VolumeIOError) { - DbCreationException("file channel enabled db could not be created", ee).reportException() - DBMaker.fileDB(dbFile).checksumHeaderBypass().make() - } - } - } - - @Throws(IOException::class) - private fun getDbFile(): File { - val appDirs = AppDirsFactory.getInstance() - val dataDir = appDirs.getUserDataDir(APP_NAME, null, APP_NAME) - val folder = File(dataDir) - if (!folder.exists() || !folder.isDirectory) { - if (folder.exists()) { - folder.delete() - } - try { - val isPosix = FileSystems.getDefault().supportedFileAttributeViews().contains("posix") - if (isPosix) { - val posixAttribute = PosixFilePermissions.asFileAttribute( - PosixFilePermissions.fromString("rwxr-x---") - ) - Files.createDirectories(folder.toPath(), posixAttribute) - } else { - Files.createDirectories(folder.toPath()) - } - } catch (e: IOException) { - throw IOException("Cannot create app folder at path ${folder.canonicalPath}", e) - } - } - val dbName = "sessions.db" - return File(dataDir, dbName) - } - -} \ No newline at end of file diff --git a/src/main/kotlin/ui/views/init.kt b/src/main/kotlin/ui/views/init.kt deleted file mode 100644 index 1715dcc..0000000 --- a/src/main/kotlin/ui/views/init.kt +++ /dev/null @@ -1 +0,0 @@ -package ui.views diff --git a/src/main/kotlin/utils/ItemObjectMapper.kt b/src/main/kotlin/utils/ItemObjectMapper.kt deleted file mode 100644 index 2c83af3..0000000 --- a/src/main/kotlin/utils/ItemObjectMapper.kt +++ /dev/null @@ -1,50 +0,0 @@ -package utils - -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import utils.Item.ObjectItem - -/** - * Creates object/instance from toString()-Model. - * - * @author dschreiber - */ -class ItemObjectMapper { - - fun parse(item: Item): Any? { - return try { - when (item) { - is ObjectItem -> { - parseObject(item) - } - else -> { - Helpers.tryParseToType(item.stringRepresentation) - } - } - } catch (e: Exception) { - Exception("Item mapping failed for item=$item", e).reportException() - item.stringRepresentation - } - } - - private fun parseObject(item: ObjectItem): HashMap { - val map = hashMapOf() - item.getAttributes().forEach { entry -> - val stringRepresentation = entry.value.stringRepresentation ?: "" - val key = entry.key.removePrefix("{").removeSuffix("}") - - if (stringRepresentation.startsWith("{") && stringRepresentation.endsWith("}")) { - // this is an object - map[key] = parse(ObjectItem("Bundle[$stringRepresentation]")) - } else { - map[key] = parse(Item.ValueItem(stringRepresentation.removePrefix("{").removeSuffix("}"))) - } - } - return map - } - - companion object { - private val LOGGER: Logger = LoggerFactory - .getLogger(ItemObjectMapper::class.java) - } -}