All Downloads are FREE. Search and download functionalities are using the official Maven repository.

nativeMain.kotbase.ReplicatorConfiguration.native.kt Maven / Gradle / Ivy

There is a newer version: 3.1.3-1.1.0
Show newest version
/*
 * Copyright 2022-2023 Jeff Lockhart
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package kotbase

import kotbase.internal.fleece.toFLArray
import kotbase.internal.fleece.toFLDict
import kotbase.internal.fleece.toKString
import kotbase.util.to
import kotlinx.cinterop.*
import libcblite.*
import kotlin.experimental.ExperimentalNativeApi
import kotlin.native.ref.createCleaner

public actual class ReplicatorConfiguration actual constructor(
    public actual val database: Database,
    public actual val target: Endpoint
) {

    public actual constructor(config: ReplicatorConfiguration) : this(
        config.database,
        config.target
    ) {
        authenticator = config.authenticator
        channels = config.channels
        conflictResolver = config.conflictResolver
        isContinuous = config.isContinuous
        documentIDs = config.documentIDs
        headers = config.headers
        pinnedServerCertificate = config.pinnedServerCertificate
        pullFilter = config.pullFilter
        pushFilter = config.pushFilter
        type = config.type
        maxAttempts = config.maxAttempts
        maxAttemptWaitTime = config.maxAttemptWaitTime
        heartbeat = config.heartbeat
        isAutoPurgeEnabled = config.isAutoPurgeEnabled
    }

    internal constructor(config: ImmutableReplicatorConfiguration) : this(
        config.database,
        config.target
    ) {
        authenticator = config.authenticator
        channels = config.channels
        conflictResolver = config.conflictResolver
        isContinuous = config.isContinuous
        documentIDs = config.documentIDs
        headers = config.headers
        isAcceptParentDomainCookies = config.isAcceptParentDomainCookies
        pinnedServerCertificate = config.pinnedServerCertificate
        pullFilter = config.pullFilter
        pushFilter = config.pushFilter
        type = config.type
        maxAttempts = config.maxAttempts
        maxAttemptWaitTime = config.maxAttemptWaitTime
        heartbeat = config.heartbeat
        isAutoPurgeEnabled = config.isAutoPurgeEnabled
    }

    public actual fun setAuthenticator(authenticator: Authenticator): ReplicatorConfiguration {
        this.authenticator = authenticator
        return this
    }

    public actual fun setChannels(channels: List?): ReplicatorConfiguration {
        this.channels = channels
        return this
    }

    public actual fun setConflictResolver(conflictResolver: ConflictResolver?): ReplicatorConfiguration {
        this.conflictResolver = conflictResolver
        return this
    }

    public actual fun setContinuous(continuous: Boolean): ReplicatorConfiguration {
        this.isContinuous = continuous
        return this
    }

    public actual fun setDocumentIDs(documentIDs: List?): ReplicatorConfiguration {
        this.documentIDs = documentIDs
        return this
    }

    public actual fun setHeaders(headers: Map?): ReplicatorConfiguration {
        this.headers = headers
        return this
    }

    public actual fun setAcceptParentDomainCookies(acceptParentCookies: Boolean): ReplicatorConfiguration {
        [email protected] = acceptParentCookies
        return this
    }

    public actual fun setPinnedServerCertificate(pinnedCert: ByteArray?): ReplicatorConfiguration {
        this.pinnedServerCertificate = pinnedCert
        return this
    }

    public actual fun setPullFilter(pullFilter: ReplicationFilter?): ReplicatorConfiguration {
        this.pullFilter = pullFilter
        return this
    }

    public actual fun setPushFilter(pushFilter: ReplicationFilter?): ReplicatorConfiguration {
        this.pushFilter = pushFilter
        return this
    }

    public actual fun setType(type: ReplicatorType): ReplicatorConfiguration {
        this.type = type
        return this
    }

    public actual fun setMaxAttempts(maxAttempts: Int): ReplicatorConfiguration {
        this.maxAttempts = maxAttempts
        return this
    }

    public actual fun setMaxAttemptWaitTime(maxAttemptWaitTime: Int): ReplicatorConfiguration {
        this.maxAttemptWaitTime = maxAttemptWaitTime
        return this
    }

    public actual fun setHeartbeat(heartbeat: Int): ReplicatorConfiguration {
        this.heartbeat = heartbeat
        return this
    }

    public actual fun setAutoPurgeEnabled(enabled: Boolean): ReplicatorConfiguration {
        this.isAutoPurgeEnabled = enabled
        return this
    }

    public actual var authenticator: Authenticator? = null

    public actual var channels: List? = null

    public actual var conflictResolver: ConflictResolver? = null

    public actual var isContinuous: Boolean = false

    public actual var documentIDs: List? = null

    public actual var headers: Map? = null

    public actual var isAcceptParentDomainCookies: Boolean = false

    public actual var pinnedServerCertificate: ByteArray? = null

    public actual var pullFilter: ReplicationFilter? = null

    public actual var pushFilter: ReplicationFilter? = null

    public actual var type: ReplicatorType = ReplicatorType.PUSH_AND_PULL

    public actual var maxAttempts: Int = 0

    public actual var maxAttemptWaitTime: Int = 0

    public actual var heartbeat: Int = 0

    public actual var isAutoPurgeEnabled: Boolean = true

    public actual companion object
}

internal class ImmutableReplicatorConfiguration(config: ReplicatorConfiguration) {

    private val memory = object {
        val arena = Arena()
        val arrays = mutableListOf()
        val dicts = mutableListOf()
        val ref = StableRef.create(this@ImmutableReplicatorConfiguration)
    }

    private fun FLArray.retain(): FLArray {
        memory.arrays.add(this)
        return this
    }

    private fun FLDict.retain(): FLDict {
        memory.dicts.add(this)
        return this
    }

    @OptIn(ExperimentalNativeApi::class)
    @Suppress("unused")
    private val cleaner = createCleaner(memory) {
        with(it) {
            arena.clear()
            arrays.forEach { array ->
                FLArray_Release(array)
            }
            dicts.forEach { dict ->
                FLDict_Release(dict)
            }
            ref.dispose()
        }
    }

    val database: Database = config.database
    val target: Endpoint = config.target
    val authenticator: Authenticator? = config.authenticator
    val channels: List? = config.channels
    val conflictResolver: ConflictResolver? = config.conflictResolver
    val isContinuous: Boolean = config.isContinuous
    val documentIDs: List? = config.documentIDs
    val headers: Map? = config.headers
    val isAcceptParentDomainCookies: Boolean = config.isAcceptParentDomainCookies
    val pinnedServerCertificate: ByteArray? = config.pinnedServerCertificate
    val pullFilter: ReplicationFilter? = config.pullFilter
    val pushFilter: ReplicationFilter? = config.pushFilter
    val type: ReplicatorType = config.type
    val maxAttempts: Int = config.maxAttempts
    val maxAttemptWaitTime: Int = config.maxAttemptWaitTime
    val heartbeat: Int = config.heartbeat
    val isAutoPurgeEnabled: Boolean = config.isAutoPurgeEnabled

    val actual: CPointer =
        memory.arena.alloc().also {
            it.acceptParentDomainCookies = config.isAcceptParentDomainCookies
            it.authenticator = config.authenticator?.actual
            it.channels = config.channels?.toFLArray()?.retain()
            it.conflictResolver = nativeConflictResolver()
            it.context = memory.ref.asCPointer()
            it.continuous = config.isContinuous
            it.database = config.database.actual
            it.disableAutoPurge = !config.isAutoPurgeEnabled
            it.documentIDs = config.documentIDs?.toFLArray()?.retain()
            it.endpoint = config.target.actual
            it.headers = config.headers?.toFLDict()?.retain()
            it.heartbeat = config.heartbeat.convert()
            it.maxAttemptWaitTime = config.maxAttemptWaitTime.convert()
            it.maxAttempts = config.maxAttempts.convert()
            it.pinnedServerCertificate.apply {
                config.pinnedServerCertificate?.let { bytes ->
                    buf = memory.arena.allocArrayOf(bytes)
                    size = bytes.size.convert()
                }
            }
            it.proxy = null
            it.pullFilter = nativePullFilter()
            it.pushFilter = nativePushFilter()
            it.replicatorType = config.type.actual
        }.ptr

    private fun nativeConflictResolver(): CBLConflictResolver? {
        if (conflictResolver == null) return null
        return staticCFunction { ref, documentId, localDocument, remoteDocument ->
            val config = ref.to()
            config.conflictResolver!!.invoke(
                Conflict(
                    documentId.toKString()!!,
                    localDocument?.asDocument(config.database),
                    remoteDocument?.asDocument(config.database)
                )
            )?.actual
        }
    }

    private fun nativePullFilter(): CBLReplicationFilter? {
        if (pullFilter == null) return null
        return staticCFunction { ref, document, flags ->
            val config = ref.to()
            config.pullFilter!!.invoke(
                Document(document!!, config.database),
                flags.toDocumentFlags()
            )
        }
    }

    private fun nativePushFilter(): CBLReplicationFilter? {
        if (pushFilter == null) return null
        return staticCFunction { ref, document, flags ->
            val config = ref.to()
            config.pushFilter!!.invoke(
                Document(document!!, config.database),
                flags.toDocumentFlags()
            )
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy