From 52ee0a0f7384fff1f7892c910bf3e56a3c084fc4 Mon Sep 17 00:00:00 2001 From: dankito Date: Sun, 5 Jul 2020 11:11:15 +0200 Subject: [PATCH] Removed suspend from methods as coroutines don't really work in Kotlin/Native --- fints4k/build.gradle | 1 - .../net/dankito/banking/fints/FinTsClient.kt | 61 +++++++++---------- .../banking/fints/FinTsClientForCustomer.kt | 6 +- .../banking/fints/webclient/IWebClient.kt | 2 +- .../banking/fints/webclient/KtorWebClient.kt | 24 +++++--- 5 files changed, 51 insertions(+), 43 deletions(-) diff --git a/fints4k/build.gradle b/fints4k/build.gradle index 96e2ad81..fd4c68a3 100644 --- a/fints4k/build.gradle +++ b/fints4k/build.gradle @@ -132,7 +132,6 @@ kotlin { iosMain { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-common:$kotlinVersion" - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core-native:1.3.5-native-mt" implementation "io.ktor:ktor-client-ios:$ktorVersion" implementation "io.ktor:ktor-client-core-native:$ktorVersion" diff --git a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/FinTsClient.kt b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/FinTsClient.kt index e481b51d..06439a2a 100644 --- a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/FinTsClient.kt +++ b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/FinTsClient.kt @@ -30,7 +30,6 @@ import net.dankito.banking.fints.tan.TanImageDecoder import net.dankito.banking.fints.transactions.IAccountTransactionsParser import net.dankito.banking.fints.transactions.Mt940AccountTransactionsParser import net.dankito.banking.fints.util.IBase64Service -import net.dankito.banking.fints.util.IThreadPool import net.dankito.banking.fints.util.PureKotlinBase64Service import net.dankito.banking.fints.util.log.LoggerFactory import net.dankito.banking.fints.webclient.IWebClient @@ -85,7 +84,7 @@ open class FinTsClient( * * On success [bank] parameter is updated afterwards. */ - open suspend fun getAnonymousBankInfo(bank: BankData): FinTsClientResponse { + open fun getAnonymousBankInfo(bank: BankData): FinTsClientResponse { val dialogContext = DialogContext(bank, CustomerData.Anonymous, product) val message = messageBuilder.createAnonymousDialogInitMessage(dialogContext) @@ -101,7 +100,7 @@ open class FinTsClient( return FinTsClientResponse(response) } - protected open suspend fun closeAnonymousDialog(dialogContext: DialogContext, response: Response) { + protected open fun closeAnonymousDialog(dialogContext: DialogContext, response: Response) { // bank already closed dialog -> there's no need to send dialog end message if (areWeThatGentleToCloseDialogs == false || dialogContext.didBankCloseDialog) { @@ -114,7 +113,7 @@ open class FinTsClient( } - open suspend fun getBankAndCustomerInfoForNewUser(bank: BankData, customer: CustomerData): AddAccountResponse { + open fun getBankAndCustomerInfoForNewUser(bank: BankData, customer: CustomerData): AddAccountResponse { // just to ensure settings are in its initial state and that bank sends use bank parameter (BPD), // user parameter (UPD) and allowed tan procedures for user (therefore the resetSelectedTanProcedure()) bank.resetBpdVersion() @@ -148,7 +147,7 @@ open class FinTsClient( } // TODO: this is only a quick fix. Find a better and general solution - protected open suspend fun getBankAndCustomerInfoForNewUserViaAnonymousDialog(bank: BankData, customer: CustomerData): AddAccountResponse { + protected open fun getBankAndCustomerInfoForNewUserViaAnonymousDialog(bank: BankData, customer: CustomerData): AddAccountResponse { val anonymousBankInfoResponse = getAnonymousBankInfo(bank) if (anonymousBankInfoResponse.isSuccessful == false) { @@ -183,7 +182,7 @@ open class FinTsClient( * * If you change customer system id during a dialog your messages get rejected by bank institute. */ - protected open suspend fun synchronizeCustomerSystemId(bank: BankData, customer: CustomerData): FinTsClientResponse { + protected open fun synchronizeCustomerSystemId(bank: BankData, customer: CustomerData): FinTsClientResponse { val dialogContext = DialogContext(bank, customer, product) val message = messageBuilder.createSynchronizeCustomerSystemIdMessage(dialogContext) @@ -209,7 +208,7 @@ open class FinTsClient( } } - open suspend fun addAccount(bank: BankData, customer: CustomerData): AddAccountResponse { + open fun addAccount(bank: BankData, customer: CustomerData): AddAccountResponse { val originalAreWeThatGentleToCloseDialogs = areWeThatGentleToCloseDialogs areWeThatGentleToCloseDialogs = false @@ -279,11 +278,11 @@ open class FinTsClient( * * Check if bank supports this. */ - open suspend fun tryGetTransactionsOfLast90DaysWithoutTan(bank: BankData, customer: CustomerData, account: AccountData): GetTransactionsResponse { + open fun tryGetTransactionsOfLast90DaysWithoutTan(bank: BankData, customer: CustomerData, account: AccountData): GetTransactionsResponse { return tryGetTransactionsOfLast90DaysWithoutTan(bank, customer, account, false) } - protected open suspend fun tryGetTransactionsOfLast90DaysWithoutTan(bank: BankData, customer: CustomerData, account: AccountData, + protected open fun tryGetTransactionsOfLast90DaysWithoutTan(bank: BankData, customer: CustomerData, account: AccountData, hasRetrievedTransactionsWithTanJustBefore: Boolean): GetTransactionsResponse { val now = DateTimeTz.nowLocal() @@ -312,7 +311,7 @@ open class FinTsClient( } } - open suspend fun getTransactions(parameter: GetTransactionsParameter, bank: BankData, + open fun getTransactions(parameter: GetTransactionsParameter, bank: BankData, customer: CustomerData, account: AccountData): GetTransactionsResponse { val dialogContext = DialogContext(bank, customer, product) @@ -375,7 +374,7 @@ open class FinTsClient( balance) } - protected open suspend fun getBalanceAfterDialogInit(account: AccountData, dialogContext: DialogContext): Response { + protected open fun getBalanceAfterDialogInit(account: AccountData, dialogContext: DialogContext): Response { val message = messageBuilder.createGetBalanceMessage(account, dialogContext) @@ -393,7 +392,7 @@ open class FinTsClient( } } - open suspend fun getTanMediaList(bank: BankData, customer: CustomerData, tanMediaKind: TanMedienArtVersion = TanMedienArtVersion.Alle, + open fun getTanMediaList(bank: BankData, customer: CustomerData, tanMediaKind: TanMedienArtVersion = TanMedienArtVersion.Alle, tanMediumClass: TanMediumKlasse = TanMediumKlasse.AlleMedien): GetTanMediaListResponse { val response = sendMessageAndHandleResponse(bank, customer) { dialogContext -> @@ -412,7 +411,7 @@ open class FinTsClient( } - open suspend fun changeTanMedium(newActiveTanMedium: TanGeneratorTanMedium, bank: BankData, customer: CustomerData): FinTsClientResponse { + open fun changeTanMedium(newActiveTanMedium: TanGeneratorTanMedium, bank: BankData, customer: CustomerData): FinTsClientResponse { var enteredAtc: EnterTanGeneratorAtcResult? = null @@ -444,7 +443,7 @@ open class FinTsClient( } } - open suspend fun doBankTransfer(bankTransferData: BankTransferData, bank: BankData, + open fun doBankTransfer(bankTransferData: BankTransferData, bank: BankData, customer: CustomerData, account: AccountData): FinTsClientResponse { val response = sendMessageAndHandleResponse(bank, customer) { dialogContext -> @@ -455,7 +454,7 @@ open class FinTsClient( } - protected open suspend fun sendMessageAndHandleResponse(bank: BankData, customer: CustomerData, messageMayRequiresTan: Boolean = true, + protected open fun sendMessageAndHandleResponse(bank: BankData, customer: CustomerData, messageMayRequiresTan: Boolean = true, createMessage: (DialogContext) -> MessageBuilderResult): Response { val dialogContext = DialogContext(bank, customer, product) @@ -477,7 +476,7 @@ open class FinTsClient( return response } - protected open suspend fun initDialog(dialogContext: DialogContext): Response { + protected open fun initDialog(dialogContext: DialogContext): Response { // we first need to retrieve supported tan procedures and jobs before we can do anything val retrieveBasicBankDataResponse = ensureBasicBankDataRetrieved(dialogContext.bank, dialogContext.customer) @@ -495,7 +494,7 @@ open class FinTsClient( return initDialogAfterSuccessfulChecks(dialogContext) } - protected open suspend fun initDialogAfterSuccessfulChecks(dialogContext: DialogContext): Response { + protected open fun initDialogAfterSuccessfulChecks(dialogContext: DialogContext): Response { val message = messageBuilder.createInitDialogMessage(dialogContext) @@ -510,7 +509,7 @@ open class FinTsClient( return response } - protected open suspend fun closeDialog(dialogContext: DialogContext) { + protected open fun closeDialog(dialogContext: DialogContext) { // bank already closed dialog -> there's no need to send dialog end message if (areWeThatGentleToCloseDialogs == false || dialogContext.didBankCloseDialog) { @@ -523,7 +522,7 @@ open class FinTsClient( } - protected open suspend fun ensureBasicBankDataRetrieved(bank: BankData, customer: CustomerData): Response { + protected open fun ensureBasicBankDataRetrieved(bank: BankData, customer: CustomerData): Response { if (bank.supportedTanProcedures.isEmpty() || bank.supportedJobs.isEmpty()) { val getBankInfoResponse = getBankAndCustomerInfoForNewUser(bank, customer) @@ -538,7 +537,7 @@ open class FinTsClient( return Response(true) } - protected open suspend fun ensureTanProcedureIsSelected(bank: BankData, customer: CustomerData): Response { + protected open fun ensureTanProcedureIsSelected(bank: BankData, customer: CustomerData): Response { if (customer.isTanProcedureSelected == false) { if (customer.supportedTanProcedures.isEmpty()) { getBankAndCustomerInfoForNewUser(bank, customer) @@ -574,7 +573,7 @@ open class FinTsClient( } - protected open suspend fun getAndHandleResponseForMessage(message: MessageBuilderResult, dialogContext: DialogContext): Response { + protected open fun getAndHandleResponseForMessage(message: MessageBuilderResult, dialogContext: DialogContext): Response { val response = if (message.createdMessage == null) Response(false, messageCreationError = message) else getAndHandleResponseForMessage(message.createdMessage, dialogContext) @@ -597,7 +596,7 @@ open class FinTsClient( return handledResponse } - protected open suspend fun getAndHandleResponseForMessage(requestBody: String, dialogContext: DialogContext): Response { + protected open fun getAndHandleResponseForMessage(requestBody: String, dialogContext: DialogContext): Response { addMessageLog(requestBody, MessageLogEntryType.Sent, dialogContext) val webResponse = getResponseForMessage(requestBody, dialogContext.bank.finTs3ServerAddress) @@ -612,13 +611,13 @@ open class FinTsClient( return response } - protected open suspend fun getResponseForMessage(requestBody: String, finTs3ServerAddress: String): WebClientResponse { + protected open fun getResponseForMessage(requestBody: String, finTs3ServerAddress: String): WebClientResponse { val encodedRequestBody = base64Service.encode(requestBody) return webClient.post(finTs3ServerAddress, encodedRequestBody, "application/octet-stream") } - protected open suspend fun fireAndForgetMessage(message: MessageBuilderResult, dialogContext: DialogContext) { + protected open fun fireAndForgetMessage(message: MessageBuilderResult, dialogContext: DialogContext) { message.createdMessage?.let { requestBody -> addMessageLog(requestBody, MessageLogEntryType.Sent, dialogContext) @@ -638,7 +637,7 @@ open class FinTsClient( addMessageLog(decodedResponse, MessageLogEntryType.Received, dialogContext) - return responseParser.parse(decodedResponse) // TODO: make suspendable + return responseParser.parse(decodedResponse) } catch (e: Exception) { log.error(e) { "Could not decode responseBody:\r\n'$responseBody'" } @@ -658,7 +657,7 @@ open class FinTsClient( } - protected open suspend fun getFollowUpMessageForContinuationId(response: Response, continuationId: String, message: MessageBuilderResult, + protected open fun getFollowUpMessageForContinuationId(response: Response, continuationId: String, message: MessageBuilderResult, dialogContext: DialogContext): Response? { messageBuilder.rebuildMessageWithContinuationId(message, continuationId, dialogContext)?.let { followUpMessage -> @@ -718,7 +717,7 @@ open class FinTsClient( } - protected open suspend fun handleMayRequiresTan(response: Response, dialogContext: DialogContext): Response { // TODO: use response from DialogContext + protected open fun handleMayRequiresTan(response: Response, dialogContext: DialogContext): Response { // TODO: use response from DialogContext if (response.isStrongAuthenticationRequired) { if (dialogContext.abortIfTanIsRequired) { @@ -779,14 +778,14 @@ open class FinTsClient( } } - protected open suspend fun sendTanToBank(enteredTan: String, tanResponse: TanResponse, dialogContext: DialogContext): Response { + protected open fun sendTanToBank(enteredTan: String, tanResponse: TanResponse, dialogContext: DialogContext): Response { val message = messageBuilder.createSendEnteredTanMessage(enteredTan, tanResponse, dialogContext) return getAndHandleResponseForMessage(message, dialogContext) } - protected open suspend fun handleUserAsksToChangeTanProcedureAndResendLastMessage(changeTanProcedureTo: TanProcedure, dialogContext: DialogContext): Response { + protected open fun handleUserAsksToChangeTanProcedureAndResendLastMessage(changeTanProcedureTo: TanProcedure, dialogContext: DialogContext): Response { dialogContext.customer.selectedTanProcedure = changeTanProcedureTo @@ -798,7 +797,7 @@ open class FinTsClient( return resendMessageInNewDialog(lastCreatedMessage, dialogContext) } - protected open suspend fun handleUserAsksToChangeTanMediumAndResendLastMessage(changeTanMediumTo: TanGeneratorTanMedium, + protected open fun handleUserAsksToChangeTanMediumAndResendLastMessage(changeTanMediumTo: TanGeneratorTanMedium, dialogContext: DialogContext, changeTanMediumResultCallback: ((FinTsClientResponse) -> Unit)?): Response { @@ -820,7 +819,7 @@ open class FinTsClient( } - protected open suspend fun resendMessageInNewDialog(lastCreatedMessage: MessageBuilderResult?, previousDialogContext: DialogContext): Response { + protected open fun resendMessageInNewDialog(lastCreatedMessage: MessageBuilderResult?, previousDialogContext: DialogContext): Response { lastCreatedMessage?.let { // do not use previousDialogContext.currentMessage as this may is previous dialog's dialog close message val newDialogContext = DialogContext(previousDialogContext.bank, previousDialogContext.customer, previousDialogContext.product, chunkedResponseHandler = previousDialogContext.chunkedResponseHandler) diff --git a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/FinTsClientForCustomer.kt b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/FinTsClientForCustomer.kt index 022e4436..63cdb983 100644 --- a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/FinTsClientForCustomer.kt +++ b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/FinTsClientForCustomer.kt @@ -38,7 +38,7 @@ open class FinTsClientForCustomer( client.addAccountAsync(bank, customer, callback) } - open suspend fun addAccount(): AddAccountResponse { + open fun addAccount(): AddAccountResponse { return client.addAccount(bank, customer) } @@ -47,7 +47,7 @@ open class FinTsClientForCustomer( client.getTransactionsAsync(parameter, bank, customer, account, callback) } - open suspend fun getTransactions(parameter: GetTransactionsParameter, account: AccountData): GetTransactionsResponse { + open fun getTransactions(parameter: GetTransactionsParameter, account: AccountData): GetTransactionsResponse { return client.getTransactions(parameter, bank, customer, account) } @@ -56,7 +56,7 @@ open class FinTsClientForCustomer( client.doBankTransferAsync(bankTransferData, bank, customer, account, callback) } - open suspend fun doBankTransfer(bankTransferData: BankTransferData, account: AccountData): FinTsClientResponse { + open fun doBankTransfer(bankTransferData: BankTransferData, account: AccountData): FinTsClientResponse { return client.doBankTransfer(bankTransferData, bank, customer, account) } diff --git a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/webclient/IWebClient.kt b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/webclient/IWebClient.kt index 60c3e2a1..69f3a051 100644 --- a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/webclient/IWebClient.kt +++ b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/webclient/IWebClient.kt @@ -20,6 +20,6 @@ interface IWebClient { } - suspend fun post(url: String, body: String, contentType: String = "application/octet-stream", userAgent: String = DefaultUserAgent) : WebClientResponse + fun post(url: String, body: String, contentType: String = "application/octet-stream", userAgent: String = DefaultUserAgent) : WebClientResponse } \ No newline at end of file diff --git a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/webclient/KtorWebClient.kt b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/webclient/KtorWebClient.kt index bae0b258..72367bd9 100644 --- a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/webclient/KtorWebClient.kt +++ b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/webclient/KtorWebClient.kt @@ -34,18 +34,28 @@ open class KtorWebClient : IWebClient { } - override suspend fun post(url: String, body: String, contentType: String, userAgent: String): WebClientResponse { + override fun post(url: String, body: String, contentType: String, userAgent: String): WebClientResponse { try { - val clientResponse = client.post(url) { - this.body = TextContent(body, contentType = ContentType.Application.OctetStream) + val job = GlobalScope.async { + try { + val clientResponse = client.post(url) { + this.body = TextContent(body, contentType = ContentType.Application.OctetStream) + } + + val responseBody = clientResponse.readText() + + WebClientResponse(clientResponse.status.value == 200, clientResponse.status.value, body = responseBody) + } catch (e: Exception) { + log.error(e) { "Could not send request to url '$url'" } + + WebClientResponse(false, error = e) + } } - val responseBody = clientResponse.readText() + while (job.isCompleted == false) { } // let's warm the CPU to get suspend function synchronous (runBlocking is not available in common projects) - return WebClientResponse(clientResponse.status.value == 200, clientResponse.status.value, body = responseBody) + return job.getCompleted() } catch (e: Exception) { - log.error(e) { "Could not send request to url '$url'" } - return WebClientResponse(false, error = e) } }