Skip to content

Commit d3137a5

Browse files
authored
GH-2076 Prototype redirect plugin + a little bit more user-friendly routing api (#2077)
1 parent 2bed99d commit d3137a5

File tree

9 files changed

+134
-44
lines changed

9 files changed

+134
-44
lines changed

.run/Run Reposilite - Test workspace.run.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
<option name="MAIN_CLASS_NAME" value="com.reposilite.ReposiliteLauncherKt" />
1111
<module name="reposilite-parent.reposilite-backend.main" />
1212
<option name="PROGRAM_PARAMETERS" value="--token name:secret --level=DEBUG" />
13-
<option name="VM_PARAMETERS" value="-Xmx32M" />
13+
<option name="VM_PARAMETERS" value="-Xmx32M -Dreposilite.redirect.default-repository=releases" />
1414
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/reposilite-test/workspace" />
1515
<extension name="net.ashald.envfile">
1616
<option name="IS_ENABLED" value="false" />

reposilite-backend/src/main/kotlin/com/reposilite/ReposiliteFactory.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ import com.reposilite.shared.extensions.LoomExtensions
2727
import com.reposilite.shared.extensions.newFixedThreadPool
2828
import com.reposilite.shared.extensions.newSingleThreadScheduledExecutor
2929
import com.reposilite.web.HttpServer
30-
import panda.utilities.console.Effect
3130
import kotlin.io.path.absolutePathString
31+
import panda.utilities.console.Effect
3232

3333
object ReposiliteFactory {
3434

reposilite-backend/src/main/kotlin/com/reposilite/maven/infrastructure/MavenEndpoints.kt

+24-16
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,16 @@ import com.reposilite.maven.api.DeleteRequest
2222
import com.reposilite.maven.api.DeployRequest
2323
import com.reposilite.maven.api.LookupRequest
2424
import com.reposilite.shared.extensions.resultAttachment
25+
import com.reposilite.shared.extensions.uri
26+
import com.reposilite.storage.api.Location
27+
import com.reposilite.token.AccessTokenIdentifier
2528
import com.reposilite.web.api.ReposiliteRoute
2629
import io.javalin.community.routing.Route.DELETE
2730
import io.javalin.community.routing.Route.GET
2831
import io.javalin.community.routing.Route.HEAD
2932
import io.javalin.community.routing.Route.POST
3033
import io.javalin.community.routing.Route.PUT
34+
import io.javalin.http.Context
3135
import io.javalin.openapi.ContentType.FORM_DATA_MULTIPART
3236
import io.javalin.openapi.HttpMethod
3337
import io.javalin.openapi.OpenApi
@@ -61,26 +65,30 @@ internal class MavenEndpoints(
6165
private val findFile = ReposiliteRoute<Unit>("/{repository}/<gav>", HEAD, GET) {
6266
accessed {
6367
requireGav { gav ->
64-
LookupRequest(this?.identifier, requireParameter("repository"), gav)
65-
.let { request -> mavenFacade.findFile(request) }
66-
.peek {
67-
ctx.resultAttachment(
68-
name = it.document.name,
69-
contentType = it.document.contentType,
70-
contentLength = it.document.contentLength,
71-
compressionStrategy = compressionStrategy,
72-
cache = it.cachable,
73-
data = it.content
74-
)
75-
}
76-
.onError {
77-
ctx.status(it.status).html(frontendFacade.createNotFoundPage(uri, it.message))
78-
mavenFacade.logger.debug("FIND | Could not find file due to $it")
79-
}
68+
findFile(ctx, this?.identifier, requireParameter("repository"), gav)
8069
}
8170
}
8271
}
8372

73+
fun findFile(ctx: Context, identifier: AccessTokenIdentifier?, repository: String, gav: Location) {
74+
LookupRequest(identifier, repository, gav)
75+
.let { request -> mavenFacade.findFile(request) }
76+
.peek {
77+
ctx.resultAttachment(
78+
name = it.document.name,
79+
contentType = it.document.contentType,
80+
contentLength = it.document.contentLength,
81+
compressionStrategy = compressionStrategy,
82+
cache = it.cachable,
83+
data = it.content
84+
)
85+
}
86+
.onError {
87+
ctx.status(it.status).html(frontendFacade.createNotFoundPage(ctx.uri(), it.message))
88+
mavenFacade.logger.debug("FIND | Could not find file due to $it")
89+
}
90+
}
91+
8492
@OpenApi(
8593
tags = [ "Maven" ],
8694
path = "/{repository}/{gav}",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package com.reposilite.redirect
2+
3+
import com.reposilite.configuration.local.LocalConfiguration
4+
import com.reposilite.frontend.FrontendFacade
5+
import com.reposilite.maven.MavenFacade
6+
import com.reposilite.maven.infrastructure.MavenEndpoints
7+
import com.reposilite.plugin.api.Facade
8+
import com.reposilite.plugin.api.Plugin
9+
import com.reposilite.plugin.api.ReposilitePlugin
10+
import com.reposilite.plugin.event
11+
import com.reposilite.plugin.facade
12+
import com.reposilite.storage.api.Location
13+
import com.reposilite.web.api.ReposiliteRoute
14+
import com.reposilite.web.api.RoutingSetupEvent
15+
import io.javalin.community.routing.Route.GET
16+
import io.javalin.community.routing.Route.HEAD
17+
18+
@Plugin(name = "redirect", dependencies = ["local-configuration", "frontend", "maven"])
19+
class RedirectPlugin : ReposilitePlugin() {
20+
21+
private val redirectTo: String? = System.getProperty("reposilite.redirect.default-repository", "")
22+
23+
override fun initialize(): Facade? {
24+
if (redirectTo.isNullOrEmpty()) {
25+
return null
26+
}
27+
28+
val mavenFacade = facade<MavenFacade>()
29+
30+
val mavenEndpoints = MavenEndpoints(
31+
mavenFacade = mavenFacade,
32+
frontendFacade = facade<FrontendFacade>(),
33+
compressionStrategy = facade<LocalConfiguration>().compressionStrategy.get()
34+
)
35+
36+
logger.info("")
37+
logger.info("--- Redirect")
38+
39+
val redirectedRoutes = mavenFacade.getRepository(redirectTo)
40+
?.storageProvider
41+
?.getFiles(Location.of("/"))
42+
?.orNull()
43+
?.map {
44+
logger.info("Redirecting /${it.getSimpleName()}/<gav> to /$redirectTo/${it.getSimpleName()}/<gav>")
45+
46+
ReposiliteRoute<Unit>("/${it.getSimpleName()}/<gav>", HEAD, GET) {
47+
accessed {
48+
mavenEndpoints.findFile(
49+
ctx = ctx,
50+
identifier = this?.identifier,
51+
repository = redirectTo,
52+
gav = it.resolve(requireParameter("gav"))
53+
)
54+
}
55+
}
56+
}
57+
?: emptyList()
58+
59+
event { event: RoutingSetupEvent ->
60+
event.register(redirectedRoutes)
61+
}
62+
63+
return null
64+
}
65+
66+
}

reposilite-backend/src/main/kotlin/com/reposilite/web/api/Routing.kt

+15-13
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package com.reposilite.web.api
1818

1919
import com.reposilite.shared.ContextDsl
20+
import com.reposilite.web.infrastructure.ReposiliteDslRoute
2021
import com.reposilite.web.routing.RouteMethod
2122
import io.javalin.community.routing.Route
2223
import io.javalin.community.routing.dsl.DefaultDslRoute
@@ -33,17 +34,8 @@ abstract class ReposiliteRoutes : DslContainer<DslRoute<ContextDsl<*>, Unit>, Co
3334
.map { it as ReposiliteRoute<Any> }
3435
.toSet()
3536

36-
@Suppress("UNCHECKED_CAST")
37-
override fun routes(): Collection<DslRoute<ContextDsl<*>, Unit>> =
38-
routes.flatMap { route ->
39-
route.methods.map { method ->
40-
DefaultDslRoute(
41-
path = route.path,
42-
method = method,
43-
handler = route.handler as ContextDsl<*>.() -> Unit
44-
)
45-
}
46-
}
37+
override fun routes(): Collection<ReposiliteDslRoute> =
38+
routes.flatMap { it.toDslRoutes() }
4739

4840
}
4941

@@ -62,9 +54,19 @@ class ReposiliteRoute<R>(
6254
path = path,
6355
methods = methods
6456
.map { Route.valueOf(it.name) }
65-
.toTypedArray()
66-
,
57+
.toTypedArray(),
6758
handler = handler
6859
)
6960

61+
@Suppress("UNCHECKED_CAST")
62+
fun toDslRoutes(): Set<ReposiliteDslRoute> =
63+
methods.mapTo(HashSet()) { method ->
64+
@Suppress("UNCHECKED_CAST")
65+
DefaultDslRoute(
66+
path = path,
67+
method = method,
68+
handler = handler as ContextDsl<*>.() -> Unit
69+
)
70+
}
71+
7072
}

reposilite-backend/src/main/kotlin/com/reposilite/web/api/RoutingSetupEvent.kt

+13-5
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,25 @@ import com.reposilite.plugin.api.Event
2121

2222
class RoutingSetupEvent(val reposilite: Reposilite) : Event {
2323

24-
private val routes: MutableSet<ReposiliteRoutes> = mutableSetOf()
24+
private val routes: MutableSet<ReposiliteRoute<*>> = mutableSetOf()
2525

26-
fun registerRoutes(routesToAdd: ReposiliteRoutes) {
27-
routes.add(routesToAdd)
26+
fun register(routeToAdd: ReposiliteRoute<*>) {
27+
routes.add(routeToAdd)
2828
}
2929

30-
fun registerRoutes(routesToAdd: Set<ReposiliteRoutes>) {
30+
fun register(routesToAdd: Collection<ReposiliteRoute<*>>) {
3131
routes.addAll(routesToAdd)
3232
}
3333

34-
fun getRoutes(): Collection<ReposiliteRoutes> =
34+
fun registerRoutes(routesToAdd: ReposiliteRoutes) {
35+
routes.addAll(routesToAdd.routes)
36+
}
37+
38+
fun registerRoutes(routesToAdd: Collection<ReposiliteRoutes>) {
39+
routes.addAll(routesToAdd.map { it.routes }.flatten())
40+
}
41+
42+
fun getRoutes(): Collection<ReposiliteRoute<*>> =
3543
routes
3644

3745
}

reposilite-backend/src/main/kotlin/com/reposilite/web/application/JavalinConfiguration.kt

+7-2
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,13 @@ internal object JavalinConfiguration {
100100
authenticationFacade = extensionManager.facade()
101101
)
102102

103-
extensionManager.emitEvent(RoutingSetupEvent(reposilite)).getRoutes().asSequence().flatMap { it.routes() }.distinctBy { "${it.method.name}:${it.path}" }
104-
.toSet().let { route ->
103+
extensionManager.emitEvent(RoutingSetupEvent(reposilite))
104+
.getRoutes()
105+
.asSequence()
106+
.flatMap { it.toDslRoutes() }
107+
.distinctBy { "${it.method.name}:${it.path}" }
108+
.toSet()
109+
.let { route ->
105110
config.router.mount(reposiliteDsl) {
106111
it.routes(route)
107112
}

reposilite-backend/src/main/kotlin/com/reposilite/web/infrastructure/ReposiliteRouting.kt

+6-6
Original file line numberDiff line numberDiff line change
@@ -22,22 +22,22 @@ import io.javalin.http.Header
2222
import io.javalin.http.HttpStatus.INTERNAL_SERVER_ERROR
2323
import io.javalin.util.javalinLazy
2424

25-
typealias ReposiliteRouting = DslRouting<ReposiliteConfiguration, ReposiliteRoute, ReposiliteScope, Unit>
26-
typealias ReposiliteRoute = DslRoute<ContextDsl<*>, Unit>
25+
typealias ReposiliteRouting = DslRouting<ReposiliteConfiguration, ReposiliteDslRoute, ReposiliteScope, Unit>
26+
typealias ReposiliteDslRoute = DslRoute<ContextDsl<*>, Unit>
2727
typealias ReposiliteExceptionHandler = DslExceptionHandler<ContextDsl<*>, Exception, Unit>
2828
typealias ReposiliteScope = ContextDsl<*>
2929

3030
class ReposiliteDsl(
31-
private val routeFactory: (ReposiliteRoute) -> Handler,
31+
private val routeFactory: (ReposiliteDslRoute) -> Handler,
3232
private val exceptionRouteFactory: (ReposiliteExceptionHandler) -> ExceptionHandler<Exception>
33-
) : RoutingDslFactory<ReposiliteConfiguration, ReposiliteRoute, ContextDsl<*>, Unit> {
33+
) : RoutingDslFactory<ReposiliteConfiguration, ReposiliteDslRoute, ContextDsl<*>, Unit> {
3434

35-
open class ReposiliteConfiguration : RoutingDslConfiguration<ReposiliteRoute, ContextDsl<*>, Unit>()
35+
open class ReposiliteConfiguration : RoutingDslConfiguration<ReposiliteDslRoute, ContextDsl<*>, Unit>()
3636

3737
override fun createConfiguration(): ReposiliteConfiguration =
3838
ReposiliteConfiguration()
3939

40-
override fun createHandler(route: ReposiliteRoute): Handler =
40+
override fun createHandler(route: ReposiliteDslRoute): Handler =
4141
routeFactory.invoke(route)
4242

4343
override fun createExceptionHandler(handler: ReposiliteExceptionHandler): ExceptionHandler<Exception> =

reposilite-backend/src/main/resources/META-INF/services/com.reposilite.plugin.api.ReposilitePlugin

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ com.reposilite.auth.application.AuthenticationPlugin
22
com.reposilite.console.application.ConsolePlugin
33
com.reposilite.frontend.application.FrontendPlugin
44
com.reposilite.maven.application.MavenPlugin
5+
com.reposilite.redirect.RedirectPlugin
56
com.reposilite.javadocs.application.JavadocPlugin
67
com.reposilite.configuration.application.ConfigurationPlugin
78
com.reposilite.configuration.local.LocalConfigurationPlugin

0 commit comments

Comments
 (0)