
commonMain.io.polywrap.configBuilder.BaseConfigBuilder.kt Maven / Gradle / Ivy
package io.polywrap.configBuilder
import io.polywrap.client.PolywrapClient
import io.polywrap.core.WrapEnv
import io.polywrap.core.WrapPackage
import io.polywrap.core.Wrapper
import io.polywrap.core.msgpack.EnvSerializer
import io.polywrap.core.msgpack.msgPackDecode
import io.polywrap.core.msgpack.msgPackEncode
import io.polywrap.core.resolution.UriResolver
import kotlinx.serialization.serializer
import kotlin.collections.Map
/**
* Defines a builder for creating configured [PolywrapClient] instances with support for
* adding, removing, and modifying various configuration options.
*/
abstract class BaseConfigBuilder {
/**
* Holds the current configuration being built.
*/
val config = BuilderConfig(
envs = mutableMapOf(),
interfaces = mutableMapOf(),
redirects = mutableMapOf(),
wrappers = mutableMapOf(),
packages = mutableMapOf(),
resolvers = mutableListOf(),
ffiBundles = mutableListOf()
)
/**
* Builds a [PolywrapClient] instance with the current builder configuration and
* optional additional configuration specified through a builder DSL.
*
* @return A [PolywrapClient] instance with the specified configuration.
*/
abstract fun build(): PolywrapClient
/**
* Adds all default configuration [Bundle]s to the current configuration.
*
* @return This [BaseConfigBuilder] instance for chaining calls.
*/
abstract fun addDefaults(): BaseConfigBuilder
/**
* Adds a [NativeBundle] from the FFI.
* Bundles defined in the FFI are always added to the final configuration before all other items,
* and therefore can be overwritten regardless of the order in which they are added.
*
* @return This [BaseConfigBuilder] instance for chaining calls.
*/
fun addBundle(bundle: NativeBundle): BaseConfigBuilder = this.apply {
config.ffiBundles.add(bundle)
}
/**
* Adds a [Bundle] to the current configuration.
*
* @return This [BaseConfigBuilder] instance for chaining calls.
*/
fun addBundle(bundle: Bundle): BaseConfigBuilder = this.apply {
bundle.items.forEach { (uri, item) ->
item.pkg?.let { setPackage(uri to it) }
item.implements?.forEach { addInterfaceImplementation(it.toString(), uri) }
item.redirectFrom?.forEach { setRedirect(it.toString() to uri) }
item.env?.let { addEnv(uri to it) }
}
}
/**
* Adds the given [BuilderConfig] to the current configuration.
*
* @param config The [BuilderConfig] to add.
* @return This [BaseConfigBuilder] instance for chaining calls.
*/
fun add(config: BuilderConfig): BaseConfigBuilder = this.apply {
config.envs.forEach { this.config.envs[validateUri(it.key)] = it.value }
config.redirects.forEach { setRedirect(it.toPair()) }
config.wrappers.forEach { setWrapper(it.toPair()) }
config.packages.forEach { setPackage(it.toPair()) }
config.interfaces.forEach { (interfaceUri, implementations) ->
addInterfaceImplementations(interfaceUri, implementations.toList())
}
addResolvers(config.resolvers)
}
/**
* Adds a wrapper with a specified URI key to the current configuration.
*
* @param wrapper A [Pair] of the URI key and the [Wrapper] to add.
* @return This [BaseConfigBuilder] instance for chaining calls.
*/
fun setWrapper(wrapper: Pair): BaseConfigBuilder = this.apply {
config.wrappers[validateUri(wrapper.first)] = wrapper.second
}
/**
* Adds a set of wrappers with specified URI keys to the current configuration.
*
* @param wrappers A [Map] of URI keys to [Wrapper] instances to add.
* @return This [BaseConfigBuilder] instance for chaining calls.
*/
fun setWrappers(wrappers: Map): BaseConfigBuilder = this.apply {
wrappers.forEach { setWrapper(it.toPair()) }
}
/**
* Removes a wrapper with the specified URI key from the current configuration.
*
* @param uri The URI key of the wrapper to remove.
* @return This [BaseConfigBuilder] instance for chaining calls.
*/
fun removeWrapper(uri: String): BaseConfigBuilder = this.apply {
config.wrappers.remove(validateUri(uri))
}
/**
* Adds a package with a specified URI key to the current configuration.
*
* @param wrapPackage A [Pair] of the URI key and the [WrapPackage] to add.
* @return This [BaseConfigBuilder] instance for chaining calls.
*/
fun setPackage(wrapPackage: Pair): BaseConfigBuilder = this.apply {
config.packages[validateUri(wrapPackage.first)] = wrapPackage.second
}
/**
* Adds a set of packages with specified URI keys to the current configuration.
*
* @param packages A [Map] of URI keys to [WrapPackage] instances to add.
* @return This [BaseConfigBuilder] instance for chaining calls.
*/
fun setPackages(packages: Map): BaseConfigBuilder = this.apply {
packages.forEach { setPackage(it.toPair()) }
}
/**
* Removes a package with the specified URI key from the current configuration.
*
* @param uri The URI key of the package to remove.
* @return This [BaseConfigBuilder] instance for chaining calls.
*/
fun removePackage(uri: String): BaseConfigBuilder = this.apply {
config.packages.remove(validateUri(uri))
}
/**
* Adds an environment variable with a specified URI key to the current configuration.
*
* @param env A [Pair] of the URI key and the [WrapEnv] or serializable Env class instance to add.
* @return This [BaseConfigBuilder] instance for chaining calls.
*/
inline fun addEnv(env: Pair): BaseConfigBuilder = this.apply {
val sanitizedUri = validateUri(env.first)
val existingEnv = config.envs[sanitizedUri]
if (existingEnv != null) {
val previous: WrapEnv = msgPackDecode(EnvSerializer, existingEnv).getOrThrow()
val new = if (E::class == Map::class) {
validateMapAsEnv(env.second as Map<*, *>)
} else {
val newEnv = msgPackEncode(serializer(), env.second)
msgPackDecode(EnvSerializer, newEnv).getOrThrow()
}
config.envs[sanitizedUri] = msgPackEncode(EnvSerializer, previous + new)
} else {
val newEnv = if (E::class == Map::class) {
val wrapEnv = validateMapAsEnv(env.second as Map<*, *>)
msgPackEncode(EnvSerializer, wrapEnv)
} else {
msgPackEncode(serializer(), env.second)
}
config.envs[sanitizedUri] = newEnv
}
}
/**
* Adds a set of environment variables with specified URI keys to the current configuration.
*
* @param envs A [Map] of URI keys to [WrapEnv] or serializable Env class instances to add.
* @return This [BaseConfigBuilder] instance for chaining calls.
*/
inline fun addEnvs(envs: Map): BaseConfigBuilder = this.apply {
envs.forEach { env -> addEnv(env.toPair()) }
}
/**
* Removes an environment variable with the specified URI key from the current configuration.
*
* @param uri The URI key of the environment variable to remove.
* @return This [BaseConfigBuilder] instance for chaining calls.
*/
fun removeEnv(uri: String): BaseConfigBuilder = this.apply {
config.envs.remove(validateUri(uri))
}
/**
* Sets or replaces an environment variable with a specified URI key in the current configuration.
*
* @param env A [Pair] of the URI key and the [WrapEnv] or serializable Env class instance to set.
* @return This [BaseConfigBuilder] instance for chaining calls.
*/
inline fun setEnv(env: Pair): BaseConfigBuilder = this.apply {
config.envs[validateUri(env.first)] = if (E::class == Map::class) {
val newEnv = validateMapAsEnv(env.second as Map<*, *>)
msgPackEncode(EnvSerializer, newEnv)
} else {
msgPackEncode(serializer(), env.second)
}
}
/**
* Adds an interface implementation with the specified interface and implementation URIs.
*
* @param interfaceUri The URI of the interface to associate with the implementation.
* @param implementationUri The URI of the implementation.
* @return This [BaseConfigBuilder] instance for chaining calls.
*/
fun addInterfaceImplementation(
interfaceUri: String,
implementationUri: String
): BaseConfigBuilder = this.apply {
val sanitizedInterfaceUri = validateUri(interfaceUri)
val existingInterface = this.config.interfaces[sanitizedInterfaceUri]
if (existingInterface != null) {
existingInterface.add(validateUri(implementationUri))
} else {
this.config.interfaces[sanitizedInterfaceUri] = mutableSetOf(validateUri(implementationUri))
}
}
/**
* Adds multiple interface implementations with the specified interface URI and a list of implementation URIs.
*
* @param interfaceUri The URI of the interface to associate with the implementations.
* @param implementationUris A [List] of URIs of the implementations.
* @return This [BaseConfigBuilder] instance for chaining calls.
*/
fun addInterfaceImplementations(
interfaceUri: String,
implementationUris: List
): BaseConfigBuilder = this.apply {
val sanitizedInterfaceUri = validateUri(interfaceUri)
val existingInterface = this.config.interfaces[sanitizedInterfaceUri]
if (existingInterface != null) {
implementationUris.forEach { existingInterface.add(validateUri(it)) }
} else {
val sanitizedImplUris = implementationUris.map { validateUri(it) }
this.config.interfaces[sanitizedInterfaceUri] = sanitizedImplUris.toMutableSet()
}
}
/**
* Removes an interface implementation with the specified interface and implementation URIs.
*
* @param interfaceUri The URI of the interface associated with the implementation.
* @param implementationUri The URI of the implementation to remove.
* @return This [BaseConfigBuilder] instance for chaining calls.
*/
fun removeInterfaceImplementation(
interfaceUri: String,
implementationUri: String
): BaseConfigBuilder = this.apply {
val sanitizedInterfaceUri = validateUri(interfaceUri)
val existingInterface = this.config.interfaces[sanitizedInterfaceUri] ?: return this
existingInterface.remove(validateUri(implementationUri))
if (existingInterface.isEmpty()) {
this.config.interfaces.remove(sanitizedInterfaceUri)
}
}
/**
* Adds a redirect with a specified source and destination URI.
*
* @param redirect A [Pair] of the source URI and the destination URI.
* @return This [BaseConfigBuilder] instance for chaining calls.
*/
fun setRedirect(redirect: Pair): BaseConfigBuilder = this.apply {
this.config.redirects[validateUri(redirect.first)] = validateUri(redirect.second)
}
/**
* Adds a set of redirects with specified source and destination URIs.
*
* @param redirects A [Map] of source URIs to destination URIs.
* @return This [BaseConfigBuilder] instance for chaining calls.
*/
fun setRedirects(redirects: Map): BaseConfigBuilder = this.apply {
redirects.forEach { setRedirect(it.toPair()) }
}
/**
* Removes a redirect with the specified source URI.
*
* @param from The source URI of the redirect to remove.
* @return This [BaseConfigBuilder] instance for chaining calls.
*/
fun removeRedirect(from: String): BaseConfigBuilder = this.apply {
this.config.redirects.remove(validateUri(from))
}
/**
* Adds a [UriResolver] to the current configuration.
*
* @param resolver The [UriResolver] instance to add.
* @return This [BaseConfigBuilder] instance for chaining calls.
*/
fun addResolver(resolver: UriResolver): BaseConfigBuilder = this.apply {
this.config.resolvers.add(resolver)
}
/**
* Adds a list of [UriResolver] instances to the current configuration.
*
* @param resolvers A [List] of [UriResolver] instances to add.
* @return This [BaseConfigBuilder] instance for chaining calls.
*/
fun addResolvers(resolvers: List): BaseConfigBuilder = this.apply {
resolvers.forEach { addResolver(it) }
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy