This commit is contained in:
parent
44cd69f79a
commit
a712c34c18
4 changed files with 30 additions and 233 deletions
|
@ -1,2 +1,2 @@
|
||||||
# labyrinth
|
# labyrinth-generator
|
||||||
|
|
||||||
|
|
3
pom.xml
3
pom.xml
|
@ -1,5 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
<parent>
|
<parent>
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
package ch.fritteli.labyrinth.generator;
|
package ch.fritteli.labyrinth.generator;
|
||||||
|
|
||||||
import ch.fritteli.labyrinth.generator.model.Labyrinth;
|
import ch.fritteli.labyrinth.generator.model.Labyrinth;
|
||||||
import ch.fritteli.labyrinth.generator.net.TheListener;
|
|
||||||
import ch.fritteli.labyrinth.generator.renderer.html.HTMLRenderer;
|
import ch.fritteli.labyrinth.generator.renderer.html.HTMLRenderer;
|
||||||
import ch.fritteli.labyrinth.generator.renderer.htmlfile.HTMLFileRenderer;
|
import ch.fritteli.labyrinth.generator.renderer.htmlfile.HTMLFileRenderer;
|
||||||
import ch.fritteli.labyrinth.generator.renderer.pdffile.PDFFileRenderer;
|
import ch.fritteli.labyrinth.generator.renderer.pdffile.PDFFileRenderer;
|
||||||
import ch.fritteli.labyrinth.generator.renderer.text.TextRenderer;
|
import ch.fritteli.labyrinth.generator.renderer.text.TextRenderer;
|
||||||
import ch.fritteli.labyrinth.generator.renderer.textfile.TextFileRenderer;
|
import ch.fritteli.labyrinth.generator.renderer.textfile.TextFileRenderer;
|
||||||
import io.vavr.control.Option;
|
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
@ -15,38 +13,34 @@ import java.nio.file.Paths;
|
||||||
|
|
||||||
public class Main {
|
public class Main {
|
||||||
public static void main(@NonNull final String[] args) {
|
public static void main(@NonNull final String[] args) {
|
||||||
final Option<TheListener> listener = TheListener.createListener();
|
int width = 100;
|
||||||
if (listener.isEmpty()) {
|
int height = 100;
|
||||||
System.out.println("In order to start the webserver, specify the port to listen to via the system property 'fritteli.labyrinth.listenerport', i.e.: -Dfritteli.labyrinth.listenerport=12345");
|
final Labyrinth labyrinth = new Labyrinth(width, height/*, 0*/);
|
||||||
int width = 100;
|
final TextRenderer textRenderer = TextRenderer.newInstance();
|
||||||
int height = 100;
|
final HTMLRenderer htmlRenderer = HTMLRenderer.newInstance();
|
||||||
final Labyrinth labyrinth = new Labyrinth(width, height/*, 0*/);
|
final Path userHome = Paths.get(System.getProperty("user.home"));
|
||||||
final TextRenderer textRenderer = TextRenderer.newInstance();
|
final String baseFilename = getBaseFilename(labyrinth);
|
||||||
final HTMLRenderer htmlRenderer = HTMLRenderer.newInstance();
|
final TextFileRenderer textFileRenderer = TextFileRenderer.newInstance()
|
||||||
final Path userHome = Paths.get(System.getProperty("user.home"));
|
.setTargetLabyrinthFile(userHome.resolve(baseFilename + ".txt"))
|
||||||
final String baseFilename = getBaseFilename(labyrinth);
|
.setTargetSolutionFile(userHome.resolve(baseFilename + "-solution.txt"));
|
||||||
final TextFileRenderer textFileRenderer = TextFileRenderer.newInstance()
|
final HTMLFileRenderer htmlFileRenderer = HTMLFileRenderer.newInstance()
|
||||||
.setTargetLabyrinthFile(userHome.resolve(baseFilename + ".txt"))
|
.setTargetFile(userHome.resolve(baseFilename + ".html"));
|
||||||
.setTargetSolutionFile(userHome.resolve(baseFilename + "-solution.txt"));
|
final PDFFileRenderer pdfFileRenderer = PDFFileRenderer.newInstance()
|
||||||
final HTMLFileRenderer htmlFileRenderer = HTMLFileRenderer.newInstance()
|
.setTargetFile(userHome.resolve(baseFilename + ".pdf"));
|
||||||
.setTargetFile(userHome.resolve(baseFilename + ".html"));
|
|
||||||
final PDFFileRenderer pdfFileRenderer = PDFFileRenderer.newInstance()
|
|
||||||
.setTargetFile(userHome.resolve(baseFilename + ".pdf"));
|
|
||||||
|
|
||||||
System.out.println("Labyrinth-ID: " + labyrinth.getRandomSeed());
|
System.out.println("Labyrinth-ID: " + labyrinth.getRandomSeed());
|
||||||
// Render Labyrinth to stdout
|
// Render Labyrinth to stdout
|
||||||
System.out.println(textRenderer.render(labyrinth));
|
System.out.println(textRenderer.render(labyrinth));
|
||||||
// Render Labyrinth solution to stdout
|
// Render Labyrinth solution to stdout
|
||||||
System.out.println(textRenderer.setRenderSolution(true).render(labyrinth));
|
System.out.println(textRenderer.setRenderSolution(true).render(labyrinth));
|
||||||
// Render HTML to stdout
|
// Render HTML to stdout
|
||||||
System.out.println(htmlRenderer.render(labyrinth));
|
System.out.println(htmlRenderer.render(labyrinth));
|
||||||
// Render Labyrinth and solution to (separate) files
|
// Render Labyrinth and solution to (separate) files
|
||||||
System.out.println(textFileRenderer.render(labyrinth));
|
System.out.println(textFileRenderer.render(labyrinth));
|
||||||
// Render HTML to file
|
// Render HTML to file
|
||||||
System.out.println(htmlFileRenderer.render(labyrinth));
|
System.out.println(htmlFileRenderer.render(labyrinth));
|
||||||
// Render PDF to file
|
// Render PDF to file
|
||||||
System.out.println(pdfFileRenderer.render(labyrinth));
|
System.out.println(pdfFileRenderer.render(labyrinth));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getBaseFilename(@NonNull final Labyrinth labyrinth) {
|
private static String getBaseFilename(@NonNull final Labyrinth labyrinth) {
|
||||||
|
|
|
@ -1,198 +0,0 @@
|
||||||
package ch.fritteli.labyrinth.generator.net;
|
|
||||||
|
|
||||||
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 com.sun.net.httpserver.Headers;
|
|
||||||
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 org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
public class TheListener {
|
|
||||||
|
|
||||||
private final HttpServer httpServer;
|
|
||||||
|
|
||||||
public TheListener(final int port) throws IOException {
|
|
||||||
this.httpServer = HttpServer.create(new InetSocketAddress(port), 0);
|
|
||||||
this.httpServer.createContext("/create", exchange -> {
|
|
||||||
final String requestMethod = exchange.getRequestMethod();
|
|
||||||
if (!requestMethod.equals("GET")) {
|
|
||||||
exchange.getResponseBody().close();
|
|
||||||
exchange.sendResponseHeaders(405, -1);
|
|
||||||
exchange.close();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final Map<RequestParameter, String> requestParams = this.parseQueryString(exchange.getRequestURI().getQuery());
|
|
||||||
final int width = this.getOrDefault(requestParams.get(RequestParameter.WIDTH), Integer::valueOf, 1);
|
|
||||||
final int height = this.getOrDefault(requestParams.get(RequestParameter.HEIGHT), Integer::valueOf, 1);
|
|
||||||
final Option<Long> seedOption = requestParams.get(RequestParameter.ID).toTry().map(Long::valueOf).toOption();
|
|
||||||
final long seed;
|
|
||||||
final Option<OutputType> outputOption = requestParams.get(RequestParameter.OUTPUT).flatMap(OutputType::ofString);
|
|
||||||
final OutputType output;
|
|
||||||
final Headers responseHeaders = exchange.getResponseHeaders();
|
|
||||||
boolean needsRedirect = false;
|
|
||||||
if (seedOption.isEmpty()) {
|
|
||||||
needsRedirect = true;
|
|
||||||
seed = System.nanoTime();
|
|
||||||
} else {
|
|
||||||
seed = seedOption.get();
|
|
||||||
}
|
|
||||||
if (outputOption.isEmpty()) {
|
|
||||||
needsRedirect = true;
|
|
||||||
output = OutputType.HTML;
|
|
||||||
} else {
|
|
||||||
output = outputOption.get();
|
|
||||||
}
|
|
||||||
if (needsRedirect) {
|
|
||||||
responseHeaders.add("Location", "/create?width=" + width + "&height=" + height + "&output=" + output.toString() + "&id=" + seed);
|
|
||||||
exchange.sendResponseHeaders(302, -1);
|
|
||||||
exchange.close();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
responseHeaders.add("Content-type", output.getContentType());
|
|
||||||
exchange.sendResponseHeaders(200, 0);
|
|
||||||
final Labyrinth labyrinth = new Labyrinth(width, height, seed);
|
|
||||||
final byte[] render = output.render(labyrinth);
|
|
||||||
final OutputStream responseBody = exchange.getResponseBody();
|
|
||||||
responseBody.write(render);
|
|
||||||
responseBody.flush();
|
|
||||||
exchange.close();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Option<TheListener> createListener() {
|
|
||||||
final String listenerPort = System.getProperty("fritteli.labyrinth.listenerport");
|
|
||||||
final Option<TheListener> listenerOption = Option.of(listenerPort)
|
|
||||||
.toTry()
|
|
||||||
.map(Integer::valueOf)
|
|
||||||
.onFailure(cause -> System.err.println("Invalid port specified via system property 'fritteli.labyrinth.listenerport': "
|
|
||||||
+ listenerPort
|
|
||||||
+ ". Not starting webserver."))
|
|
||||||
.mapTry(TheListener::new)
|
|
||||||
.onFailure(cause -> System.err.println("Failed to create Listener: " + cause))
|
|
||||||
.toOption();
|
|
||||||
listenerOption.forEach(TheListener::start);
|
|
||||||
return listenerOption;
|
|
||||||
}
|
|
||||||
|
|
||||||
private <T> T getOrDefault(@NonNull final Option<String> input, @NonNull final Function<String, T> mapper, @Nullable final T defaultValue) {
|
|
||||||
return input.toTry().map(mapper).getOrElse(defaultValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private Map<RequestParameter, String> parseQueryString(@Nullable final String query) {
|
|
||||||
if (query == null) {
|
|
||||||
return HashMap.empty();
|
|
||||||
}
|
|
||||||
HashMap<RequestParameter, String> result = HashMap.empty();
|
|
||||||
final String[] parts = query.split("&");
|
|
||||||
for (final String part : parts) {
|
|
||||||
final int split = part.indexOf('=');
|
|
||||||
if (split == -1) {
|
|
||||||
final Try<RequestParameter> tryKey = Try.of(() -> this.normalizeParameterName(part));
|
|
||||||
if (tryKey.isSuccess()) {
|
|
||||||
result = result.put(tryKey.get(), null);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
final String key = part.substring(0, split);
|
|
||||||
final String value = part.substring(split + 1);
|
|
||||||
final Try<RequestParameter> tryKey = Try.of(() -> this.normalizeParameterName(key));
|
|
||||||
if (tryKey.isSuccess()) {
|
|
||||||
result = result.put(tryKey.get(), value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private RequestParameter normalizeParameterName(final String paramName) {
|
|
||||||
return RequestParameter.parseName(paramName).get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void start() {
|
|
||||||
Runtime.getRuntime().addShutdownHook(new Thread(this::stop, "listener-stopper"));
|
|
||||||
this.httpServer.start();
|
|
||||||
System.out.println("Listening on " + this.httpServer.getAddress());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void stop() {
|
|
||||||
System.out.println("Stopping listener ...");
|
|
||||||
this.httpServer.stop(5);
|
|
||||||
System.out.println("Listener stopped.");
|
|
||||||
}
|
|
||||||
|
|
||||||
private enum RequestParameter {
|
|
||||||
WIDTH("w", "width"),
|
|
||||||
HEIGHT("h", "height"),
|
|
||||||
ID("i", "id"),
|
|
||||||
OUTPUT("o", "output");
|
|
||||||
private final Set<String> names;
|
|
||||||
|
|
||||||
RequestParameter(@NonNull final String... names) {
|
|
||||||
this.names = HashSet.of(names);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Option<RequestParameter> parseName(@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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private enum OutputType {
|
|
||||||
TEXT_PLAIN("text/plain; charset=UTF-8", labyrinth -> TextRenderer.newInstance().render(labyrinth).getBytes(StandardCharsets.UTF_8), "t", "text"),
|
|
||||||
HTML("text/html", labyrinth -> HTMLRenderer.newInstance().render(labyrinth).getBytes(StandardCharsets.UTF_8), "h", "html"),
|
|
||||||
PDF("application/pdf", labyrinth -> PDFRenderer.newInstance().render(labyrinth), "p", "pdf");
|
|
||||||
@Getter
|
|
||||||
@NonNull
|
|
||||||
private final String contentType;
|
|
||||||
@NonNull
|
|
||||||
private final List<String> names;
|
|
||||||
@NonNull
|
|
||||||
private final Function<Labyrinth, byte[]> render;
|
|
||||||
|
|
||||||
OutputType(@NonNull final String contentType, @NonNull final Function<Labyrinth, byte[]> render, @NonNull final String... names) {
|
|
||||||
this.contentType = contentType;
|
|
||||||
this.render = render;
|
|
||||||
this.names = List.of(names);
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] render(@NonNull final Labyrinth labyrinth) {
|
|
||||||
return this.render.apply(labyrinth);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue