Skip to content

Commit

Permalink
Merge branch 'release/0.3.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
rishabh9 committed May 21, 2020
2 parents e3cc835 + fd10136 commit 212367a
Show file tree
Hide file tree
Showing 4 changed files with 212 additions and 43 deletions.
88 changes: 74 additions & 14 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -12,30 +12,21 @@ A minimal implementation of Nexus repository to practice Vert.x
* [x] Jitpack.

.Snapshots
* [x] Enable snapshots.
* [x] Enable snapshot repositories of above mirrors.

.Publishing artifacts
* [ ] Publish artifacts to Kumoru. (_Contemplating_)
* [x] Publish artifacts to Kumoru.

.HTTP methods supported
* [x] GET
* [x] PUT

== Pre-Requisites

1. JDK 11
1. Java 11
2. Docker

== Building and Running Locally

To build your application:
```
./gradlew clean build
```

To package your application into Docker container:
```
./gradlew jibDockerBuild
```
== Running the server

To run your application:
```
Expand All @@ -52,4 +43,73 @@ docker run -e KUMORU_ACCESS_LOG=true -p 8888:8888 -v /tmp/repo:/srv/repo rishabh

> All logs are written to the `STDOUT`.

== Configuring Maven

.Mirroring
Edit Maven's `settings.xml` and add a `<mirror>`:

```
<mirrors>
<mirror>
<id>kumoru</id>
<mirrorOf>*</mirrorOf>
<name>Kumoru - A minimal Nexus repository</name>
<url>http://localhost:8888</url>
</mirror>

