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,9 +13,6 @@ 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(); |  | ||||||
|         if (listener.isEmpty()) { |  | ||||||
|             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"); |  | ||||||
|         int width = 100; |         int width = 100; | ||||||
|         int height = 100; |         int height = 100; | ||||||
|         final Labyrinth labyrinth = new Labyrinth(width, height/*, 0*/); |         final Labyrinth labyrinth = new Labyrinth(width, height/*, 0*/); | ||||||
|  | @ -47,7 +42,6 @@ public class Main { | ||||||
|         // 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) { | ||||||
|         return "labyrinth-" + labyrinth.getWidth() + "x" + labyrinth.getHeight() + "-" + labyrinth.getRandomSeed(); |         return "labyrinth-" + labyrinth.getWidth() + "x" + labyrinth.getHeight() + "-" + labyrinth.getRandomSeed(); | ||||||
|  |  | ||||||
|  | @ -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…
	
	Add table
		Add a link
		
	
		Reference in a new issue