feature/undertow #4

Merged
manuel merged 15 commits from feature/undertow into master 2023-04-08 22:40:46 +02:00
4 changed files with 125 additions and 109 deletions
Showing only changes of commit 65421caf85 - Show all commits

View file

@ -1,22 +1,17 @@
package ch.fritteli.labyrinth.server;
import ch.fritteli.labyrinth.generator.model.Labyrinth;
import ch.fritteli.labyrinth.generator.renderer.html.HTMLRenderer;
import ch.fritteli.labyrinth.generator.renderer.pdf.PDFRenderer;
import ch.fritteli.labyrinth.generator.renderer.text.TextRenderer;
import ch.fritteli.labyrinth.generator.serialization.SerializerDeserializer;
import com.sun.net.httpserver.Headers;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpServer;
import io.vavr.collection.HashMap;
import io.vavr.collection.HashSet;
import io.vavr.collection.List;
import io.vavr.collection.Map;
import io.vavr.collection.Set;
import io.vavr.collection.Stream;
import io.vavr.control.Option;
import io.vavr.control.Try;
import lombok.Getter;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.Nullable;
@ -251,71 +246,4 @@ public class LabyrinthServer {
return Stream.of(values()).find(param -> param.names.exists(name::equalsIgnoreCase));
}
}
public enum OutputType {
TEXT_PLAIN("text/plain; charset=UTF-8",
labyrinth -> TextRenderer.newInstance().render(labyrinth).getBytes(StandardCharsets.UTF_8),
"txt",
false,
"t",
"text"
),
HTML("text/html",
labyrinth -> HTMLRenderer.newInstance().render(labyrinth).getBytes(StandardCharsets.UTF_8),
"html",
false,
"h",
"html"
),
PDF("application/pdf", labyrinth -> PDFRenderer.newInstance().render(labyrinth), "pdf", false, "p", "pdf"),
PDFFILE("application/pdf",
labyrinth -> PDFRenderer.newInstance().render(labyrinth),
"pdf",
true,
"f",
"pdffile"
),
BINARY("application/octet-stream", SerializerDeserializer::serialize, "laby", true, "b", "binary");
@Getter
@NonNull
private final String contentType;
@NonNull
private final List<String> names;
@NonNull
private final Function<Labyrinth, byte[]> render;
@Getter
private final boolean attachment;
@Getter
@NonNull
private final String fileExtension;
OutputType(@NonNull final String contentType,
@NonNull final Function<Labyrinth, byte[]> render,
@NonNull final String fileExtension,
final boolean attachment,
@NonNull final String... names) {
this.contentType = contentType;
this.render = render;
this.fileExtension = fileExtension;
this.attachment = attachment;
this.names = List.of(names);
}
public static Option<OutputType> ofString(@Nullable final String name) {
if (name == null) {
return Option.none();
}
final String nameLC = name.toLowerCase();
return Stream.of(values()).find(param -> param.names.contains(nameLC));
}
@Override
public String toString() {
return this.names.last();
}
public byte[] render(@NonNull final Labyrinth labyrinth) {
return this.render.apply(labyrinth);
}
}
}

View file

@ -0,0 +1,77 @@
package ch.fritteli.labyrinth.server;
import ch.fritteli.labyrinth.generator.model.Labyrinth;
import ch.fritteli.labyrinth.generator.renderer.html.HTMLRenderer;
import ch.fritteli.labyrinth.generator.renderer.pdf.PDFRenderer;
import ch.fritteli.labyrinth.generator.renderer.text.TextRenderer;
import ch.fritteli.labyrinth.generator.serialization.SerializerDeserializer;
import io.vavr.collection.List;
import io.vavr.collection.Stream;
import io.vavr.control.Option;
import lombok.Getter;
import lombok.NonNull;
import org.jetbrains.annotations.Nullable;
import java.nio.charset.StandardCharsets;
import java.util.function.Function;
public enum OutputType {
TEXT_PLAIN("text/plain; charset=UTF-8",
labyrinth -> TextRenderer.newInstance().render(labyrinth).getBytes(StandardCharsets.UTF_8),
"txt",
false,
"t",
"text"
),
HTML("text/html",
labyrinth -> HTMLRenderer.newInstance().render(labyrinth).getBytes(StandardCharsets.UTF_8),
"html",
false,
"h",
"html"
),
PDF("application/pdf", labyrinth -> PDFRenderer.newInstance().render(labyrinth), "pdf", false, "p", "pdf"),
PDFFILE("application/pdf", labyrinth -> PDFRenderer.newInstance().render(labyrinth), "pdf", true, "f", "pdffile"),
BINARY("application/octet-stream", SerializerDeserializer::serialize, "laby", true, "b", "binary");
@Getter
@NonNull
private final String contentType;
@NonNull
private final List<String> names;
@NonNull
private final Function<Labyrinth, byte[]> render;
@Getter
private final boolean attachment;
@Getter
@NonNull
private final String fileExtension;
OutputType(@NonNull final String contentType,
@NonNull final Function<Labyrinth, byte[]> render,
@NonNull final String fileExtension,
final boolean attachment,
@NonNull final String... names) {
this.contentType = contentType;
this.render = render;
this.fileExtension = fileExtension;
this.attachment = attachment;
this.names = List.of(names);
}
public static Option<OutputType> ofString(@Nullable final String name) {
if (name == null) {
return Option.none();
}
final String nameLC = name.toLowerCase();
return Stream.of(values()).find(param -> param.names.contains(nameLC));
}
@Override
public String toString() {
return this.names.last();
}
public byte[] render(@NonNull final Labyrinth labyrinth) {
return this.render.apply(labyrinth);
}
}

View file

@ -0,0 +1,45 @@
package ch.fritteli.labyrinth.server.undertow_playground;
import ch.fritteli.labyrinth.generator.model.Labyrinth;
import ch.fritteli.labyrinth.server.OutputType;
import io.undertow.server.HttpHandler;
import io.undertow.server.HttpServerExchange;
import io.undertow.util.Headers;
import io.undertow.util.HttpString;
import io.vavr.control.Option;
import lombok.extern.slf4j.Slf4j;
import java.nio.ByteBuffer;
import java.util.Deque;
import java.util.Map;
import java.util.Random;
@Slf4j
class LabyrinthHttpHandler implements HttpHandler {
@Override
public void handleRequest(HttpServerExchange exchange) throws Exception {
if (exchange.isInIoThread()) {
exchange.dispatch(this);
return;
}
final Map<String, Deque<String>> queryParameters = exchange.getQueryParameters();
final Option<String> output = UndertowPlayground.getFirstOption(queryParameters, "output");
final Option<Integer> width = UndertowPlayground.getIntOption(queryParameters, "width");
final Option<Integer> height = UndertowPlayground.getIntOption(queryParameters, "height");
final Option<Integer> id = UndertowPlayground.getIntOption(queryParameters, "id");
log.info("Output: {}", output);
log.info("Width: {}", width);
log.info("Height: {}", height);
log.info("Id: {}", id);
final Integer theId = id.getOrElse(() -> new Random().nextInt());
final Labyrinth labyrinth = new Labyrinth(width.get(), height.get(), theId);
final OutputType outputType = output.flatMap(OutputType::ofString).get();
final byte[] result = outputType.render(labyrinth);
exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, outputType.getContentType());
exchange.getResponseHeaders().put(HttpString.tryFromString("X-Labyrinth-ID"), String.valueOf(theId));
exchange.getResponseHeaders().put(HttpString.tryFromString("X-Labyrinth-Width"), String.valueOf(width.get()));
exchange.getResponseHeaders().put(HttpString.tryFromString("X-Labyrinth-Height"), String.valueOf(height.get()));
exchange.getResponseSender().send(ByteBuffer.wrap(result));
}
}

View file

@ -1,54 +1,20 @@
package ch.fritteli.labyrinth.server.undertow_playground;
import ch.fritteli.labyrinth.generator.model.Labyrinth;
import ch.fritteli.labyrinth.server.LabyrinthServer;
import io.undertow.server.HttpHandler;
import io.undertow.server.HttpServerExchange;
import io.undertow.server.RoutingHandler;
import io.undertow.util.HeaderValues;
import io.undertow.util.Headers;
import io.undertow.util.HttpString;
import io.vavr.control.Option;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import java.nio.ByteBuffer;
import java.util.Deque;
import java.util.Map;
import java.util.Random;
@Slf4j
public class UndertowPlayground {
public static final RoutingHandler r = new RoutingHandler().get("/create/{output}", new HttpHandler() {
@Override
public void handleRequest(HttpServerExchange exchange) throws Exception {
if (exchange.isInIoThread()) {
exchange.dispatch(this);
return;
}
final Map<String, Deque<String>> queryParameters = exchange.getQueryParameters();
final Option<String> output = getFirstOption(queryParameters, "output");
final Option<Integer> width = getIntOption(queryParameters, "width");
final Option<Integer> height = getIntOption(queryParameters, "height");
final Option<Integer> id = getIntOption(queryParameters, "id");
log.info("Output: {}", output);
log.info("Width: {}", width);
log.info("Height: {}", height);
log.info("Id: {}", id);
final Integer theId = id.getOrElse(() -> new Random().nextInt());
final Labyrinth labyrinth = new Labyrinth(width.get(), height.get(), theId);
final LabyrinthServer.OutputType outputType = output.flatMap(LabyrinthServer.OutputType::ofString).get();
final byte[] result = outputType.render(labyrinth);
exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, outputType.getContentType());
exchange.getResponseHeaders().put(HttpString.tryFromString("X-Labyrinth-ID"), String.valueOf(theId));
exchange.getResponseHeaders()
.put(HttpString.tryFromString("X-Labyrinth-Width"), String.valueOf(width.get()));
exchange.getResponseHeaders()
.put(HttpString.tryFromString("X-Labyrinth-Height"), String.valueOf(height.get()));
exchange.getResponseSender().send(ByteBuffer.wrap(result));
}
}).post("/render", new HttpHandler() {
public static final RoutingHandler r = new RoutingHandler().get("/create/{output}", new LabyrinthHttpHandler()).post("/render", new HttpHandler() {
@Override
public void handleRequest(final HttpServerExchange exchange) {
if (exchange.isInIoThread()) {
@ -67,13 +33,13 @@ public class UndertowPlayground {
});
@NonNull
private static Option<Integer> getIntOption(@NonNull final Map<String, Deque<String>> queryParams,
public static Option<Integer> getIntOption(@NonNull final Map<String, Deque<String>> queryParams,
@NonNull final String paramName) {
return getFirstOption(queryParams, paramName).toTry().map(Integer::parseInt).toOption();
}
@NonNull
private static Option<String> getFirstOption(@NonNull final Map<String, Deque<String>> queryParams,
public static Option<String> getFirstOption(@NonNull final Map<String, Deque<String>> queryParams,
@NonNull final String paramName) {
return Option.of(queryParams.get(paramName)).map(Deque::peek).flatMap(Option::of);
}