diff --git a/android/src/main/java/com/stripeterminalreactnative/Errors.kt b/android/src/main/java/com/stripeterminalreactnative/Errors.kt index 0bc78e83..f8514e3d 100644 --- a/android/src/main/java/com/stripeterminalreactnative/Errors.kt +++ b/android/src/main/java/com/stripeterminalreactnative/Errors.kt @@ -40,6 +40,16 @@ internal fun requireCancelable(cancelable: T?, lazyMessage: () -> String): T ) } +@Throws(TerminalException::class) +internal fun throwIfBusy(command: T?, lazyMessage: () -> String): Unit? { + return command?.run { + throw TerminalException( + TerminalErrorCode.READER_BUSY, + lazyMessage() + ) + } +} + @Throws(TerminalException::class) internal fun requireParam(input: T?, lazyMessage: () -> String): T { return input ?: throw TerminalException( diff --git a/android/src/main/java/com/stripeterminalreactnative/StripeTerminalReactNativeModule.kt b/android/src/main/java/com/stripeterminalreactnative/StripeTerminalReactNativeModule.kt index 66f40d0f..22417d1e 100644 --- a/android/src/main/java/com/stripeterminalreactnative/StripeTerminalReactNativeModule.kt +++ b/android/src/main/java/com/stripeterminalreactnative/StripeTerminalReactNativeModule.kt @@ -150,6 +150,10 @@ class StripeTerminalReactNativeModule(reactContext: ReactApplicationContext) : val listener = RNDiscoveryListener(context) { discoveredReadersList = it } + throwIfBusy(discoverCancelable) { + busyMessage("discoverReaders", "discoverReaders") + } + discoverCancelable = terminal.discoverReaders( DiscoveryConfiguration(0, discoveryMethod, getBoolean(params, "simulated")), listener, @@ -160,7 +164,9 @@ class StripeTerminalReactNativeModule(reactContext: ReactApplicationContext) : @ReactMethod @Suppress("unused") fun cancelDiscovering(promise: Promise) { - cancelOperation(promise, discoverCancelable, "discoverReaders") + cancelOperation(promise, discoverCancelable, "discoverReaders") { + discoverCancelable = null + } } private fun connectReader( @@ -561,10 +567,16 @@ class StripeTerminalReactNativeModule(reactContext: ReactApplicationContext) : promise: Promise, cancelable: Cancelable?, operationName: String, + block: (() -> Unit)? = null ) = withExceptionResolver(promise) { val toCancel = requireCancelable(cancelable) { "$operationName could not be canceled because it has already been canceled or has completed." } toCancel.cancel(NoOpCallback(promise)) + block?.invoke() + } + + private fun busyMessage(command: String, busyBy: String): String { + return "Could not execute $command because the SDK is busy with another command: $busyBy." } } diff --git a/ios/Errors.swift b/ios/Errors.swift index 38794b03..6a30e353 100644 --- a/ios/Errors.swift +++ b/ios/Errors.swift @@ -38,6 +38,10 @@ class Errors { } } +func busyMessage(command: String, by busyCommand: String) -> String { + return "Could not execute \(command) because the SDK is busy with another command: \(busyCommand)." +} + extension ErrorCode.Code { var stringValue: String { switch self { diff --git a/ios/StripeTerminalReactNative.swift b/ios/StripeTerminalReactNative.swift index ab816b70..eb6417c6 100644 --- a/ios/StripeTerminalReactNative.swift +++ b/ios/StripeTerminalReactNative.swift @@ -181,6 +181,12 @@ class StripeTerminalReactNative: RCTEventEmitter, DiscoveryDelegate, BluetoothRe discoveryMethod: Mappers.mapToDiscoveryMethod(discoveryMethod), simulated: simulated ?? false ) + + guard discoverCancelable == nil else { + let message = busyMessage(command: "discoverReaders", by: "discoverReaders") + resolve(Errors.createError(code: ErrorCode.busy, message: message)) + return + } self.discoverCancelable = Terminal.shared.discoverReaders(config, delegate: self) { error in if let error = error as NSError? {