diff --git a/jvm/core/src/main/kotlin/com/intuit/playerui/core/bridge/hooks/NodeSyncBailHook1.kt b/jvm/core/src/main/kotlin/com/intuit/playerui/core/bridge/hooks/NodeSyncBailHook1.kt index f5b73a063..8ece04182 100644 --- a/jvm/core/src/main/kotlin/com/intuit/playerui/core/bridge/hooks/NodeSyncBailHook1.kt +++ b/jvm/core/src/main/kotlin/com/intuit/playerui/core/bridge/hooks/NodeSyncBailHook1.kt @@ -34,3 +34,26 @@ public class NodeSyncBailHook1( NodeSyncBailHook1(it, serializer1) }) } + +@Serializable(with = NodeSyncBailHook.Serializer::class) +public class NodeSyncBailHook( + override val node: Node, +) : SyncBailHook<(HookContext) -> BailResult, R>(), NodeHook { + + override fun call(context: HookContext, serializedArgs: Array): R? { + require(serializedArgs.isEmpty()) + return call( + { f, _ -> f(context) }, + ) { Unit as R } + } + + public fun tap(name: String, callback: () -> BailResult): String? = super.tap(name) { _ -> callback() } + + public inline fun tap(noinline callback: () -> BailResult): String? = tap(callingStackTraceElement.toString(), callback) + + public inline fun tap(noinline callback: (HookContext) -> BailResult): String? = tap(callingStackTraceElement.toString(), callback) + + internal class Serializer : NodeWrapperSerializer>({ + NodeSyncBailHook(it) + }) +} diff --git a/plugins/metrics/jvm/src/main/kotlin/com/intuit/playerui/plugins/metrics/MetricsPlugin.kt b/plugins/metrics/jvm/src/main/kotlin/com/intuit/playerui/plugins/metrics/MetricsPlugin.kt index 4438b44a8..728395377 100644 --- a/plugins/metrics/jvm/src/main/kotlin/com/intuit/playerui/plugins/metrics/MetricsPlugin.kt +++ b/plugins/metrics/jvm/src/main/kotlin/com/intuit/playerui/plugins/metrics/MetricsPlugin.kt @@ -3,6 +3,7 @@ package com.intuit.playerui.plugins.metrics import com.intuit.playerui.core.bridge.Node import com.intuit.playerui.core.bridge.NodeWrapper import com.intuit.playerui.core.bridge.getInvokable +import com.intuit.playerui.core.bridge.hooks.NodeSyncBailHook import com.intuit.playerui.core.bridge.hooks.NodeSyncHook1 import com.intuit.playerui.core.bridge.hooks.NodeSyncHook3 import com.intuit.playerui.core.bridge.runtime.Runtime @@ -48,6 +49,9 @@ public class MetricsPlugin( @Serializable(Hooks.Serializer::class) public class Hooks internal constructor(override val node: Node) : NodeWrapper { + public val resolveRequestTime: NodeSyncBailHook + by NodeSerializableField(NodeSyncBailHook.serializer(Int.serializer())) + public val onFlowBegin: NodeSyncHook1 by NodeSerializableField(NodeSyncHook1.serializer(PlayerFlowMetrics.serializer())) diff --git a/plugins/metrics/jvm/src/test/kotlin/com/intuit/playerui/plugins/metrics/MetricsPluginTest.kt b/plugins/metrics/jvm/src/test/kotlin/com/intuit/playerui/plugins/metrics/MetricsPluginTest.kt index 1f3295945..0f654ea57 100644 --- a/plugins/metrics/jvm/src/test/kotlin/com/intuit/playerui/plugins/metrics/MetricsPluginTest.kt +++ b/plugins/metrics/jvm/src/test/kotlin/com/intuit/playerui/plugins/metrics/MetricsPluginTest.kt @@ -1,5 +1,6 @@ package com.intuit.playerui.plugins.metrics +import com.intuit.hooks.BailResult import com.intuit.playerui.core.player.state.inProgressState import com.intuit.playerui.core.plugins.Plugin import com.intuit.playerui.utils.test.PlayerTest @@ -50,6 +51,21 @@ internal class MetricsPluginTest : PlayerTest() { verify { renderEndHandler wasNot Called } } + @OptIn(ExperimentalContracts::class) + @TestTemplate + fun `should trigger resolveRequestTime hook`() { + val expectedRequestTime = 1 + var actualRequestTime = 0 + + plugin?.hooks?.resolveRequestTime?.tap { -> + actualRequestTime = expectedRequestTime + BailResult.Bail(actualRequestTime) + } + + player.start(simpleFlowString) + assertEquals(expectedRequestTime, actualRequestTime) + } + @OptIn(ExperimentalContracts::class) @TestTemplate fun `should trigger onFlowBegin hook`() {