Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

jvm and ios-async-node-ability-to-remove-resolved-async-node #488

Merged
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
2f28724
Initial code commit
sakuntala-motukuri Aug 12, 2024
dcc3187
Merge branch 'main' into jvm-async-node-ability-to-remove-resolved-as…
sakuntala-motukuri Aug 12, 2024
477c0c6
jvm-async-node-ability-to-remove-resolved-async-node
sakuntala-motukuri Aug 13, 2024
8fd4dab
fixed linter
sakuntala-motukuri Aug 13, 2024
d865fb3
ios-async-node-ability-to-remove-resolved-async-node
sakuntala-motukuri Aug 13, 2024
f78df38
changed some logic and reverted NodeSerializableField
sakuntala-motukuri Aug 14, 2024
0340188
ios expose constantsController #446
cehan-Chloe Aug 9, 2024
2425424
add docstrings to public funcs
cehan-Chloe Aug 12, 2024
729929f
fix return type and add tests
cehan-Chloe Aug 12, 2024
da38906
add comments
cehan-Chloe Aug 14, 2024
bceb781
Android/JVM - expose constantController
cehan-Chloe Aug 14, 2024
850bf52
fix test build
cehan-Chloe Aug 14, 2024
f55e495
remove start player in tests
cehan-Chloe Aug 14, 2024
a2c46cc
fix test build
cehan-Chloe Aug 14, 2024
2a63f45
Changed logic and updated test cases for android
sakuntala-motukuri Aug 17, 2024
5bcdcb3
Merge branch 'main' into jvm-async-node-ability-to-remove-resolved-as…
sakuntala-motukuri Aug 17, 2024
6917491
Updated 'handle multiple updates through callback mechanism'
sakuntala-motukuri Aug 19, 2024
de6df57
updated async-node ios version and fixed review comments
sakuntala-motukuri Aug 21, 2024
d252411
Fixed ios tests
sakuntala-motukuri Aug 21, 2024
04f3573
Removed callback from testHandleMultipleUpdatesThroughCallback
sakuntala-motukuri Aug 22, 2024
663ce13
Merge branch 'main' into jvm-async-node-ability-to-remove-resolved-as…
sakuntala-motukuri Aug 22, 2024
91359bc
Fixed review comments and updated ios test cases
sakuntala-motukuri Aug 22, 2024
a9542b4
updated test to .emptyNode case
sakuntala-motukuri Aug 22, 2024
f864330
added assertions in ios
sakuntala-motukuri Aug 23, 2024
45fe9fc
added suspend in jvm
sakuntala-motukuri Aug 23, 2024
ad6d7b8
Fixed review comments for null node test and callback test
sakuntala-motukuri Aug 26, 2024
428d005
Linter fix
sakuntala-motukuri Aug 26, 2024
ace8b73
Updated review comments
sakuntala-motukuri Aug 26, 2024
e8dc375
Added doc comment
sakuntala-motukuri Aug 26, 2024
5b850e0
updated ios review comments and updated tests
sakuntala-motukuri Sep 3, 2024
df5c4d6
Merge branch 'main' into jvm-async-node-ability-to-remove-resolved-as…
sakuntala-motukuri Sep 3, 2024
32b9c57
removed white spaces
sakuntala-motukuri Sep 3, 2024
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
127 changes: 86 additions & 41 deletions ios/core/Sources/Types/Hooks/Hook.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//
// Hook.swift
//
//
//
// Created by Borawski, Harris on 2/12/20.
//
Expand All @@ -11,16 +11,16 @@
/// A base for implementing JS backed hooks
open class BaseJSHook {
private let baseValue: JSValue

/// The JS reference to the hook
public var hook: JSValue { baseValue.objectForKeyedSubscript("hooks").objectForKeyedSubscript(name) }

/// The JSContext for the hook
public var context: JSContext { hook.context }

/// The name of the hook
public let name: String

/// Retrieves a hook by name from an object in JS
/// - Parameters:
/// - baseValue: The object that has `hooks`
Expand All @@ -39,9 +39,9 @@
/**
Attach a closure to the hook, so when the hook is fired in the JS runtime
we receive the event in the native runtime

- parameters:
- hook: A function to run when the JS hook is fired
- hook: A function to run when the JS hook is fired
*/
public func tap(_ hook: @escaping (T) -> Void) {
let tapMethod: @convention(block) (JSValue?) -> Void = { value in
Expand All @@ -51,7 +51,7 @@
else { return }
hook(hookValue)
}

self.hook.invokeMethod("tap", withArguments: [name, JSValue(object: tapMethod, in: context) as Any])
}
}
Expand All @@ -64,9 +64,9 @@
/**
Attach a closure to the hook, so when the hook is fired in the JS runtime
we receive the event in the native runtime

- parameters:
- hook: A function to run when the JS hook is fired
- hook: A function to run when the JS hook is fired
*/
public func tap(_ hook: @escaping (T, U) -> Void) {
let tapMethod: @convention(block) (JSValue?, JSValue?) -> Void = { value, value2 in
Expand All @@ -78,7 +78,7 @@
else { return }
hook(hookValue, hookValue2)
}

self.hook.invokeMethod("tap", withArguments: [name, JSValue(object: tapMethod, in: context) as Any])
}
}
Expand All @@ -91,9 +91,9 @@
/**
Attach a closure to the hook, so when the hook is fired in the JS runtime
we receive the event in the native runtime

- parameters:
- hook: A function to run when the JS hook is fired
- hook: A function to run when the JS hook is fired
*/
public func tap(_ hook: @escaping (T) -> Void) {
let tapMethod: @convention(block) (JSValue?) -> Void = { value in
Expand All @@ -103,7 +103,7 @@
else { return }
hook(hookValue)
}

self.hook.invokeMethod("tap", withArguments: [name, JSValue(object: tapMethod, in: context) as Any])
}
}
Expand All @@ -116,13 +116,13 @@
/**
Attach a closure to the hook, so when the hook is fired in the JS runtime
we receive the event in the native runtime

- parameters:
- hook: A function to run when the JS hook is fired
- hook: A function to run when the JS hook is fired
*/
public func tap(_ hook: @escaping (T, U) -> Void) {
let tapMethod: @convention(block) (JSValue?, JSValue?) -> Void = { value, value2 in

Check warning on line 125 in ios/core/Sources/Types/Hooks/Hook.swift

View check run for this annotation

Codecov / codecov/patch

ios/core/Sources/Types/Hooks/Hook.swift#L125

Added line #L125 was not covered by tests
let decoder = JSONDecoder()
guard
let val = value,
Expand All @@ -132,7 +132,7 @@
else { return }
hook(hookValue, hookValue2)
}

Check warning on line 135 in ios/core/Sources/Types/Hooks/Hook.swift

View check run for this annotation

Codecov / codecov/patch

ios/core/Sources/Types/Hooks/Hook.swift#L135

Added line #L135 was not covered by tests
self.hook.invokeMethod("tap", withArguments: [name, JSValue(object: tapMethod, in: context) as Any])
}
}
Expand All @@ -143,36 +143,81 @@
*/
public class AsyncHook<T>: BaseJSHook where T: CreatedFromJSValue {
private var handler: AsyncHookHandler?

public typealias AsyncHookHandler = (T) async throws -> JSValue?

/**
Attach a closure to the hook, so when the hook is fired in the JS runtime
we receive the event in the native runtime

- parameters:
- hook: A function to run when the JS hook is fired
- hook: A function to run when the JS hook is fired
*/
public func tap(_ hook: @escaping AsyncHookHandler) {
let tapMethod: @convention(block) (JSValue?) -> JSValue = { value in
guard
let val = value,
let hookValue = T.createInstance(value: val) as? T
else { return JSValue() }

let promise =
JSUtilities.createPromise(context: self.context, handler: { (resolve, _) in
Task {
let result = try await hook(hookValue)
DispatchQueue.main.async {
resolve(result as Any)
}
}
})

return promise ?? JSValue()
}
guard
let val = value,
let hookValue = T.createInstance(value: val) as? T
else { return JSValue() }

let promise =
JSUtilities.createPromise(context: self.context, handler: { (resolve, _) in
Task {
let result = try await hook(hookValue)
DispatchQueue.main.async {
resolve(result as Any)
}
}
})

return promise ?? JSValue()
}

self.hook.invokeMethod("tap", withArguments: [name, JSValue(object: tapMethod, in: context) as Any])
}

