Made FinTsClient methods suspendable; could remove ThreadPool for that

This commit is contained in:
dankito 2020-06-14 21:09:36 +02:00
parent 2406fa51e6
commit 9a5e0a1098
11 changed files with 76 additions and 92 deletions

View File

@ -3,6 +3,8 @@ package net.dankito.banking.fints
import com.soywiz.klock.DateTime import com.soywiz.klock.DateTime
import com.soywiz.klock.DateTimeSpan import com.soywiz.klock.DateTimeSpan
import com.soywiz.klock.DateTimeTz import com.soywiz.klock.DateTimeTz
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import net.dankito.banking.fints.callback.FinTsClientCallback import net.dankito.banking.fints.callback.FinTsClientCallback
import net.dankito.banking.fints.messages.MessageBuilder import net.dankito.banking.fints.messages.MessageBuilder
import net.dankito.banking.fints.messages.MessageBuilderResult import net.dankito.banking.fints.messages.MessageBuilderResult
@ -40,7 +42,6 @@ open class FinTsClient(
protected val callback: FinTsClientCallback, protected val callback: FinTsClientCallback,
protected val webClient: IWebClient = KtorWebClient(), protected val webClient: IWebClient = KtorWebClient(),
protected val base64Service: IBase64Service = PureKotlinBase64Service(), protected val base64Service: IBase64Service = PureKotlinBase64Service(),
protected val threadPool: IThreadPool,
protected val messageBuilder: MessageBuilder = MessageBuilder(), protected val messageBuilder: MessageBuilder = MessageBuilder(),
protected val responseParser: ResponseParser = ResponseParser(), protected val responseParser: ResponseParser = ResponseParser(),
protected val mt940Parser: IAccountTransactionsParser = Mt940AccountTransactionsParser(), protected val mt940Parser: IAccountTransactionsParser = Mt940AccountTransactionsParser(),
@ -73,7 +74,7 @@ open class FinTsClient(
*/ */
open fun getAnonymousBankInfoAsync(bank: BankData, callback: (FinTsClientResponse) -> Unit) { open fun getAnonymousBankInfoAsync(bank: BankData, callback: (FinTsClientResponse) -> Unit) {
threadPool.runAsync { GlobalScope.launch {
callback(getAnonymousBankInfo(bank)) callback(getAnonymousBankInfo(bank))
} }
} }
@ -84,7 +85,7 @@ open class FinTsClient(
* *
* On success [bank] parameter is updated afterwards. * On success [bank] parameter is updated afterwards.
*/ */
open fun getAnonymousBankInfo(bank: BankData): FinTsClientResponse { open suspend 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)
@ -100,7 +101,7 @@ open class FinTsClient(
return FinTsClientResponse(response) return FinTsClientResponse(response)
} }
protected open fun closeAnonymousDialog(dialogContext: DialogContext, response: Response) { protected open suspend 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) {
@ -113,7 +114,7 @@ open class FinTsClient(
} }
open fun getBankAndCustomerInfoForNewUser(bank: BankData, customer: CustomerData): AddAccountResponse { open suspend 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()
@ -147,7 +148,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 fun getBankAndCustomerInfoForNewUserViaAnonymousDialog(bank: BankData, customer: CustomerData): AddAccountResponse { protected open suspend fun getBankAndCustomerInfoForNewUserViaAnonymousDialog(bank: BankData, customer: CustomerData): AddAccountResponse {
val anonymousBankInfoResponse = getAnonymousBankInfo(bank) val anonymousBankInfoResponse = getAnonymousBankInfo(bank)
if (anonymousBankInfoResponse.isSuccessful == false) { if (anonymousBankInfoResponse.isSuccessful == false) {
@ -182,7 +183,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 fun synchronizeCustomerSystemId(bank: BankData, customer: CustomerData): FinTsClientResponse { protected open suspend 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)
@ -203,12 +204,12 @@ open class FinTsClient(
open fun addAccountAsync(bank: BankData, customer: CustomerData, open fun addAccountAsync(bank: BankData, customer: CustomerData,
callback: (AddAccountResponse) -> Unit) { callback: (AddAccountResponse) -> Unit) {
threadPool.runAsync { GlobalScope.launch {
callback(addAccount(bank, customer)) callback(addAccount(bank, customer))
} }
} }
open fun addAccount(bank: BankData, customer: CustomerData): AddAccountResponse { open suspend fun addAccount(bank: BankData, customer: CustomerData): AddAccountResponse {
val originalAreWeThatGentleToCloseDialogs = areWeThatGentleToCloseDialogs val originalAreWeThatGentleToCloseDialogs = areWeThatGentleToCloseDialogs
areWeThatGentleToCloseDialogs = false areWeThatGentleToCloseDialogs = false
@ -278,11 +279,11 @@ open class FinTsClient(
* *
* Check if bank supports this. * Check if bank supports this.
*/ */
open fun tryGetTransactionsOfLast90DaysWithoutTan(bank: BankData, customer: CustomerData, account: AccountData): GetTransactionsResponse { open suspend fun tryGetTransactionsOfLast90DaysWithoutTan(bank: BankData, customer: CustomerData, account: AccountData): GetTransactionsResponse {
return tryGetTransactionsOfLast90DaysWithoutTan(bank, customer, account, false) return tryGetTransactionsOfLast90DaysWithoutTan(bank, customer, account, false)
} }
protected open fun tryGetTransactionsOfLast90DaysWithoutTan(bank: BankData, customer: CustomerData, account: AccountData, protected open suspend fun tryGetTransactionsOfLast90DaysWithoutTan(bank: BankData, customer: CustomerData, account: AccountData,
hasRetrievedTransactionsWithTanJustBefore: Boolean): GetTransactionsResponse { hasRetrievedTransactionsWithTanJustBefore: Boolean): GetTransactionsResponse {
val now = DateTimeTz.nowLocal() val now = DateTimeTz.nowLocal()
@ -306,12 +307,12 @@ open class FinTsClient(
open fun getTransactionsAsync(parameter: GetTransactionsParameter, bank: BankData, open fun getTransactionsAsync(parameter: GetTransactionsParameter, bank: BankData,
customer: CustomerData, account: AccountData, callback: (GetTransactionsResponse) -> Unit) { customer: CustomerData, account: AccountData, callback: (GetTransactionsResponse) -> Unit) {
threadPool.runAsync { GlobalScope.launch {
callback(getTransactions(parameter, bank, customer, account)) callback(getTransactions(parameter, bank, customer, account))
} }
} }
open fun getTransactions(parameter: GetTransactionsParameter, bank: BankData, open suspend 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)
@ -374,7 +375,7 @@ open class FinTsClient(
balance) balance)
} }
protected open fun getBalanceAfterDialogInit(account: AccountData, dialogContext: DialogContext): Response { protected open suspend fun getBalanceAfterDialogInit(account: AccountData, dialogContext: DialogContext): Response {
val message = messageBuilder.createGetBalanceMessage(account, dialogContext) val message = messageBuilder.createGetBalanceMessage(account, dialogContext)
@ -387,12 +388,12 @@ open class FinTsClient(
tanMediumClass: TanMediumKlasse = TanMediumKlasse.AlleMedien, tanMediumClass: TanMediumKlasse = TanMediumKlasse.AlleMedien,
callback: (GetTanMediaListResponse) -> Unit) { callback: (GetTanMediaListResponse) -> Unit) {
threadPool.runAsync { GlobalScope.launch {
callback(getTanMediaList(bank, customer)) callback(getTanMediaList(bank, customer))
} }
} }
open fun getTanMediaList(bank: BankData, customer: CustomerData, tanMediaKind: TanMedienArtVersion = TanMedienArtVersion.Alle, open suspend 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 ->
@ -411,7 +412,7 @@ open class FinTsClient(
} }
open fun changeTanMedium(newActiveTanMedium: TanGeneratorTanMedium, bank: BankData, customer: CustomerData): FinTsClientResponse { open suspend fun changeTanMedium(newActiveTanMedium: TanGeneratorTanMedium, bank: BankData, customer: CustomerData): FinTsClientResponse {
var enteredAtc: EnterTanGeneratorAtcResult? = null var enteredAtc: EnterTanGeneratorAtcResult? = null
@ -438,12 +439,12 @@ open class FinTsClient(
open fun doBankTransferAsync(bankTransferData: BankTransferData, bank: BankData, open fun doBankTransferAsync(bankTransferData: BankTransferData, bank: BankData,
customer: CustomerData, account: AccountData, callback: (FinTsClientResponse) -> Unit) { customer: CustomerData, account: AccountData, callback: (FinTsClientResponse) -> Unit) {
threadPool.runAsync { GlobalScope.launch {
callback(doBankTransfer(bankTransferData, bank, customer, account)) callback(doBankTransfer(bankTransferData, bank, customer, account))
} }
} }
open fun doBankTransfer(bankTransferData: BankTransferData, bank: BankData, open suspend 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 ->
@ -454,7 +455,7 @@ open class FinTsClient(
} }
protected open fun sendMessageAndHandleResponse(bank: BankData, customer: CustomerData, messageMayRequiresTan: Boolean = true, protected open suspend 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)
@ -476,7 +477,7 @@ open class FinTsClient(
return response return response
} }
protected open fun initDialog(dialogContext: DialogContext): Response { protected open suspend 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)
@ -494,7 +495,7 @@ open class FinTsClient(
return initDialogAfterSuccessfulChecks(dialogContext) return initDialogAfterSuccessfulChecks(dialogContext)
} }
protected open fun initDialogAfterSuccessfulChecks(dialogContext: DialogContext): Response { protected open suspend fun initDialogAfterSuccessfulChecks(dialogContext: DialogContext): Response {
val message = messageBuilder.createInitDialogMessage(dialogContext) val message = messageBuilder.createInitDialogMessage(dialogContext)
@ -509,7 +510,7 @@ open class FinTsClient(
return response return response
} }
protected open fun closeDialog(dialogContext: DialogContext) { protected open suspend 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) {
@ -522,7 +523,7 @@ open class FinTsClient(
} }
protected open fun ensureBasicBankDataRetrieved(bank: BankData, customer: CustomerData): Response { protected open suspend 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)
@ -537,7 +538,7 @@ open class FinTsClient(
return Response(true) return Response(true)
} }
protected open fun ensureTanProcedureIsSelected(bank: BankData, customer: CustomerData): Response { protected open suspend 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)
@ -573,7 +574,7 @@ open class FinTsClient(
} }
protected open fun getAndHandleResponseForMessage(message: MessageBuilderResult, dialogContext: DialogContext): Response { protected open suspend 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)
@ -596,7 +597,7 @@ open class FinTsClient(
return handledResponse return handledResponse
} }
protected open fun getAndHandleResponseForMessage(requestBody: String, dialogContext: DialogContext): Response { protected open suspend 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)
@ -611,13 +612,13 @@ open class FinTsClient(
return response return response
} }
protected open fun getResponseForMessage(requestBody: String, finTs3ServerAddress: String): WebClientResponse { protected open suspend 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 fun fireAndForgetMessage(message: MessageBuilderResult, dialogContext: DialogContext) { protected open suspend fun fireAndForgetMessage(message: MessageBuilderResult, dialogContext: DialogContext) {
message.createdMessage?.let { requestBody -> message.createdMessage?.let { requestBody ->
addMessageLog(requestBody, MessageLogEntryType.Sent, dialogContext) addMessageLog(requestBody, MessageLogEntryType.Sent, dialogContext)
@ -627,7 +628,7 @@ open class FinTsClient(
} }
} }
protected open fun handleResponse(webResponse: WebClientResponse, dialogContext: DialogContext): Response { protected open suspend fun handleResponse(webResponse: WebClientResponse, dialogContext: DialogContext): Response {
val responseBody = webResponse.body val responseBody = webResponse.body
if (webResponse.successful && responseBody != null) { if (webResponse.successful && responseBody != null) {
@ -637,7 +638,7 @@ open class FinTsClient(
addMessageLog(decodedResponse, MessageLogEntryType.Received, dialogContext) addMessageLog(decodedResponse, MessageLogEntryType.Received, dialogContext)
return responseParser.parse(decodedResponse) return responseParser.parse(decodedResponse) // TODO: make suspendable
} 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'" }
@ -657,7 +658,7 @@ open class FinTsClient(
} }
protected open fun getFollowUpMessageForContinuationId(response: Response, continuationId: String, message: MessageBuilderResult, protected open suspend 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 ->
@ -717,7 +718,7 @@ open class FinTsClient(
} }
protected open fun handleMayRequiresTan(response: Response, dialogContext: DialogContext): Response { // TODO: use response from DialogContext protected open suspend fun handleMayRequiresTan(response: Response, dialogContext: DialogContext): Response { // TODO: use response from DialogContext
if (response.isStrongAuthenticationRequired) { if (response.isStrongAuthenticationRequired) {
if (dialogContext.abortIfTanIsRequired) { if (dialogContext.abortIfTanIsRequired) {
@ -778,14 +779,14 @@ open class FinTsClient(
} }
} }
protected open fun sendTanToBank(enteredTan: String, tanResponse: TanResponse, dialogContext: DialogContext): Response { protected open suspend 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 fun handleUserAsksToChangeTanProcedureAndResendLastMessage(changeTanProcedureTo: TanProcedure, dialogContext: DialogContext): Response { protected open suspend fun handleUserAsksToChangeTanProcedureAndResendLastMessage(changeTanProcedureTo: TanProcedure, dialogContext: DialogContext): Response {
dialogContext.customer.selectedTanProcedure = changeTanProcedureTo dialogContext.customer.selectedTanProcedure = changeTanProcedureTo
@ -797,7 +798,7 @@ open class FinTsClient(
return resendMessageInNewDialog(lastCreatedMessage, dialogContext) return resendMessageInNewDialog(lastCreatedMessage, dialogContext)
} }
protected open fun handleUserAsksToChangeTanMediumAndResendLastMessage(changeTanMediumTo: TanGeneratorTanMedium, protected open suspend fun handleUserAsksToChangeTanMediumAndResendLastMessage(changeTanMediumTo: TanGeneratorTanMedium,
dialogContext: DialogContext, dialogContext: DialogContext,
changeTanMediumResultCallback: ((FinTsClientResponse) -> Unit)?): Response { changeTanMediumResultCallback: ((FinTsClientResponse) -> Unit)?): Response {
@ -819,7 +820,7 @@ open class FinTsClient(
} }
protected open fun resendMessageInNewDialog(lastCreatedMessage: MessageBuilderResult?, previousDialogContext: DialogContext): Response { protected open suspend 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

@ -10,7 +10,6 @@ import net.dankito.banking.fints.response.client.GetTransactionsResponse
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.webclient.IWebClient import net.dankito.banking.fints.webclient.IWebClient
import net.dankito.banking.fints.webclient.KtorWebClient import net.dankito.banking.fints.webclient.KtorWebClient
@ -22,14 +21,13 @@ open class FinTsClientForCustomer(
callback: FinTsClientCallback, callback: FinTsClientCallback,
webClient: IWebClient = KtorWebClient(), webClient: IWebClient = KtorWebClient(),
base64Service: IBase64Service = PureKotlinBase64Service(), base64Service: IBase64Service = PureKotlinBase64Service(),
threadPool: IThreadPool,
messageBuilder: MessageBuilder = MessageBuilder(), messageBuilder: MessageBuilder = MessageBuilder(),
responseParser: ResponseParser = ResponseParser(), responseParser: ResponseParser = ResponseParser(),
mt940Parser: IAccountTransactionsParser = Mt940AccountTransactionsParser(), mt940Parser: IAccountTransactionsParser = Mt940AccountTransactionsParser(),
product: ProductData = ProductData("15E53C26816138699C7B6A3E8", "1.0.0") // TODO: get version dynamically product: ProductData = ProductData("15E53C26816138699C7B6A3E8", "1.0.0") // TODO: get version dynamically
) { ) {
protected val client = FinTsClient(callback, webClient, base64Service, threadPool, messageBuilder, responseParser, mt940Parser, product) protected val client = FinTsClient(callback, webClient, base64Service, messageBuilder, responseParser, mt940Parser, product)
open val messageLogWithoutSensitiveData: List<MessageLogEntry> open val messageLogWithoutSensitiveData: List<MessageLogEntry>
@ -40,12 +38,26 @@ open class FinTsClientForCustomer(
client.addAccountAsync(bank, customer, callback) client.addAccountAsync(bank, customer, callback)
} }
open suspend fun addAccount(): AddAccountResponse {
return client.addAccount(bank, customer)
}
open fun getTransactionsAsync(parameter: GetTransactionsParameter, account: AccountData, callback: (GetTransactionsResponse) -> Unit) { open fun getTransactionsAsync(parameter: GetTransactionsParameter, account: AccountData, callback: (GetTransactionsResponse) -> Unit) {
client.getTransactionsAsync(parameter, bank, customer, account, callback) client.getTransactionsAsync(parameter, bank, customer, account, callback)
} }
open suspend fun getTransactions(parameter: GetTransactionsParameter, account: AccountData): GetTransactionsResponse {
return client.getTransactions(parameter, bank, customer, account)
}
open fun doBankTransferAsync(bankTransferData: BankTransferData, account: AccountData, callback: (FinTsClientResponse) -> Unit) { open fun doBankTransferAsync(bankTransferData: BankTransferData, account: AccountData, callback: (FinTsClientResponse) -> Unit) {
client.doBankTransferAsync(bankTransferData, bank, customer, account, callback) client.doBankTransferAsync(bankTransferData, bank, customer, account, callback)
} }
open suspend fun doBankTransfer(bankTransferData: BankTransferData, account: AccountData): FinTsClientResponse {
return client.doBankTransfer(bankTransferData, bank, customer, account)
}
} }

View File

@ -20,6 +20,6 @@ interface IWebClient {
} }
fun post(url: String, body: String, contentType: String = "application/octet-stream", userAgent: String = DefaultUserAgent) : WebClientResponse suspend fun post(url: String, body: String, contentType: String = "application/octet-stream", userAgent: String = DefaultUserAgent) : WebClientResponse
} }

View File

@ -34,29 +34,20 @@ open class KtorWebClient : IWebClient {
} }
override fun post(url: String, body: String, contentType: String, userAgent: String): WebClientResponse { override suspend fun post(url: String, body: String, contentType: String, userAgent: String): WebClientResponse {
try { try {
val job = GlobalScope.async { val clientResponse = client.post<HttpResponse>(url) {
try { this.body = TextContent(body, contentType = ContentType.Application.OctetStream)
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)
}
} }
while (job.isCompleted == false) { } // let's warm the CPU to get suspend function synchronous (runBlocking is not available in common projects) val responseBody = clientResponse.readText()
return job.getCompleted() return WebClientResponse(clientResponse.status.value == 200, clientResponse.status.value, body = responseBody)
} 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)
} }
} }
} }

View File

@ -33,16 +33,13 @@ import kotlin.test.Test
@Ignore // not an automatic test, supply your settings below @Ignore // not an automatic test, supply your settings below
abstract class FinTsClientTestBase { open class FinTsClientTestBase {
companion object { companion object {
val DateTimeFormatForUniqueBankTransferUsage = DateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS") val DateTimeFormatForUniqueBankTransferUsage = DateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS")
} }
protected abstract fun createThreadPool(): IThreadPool
private var didAskUserForTanProcedure = false private var didAskUserForTanProcedure = false
private var didAskUserToEnterTan = false private var didAskUserToEnterTan = false
@ -69,7 +66,7 @@ abstract class FinTsClientTestBase {
} }
private val underTest = object : FinTsClient(callback, KtorWebClient(), PureKotlinBase64Service(), createThreadPool()) { private val underTest = object : FinTsClient(callback, KtorWebClient(), PureKotlinBase64Service()) {
fun testSynchronizeCustomerSystemId(bank: BankData, customer: CustomerData): FinTsClientResponse { fun testSynchronizeCustomerSystemId(bank: BankData, customer: CustomerData): FinTsClientResponse {
return synchronizeCustomerSystemId(bank, customer) return synchronizeCustomerSystemId(bank, customer)

View File

@ -1,12 +0,0 @@
package net.dankito.banking.fints
import net.dankito.banking.fints.util.*
class FinTsClientTestJvm : FinTsClientTestBase() {
override fun createThreadPool(): IThreadPool {
return JavaThreadPool()
}
}

View File

@ -1,5 +1,6 @@
package net.dankito.banking.fints.bankdetails package net.dankito.banking.fints.bankdetails
import kotlinx.coroutines.runBlocking
import net.dankito.banking.fints.FinTsClient import net.dankito.banking.fints.FinTsClient
import net.dankito.banking.bankfinder.InMemoryBankFinder import net.dankito.banking.bankfinder.InMemoryBankFinder
import net.dankito.banking.fints.callback.NoOpFinTsClientCallback import net.dankito.banking.fints.callback.NoOpFinTsClientCallback
@ -48,9 +49,9 @@ class BanksFinTsDetailsRetriever {
private val messageBuilder = MessageBuilder() private val messageBuilder = MessageBuilder()
private val finTsClient = object : FinTsClient(NoOpFinTsClientCallback(), KtorWebClient(), PureKotlinBase64Service(), JavaThreadPool()) { private val finTsClient = object : FinTsClient(NoOpFinTsClientCallback(), KtorWebClient(), PureKotlinBase64Service()) {
fun getAndHandleResponseForMessagePublic(message: MessageBuilderResult, dialogContext: DialogContext): Response { suspend fun getAndHandleResponseForMessagePublic(message: MessageBuilderResult, dialogContext: DialogContext): Response {
return getAndHandleResponseForMessage(message, dialogContext) return getAndHandleResponseForMessage(message, dialogContext)
} }
@ -124,7 +125,7 @@ class BanksFinTsDetailsRetriever {
} }
private fun getAnonymousBankInfo(bank: BankData): Response { private suspend fun getAnonymousBankInfo(bank: BankData): Response {
val dialogContext = DialogContext(bank, CustomerData.Anonymous, product) val dialogContext = DialogContext(bank, CustomerData.Anonymous, product)
val requestBody = messageBuilder.createAnonymousDialogInitMessage(dialogContext) val requestBody = messageBuilder.createAnonymousDialogInitMessage(dialogContext)
@ -135,7 +136,7 @@ class BanksFinTsDetailsRetriever {
return anonymousBankInfoResponse return anonymousBankInfoResponse
} }
private fun getAndSaveBankDetails(bankInfo: BankInfo, responsesFolder: File, csvPrinter: CSVPrinter) { private fun getAndSaveBankDetails(bankInfo: BankInfo, responsesFolder: File, csvPrinter: CSVPrinter) = runBlocking {
val bank = bankDataMapper.mapFromBankInfo(bankInfo) val bank = bankDataMapper.mapFromBankInfo(bankInfo)
val anonymousBankInfoResponse = getAnonymousBankInfo(bank) val anonymousBankInfoResponse = getAnonymousBankInfo(bank)
@ -147,7 +148,7 @@ class BanksFinTsDetailsRetriever {
requestNotSuccessful.add(bankInfo) requestNotSuccessful.add(bankInfo)
log.warn("Did not receive response from bank $bankInfo: ${anonymousBankInfoResponse.receivedSegments.joinToString(System.lineSeparator()) { it.segmentString + Separators.SegmentSeparator }}") log.warn("Did not receive response from bank $bankInfo: ${anonymousBankInfoResponse.receivedSegments.joinToString(System.lineSeparator()) { it.segmentString + Separators.SegmentSeparator }}")
return return@runBlocking
} }

View File

@ -113,8 +113,8 @@ class BankingModule(private val applicationContext: Context) {
@Provides @Provides
@Singleton @Singleton
fun provideBankingClientCreator(webClient: IWebClient, base64Service: net.dankito.banking.util.IBase64Service) : IBankingClientCreator { fun provideBankingClientCreator() : IBankingClientCreator {
return fints4kBankingClientCreator(webClient, base64Service) return fints4kBankingClientCreator()
} }
@Provides @Provides

View File

@ -40,7 +40,7 @@ class MainWindow : View(messages["application.title"]) {
tesseractTextExtractor, TikaTextExtractor() tesseractTextExtractor, TikaTextExtractor()
)) ))
private val presenter = BankingPresenter(fints4kBankingClientCreator(OkHttpWebClient(), Base64ServiceJava8()), private val presenter = BankingPresenter(fints4kBankingClientCreator(),
LuceneBankFinder(indexFolder), dataFolder, LuceneBankingPersistence(indexFolder, databaseFolder), LuceneBankFinder(indexFolder), dataFolder, LuceneBankingPersistence(indexFolder, databaseFolder),
LuceneRemitteeSearcher(indexFolder), BankIconFinder(), textExtractorRegistry, RouterJavaFx()) LuceneRemitteeSearcher(indexFolder), BankIconFinder(), textExtractorRegistry, RouterJavaFx())
// private val presenter = BankingPresenter(hbci4jBankingClientCreator(), LuceneBankFinder(indexFolder), // private val presenter = BankingPresenter(hbci4jBankingClientCreator(), LuceneBankFinder(indexFolder),

View File

@ -21,8 +21,6 @@ import net.dankito.banking.fints.model.*
import net.dankito.banking.mapper.BankDataMapper import net.dankito.banking.mapper.BankDataMapper
import net.dankito.banking.fints.util.IBase64Service import net.dankito.banking.fints.util.IBase64Service
import net.dankito.banking.fints.util.PureKotlinBase64Service import net.dankito.banking.fints.util.PureKotlinBase64Service
import net.dankito.banking.fints.util.IThreadPool
import net.dankito.banking.fints.util.JavaThreadPool
import net.dankito.utils.serialization.JacksonJsonSerializer import net.dankito.utils.serialization.JacksonJsonSerializer
import net.dankito.banking.fints.webclient.IWebClient import net.dankito.banking.fints.webclient.IWebClient
import net.dankito.banking.fints.webclient.KtorWebClient import net.dankito.banking.fints.webclient.KtorWebClient
@ -38,7 +36,6 @@ open class fints4kBankingClient(
protected val dataFolder: File, protected val dataFolder: File,
webClient: IWebClient = KtorWebClient(), webClient: IWebClient = KtorWebClient(),
base64Service: IBase64Service = PureKotlinBase64Service(), base64Service: IBase64Service = PureKotlinBase64Service(),
threadPool: IThreadPool = JavaThreadPool(),
callback: BankingClientCallback callback: BankingClientCallback
) : IBankingClient { ) : IBankingClient {
@ -92,7 +89,7 @@ open class fints4kBankingClient(
return mapper.mapEnterTanGeneratorAtcResult(result) return mapper.mapEnterTanGeneratorAtcResult(result)
} }
}, webClient, base64Service, threadPool) }, webClient, base64Service)
override val messageLogWithoutSensitiveData: List<MessageLogEntry> override val messageLogWithoutSensitiveData: List<MessageLogEntry>

View File

@ -10,17 +10,14 @@ import net.dankito.utils.web.client.IWebClient
import java.io.File import java.io.File
open class fints4kBankingClientCreator( open class fints4kBankingClientCreator : IBankingClientCreator {
protected val webClient: IWebClient, // TODO: remove?
protected val base64Service: IBase64Service // TODO: remove?
) : IBankingClientCreator {
override fun createClient( override fun createClient(
bankInfo: BankInfo, bankInfo: BankInfo,
customerId: String, customerId: String,
pin: String, pin: String,
dataFolder: File, dataFolder: File,
threadPool: IThreadPool, // TODO: remove? threadPool: IThreadPool,
callback: BankingClientCallback callback: BankingClientCallback
): IBankingClient { ): IBankingClient {