diff --git a/api/v1/client/src/commonMain/kotlin/OrtServerClient.kt b/api/v1/client/src/commonMain/kotlin/OrtServerClient.kt new file mode 100644 index 000000000..4c659d524 --- /dev/null +++ b/api/v1/client/src/commonMain/kotlin/OrtServerClient.kt @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2024 The ORT Server Authors (See ) + * + * 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 + * + * https://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. + * + * SPDX-License-Identifier: Apache-2.0 + * License-Filename: LICENSE + */ + +package org.eclipse.apoapsis.ortserver.client + +import io.ktor.client.HttpClient +import io.ktor.client.plugins.auth.Auth +import io.ktor.client.plugins.auth.providers.BearerTokens +import io.ktor.client.plugins.auth.providers.bearer +import io.ktor.client.plugins.defaultRequest + +import kotlinx.serialization.json.Json + +import org.eclipse.apoapsis.ortserver.client.api.RepositoriesApi +import org.eclipse.apoapsis.ortserver.client.auth.AuthService + +class OrtServerClient( + /** + * The configured HTTP client for the interaction with the API. + */ + client: HttpClient, + + /** + * The configuration for the ORT server client. + */ + config: OrtServerClientConfig +) { + companion object { + /** + * The JSON configuration to use for serialization and deserialization. + */ + val JSON = Json { + ignoreUnknownKeys = true + isLenient = true + } + + /** + * Create a new instance of the ORT server client using the given [config] and configure an HTTP client with + * the necessary authentication. + */ + fun create(config: OrtServerClientConfig): OrtServerClient { + val auth = AuthService( + client = createDefaultHttpClient(JSON), + tokenUrl = config.tokenUrl, + clientId = config.clientId + ) + + val client = createOrtHttpClient(JSON) { + defaultRequest { + url(config.baseUrl) + } + + install(Auth) { + bearer { + loadTokens { + val tokenInfo = auth.generateToken(config.username, config.password) + + BearerTokens(tokenInfo.accessToken, tokenInfo.refreshToken) + } + + refreshTokens { + val tokenInfo = runCatching { + auth.refreshToken(oldTokens?.refreshToken.orEmpty()) + }.getOrElse { + auth.generateToken(config.username, config.password) + } + + BearerTokens(tokenInfo.accessToken, tokenInfo.refreshToken) + } + } + } + } + return OrtServerClient(client, config) + } + } + + /** + * Provide access to the repositories API, allowing operations on repositories in the ORT server. + */ + val repositories = RepositoriesApi(client) +} diff --git a/api/v1/client/src/commonMain/kotlin/OrtServerClientConfig.kt b/api/v1/client/src/commonMain/kotlin/OrtServerClientConfig.kt new file mode 100644 index 000000000..366656a03 --- /dev/null +++ b/api/v1/client/src/commonMain/kotlin/OrtServerClientConfig.kt @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2024 The ORT Server Authors (See ) + * + * 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 + * + * https://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. + * + * SPDX-License-Identifier: Apache-2.0 + * License-Filename: LICENSE + */ + +package org.eclipse.apoapsis.ortserver.client + +data class OrtServerClientConfig( + /** + * The base URL of the ORT server, including only the host and optionally the port. Do not include the API version + * in the base URL. + */ + val baseUrl: String, + + /** + * The client ID to use for authentication. + */ + val clientId: String, + + /** + * The URL to use for token generation. + */ + val tokenUrl: String, + + /** + * The username to use for authentication. + */ + val username: String, + + /** + * The password to use for authentication. + */ + val password: String +)