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

commonMain.com.algolia.search.client.ClientSearch.kt Maven / Gradle / Ivy

@file:Suppress("FunctionName")

package com.algolia.search.client

import com.algolia.search.client.internal.ClientSearchImpl
import com.algolia.search.configuration.Configuration
import com.algolia.search.configuration.ConfigurationSearch
import com.algolia.search.configuration.Credentials
import com.algolia.search.configuration.internal.Credentials
import com.algolia.search.configuration.internal.DEFAULT_LOG_LEVEL
import com.algolia.search.endpoint.EndpointAPIKey
import com.algolia.search.endpoint.EndpointDictionary
import com.algolia.search.endpoint.EndpointMultiCluster
import com.algolia.search.endpoint.EndpointMultipleIndex
import com.algolia.search.helper.internal.sha256
import com.algolia.search.helper.toAPIKey
import com.algolia.search.logging.LogLevel
import com.algolia.search.model.APIKey
import com.algolia.search.model.ApplicationID
import com.algolia.search.model.IndexName
import com.algolia.search.model.LogType
import com.algolia.search.model.apikey.SecuredAPIKeyRestriction
import com.algolia.search.model.internal.Time
import com.algolia.search.model.response.ResponseAPIKey
import com.algolia.search.model.response.ResponseBatches
import com.algolia.search.model.response.ResponseDictionary
import com.algolia.search.model.response.ResponseLogs
import com.algolia.search.model.response.creation.CreationAPIKey
import com.algolia.search.model.response.deletion.DeletionAPIKey
import com.algolia.search.model.task.AppTaskID
import com.algolia.search.model.task.TaskIndex
import com.algolia.search.model.task.TaskInfo
import com.algolia.search.model.task.TaskStatus
import com.algolia.search.transport.CustomRequester
import com.algolia.search.transport.RequestOptions
import com.algolia.search.transport.internal.Transport
import io.ktor.util.decodeBase64String
import io.ktor.util.encodeBase64

/**
 * Client to perform operations on indices.
 */
public interface ClientSearch :
    EndpointMultipleIndex,
    EndpointAPIKey,
    EndpointMultiCluster,
    EndpointDictionary,
    Configuration,
    Credentials,
    CustomRequester {

    /**
     *  Initialize an [Index] configured with [ConfigurationSearch].
     */
    public fun initIndex(indexName: IndexName): Index

    /**
     * Wait on multiple [TaskIndex] operations. To be used with [multipleBatchObjects].
     *
     * @param timeout If a value is specified, the method will throw [TimeoutCancellationException] after waiting for
     * the allotted time in milliseconds.
     */
    public suspend fun List.waitAll(timeout: Long? = null): List

    /**
     * Convenience method similar to [waitAll] but with a [ResponseBatches] as receiver.
     */
    public suspend fun ResponseBatches.waitAll(timeout: Long? = null): List

    /**
     * Wait on a [CreationAPIKey] operation.
     *
     * @param timeout If a value is specified, the method will throw [TimeoutCancellationException] after waiting for
     * the allotted time in milliseconds.
     */
    public suspend fun CreationAPIKey.wait(timeout: Long? = null): ResponseAPIKey

    /**
     * Wait on a [DeletionAPIKey] operation.
     *
     * @param timeout If a value is specified, the method will throw [TimeoutCancellationException] after waiting for
     * the allotted time in milliseconds.
     */
    public suspend fun DeletionAPIKey.wait(timeout: Long? = null): Boolean

    /**
     * Wait on a [ResponseDictionary] operation.
     *
     * @param timeout If a value is specified, the method will throw [TimeoutCancellationException] after waiting for
     * the allotted time in milliseconds.
     */
    public suspend fun ResponseDictionary.wait(
        timeout: Long? = null,
        requestOptions: RequestOptions? = null,
    ): TaskStatus

    /**
     * Wait for a task at application level to complete before executing the next line of code.
     *
     * @param taskID ID of the task to wait for.
     * @param timeout If a value is specified, the method will throw [TimeoutCancellationException] after waiting for
     * the allotted time in milliseconds.
     * @param requestOptions Configure request locally with [RequestOptions]
     */
    public suspend fun waitTask(
        taskID: AppTaskID,
        timeout: Long? = null,
        requestOptions: RequestOptions? = null,
    ): TaskStatus

    /**
     * Check the current [TaskStatus] of a given application level task.
     *
     * @param taskID ID of the task to get its info.
     * @param requestOptions Configure request locally with [RequestOptions]
     */
    public suspend fun getTask(
        taskID: AppTaskID,
        requestOptions: RequestOptions? = null,
    ): TaskInfo

    /**
     * Convenience methods to get the logs directly from the [ClientSearch] without instantiating an [Index].
     *
     * @see EndpointAdvanced.getLogs
     */
    public suspend fun getLogs(
        page: Int? = null,
        hitsPerPage: Int? = null,
        logType: LogType? = null,
        requestOptions: RequestOptions? = null,
    ): ResponseLogs

    public companion object {
        /**
         * Generate a virtual [APIKey] without any call to the server.
         * Use [SecuredAPIKeyRestriction] to restrict [APIKey] usage.
         * You can generate a Secured APIKey from any [APIKey].
         * Learn more about secured [API keys][https://www.algolia.com/doc/guides/security/api-keys/#secured-api-keys].
         */
        public fun generateAPIKey(parentAPIKey: APIKey, restriction: SecuredAPIKeyRestriction): APIKey {
            val restrictionString = restriction.buildRestrictionString()
            val hash = parentAPIKey.raw.sha256(restrictionString)
            return "$hash$restrictionString".encodeBase64().toAPIKey()
        }

        /**
         * Gets how many milliseconds are left before the secured API key expires.
         *
         * @param apiKey The secured API Key to check.
         * @return Milliseconds left before the secured API key expires.
         * @throws IllegalArgumentException if [apiKey] doesn't have a [SecuredAPIKeyRestriction.validUntil].
         */
        public fun getSecuredApiKeyRemainingValidity(apiKey: APIKey): Long {
            val decoded = apiKey.raw.decodeBase64String()
            val pattern = Regex("validUntil=(\\d+)")
            val match = pattern.find(decoded)
            return if (match != null) {
                match.groupValues[1].toLong() - Time.getCurrentTimeMillis()
            } else {
                throw IllegalArgumentException("The Secured API Key doesn't have a validUntil parameter.")
            }
        }
    }
}

/**
 * Create a [ClientSearch] instance.
 *
 * @param applicationID application ID
 * @param apiKey API Key
 * @param logLevel log level
 */
public fun ClientSearch(
    applicationID: ApplicationID,
    apiKey: APIKey,
    logLevel: LogLevel = DEFAULT_LOG_LEVEL,
): ClientSearch = ClientSearchImpl(
    Transport(
        ConfigurationSearch(applicationID = applicationID, apiKey = apiKey, logLevel = logLevel),
        Credentials(applicationID = applicationID, apiKey = apiKey)
    )
)

/**
 * Create a [ClientSearch] instance.
 *
 * @param configuration search configuration
 */
public fun ClientSearch(
    configuration: ConfigurationSearch,
): ClientSearch = ClientSearchImpl(
    Transport(configuration, configuration)
)




© 2015 - 2025 Weber Informatics LLC | Privacy Policy