Check warning on line 177 in ios/core/Sources/Types/Hooks/Hook.swift

View check run for this annotation

Codecov / codecov/patch

ios/core/Sources/Types/Hooks/Hook.swift#L158-L177

Added lines #L158 - L177 were not covered by tests
}

self.hook.invokeMethod("tap", withArguments: [name, JSValue(object: tapMethod, in: context) as Any])
}
/**
This class represents an object in the JS runtime that can be tapped into
to receive JS events that has 2 parameters and
returns a promise that resolves when the asynchronous task is completed
*/
sakuntala-motukuri marked this conversation as resolved.
Show resolved Hide resolved
public class AsyncHook2<T, U>: BaseJSHook where T: CreatedFromJSValue, U: CreatedFromJSValue {
private var handler: AsyncHookHandler?

public typealias AsyncHookHandler = (T, U) async throws -> JSValue?

/**
Attach a closure to the hook, so when the hook is fired in the JS runtime
we receive the event in the native runtime

- parameters:
- hook: A function to run when the JS hook is fired
*/
public func tap(_ hook: @escaping AsyncHookHandler) {
let tapMethod: @convention(block) (JSValue?,JSValue?) -> JSValue = { value, value2 in
guard
let val = value,
let val2 = value2,
let hookValue = T.createInstance(value: val) as? T,
let hookValue2 = U.createInstance(value: val2) as? U
else { return JSValue() }


let promise =
JSUtilities.createPromise(context: self.context, handler: { (resolve, _) in
Task {
let result = try await hook(hookValue, hookValue2)
DispatchQueue.main.async {
resolve(result as Any)
}
}
})

return promise ?? JSValue()
}

self.hook.invokeMethod("tap", withArguments: [name, JSValue(object: tapMethod, in: context) as Any])
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ public val Runtime<*>.Promise: Promise.Api get() = getObject("Promise")?.let { p
} ?: throw PlayerRuntimeException("'Promise' not defined in runtime")

/** Helper to bridge complex [Promise] logic with the JS promise constructor */
public fun <T : Any> Runtime<*>.Promise(block: suspend ((T) -> Unit, (Throwable) -> Unit) -> Unit): Promise {
public fun <T : Any?> Runtime<*>.Promise(block: suspend ((T) -> Unit, (Throwable) -> Unit) -> Unit): Promise {
sakuntala-motukuri marked this conversation as resolved.
Show resolved Hide resolved
val key = "promiseHandler_${UUID.randomUUID().toString().replace("-", "")}"
add(key) { resolve: Invokable<Any?>, reject: Invokable<Any?> ->
runtime.scope.launch {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.intuit.playerui.core.bridge.hooks

import com.intuit.hooks.AsyncParallelBailHook
import com.intuit.hooks.BailResult
import com.intuit.hooks.HookContext
import com.intuit.playerui.core.bridge.Node
import com.intuit.playerui.core.bridge.serialization.serializers.NodeWrapperSerializer
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializable

@OptIn(ExperimentalCoroutinesApi::class)
@Serializable(with = NodeAsyncParallelBailHook2.Serializer::class)
public class NodeAsyncParallelBailHook2<T1, T2, R : Any?>(
override val node: Node,
serializer1: KSerializer<T1>,
serializer2: KSerializer<T2>,
) : AsyncParallelBailHook<suspend (HookContext, T1, T2) -> BailResult<R>, R>(), AsyncNodeHook<R> {

init {
init(serializer1, serializer2)
}

override suspend fun callAsync(context: HookContext, serializedArgs: Array<Any?>): R {
require(serializedArgs.size == 2) { "Expected exactly two arguments, but got ${serializedArgs.size}" }
val (p1, p2) = serializedArgs
val result = call(10) { f, _ ->
f(context, p1 as T1, p2 as T2)
} as R
return result
}

internal class Serializer<T1, T2, R : Any>(
private val serializer1: KSerializer<T1>,
private val serializer2: KSerializer<T2>,
`_`: KSerializer<R>,
) : NodeWrapperSerializer<NodeAsyncParallelBailHook2<T1, T2, R>>({
NodeAsyncParallelBailHook2(it, serializer1, serializer2)
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ internal interface NodeHook<R> : NodeWrapper {
fun call(context: HookContext, serializedArgs: Array<Any?>): R
}

internal interface AsyncNodeHook<R : Any> : NodeHook<Promise> {
internal interface AsyncNodeHook<R : Any?> : NodeHook<Promise> {
override fun call(context: HookContext, serializedArgs: Array<Any?>): Promise = node.runtime.Promise { resolve, reject ->
val result = callAsync(context, serializedArgs)
resolve(result)
Expand Down
Loading