Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,18 @@ tasks {
)
baseOutputDirectory = javadocDirectory
}
val download83 by registering(DownloadJavadocs::class) {
version = "8.3"
urls = listOf(
"https://files.inductiveautomation.com/sdk/javadoc/ignition83/8.3.0/allclasses-index.html",
"https://docs.oracle.com/en/java/javase/17/docs/api/allclasses-index.html",
"https://www.javadoc.io/static/org.python/jython-standalone/2.7.3/allclasses-noframe.html",
)
baseOutputDirectory = javadocDirectory
}
processResources {
duplicatesStrategy = DuplicatesStrategy.WARN
dependsOn(download79, download80, download81)
dependsOn(download79, download80, download81, download83)
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package io.github.inductiveautomation.kindling.statistics

import io.github.inductiveautomation.kindling.statistics.config83.PlatformResourceCategory
import io.github.inductiveautomation.kindling.statistics.config83.ResourceCategory
import io.github.inductiveautomation.kindling.utils.MajorVersion
import io.github.inductiveautomation.kindling.utils.Properties
import io.github.inductiveautomation.kindling.utils.SQLiteConnection
import io.github.inductiveautomation.kindling.utils.XML_FACTORY
Expand All @@ -15,7 +18,11 @@ import java.nio.file.Path
import java.sql.Connection
import java.util.Properties
import kotlin.io.path.createTempFile
import kotlin.io.path.div
import kotlin.io.path.exists
import kotlin.io.path.inputStream
import kotlin.io.path.listDirectoryEntries
import kotlin.io.path.name
import kotlin.io.path.outputStream

class GatewayBackup(path: Path) {
Expand All @@ -24,6 +31,10 @@ class GatewayBackup(path: Path) {

val info: Document = root.resolve(BACKUP_INFO).inputStream().use(XML_FACTORY::parse)

val version by lazy {
MajorVersion.lookup(info.getElementsByTagName("version").item(0).textContent)
}

val projectsDirectory: Path = root.resolve(PROJECTS)

val configDirectory: Path = root.resolve(CONFIG)
Expand Down Expand Up @@ -51,6 +62,8 @@ class GatewayBackup(path: Path) {
Properties(root.resolve(REDUNDANCY).inputStream(), Properties::loadFromXML)
}

val resources: Resources by lazy { Resources() }

companion object {
private const val IDB = "db_backup_sqlite.idb"
private const val BACKUP_INFO = "backupinfo.xml"
Expand All @@ -59,4 +72,31 @@ class GatewayBackup(path: Path) {
private const val PROJECTS = "projects"
private const val CONFIG = "config"
}

inner class Resources {
val directory = configDirectory / "resources"

// Can be changed later for 8.3-specific stats with deployment modes
private var deploymentId: String = "core"

val modules: List<String> = directory.listDirectoryEntries().map { it.name }

fun getPlatformCategory(category: PlatformResourceCategory): ResourceCategory {
val path = directory / deploymentId / "ignition" / category.folderName
return ResourceCategory(path)
}

fun getModuleCategory(moduleId: String, type: String): ResourceCategory {
val path = directory / deploymentId / moduleId / type
check(path.exists()) { "No resource category $moduleId/$type" }
return ResourceCategory(path)
}

fun <T> withDeploymentId(deploymentId: String, block: Resources.() -> T): T {
this.deploymentId = deploymentId
val result = this.block()
this.deploymentId = "core"
return result
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
package io.github.inductiveautomation.kindling.statistics

import io.github.inductiveautomation.kindling.utils.MajorVersion

fun interface StatisticCalculator<T : Statistic> {
suspend fun calculate(backup: GatewayBackup): T?
}

abstract class CalculatorSupport<T : Statistic>(
private val calculatorMap: Map<MajorVersion, StatisticCalculator<T>>,
) : Map<MajorVersion, StatisticCalculator<T>> by calculatorMap
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
package io.github.inductiveautomation.kindling.statistics.categories

import com.inductiveautomation.ignition.common.datasource.DatabaseVendor
import io.github.inductiveautomation.kindling.statistics.CalculatorSupport
import io.github.inductiveautomation.kindling.statistics.GatewayBackup
import io.github.inductiveautomation.kindling.statistics.Statistic
import io.github.inductiveautomation.kindling.statistics.StatisticCalculator
import io.github.inductiveautomation.kindling.statistics.config83.PlatformResourceCategory
import io.github.inductiveautomation.kindling.utils.MajorVersion
import io.github.inductiveautomation.kindling.utils.executeQuery
import io.github.inductiveautomation.kindling.utils.get
import io.github.inductiveautomation.kindling.utils.toList
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.coroutineScope
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive

data class DatabaseStatistics(
val connections: List<Connection>,
Expand All @@ -23,8 +32,17 @@ data class DatabaseStatistics(
val cacheSize: Long,
)

companion object Calculators : CalculatorSupport<DatabaseStatistics>(
mapOf(
MajorVersion.SevenNine to Calculator,
MajorVersion.EightZero to Calculator,
MajorVersion.EightOne to Calculator,
MajorVersion.EightThree to Calculator83,
),
)

@Suppress("SqlResolve")
companion object Calculator : StatisticCalculator<DatabaseStatistics> {
object Calculator : StatisticCalculator<DatabaseStatistics> {
private val DATABASE_STATS =
"""
SELECT
Expand Down Expand Up @@ -62,4 +80,30 @@ data class DatabaseStatistics(
return DatabaseStatistics(connections)
}
}

object Calculator83 : StatisticCalculator<DatabaseStatistics> {
@OptIn(ExperimentalSerializationApi::class)
override suspend fun calculate(backup: GatewayBackup): DatabaseStatistics? = coroutineScope {
val dbConnections = backup.resources.getPlatformCategory(PlatformResourceCategory.DATABASE_CONNECTION)
val sfEngine = backup.resources.getPlatformCategory(PlatformResourceCategory.STORE_AND_FORWARD_ENGINE)

val connections = dbConnections.resources.map { connectionResource ->
async {
val sfResource = sfEngine[connectionResource.name] ?: return@async null
Connection(
name = connectionResource.name,
description = connectionResource.data.description,
vendor = DatabaseVendor.valueOf(connectionResource.config["translator"]!!.jsonPrimitive.content),
enabled = connectionResource.data.attributes.enabled,
sfEnabled = sfResource.data.attributes.enabled,
bufferSize = sfResource.config["dataThreshold"]!!.jsonPrimitive.content.toLong(),
cacheSize = sfResource.config["secondaryMaintenancePolicy"]!!.jsonObject["limit"]!!.jsonObject["value"]!!.jsonPrimitive.content.toLong(),
)
}
}.toList().awaitAll().filterNotNull()

if (connections.isEmpty()) return@coroutineScope null
DatabaseStatistics(connections)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
package io.github.inductiveautomation.kindling.statistics.categories

import io.github.inductiveautomation.kindling.statistics.CalculatorSupport
import io.github.inductiveautomation.kindling.statistics.GatewayBackup
import io.github.inductiveautomation.kindling.statistics.Statistic
import io.github.inductiveautomation.kindling.statistics.StatisticCalculator
import io.github.inductiveautomation.kindling.utils.MajorVersion
import io.github.inductiveautomation.kindling.utils.executeQuery
import io.github.inductiveautomation.kindling.utils.get
import io.github.inductiveautomation.kindling.utils.toList
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.coroutineScope
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive

data class DeviceStatistics(
val devices: List<Device>,
Expand All @@ -20,8 +27,17 @@ data class DeviceStatistics(
val total = devices.size
val enabled = devices.count { it.enabled }

companion object Calculators : CalculatorSupport<DeviceStatistics>(
mapOf(
MajorVersion.SevenNine to Calculator,
MajorVersion.EightZero to Calculator,
MajorVersion.EightOne to Calculator,
MajorVersion.EightThree to Calculator83,
),
)

@Suppress("SqlResolve")
companion object Calculator : StatisticCalculator<DeviceStatistics> {
object Calculator : StatisticCalculator<DeviceStatistics> {
private val DEVICES =
"""
SELECT
Expand Down Expand Up @@ -52,4 +68,24 @@ data class DeviceStatistics(
return DeviceStatistics(devices)
}
}

object Calculator83 : StatisticCalculator<DeviceStatistics> {
override suspend fun calculate(backup: GatewayBackup): DeviceStatistics? = coroutineScope {
val devicesCategory = backup.resources.getModuleCategory("com.inductiveautomation.opcua", "device")

val devices: List<Device> = devicesCategory.resources.map {
async {
Device(
name = it.name,
type = it.config["profile"]!!.jsonObject["type"]!!.jsonPrimitive.content,
description = it.data.description,
enabled = it.data.attributes.enabled,
)
}
}.toList().awaitAll()

if (devices.isEmpty()) return@coroutineScope null
DeviceStatistics(devices)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
package io.github.inductiveautomation.kindling.statistics.categories

import io.github.inductiveautomation.kindling.statistics.CalculatorSupport
import io.github.inductiveautomation.kindling.statistics.GatewayBackup
import io.github.inductiveautomation.kindling.statistics.Statistic
import io.github.inductiveautomation.kindling.statistics.StatisticCalculator
import io.github.inductiveautomation.kindling.statistics.config83.PlatformResourceCategory
import io.github.inductiveautomation.kindling.utils.MajorVersion
import io.github.inductiveautomation.kindling.utils.executeQuery
import io.github.inductiveautomation.kindling.utils.get
import io.github.inductiveautomation.kindling.utils.toList
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.coroutineScope
import kotlinx.serialization.json.jsonPrimitive

data class GatewayNetworkStatistics(
val outgoing: List<OutgoingConnection>,
Expand All @@ -21,8 +28,17 @@ data class GatewayNetworkStatistics(
val uuid: String,
)

companion object Calculators : CalculatorSupport<GatewayNetworkStatistics>(
mapOf(
MajorVersion.SevenNine to Calculator,
MajorVersion.EightZero to Calculator,
MajorVersion.EightOne to Calculator,
MajorVersion.EightThree to Calculator83,
),
)

@Suppress("SqlResolve")
companion object Calculator : StatisticCalculator<GatewayNetworkStatistics> {
object Calculator : StatisticCalculator<GatewayNetworkStatistics> {
private val OUTGOING_CONNECTIONS =
"""
SELECT
Expand Down Expand Up @@ -65,4 +81,34 @@ data class GatewayNetworkStatistics(
return GatewayNetworkStatistics(outgoing, incoming)
}
}

object Calculator83 : StatisticCalculator<GatewayNetworkStatistics> {
override suspend fun calculate(backup: GatewayBackup): GatewayNetworkStatistics? = coroutineScope {
val outgoingCategory = backup.resources.getPlatformCategory(
PlatformResourceCategory.GATEWAY_NETWORK_OUTGOING,
)
val incomingCategory = backup.resources.getPlatformCategory(
PlatformResourceCategory.GATEWAY_NETWORK_INCOMING,
)

val outgoing = outgoingCategory.resources.map {
async {
OutgoingConnection(
host = it.config["host"]!!.jsonPrimitive.content,
port = it.config["port"]!!.jsonPrimitive.content.toInt(),
enabled = it.data.attributes.enabled,
)
}
}.toList().awaitAll()

val incoming = incomingCategory.resources.map {
async {
IncomingConnection(it.config["connectionId"]!!.jsonPrimitive.content)
}
}.toList().awaitAll()

if (outgoing.isEmpty() && incoming.isEmpty()) return@coroutineScope null
GatewayNetworkStatistics(outgoing, incoming)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
package io.github.inductiveautomation.kindling.statistics.categories

import io.github.inductiveautomation.kindling.statistics.CalculatorSupport
import io.github.inductiveautomation.kindling.statistics.GatewayBackup
import io.github.inductiveautomation.kindling.statistics.Statistic
import io.github.inductiveautomation.kindling.statistics.StatisticCalculator
import io.github.inductiveautomation.kindling.statistics.config83.PlatformResourceCategory
import io.github.inductiveautomation.kindling.utils.MajorVersion
import io.github.inductiveautomation.kindling.utils.asScalarMap
import io.github.inductiveautomation.kindling.utils.executeQuery
import kotlinx.serialization.json.jsonPrimitive

data class MetaStatistics(
val uuid: String?,
Expand All @@ -15,8 +19,17 @@ data class MetaStatistics(
val initMemory: Int,
val maxMemory: Int,
) : Statistic {
companion object Calculators : CalculatorSupport<MetaStatistics>(
mapOf(
MajorVersion.SevenNine to Calculator,
MajorVersion.EightZero to Calculator,
MajorVersion.EightOne to Calculator,
MajorVersion.EightThree to Calculator83,
),
)

@Suppress("SqlResolve")
companion object Calculator : StatisticCalculator<MetaStatistics> {
object Calculator : StatisticCalculator<MetaStatistics> {
private val SYS_PROPS =
"""
SELECT *
Expand All @@ -41,4 +54,29 @@ data class MetaStatistics(
)
}
}

object Calculator83 : StatisticCalculator<MetaStatistics> {
override suspend fun calculate(backup: GatewayBackup): MetaStatistics {
val sysProps = backup.resources.getPlatformCategory(
PlatformResourceCategory.SYSTEM_PROPERTIES,
).resources.single().config

val localSysProps = backup.resources.withDeploymentId("local") {
getPlatformCategory(PlatformResourceCategory.LOCAL_SYSTEM_PROPERTIES)
}.resources.single().config

val edition = backup.info.getElementsByTagName("edition").item(0)?.textContent
val version = backup.info.getElementsByTagName("version").item(0).textContent

return MetaStatistics(
uuid = localSysProps["systemUID"]?.jsonPrimitive?.content,
gatewayName = sysProps["systemName"]!!.jsonPrimitive.content,
edition = edition.takeUnless { it.isNullOrEmpty() } ?: "Standard",
role = backup.redundancyInfo.getProperty("redundancy.noderole"),
version = version,
initMemory = backup.ignitionConf.getProperty("wrapper.java.initmemory").takeWhile { it.isDigit() }.toInt(),
maxMemory = backup.ignitionConf.getProperty("wrapper.java.maxmemory").takeWhile { it.isDigit() }.toInt(),
)
}
}
}
Loading
Loading