Removed suspend from methods as coroutines don't really work in Kotlin/Native

This commit is contained in:
dankito 2020-07-05 11:11:15 +02:00
parent 4999404113
commit 52ee0a0f73
5 changed files with 51 additions and 43 deletions

View File

@ -132,7 +132,6 @@ kotlin {
iosMain { iosMain {
dependencies { dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-common:$kotlinVersion" 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-ios:$ktorVersion"
implementation "io.ktor:ktor-client-core-native:$ktorVersion" implementation "io.ktor:ktor-client-core-native:$ktorVersion"

View File

@ -30,7 +30,6 @@ import net.dankito.banking.fints.tan.TanImageDecoder
import net.dankito.banking.fints.transactions.IAccountTransactionsParser import net.dankito.banking.fints.transactions.IAccountTransactionsParser
import net.dankito.banking.fints.transactions.Mt940AccountTransactionsParser import net.dankito.banking.fints.transactions.Mt940AccountTransactionsParser
import net.dankito.banking.fints.util.IBase64Service 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.PureKotlinBase64Service
import net.dankito.banking.fints.util.log.LoggerFactory import net.dankito.banking.fints.util.log.LoggerFactory
import net.dankito.banking.fints.webclient.IWebClient import net.dankito.banking.fints.webclient.IWebClient
@ -85,7 +84,7 @@ open class FinTsClient(
* *
* On success [bank] parameter is updated afterwards. * 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 dialogContext = DialogContext(bank, CustomerData.Anonymous, product)
val message = messageBuilder.createAnonymousDialogInitMessage(dialogContext) val message = messageBuilder.createAnonymousDialogInitMessage(dialogContext)
@ -101,7 +100,7 @@ open class FinTsClient(
return FinTsClientResponse(response) 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 // bank already closed dialog -> there's no need to send dialog end message
if (areWeThatGentleToCloseDialogs == false || dialogContext.didBankCloseDialog) { 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), // 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()) // user parameter (UPD) and allowed tan procedures for user (therefore the resetSelectedTanProcedure())
bank.resetBpdVersion() bank.resetBpdVersion()
@ -148,7 +147,7 @@ open class FinTsClient(
} }
// TODO: this is only a quick fix. Find a better and general solution // 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) val anonymousBankInfoResponse = getAnonymousBankInfo(bank)
if (anonymousBankInfoResponse.isSuccessful == false) { 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. * 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 dialogContext = DialogContext(bank, customer, product)
val message = messageBuilder.createSynchronizeCustomerSystemIdMessage(dialogContext) 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 val originalAreWeThatGentleToCloseDialogs = areWeThatGentleToCloseDialogs
areWeThatGentleToCloseDialogs = false areWeThatGentleToCloseDialogs = false
@ -279,11 +278,11 @@ open class FinTsClient(
* *
* Check if bank supports this. * 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) 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 { hasRetrievedTransactionsWithTanJustBefore: Boolean): GetTransactionsResponse {
val now = DateTimeTz.nowLocal() 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 { customer: CustomerData, account: AccountData): GetTransactionsResponse {
val dialogContext = DialogContext(bank, customer, product) val dialogContext = DialogContext(bank, customer, product)
@ -375,7 +374,7 @@ open class FinTsClient(
balance) 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) 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 { tanMediumClass: TanMediumKlasse = TanMediumKlasse.AlleMedien): GetTanMediaListResponse {
val response = sendMessageAndHandleResponse(bank, customer) { dialogContext -> 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 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 { customer: CustomerData, account: AccountData): FinTsClientResponse {
val response = sendMessageAndHandleResponse(bank, customer) { dialogContext -> 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 { createMessage: (DialogContext) -> MessageBuilderResult): Response {
val dialogContext = DialogContext(bank, customer, product) val dialogContext = DialogContext(bank, customer, product)
@ -477,7 +476,7 @@ open class FinTsClient(
return response 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 // we first need to retrieve supported tan procedures and jobs before we can do anything
val retrieveBasicBankDataResponse = ensureBasicBankDataRetrieved(dialogContext.bank, dialogContext.customer) val retrieveBasicBankDataResponse = ensureBasicBankDataRetrieved(dialogContext.bank, dialogContext.customer)
@ -495,7 +494,7 @@ open class FinTsClient(
return initDialogAfterSuccessfulChecks(dialogContext) return initDialogAfterSuccessfulChecks(dialogContext)
} }
protected open suspend fun initDialogAfterSuccessfulChecks(dialogContext: DialogContext): Response { protected open fun initDialogAfterSuccessfulChecks(dialogContext: DialogContext): Response {
val message = messageBuilder.createInitDialogMessage(dialogContext) val message = messageBuilder.createInitDialogMessage(dialogContext)
@ -510,7 +509,7 @@ open class FinTsClient(
return response 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 // bank already closed dialog -> there's no need to send dialog end message
if (areWeThatGentleToCloseDialogs == false || dialogContext.didBankCloseDialog) { 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()) { if (bank.supportedTanProcedures.isEmpty() || bank.supportedJobs.isEmpty()) {
val getBankInfoResponse = getBankAndCustomerInfoForNewUser(bank, customer) val getBankInfoResponse = getBankAndCustomerInfoForNewUser(bank, customer)
@ -538,7 +537,7 @@ open class FinTsClient(
return Response(true) 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.isTanProcedureSelected == false) {
if (customer.supportedTanProcedures.isEmpty()) { if (customer.supportedTanProcedures.isEmpty()) {
getBankAndCustomerInfoForNewUser(bank, customer) 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) val response = if (message.createdMessage == null) Response(false, messageCreationError = message)
else getAndHandleResponseForMessage(message.createdMessage, dialogContext) else getAndHandleResponseForMessage(message.createdMessage, dialogContext)
@ -597,7 +596,7 @@ open class FinTsClient(
return handledResponse 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) addMessageLog(requestBody, MessageLogEntryType.Sent, dialogContext)
val webResponse = getResponseForMessage(requestBody, dialogContext.bank.finTs3ServerAddress) val webResponse = getResponseForMessage(requestBody, dialogContext.bank.finTs3ServerAddress)
@ -612,13 +611,13 @@ open class FinTsClient(
return response 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) val encodedRequestBody = base64Service.encode(requestBody)
return webClient.post(finTs3ServerAddress, encodedRequestBody, "application/octet-stream") 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 -> message.createdMessage?.let { requestBody ->
addMessageLog(requestBody, MessageLogEntryType.Sent, dialogContext) addMessageLog(requestBody, MessageLogEntryType.Sent, dialogContext)
@ -638,7 +637,7 @@ open class FinTsClient(
addMessageLog(decodedResponse, MessageLogEntryType.Received, dialogContext) addMessageLog(decodedResponse, MessageLogEntryType.Received, dialogContext)
return responseParser.parse(decodedResponse) // TODO: make suspendable return responseParser.parse(decodedResponse)
} catch (e: Exception) { } catch (e: Exception) {
log.error(e) { "Could not decode responseBody:\r\n'$responseBody'" } 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? { dialogContext: DialogContext): Response? {
messageBuilder.rebuildMessageWithContinuationId(message, continuationId, dialogContext)?.let { followUpMessage -> 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 (response.isStrongAuthenticationRequired) {
if (dialogContext.abortIfTanIsRequired) { 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) val message = messageBuilder.createSendEnteredTanMessage(enteredTan, tanResponse, dialogContext)
return getAndHandleResponseForMessage(message, 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 dialogContext.customer.selectedTanProcedure = changeTanProcedureTo
@ -798,7 +797,7 @@ open class FinTsClient(
return resendMessageInNewDialog(lastCreatedMessage, dialogContext) return resendMessageInNewDialog(lastCreatedMessage, dialogContext)
} }
protected open suspend fun handleUserAsksToChangeTanMediumAndResendLastMessage(changeTanMediumTo: TanGeneratorTanMedium, protected open fun handleUserAsksToChangeTanMediumAndResendLastMessage(changeTanMediumTo: TanGeneratorTanMedium,
dialogContext: DialogContext, dialogContext: DialogContext,
changeTanMediumResultCallback: ((FinTsClientResponse) -> Unit)?): Response { 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 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) val newDialogContext = DialogContext(previousDialogContext.bank, previousDialogContext.customer, previousDialogContext.product, chunkedResponseHandler = previousDialogContext.chunkedResponseHandler)

View File

@ -38,7 +38,7 @@ open class FinTsClientForCustomer(
client.addAccountAsync(bank, customer, callback) client.addAccountAsync(bank, customer, callback)
} }
open suspend fun addAccount(): AddAccountResponse { open fun addAccount(): AddAccountResponse {
return client.addAccount(bank, customer) return client.addAccount(bank, customer)
} }
@ -47,7 +47,7 @@ open class FinTsClientForCustomer(
client.getTransactionsAsync(parameter, bank, customer, account, callback) 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) return client.getTransactions(parameter, bank, customer, account)
} }
@ -56,7 +56,7 @@ open class FinTsClientForCustomer(
client.doBankTransferAsync(bankTransferData, bank, customer, account, callback) 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) return client.doBankTransfer(bankTransferData, bank, customer, account)
} }

View File

@ -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
} }

View File

@ -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 { try {
val clientResponse = client.post<HttpResponse>(url) { val job = GlobalScope.async {
this.body = TextContent(body, contentType = ContentType.Application.OctetStream) try {
val clientResponse = client.post<HttpResponse>(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) { } catch (e: Exception) {
log.error(e) { "Could not send request to url '$url'" }
return WebClientResponse(false, error = e) return WebClientResponse(false, error = e)
} }
} }