Skip to content

Commit

Permalink
GH-458 Rewrite routing to support multiple routes within a single end…
Browse files Browse the repository at this point in the history
…point
  • Loading branch information
dzikoysk committed Jul 4, 2021
1 parent 48e1c8d commit f10da49
Show file tree
Hide file tree
Showing 29 changed files with 204 additions and 271 deletions.
2 changes: 1 addition & 1 deletion reposilite-backend/reposilite-backend.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ dependencies {
val javalin = "4.0.0.ALPHA3"
implementation("io.javalin:javalin:$javalin")

val openapi = "1.0.8"
val openapi = "1.0.9"
kapt("com.dzikoysk:openapi-annotation-processor:$openapi")
implementation("com.dzikoysk:javalin-openapi-plugin:$openapi")
implementation("com.dzikoysk:javalin-swagger-plugin:$openapi")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import org.panda_lang.reposilite.maven.application.MavenWebConfiguration
import org.panda_lang.reposilite.statistics.application.StatisticsWebConfiguration
import org.panda_lang.reposilite.token.application.AccessTokenWebConfiguration
import org.panda_lang.reposilite.web.ReposiliteContextFactory
import org.panda_lang.reposilite.web.api.RouteHandler
import org.panda_lang.reposilite.web.api.Routes
import org.panda_lang.reposilite.web.application.WebConfiguration
import java.nio.file.Path

Expand Down Expand Up @@ -74,13 +74,13 @@ object ReposiliteWebConfiguration {
AccessTokenWebConfiguration.initialize(reposilite.accessTokenFacade, reposilite.consoleFacade)
}

fun routing(reposilite: Reposilite): Collection<RouteHandler> =
fun routing(reposilite: Reposilite): Collection<Routes> =
setOf(
AuthenticationWebConfiguration.routing(reposilite.authenticationFacade),
ConsoleWebConfiguration.routing(reposilite),
FailureWebConfiguration.routing(),
FrontendWebConfiguration.routing(reposilite.frontendFacade),
MavenWebConfiguration.routing(reposilite.contextFactory, reposilite.mavenFacade),
MavenWebConfiguration.routing(reposilite.mavenFacade),
StatisticsWebConfiguration.routing(reposilite.statisticsFacade),
// AccessTokenWebConfiguration.routing(),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import org.panda_lang.reposilite.auth.infrastructure.AuthenticationEndpoint
import org.panda_lang.reposilite.auth.infrastructure.PostAuthHandler
import org.panda_lang.reposilite.maven.MavenFacade
import org.panda_lang.reposilite.token.AccessTokenFacade
import org.panda_lang.reposilite.web.api.RouteHandler
import org.panda_lang.reposilite.web.api.Routes

internal object AuthenticationWebConfiguration {

Expand All @@ -35,7 +35,7 @@ internal object AuthenticationWebConfiguration {
return AuthenticationFacade(journalist, authenticator, sessionService)
}

fun routing(authenticationFacade: AuthenticationFacade): Set<RouteHandler> =
fun routing(authenticationFacade: AuthenticationFacade): Set<Routes> =
setOf(
AuthenticationEndpoint(authenticationFacade),
PostAuthHandler()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,19 @@ import com.dzikoysk.openapi.annotations.OpenApi
import com.dzikoysk.openapi.annotations.OpenApiContent
import com.dzikoysk.openapi.annotations.OpenApiParam
import com.dzikoysk.openapi.annotations.OpenApiResponse
import io.javalin.http.Context
import org.panda_lang.reposilite.auth.AuthenticationFacade
import org.panda_lang.reposilite.auth.api.AuthenticationResponse
import org.panda_lang.reposilite.failure.api.ErrorResponse
import org.panda_lang.reposilite.web.api.RouteHandler
import org.panda_lang.reposilite.web.api.Route
import org.panda_lang.reposilite.web.api.RouteMethod.GET
import org.panda_lang.reposilite.web.api.Routes

private const val ROUTE = "/api/auth"

internal class AuthenticationEndpoint(private val authenticationFacade: AuthenticationFacade) : RouteHandler {

override val route = ROUTE
override val methods = listOf(GET)
internal class AuthenticationEndpoint(private val authenticationFacade: AuthenticationFacade) : Routes {

@OpenApi(
path = ROUTE,
operationId = "auth",
methods = [HttpMethod.GET],
summary = "Get token details",
description = "Returns details about the requested token",
Expand All @@ -55,10 +51,12 @@ internal class AuthenticationEndpoint(private val authenticationFacade: Authenti
)
]
)
override fun handle(ctx: Context) {
private val authInfo = Route(ROUTE, GET) {
authenticationFacade.authenticateByHeader(ctx.headerMap())
.map { AuthenticationResponse(it.alias, it.permissions.map { permission -> permission.toString() }) }
.let { ctx.json(it.any) }
}

override val routes = setOf(authInfo)

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,22 @@
*/
package org.panda_lang.reposilite.auth.infrastructure

import io.javalin.http.Context
import io.javalin.http.HttpCode
import org.panda_lang.reposilite.web.api.RouteHandler
import org.panda_lang.reposilite.web.api.Route
import org.panda_lang.reposilite.web.api.RouteMethod.AFTER
import org.panda_lang.reposilite.web.api.Routes

private const val WWW_AUTHENTICATE = "www-authenticate"
private const val WWW_BASIC_REALM = """Basic realm="Reposilite", charset="UTF-8" """

internal class PostAuthHandler : RouteHandler {
internal class PostAuthHandler : Routes {

override val route = "/*"
override val methods = listOf(AFTER)

override fun handle(context: Context) {
if (context.status() == HttpCode.UNAUTHORIZED.status) {
context.header(WWW_AUTHENTICATE, WWW_BASIC_REALM)
private val realmDescription = Route("/*", AFTER) {
if (ctx.status() == HttpCode.UNAUTHORIZED.status) {
ctx.header(WWW_AUTHENTICATE, WWW_BASIC_REALM)
}
}

override val routes = setOf(realmDescription)

}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import org.panda_lang.reposilite.console.VersionCommand
import org.panda_lang.reposilite.console.infrastructure.CliEndpoint
import org.panda_lang.reposilite.console.infrastructure.RemoteExecutionEndpoint
import org.panda_lang.reposilite.failure.FailureFacade
import org.panda_lang.reposilite.web.api.RouteHandler
import org.panda_lang.reposilite.web.api.Routes

private const val REMOTE_VERSION = "https://repo.panda-lang.org/org/panda-lang/reposilite/latest"

Expand All @@ -51,9 +51,9 @@ internal object ConsoleWebConfiguration {
}
}

fun routing(reposilite: Reposilite): List<RouteHandler> =
listOf(
RemoteExecutionEndpoint(reposilite.contextFactory, reposilite.consoleFacade)
fun routing(reposilite: Reposilite): Set<Routes> =
setOf(
RemoteExecutionEndpoint(reposilite.consoleFacade)
)

fun javalin(javalin: Javalin, reposilite: Reposilite) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,32 +20,22 @@ import com.dzikoysk.openapi.annotations.OpenApi
import com.dzikoysk.openapi.annotations.OpenApiContent
import com.dzikoysk.openapi.annotations.OpenApiParam
import com.dzikoysk.openapi.annotations.OpenApiResponse
import io.javalin.http.Context
import io.javalin.http.HttpCode.UNAUTHORIZED
import org.panda_lang.reposilite.console.ConsoleFacade
import org.panda_lang.reposilite.console.MAX_COMMAND_LENGTH
import org.panda_lang.reposilite.console.api.ExecutionResponse
import org.panda_lang.reposilite.failure.api.ErrorResponse
import org.panda_lang.reposilite.failure.api.errorResponse
import org.panda_lang.reposilite.token.infrastructure.AccessTokenTable.description
import org.panda_lang.reposilite.web.ReposiliteContextFactory
import org.panda_lang.reposilite.web.api.RouteHandler
import org.panda_lang.reposilite.web.api.Route
import org.panda_lang.reposilite.web.api.RouteMethod.POST
import org.panda_lang.reposilite.web.context
import org.panda_lang.reposilite.web.api.Routes

private const val ROUTE = "/api/execute"

internal class RemoteExecutionEndpoint(
private val contextFactory: ReposiliteContextFactory,
private val consoleFacade: ConsoleFacade
) : RouteHandler {

override val route = ROUTE
override val methods = listOf(POST)
internal class RemoteExecutionEndpoint(private val consoleFacade: ConsoleFacade) : Routes {

@OpenApi(
path = ROUTE,
operationId = "cli",
methods = [HttpMethod.POST],
summary = "Remote command execution",
description = "Execute command using POST request. The commands are the same as in the console and can be listed using the 'help' command.",
Expand All @@ -69,19 +59,20 @@ internal class RemoteExecutionEndpoint(
)
]
)
override fun handle(ctx: Context) =
context(contextFactory, ctx) {
context.logger.info("REMOTE EXECUTION ${context.uri} from ${context.address}")

authenticated {
if (!isManager()) {
response = errorResponse(UNAUTHORIZED, "Authenticated user is not a manager")
return@authenticated
}
private val executeCommand = Route(ROUTE, POST) {
context.logger.info("REMOTE EXECUTION ${context.uri} from ${context.address}")

context.logger.info("${accessToken.alias} (${context.address}) requested command: ${context.body.value}")
response = consoleFacade.executeCommand(context.body.value)
authenticated {
if (!isManager()) {
response = errorResponse(UNAUTHORIZED, "Authenticated user is not a manager")
return@authenticated
}

context.logger.info("${accessToken.alias} (${context.address}) requested command: ${context.body.value}")
response = consoleFacade.executeCommand(context.body.value)
}
}

override val routes = setOf(executeCommand)

}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import org.panda_lang.reposilite.console.ConsoleFacade
import org.panda_lang.reposilite.failure.FailureFacade
import org.panda_lang.reposilite.failure.FailuresCommand
import org.panda_lang.reposilite.failure.infrastructure.FailureHandler
import org.panda_lang.reposilite.web.api.RouteHandler
import org.panda_lang.reposilite.web.api.Routes

internal object FailureWebConfiguration {

Expand All @@ -33,7 +33,7 @@ internal object FailureWebConfiguration {
consoleFacade.registerCommand(FailuresCommand(failureFacade))
}

fun routing(): List<RouteHandler> =
fun routing(): List<Routes> =
listOf()

fun javalin(javalin: Javalin, failureFacade: FailureFacade) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ package org.panda_lang.reposilite.frontend.application
import org.panda_lang.reposilite.config.Configuration
import org.panda_lang.reposilite.frontend.FrontendFacade
import org.panda_lang.reposilite.frontend.infrastructure.FrontendHandler
import org.panda_lang.reposilite.web.api.RouteHandler
import org.panda_lang.reposilite.web.api.Routes

internal object FrontendWebConfiguration {

fun createFacade(configuration: Configuration): FrontendFacade =
FrontendFacade.load(configuration)

fun routing(frontendFacade: FrontendFacade): List<RouteHandler> =
fun routing(frontendFacade: FrontendFacade): List<Routes> =
listOf(
FrontendHandler(frontendFacade)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,48 +18,38 @@ package org.panda_lang.reposilite.frontend.infrastructure
import com.dzikoysk.openapi.annotations.HttpMethod
import com.dzikoysk.openapi.annotations.OpenApi
import com.dzikoysk.openapi.annotations.OpenApiResponse
import io.javalin.http.Context
import org.eclipse.jetty.http.HttpStatus
import org.eclipse.jetty.http.MimeTypes
import org.panda_lang.reposilite.frontend.FrontendFacade
import org.panda_lang.reposilite.web.api.RouteHandler
import org.panda_lang.reposilite.web.api.Route
import org.panda_lang.reposilite.web.api.RouteMethod.GET
import org.panda_lang.reposilite.web.api.Routes
import org.panda_lang.reposilite.web.encoding

private const val ROUTE = "/*"

internal class FrontendHandler(private val frontendFacade: FrontendFacade) : RouteHandler {

override val route = ROUTE
override val methods = listOf(GET)
internal class FrontendHandler(private val frontendFacade: FrontendFacade) : Routes {

@OpenApi(
path = ROUTE,
methods = [ HttpMethod.GET ],
operationId = "frontend",
summary = "Get frontend application",
description = "Returns Vue.js application wrapped into one app.js file",
tags = [ "Resource" ],
responses = [ OpenApiResponse(status = "200", description = "Default response") ]
)
override fun handle(context: Context) {
var qualifier = context.splat(0) ?: ""

if (qualifier.isEmpty()) {
qualifier = "index.html"
}

val resource = FrontendFacade::class.java.getResourceAsStream("/static/$qualifier")

if (resource == null) {
context.status(HttpStatus.NOT_FOUND_404)
return
}

context
.result(resource)
.contentType(MimeTypes.getDefaultMimeByExtension(qualifier))
.encoding("UTF-8")
private val frontend = Route(ROUTE, GET) {
val qualifier = wildcard(defaultValue = "index.html")

FrontendFacade::class.java.getResourceAsStream("/static/$qualifier")
?.let {
ctx.result(it)
.contentType(MimeTypes.getDefaultMimeByExtension(qualifier))
.encoding("UTF-8")
}
?: ctx.status(HttpStatus.NOT_FOUND_404)
}

override val routes = setOf(frontend)

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,19 @@

package org.panda_lang.reposilite.maven

import net.dzikoysk.dynamiclogger.Journalist
import org.panda_lang.reposilite.config.Configuration.RepositoryConfiguration
import org.panda_lang.reposilite.maven.api.Repository
import org.panda_lang.reposilite.maven.api.RepositoryVisibility
import org.panda_lang.reposilite.storage.StorageProviderFactory

internal class RepositoryFactory(private val storageProviderFactory: StorageProviderFactory) {
internal object RepositoryFactory {

fun createRepository(repositoryName: String, repositoryConfiguration: RepositoryConfiguration): Repository =
fun createRepository(journalist: Journalist, repositoryName: String, repositoryConfiguration: RepositoryConfiguration): Repository =
Repository(
repositoryName,
RepositoryVisibility.valueOf(repositoryConfiguration.visibility.toUpperCase()),
storageProviderFactory.createStorageProvider(repositoryName, repositoryConfiguration.storageProvider),
StorageProviderFactory.createStorageProvider(journalist, repositoryName, repositoryConfiguration.storageProvider),
repositoryConfiguration.deployEnabled
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import net.dzikoysk.dynamiclogger.Journalist
import net.dzikoysk.dynamiclogger.Logger
import org.panda_lang.reposilite.config.Configuration.RepositoryConfiguration
import org.panda_lang.reposilite.maven.api.Repository
import org.panda_lang.reposilite.storage.StorageProviderFactory

internal class RepositoryService(
private val journalist: Journalist,
Expand All @@ -40,12 +39,10 @@ internal class RepositoryService(
internal object RepositoryServiceFactory {

fun createRepositoryService(journalist: Journalist, repositoriesConfigurations: Map<String, RepositoryConfiguration>): RepositoryService {
val storageProviderFactory = StorageProviderFactory()
val repositoryFactory = RepositoryFactory(storageProviderFactory)
val repositories: MutableMap<String, Repository> = LinkedHashMap(repositoriesConfigurations.size)

for ((repositoryName, repositoryConfiguration) in repositoriesConfigurations) {
repositories[repositoryName] = repositoryFactory.createRepository(repositoryName, repositoryConfiguration)
repositories[repositoryName] = RepositoryFactory.createRepository(journalist, repositoryName, repositoryConfiguration)
}

return RepositoryService(journalist, repositories)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,8 @@ import org.panda_lang.reposilite.maven.MetadataService
import org.panda_lang.reposilite.maven.RepositorySecurityProvider
import org.panda_lang.reposilite.maven.RepositoryServiceFactory
import org.panda_lang.reposilite.maven.infrastructure.DeploymentEndpoint
import org.panda_lang.reposilite.maven.infrastructure.IndexEndpoint
import org.panda_lang.reposilite.maven.infrastructure.LookupEndpoint
import org.panda_lang.reposilite.web.ReposiliteContextFactory
import org.panda_lang.reposilite.web.api.RouteHandler
import org.panda_lang.reposilite.web.api.Routes

internal object MavenWebConfiguration {

Expand All @@ -42,11 +40,10 @@ internal object MavenWebConfiguration {
return MavenFacade(journalist, metadataService, lookupService, deployService)
}

fun routing(contextFactory: ReposiliteContextFactory, mavenFacade: MavenFacade): List<RouteHandler> =
fun routing(mavenFacade: MavenFacade): List<Routes> =
listOf(
IndexEndpoint(contextFactory, mavenFacade),
LookupEndpoint(contextFactory, mavenFacade),
DeploymentEndpoint(contextFactory, mavenFacade)
LookupEndpoint(mavenFacade),
DeploymentEndpoint(mavenFacade)
)

}
Loading

0 comments on commit f10da49

Please sign in to comment.