Started FinTsClientSwift but which results due Kotlin/Native's shared XOR mutable in very ugly code

This commit is contained in:
dankito 2020-07-06 15:26:45 +02:00
parent 7e19930742
commit fa6fdd0800
3 changed files with 255 additions and 0 deletions

View File

@ -0,0 +1,32 @@
import com.soywiz.klock.Date
import kotlinx.cinterop.addressOf
import kotlinx.cinterop.convert
import kotlinx.cinterop.usePinned
import platform.Foundation.*
fun String.toNsData(): NSData {
return this.encodeToByteArray().toNSData()
}
fun ByteArray.toNSData(): NSData = NSMutableData().apply {
if (isEmpty()) return@apply
this@toNSData.usePinned {
appendBytes(it.addressOf(0), size.convert())
}
}
fun NSDate?.toDate(): Date? {
return this?.toDate()
}
fun NSDate.toDate(): Date {
val calendar = NSCalendar.currentCalendar()
return Date.invoke(
calendar.component(NSCalendarUnitYear, this).toInt(),
calendar.component(NSCalendarUnitMonth, this).toInt(),
calendar.component(NSCalendarUnitDay, this).toInt()
)
}

View File

@ -0,0 +1,207 @@
import net.dankito.banking.fints.FinTsClient
import net.dankito.banking.fints.callback.FinTsClientCallback
import net.dankito.banking.fints.model.AccountData
import net.dankito.banking.fints.model.AccountFeature
import net.dankito.banking.fints.model.BankData
import net.dankito.banking.fints.model.CustomerData
import net.dankito.banking.fints.response.client.AddAccountResponse
import net.dankito.banking.fints.response.client.FinTsClientResponse
import net.dankito.banking.fints.response.client.GetTransactionsResponse
import net.dankito.banking.fints.util.log.LoggerFactory
import net.dankito.banking.fints.webclient.IWebClient
import kotlin.native.concurrent.TransferMode
import kotlin.native.concurrent.Worker
import kotlin.native.concurrent.freeze
open class FinTsClientWorkerArgument(val bank: BankData, val customer: CustomerData, val webClient: IWebClient, val callback: FinTsClientCallback)
class GetTransactionsWorkerArgument(val parameter: GetTransactionsParameter, val account: AccountData,
bank: BankData, customer: CustomerData, webClient: IWebClient, callback: FinTsClientCallback)
: FinTsClientWorkerArgument(bank, customer, webClient, callback)
data class FinTsClientWorkerResult<T : FinTsClientResponse>(
val bank: BankData, val customer: CustomerData, val response: T)
open class FinTsClientSwift(
protected val bank: BankData,
protected val customer: CustomerData,
protected val webClient: IWebClient,
protected val callback: FinTsClientCallback
) {
init {
webClient.freeze()
callback.freeze()
}
protected val worker = Worker.start(name = "FinTsClient worker for $customer")
open fun addAccountAsync(callback: (AddAccountResponse) -> Unit) {
val future = worker.execute(TransferMode.SAFE, { createWorkerArgument() }) { arg ->
val client = FinTsClient(arg.callback, arg.webClient)
// unbelievable, i am not allowed to use the createCopy() methods
val bank = BankData(
arg.bank.bankCode, arg.bank.countryCode, arg.bank.finTs3ServerAddress, arg.bank.bic, arg.bank.bpdVersion,
arg.bank.name, arg.bank.countMaxJobsPerMessage, arg.bank.supportedHbciVersions, arg.bank.supportedTanProcedures,
arg.bank.changeTanMediumParameters, arg.bank.pinInfo, arg.bank.supportedLanguages, arg.bank.supportedJobs
)
val customer = CustomerData(
arg.customer.customerId, arg.customer.pin, arg.customer.userId, arg.customer.name, arg.customer.updVersion,
arg.customer.supportedTanProcedures, arg.customer.selectedTanProcedure, arg.customer.tanMedia,
arg.customer.selectedLanguage, arg.customer.customerSystemId, arg.customer.customerSystemStatus
)
val response = client.addAccount(bank, customer)
FinTsClientWorkerResult(bank.freeze(), customer.freeze(), response.freeze())
}
future.consume { result ->
map(bank, result.bank)
map(customer, result.customer)
callback(result.response)
}
}
open fun getTransactionsAsync(parameter: GetTransactionsParameter, account: AccountData, callback: (GetTransactionsResponse) -> Unit) {
val future = worker.execute(TransferMode.SAFE, { createWorkerArgument(parameter, account) }) { arg ->
val client = FinTsClient(arg.callback, arg.webClient)
// unbelievable, i am not allowed to use the createCopy() methods
val bank = BankData(
arg.bank.bankCode, arg.bank.countryCode, arg.bank.finTs3ServerAddress, arg.bank.bic, arg.bank.bpdVersion,
arg.bank.name, arg.bank.countMaxJobsPerMessage, arg.bank.supportedHbciVersions, arg.bank.supportedTanProcedures,
arg.bank.changeTanMediumParameters, arg.bank.pinInfo, arg.bank.supportedLanguages, arg.bank.supportedJobs
)
val customer = CustomerData(
arg.customer.customerId, arg.customer.pin, arg.customer.userId, arg.customer.name, arg.customer.updVersion,
arg.customer.supportedTanProcedures, arg.customer.selectedTanProcedure, arg.customer.tanMedia,
arg.customer.selectedLanguage, arg.customer.customerSystemId, arg.customer.customerSystemStatus
)
val parameter = net.dankito.banking.fints.model.GetTransactionsParameter(
arg.parameter.alsoRetrieveBalance, arg.parameter.fromDate.toDate(), arg.parameter.toDate.toDate(),
arg.parameter.maxCountEntries, arg.parameter.abortIfTanIsRequired, arg.parameter.retrievedChunkListener
)
val response = client.getTransactions(parameter, bank, customer, arg.account) // TODO: map account
FinTsClientWorkerResult(bank.freeze(), customer.freeze(), response.freeze())
}
future.consume { result ->
map(bank, result.bank)
map(customer, result.customer)
callback(result.response)
}
}
protected open fun createWorkerArgument(): FinTsClientWorkerArgument {
val bank = createImmutableCopy(this.bank)
val customer = createImmutableCopy(this.customer)
return FinTsClientWorkerArgument(bank, customer, webClient, callback)
}
protected open fun createWorkerArgument(parameter: GetTransactionsParameter, account: AccountData): GetTransactionsWorkerArgument {
val bank = createImmutableCopy(this.bank)
val customer = createImmutableCopy(this.customer)
val frozenAccount = createImmutableCopy(account)
return GetTransactionsWorkerArgument(parameter.freeze(), frozenAccount, bank, customer, webClient, callback)
}
protected open fun createCopy(bank: BankData): BankData {
return BankData(
bank.bankCode, bank.countryCode, bank.finTs3ServerAddress, bank.bic, bank.bpdVersion,
bank.name, bank.countMaxJobsPerMessage, bank.supportedHbciVersions, bank.supportedTanProcedures,
bank.changeTanMediumParameters, bank.pinInfo, bank.supportedLanguages, bank.supportedJobs
)
}
protected open fun createImmutableCopy(bank: BankData): BankData {
return createCopy(bank).freeze()
}
protected open fun createCopy(customer: CustomerData): CustomerData {
return CustomerData(
customer.customerId, customer.pin, customer.userId, customer.name, customer.updVersion,
customer.supportedTanProcedures, customer.selectedTanProcedure, customer.tanMedia,
customer.selectedLanguage, customer.customerSystemId, customer.customerSystemStatus
)
}
protected open fun createImmutableCopy(customer: CustomerData): CustomerData {
return createCopy(customer).freeze()
}
protected open fun createCopy(account: AccountData): AccountData {
val copy = AccountData(
account.accountIdentifier, account.subAccountAttribute, account.bankCountryCode,
account.bankCode, account.iban, account.customerId, account.accountType, account.currency,
account.accountHolderName, account.productName, account.accountLimit, account.allowedJobNames,
account.allowedJobs, account.supportsRetrievingTransactionsOfLast90DaysWithoutTan,
account.triedToRetrieveTransactionsOfLast90DaysWithoutTan
)
AccountFeature.values().forEach { feature ->
copy.setSupportsFeature(feature, account.supportsFeature(feature))
}
return copy
}
protected open fun createImmutableCopy(account: AccountData): AccountData {
return createCopy(account).freeze()
}
protected open fun map(to: BankData, from: BankData) {
to.bankCode = from.bankCode
to.countryCode = from.countryCode
to.finTs3ServerAddress = from.finTs3ServerAddress
to.bic = from.bic
to.bpdVersion = from.bpdVersion
to.name = from.name
to.countMaxJobsPerMessage = from.countMaxJobsPerMessage
to.supportedHbciVersions = from.supportedHbciVersions
to.supportedTanProcedures = from.supportedTanProcedures
to.changeTanMediumParameters = from.changeTanMediumParameters
to.pinInfo = from.pinInfo
to.supportedLanguages = from.supportedLanguages
to.supportedJobs = from.supportedJobs
}
protected open fun map(to: CustomerData, from: CustomerData) {
to.customerId = from.customerId
to.pin = from.pin
to.userId = from.userId
to.name = from.name
to.updVersion = from.updVersion
to.supportedTanProcedures = from.supportedTanProcedures
to.selectedTanProcedure = from.selectedTanProcedure
to.tanMedia = from.tanMedia
to.selectedLanguage = from.selectedLanguage
to.customerSystemId = from.customerSystemId
to.customerSystemStatus = from.customerSystemStatus
// TODO: create convenience method to set accounts
to.accounts.forEach { account ->
to.removeAccount(account)
}
from.accounts.forEach { account ->
to.addAccount(account) // TODO: also map account?
}
}
}

View File

@ -0,0 +1,16 @@
import net.dankito.banking.fints.model.AccountTransaction
import platform.Foundation.NSDate
class GetTransactionsParameter(
val alsoRetrieveBalance: Boolean = true,
val fromDate: NSDate? = null,
val toDate: NSDate? = null,
val maxCountEntries: Int? = null,
val abortIfTanIsRequired: Boolean = false,
val retrievedChunkListener: ((List<AccountTransaction>) -> Unit)? = null
) {
constructor() : this(true, null, null, null, false, null)
}