Skip to content

Commit

Permalink
Add first endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
zrdzn committed Nov 11, 2024
1 parent 66e7806 commit f6e440c
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import com.reposilite.packages.oci.api.SaveManifestRequest
import com.reposilite.packages.oci.api.UploadState
import com.reposilite.plugin.api.Facade
import com.reposilite.shared.ErrorResponse
import com.reposilite.shared.badRequestError
import com.reposilite.shared.notFoundError
import com.reposilite.storage.StorageProvider
import com.reposilite.storage.api.toLocation
import panda.std.Result
Expand Down Expand Up @@ -52,7 +54,7 @@ class OciFacade(
return saveManifestRequest.let { ManifestResponse(it.schemaVersion, it.mediaType, it.config, it.layers) }.asSuccess()
}

fun retrieveUploadSessionId(namespace: String): Result<String, ErrorResponse> {
fun retrieveBlobUploadSessionId(namespace: String): Result<String, ErrorResponse> {
val sessionId = UUID.randomUUID().toString()

sessions[sessionId] = UploadState(
Expand All @@ -66,6 +68,15 @@ class OciFacade(
return sessionId.asSuccess()
}

fun uploadBlobStreamPart(namespace: String, sessionId: String, part: ByteArray): Result<UploadState, ErrorResponse> {
val session = sessions[sessionId] ?: return notFoundError("Session not found")

session.uploadedData += part
session.bytesReceived += part.size

return session.asSuccess()
}

fun findBlobByDigest(namespace: String, digest: String): Result<BlobResponse, ErrorResponse> =
storageProvider.getFile("blobs/${namespace}/${digest}".toLocation())
.map {
Expand All @@ -88,6 +99,14 @@ class OciFacade(
.map { it.readAllBytes().joinToString("") { "%02x".format(it) } }
}

fun validateDigest(digest: String): Result<String, ErrorResponse> {
if (!digest.startsWith("sha256:")) {
return badRequestError("Invalid digest format")
}

return digest.asSuccess()
}

override fun getLogger(): Logger =
journalist.logger

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package com.reposilite.packages.oci.api
data class UploadState(
val sessionId: String,
val name: String,
val uploadedData: ByteArray,
val bytesReceived: Int,
var uploadedData: ByteArray,
var bytesReceived: Int,
val createdAt: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright (c) 2023 dzikoysk
*
* 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 com.reposilite.packages.oci.infrastructure

import com.reposilite.packages.oci.OciFacade
import com.reposilite.packages.oci.api.ManifestResponse
import com.reposilite.packages.oci.api.SaveManifestRequest
import com.reposilite.shared.badRequest
import com.reposilite.shared.extractFromHeader
import com.reposilite.shared.notFoundError
import com.reposilite.web.api.ReposiliteRoute
import com.reposilite.web.api.ReposiliteRoutes
import io.javalin.community.routing.Route.*
import io.javalin.http.bodyAsClass
import panda.std.Result.supplyThrowing

internal class OciEndpoints(
private val ociFacade: OciFacade,
private val basePath: String,
private val compressionStrategy: String
) : ReposiliteRoutes() {

fun saveManifest(namespace: String, reference: String) =
ReposiliteRoute<ManifestResponse>("/api/oci/v2/$namespace/manifests/$reference", PUT) {
accessed {
val contentType = ctx.header("Content-Type")
if (contentType != "application/vnd.docker.distribution.manifest.v2+json") {
response = notFoundError("Invalid content type")
return@accessed
}

response = supplyThrowing { ctx.bodyAsClass<SaveManifestRequest>() }
.mapErr { badRequest("Request does not contain valid body") }
.flatMap { saveManifestRequest ->
ociFacade.validateDigest(reference)
.flatMap { ociFacade.saveManifest(namespace, reference, saveManifestRequest) }
.flatMapErr { ociFacade.saveTaggedManifest(namespace, reference, saveManifestRequest) }
}
}
}

override val routes = routes(saveManifest())

}

0 comments on commit f6e440c

Please sign in to comment.