</mirrors>
```

.Publishing

In your `pom.xml` add

```
<distributionManagement>
<repository>
<id>kumoru</id>
<name>Kumoru - A minimal Nexus repository</name>
<url>http://localhost:8888</url>
</repository>
</distributionManagement>
```

== Configuring Gradle

.Mirroring

Add to you `build.gradle`

```
repositories {
maven {
url: "http://localhost:8080"
}
}
```

.Publishing

Add to your `build.gradle`

```
publishing {
repositories {
maven {
url: "http://localhost:8080"
}
}
}
```

== Building the code

To build your application:
```
./gradlew clean build
```

To package your application into Docker container:
```
./gradlew jibDockerBuild
```
64 changes: 46 additions & 18 deletions src/main/java/com/github/rishabh9/kumoru/MainVerticle.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@
import com.github.rishabh9.kumoru.handlers.LocalResourceHandler;
import com.github.rishabh9.kumoru.handlers.MavenMirrorHandler;
import com.github.rishabh9.kumoru.handlers.SendFileHandler;
import com.github.rishabh9.kumoru.handlers.UploadHandler;
import com.github.rishabh9.kumoru.handlers.ValidRequestHandler;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.Promise;
import io.vertx.core.http.HttpServer;
import io.vertx.core.http.HttpServerOptions;
import io.vertx.ext.web.Route;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.handler.BodyHandler;
import io.vertx.ext.web.handler.LoggerFormat;
import io.vertx.ext.web.handler.LoggerHandler;
import lombok.extern.log4j.Log4j2;
Expand All @@ -25,7 +27,28 @@ public void start(final Promise<Void> startFuture) {

// Get all environment variables
final int port = getKumoruPort();
final boolean enableAccessLog = enableAccessLog();
final Router router = configureRoutes(enableAccessLog(), getBodyLimit());

// Logging network server activity
final HttpServerOptions options = new HttpServerOptions().setLogActivity(true);
final HttpServer httpServer = vertx.createHttpServer(options);
httpServer.requestHandler(router);
httpServer.listen(
port,
asyncResult -> {
if (asyncResult.succeeded()) {
startFuture.complete();
log.info(
"Kumoru server [v{}] started on port {}",
VersionProperties.INSTANCE.getVersion(),
port);
} else {
startFuture.fail(asyncResult.cause());
}
});
}

private Router configureRoutes(final boolean enableAccessLog, final long bodyLimit) {

// All handlers
final ValidRequestHandler validRequestHandler = new ValidRequestHandler();
Expand All @@ -35,6 +58,7 @@ public void start(final Promise<Void> startFuture) {
final JitPackMirrorHandler jitPackMirror = new JitPackMirrorHandler(vertx);
final SendFileHandler sendFileHandler = new SendFileHandler();
final FinalHandler finalHandler = new FinalHandler();
final UploadHandler uploadHandler = new UploadHandler(vertx);

final Router router = Router.router(vertx);
// for all routes do
Expand All @@ -43,6 +67,7 @@ public void start(final Promise<Void> startFuture) {
route.handler(LoggerHandler.create(LoggerFormat.DEFAULT));
}
route.handler(validRequestHandler);

// for GET method do
router
.get()
Expand All @@ -53,23 +78,26 @@ public void start(final Promise<Void> startFuture) {
.handler(sendFileHandler)
.handler(finalHandler);

// Logging network server activity
final HttpServerOptions options = new HttpServerOptions().setLogActivity(true);
final HttpServer httpServer = vertx.createHttpServer(options);
httpServer.requestHandler(router);
httpServer.listen(
port,
asyncResult -> {
if (asyncResult.succeeded()) {
startFuture.complete();
log.info(
"Kumoru server [v{}] started on port {}",
VersionProperties.INSTANCE.getVersion(),
port);
} else {
startFuture.fail(asyncResult.cause());
}
});
// for PUT method do
router
.put()
.handler(BodyHandler.create().setBodyLimit(bodyLimit).setDeleteUploadedFilesOnEnd(true))
.handler(uploadHandler);

return router;
}

private int getBodyLimit() {
// Body limited to 50MB
final int defaultBodyLimit = 50000000;
final String bodyLimit = System.getenv("KUMORU_BODY_LIMIT");
log.debug("Body limit configured as {} bytes", bodyLimit);
if (null != bodyLimit && !bodyLimit.isEmpty() && !bodyLimit.matches(".*\\D.*")) {
return Integer.parseInt(bodyLimit);
} else {
log.debug("Setting body limit as {} bytes", defaultBodyLimit);
return defaultBodyLimit;
}
}

private boolean enableAccessLog() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package com.github.rishabh9.kumoru.handlers;

import io.vertx.core.Vertx;
import io.vertx.ext.web.RoutingContext;
import lombok.extern.log4j.Log4j2;

@Log4j2
public class UploadHandler extends KumoruHandler {

private final Vertx vertx;

public UploadHandler(final Vertx vertx) {
this.vertx = vertx;
}

@Override
public void handle(final RoutingContext routingContext) {
final String path = routingContext.normalisedPath();
final String subPath = path.substring(0, path.lastIndexOf("/"));
final String directory = REPO_ROOT + subPath;
vertx
.fileSystem()
.exists(
directory,
existsResult -> {
if (existsResult.succeeded()
&& null != existsResult.result()
&& existsResult.result()) {
log.debug("The directory {} already exists", subPath);
writeFile(routingContext);
} else {
log.debug("The directory {} does not exists", subPath);
createDirectory(routingContext, directory);
}
});
}

private void createDirectory(final RoutingContext routingContext, final String directory) {
vertx
.fileSystem()
.mkdirs(
directory,
mkdirsResult -> {
if (mkdirsResult.succeeded()) {
log.debug("Created directory {}", directory);
writeFile(routingContext);
} else {
log.error("Failed to create directory {}", directory, mkdirsResult.cause());
routingContext
.response()
.setStatusCode(INTERNAL_ERROR)
.setStatusMessage(mkdirsResult.cause().getMessage())
.end();
}
});
}

private void writeFile(final RoutingContext routingContext) {
final String path = routingContext.normalisedPath();
vertx
.fileSystem()
.writeFile(
REPO_ROOT + path,
routingContext.getBody(),
writeResult -> {
if (writeResult.succeeded()) {
log.debug("Saved {} to disk", path);
routingContext.response().end();
} else {
log.error("There was error writing {} to disk", path, writeResult.cause());
routingContext
.response()
.setStatusCode(INTERNAL_ERROR)
.setStatusMessage(writeResult.cause().getMessage())
.end();
}
});
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.github.rishabh9.kumoru.handlers;

import static io.vertx.core.http.HttpMethod.GET;
import static io.vertx.core.http.HttpMethod.PUT;

import io.vertx.core.http.HttpMethod;
import io.vertx.ext.web.RoutingContext;
Expand All @@ -18,22 +19,23 @@ public void handle(final RoutingContext routingContext) {
.setStatusCode(METHOD_NOT_ALLOWED)
.setStatusMessage("Method Not Allowed")
.end();
}
final String path = routingContext.normalisedPath();
if (isValidPath(path)) {
routingContext.next();
} else {
log.error("Path has invalid characters: {}", path);
routingContext
.response()
.setStatusCode(BAD_REQUEST)
.setStatusMessage("Path has invalid characters")
.end();
final String path = routingContext.normalisedPath();
if (isValidPath(path)) {
routingContext.next();
} else {
log.error("Path has invalid characters: {}", path);
routingContext
.response()
.setStatusCode(BAD_REQUEST)
.setStatusMessage("Path has invalid characters")
.end();
}
}
}

private boolean isSupportedMethod(final HttpMethod method) {
return GET.equals(method);
return GET.equals(method) || PUT.equals(method);
}

private boolean isValidPath(final String path) {
Expand Down

0 comments on commit 212367a

Please sign in to comment.