Expose start and end tile; accept start and end input parameters when #7
					 7 changed files with 111 additions and 12 deletions
				
			
		
							
								
								
									
										2
									
								
								pom.xml
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								pom.xml
									
										
									
									
									
								
							|  | @ -19,7 +19,7 @@ | ||||||
|         <java.target.version>17</java.target.version> |         <java.target.version>17</java.target.version> | ||||||
|         <jetbrains-annotations.version>24.0.1</jetbrains-annotations.version> |         <jetbrains-annotations.version>24.0.1</jetbrains-annotations.version> | ||||||
|         <junit-jupiter.version>5.9.2</junit-jupiter.version> |         <junit-jupiter.version>5.9.2</junit-jupiter.version> | ||||||
|         <labyrinth-generator.version>0.0.7</labyrinth-generator.version> |         <labyrinth-generator.version>0.0.8</labyrinth-generator.version> | ||||||
|         <logback.version>1.4.6</logback.version> |         <logback.version>1.4.6</logback.version> | ||||||
|         <lombok.version>1.18.26</lombok.version> |         <lombok.version>1.18.26</lombok.version> | ||||||
|         <slf4j.version>2.0.7</slf4j.version> |         <slf4j.version>2.0.7</slf4j.version> | ||||||
|  |  | ||||||
|  | @ -1,7 +1,8 @@ | ||||||
| package ch.fritteli.labyrinth.server; | package ch.fritteli.labyrinth.server; | ||||||
| 
 | 
 | ||||||
| import ch.fritteli.labyrinth.server.handler.CreateHandler; | import ch.fritteli.labyrinth.server.handler.CreateHandler; | ||||||
| import ch.fritteli.labyrinth.server.handler.RenderHandler; | import ch.fritteli.labyrinth.server.handler.RenderV1Handler; | ||||||
|  | import ch.fritteli.labyrinth.server.handler.RenderV2Handler; | ||||||
| import io.undertow.Undertow; | import io.undertow.Undertow; | ||||||
| import io.undertow.server.RoutingHandler; | import io.undertow.server.RoutingHandler; | ||||||
| import io.vavr.control.Try; | import io.vavr.control.Try; | ||||||
|  | @ -21,7 +22,8 @@ public class LabyrinthServer { | ||||||
|         log.info("Starting Server at http://{}:{}/", hostAddress, port); |         log.info("Starting Server at http://{}:{}/", hostAddress, port); | ||||||
|         final RoutingHandler routingHandler = new RoutingHandler() |         final RoutingHandler routingHandler = new RoutingHandler() | ||||||
|                 .get(CreateHandler.PATH_TEMPLATE, new CreateHandler()) |                 .get(CreateHandler.PATH_TEMPLATE, new CreateHandler()) | ||||||
|                 .post(RenderHandler.PATH_TEMPLATE, new RenderHandler()); |                 .post(RenderV1Handler.PATH_TEMPLATE, new RenderV1Handler()) | ||||||
|  |                 .post(RenderV2Handler.PATH_TEMPLATE, new RenderV2Handler()); | ||||||
| 
 | 
 | ||||||
|         this.undertow = Undertow.builder() |         this.undertow = Undertow.builder() | ||||||
|                 .addHttpListener(port, hostAddress) |                 .addHttpListener(port, hostAddress) | ||||||
|  |  | ||||||
|  | @ -5,7 +5,8 @@ import ch.fritteli.labyrinth.generator.renderer.html.HTMLRenderer; | ||||||
| import ch.fritteli.labyrinth.generator.renderer.json.JsonRenderer; | import ch.fritteli.labyrinth.generator.renderer.json.JsonRenderer; | ||||||
| import ch.fritteli.labyrinth.generator.renderer.pdf.PDFRenderer; | import ch.fritteli.labyrinth.generator.renderer.pdf.PDFRenderer; | ||||||
| import ch.fritteli.labyrinth.generator.renderer.text.TextRenderer; | import ch.fritteli.labyrinth.generator.renderer.text.TextRenderer; | ||||||
| import ch.fritteli.labyrinth.generator.serialization.SerializerDeserializer; | import ch.fritteli.labyrinth.generator.serialization.v1.SerializerDeserializerV1; | ||||||
|  | import ch.fritteli.labyrinth.generator.serialization.v2.SerializerDeserializerV2; | ||||||
| import io.vavr.collection.List; | import io.vavr.collection.List; | ||||||
| import io.vavr.collection.Stream; | import io.vavr.collection.Stream; | ||||||
| import io.vavr.control.Option; | import io.vavr.control.Option; | ||||||
|  | @ -55,10 +56,16 @@ public enum OutputType { | ||||||
|             "pdffile"), |             "pdffile"), | ||||||
|     BINARY("application/octet-stream", |     BINARY("application/octet-stream", | ||||||
|             "laby", |             "laby", | ||||||
|             SerializerDeserializer::serialize, |             SerializerDeserializerV1::serialize, | ||||||
|             true, |             true, | ||||||
|             "b", |             "b", | ||||||
|             "binary"); |             "binary"), | ||||||
|  |     BINARY_V2("application/octet-stream", | ||||||
|  |             "lab2", | ||||||
|  |             SerializerDeserializerV2::serialize, | ||||||
|  |             true, | ||||||
|  |             "v", | ||||||
|  |             "binaryv2"); | ||||||
|     @Getter |     @Getter | ||||||
|     @NonNull |     @NonNull | ||||||
|     private final String contentType; |     private final String contentType; | ||||||
|  |  | ||||||
|  | @ -1,6 +1,8 @@ | ||||||
| package ch.fritteli.labyrinth.server.handler; | package ch.fritteli.labyrinth.server.handler; | ||||||
| 
 | 
 | ||||||
|  | import ch.fritteli.labyrinth.generator.Generator; | ||||||
| import ch.fritteli.labyrinth.generator.model.Labyrinth; | import ch.fritteli.labyrinth.generator.model.Labyrinth; | ||||||
|  | import ch.fritteli.labyrinth.generator.model.Position; | ||||||
| import ch.fritteli.labyrinth.server.OutputType; | import ch.fritteli.labyrinth.server.OutputType; | ||||||
| import io.vavr.Tuple; | import io.vavr.Tuple; | ||||||
| import io.vavr.Tuple2; | import io.vavr.Tuple2; | ||||||
|  | @ -25,6 +27,8 @@ class ParametersToLabyrinthExtractor { | ||||||
|         final Option<Integer> width = getParameterValue(RequestParameter.WIDTH); |         final Option<Integer> width = getParameterValue(RequestParameter.WIDTH); | ||||||
|         final Option<Integer> height = getParameterValue(RequestParameter.HEIGHT); |         final Option<Integer> height = getParameterValue(RequestParameter.HEIGHT); | ||||||
|         final Option<Long> id = getParameterValue(RequestParameter.ID); |         final Option<Long> id = getParameterValue(RequestParameter.ID); | ||||||
|  |         final Option<Position> start = getParameterValue(RequestParameter.START); | ||||||
|  |         final Option<Position> end = getParameterValue(RequestParameter.END); | ||||||
| 
 | 
 | ||||||
|         if (output.isEmpty()) { |         if (output.isEmpty()) { | ||||||
|             return Try.failure(new IllegalArgumentException("Path parameter %s is required and must be one of: %s".formatted( |             return Try.failure(new IllegalArgumentException("Path parameter %s is required and must be one of: %s".formatted( | ||||||
|  | @ -45,7 +49,16 @@ class ParametersToLabyrinthExtractor { | ||||||
|             ))); |             ))); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         return Try.of(() -> Tuple.of(output.get(), new Labyrinth(width.get(), height.get(), id.getOrElse(() -> new Random().nextLong())))); |         return Try.of(() -> { | ||||||
|  |             final Labyrinth labyrinth; | ||||||
|  |             if (start.isDefined() && end.isDefined()) { | ||||||
|  |                 labyrinth = new Labyrinth(width.get(), height.get(), id.getOrElse(() -> new Random().nextLong()), start.get(), end.get()); | ||||||
|  |             } else { | ||||||
|  |                 labyrinth = new Labyrinth(width.get(), height.get(), id.getOrElse(() -> new Random().nextLong())); | ||||||
|  |             } | ||||||
|  |             new Generator(labyrinth).run(); | ||||||
|  |             return Tuple.of(output.get(), labyrinth); | ||||||
|  |         }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @NonNull |     @NonNull | ||||||
|  |  | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| package ch.fritteli.labyrinth.server.handler; | package ch.fritteli.labyrinth.server.handler; | ||||||
| 
 | 
 | ||||||
| import ch.fritteli.labyrinth.generator.model.Labyrinth; | import ch.fritteli.labyrinth.generator.model.Labyrinth; | ||||||
| import ch.fritteli.labyrinth.generator.serialization.SerializerDeserializer; | import ch.fritteli.labyrinth.generator.serialization.v1.SerializerDeserializerV1; | ||||||
| import ch.fritteli.labyrinth.server.OutputType; | import ch.fritteli.labyrinth.server.OutputType; | ||||||
| import io.undertow.server.HttpServerExchange; | import io.undertow.server.HttpServerExchange; | ||||||
| import io.undertow.util.HeaderValues; | import io.undertow.util.HeaderValues; | ||||||
|  | @ -12,9 +12,9 @@ import lombok.NonNull; | ||||||
| import lombok.extern.slf4j.Slf4j; | import lombok.extern.slf4j.Slf4j; | ||||||
| 
 | 
 | ||||||
| @Slf4j | @Slf4j | ||||||
| public class RenderHandler extends AbstractHttpHandler { | public class RenderV1Handler extends AbstractHttpHandler { | ||||||
| 
 | 
 | ||||||
|     public static final String PATH_TEMPLATE = "/render/{output}"; |     public static final String PATH_TEMPLATE = "/render/v1/{output}"; | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public void handle(final HttpServerExchange exchange) { |     public void handle(final HttpServerExchange exchange) { | ||||||
|  | @ -28,7 +28,7 @@ public class RenderHandler extends AbstractHttpHandler { | ||||||
|             final OutputType output = this.getOutputType(httpServerExchange); |             final OutputType output = this.getOutputType(httpServerExchange); | ||||||
|             final byte[] render; |             final byte[] render; | ||||||
|             try { |             try { | ||||||
|                 final Labyrinth labyrinth = SerializerDeserializer.deserialize(bytes); |                 final Labyrinth labyrinth = SerializerDeserializerV1.deserialize(bytes); | ||||||
|                 render = output.render(labyrinth); |                 render = output.render(labyrinth); | ||||||
|             } catch (final Exception e) { |             } catch (final Exception e) { | ||||||
|                 log.error("Error rendering binary labyrinth data", e); |                 log.error("Error rendering binary labyrinth data", e); | ||||||
|  | @ -0,0 +1,60 @@ | ||||||
|  | package ch.fritteli.labyrinth.server.handler; | ||||||
|  | 
 | ||||||
|  | import ch.fritteli.labyrinth.generator.model.Labyrinth; | ||||||
|  | import ch.fritteli.labyrinth.generator.serialization.v2.SerializerDeserializerV2; | ||||||
|  | import ch.fritteli.labyrinth.server.OutputType; | ||||||
|  | import io.undertow.server.HttpServerExchange; | ||||||
|  | import io.undertow.util.HeaderValues; | ||||||
|  | import io.undertow.util.Headers; | ||||||
|  | import io.undertow.util.StatusCodes; | ||||||
|  | import java.nio.ByteBuffer; | ||||||
|  | import lombok.NonNull; | ||||||
|  | import lombok.extern.slf4j.Slf4j; | ||||||
|  | 
 | ||||||
|  | @Slf4j | ||||||
|  | public class RenderV2Handler extends AbstractHttpHandler { | ||||||
|  | 
 | ||||||
|  |     public static final String PATH_TEMPLATE = "/render/v2/{output}"; | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void handle(final HttpServerExchange exchange) { | ||||||
|  |         log.debug("Handling render request"); | ||||||
|  | 
 | ||||||
|  |         if (exchange.isInIoThread()) { | ||||||
|  |             exchange.dispatch(this); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         exchange.getRequestReceiver().receiveFullBytes((httpServerExchange, bytes) -> { | ||||||
|  |             final OutputType output = this.getOutputType(httpServerExchange); | ||||||
|  |             final byte[] render; | ||||||
|  |             try { | ||||||
|  |                 final Labyrinth labyrinth = SerializerDeserializerV2.deserialize(bytes); | ||||||
|  |                 render = output.render(labyrinth); | ||||||
|  |             } catch (final Exception e) { | ||||||
|  |                 log.error("Error rendering binary labyrinth data", e); | ||||||
|  |                 httpServerExchange.setStatusCode(StatusCodes.INTERNAL_SERVER_ERROR) | ||||||
|  |                         .getResponseSender() | ||||||
|  |                         .send("Error rendering labyrinth: %s".formatted(e.getMessage())); | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |             httpServerExchange | ||||||
|  |                     .setStatusCode(StatusCodes.OK) | ||||||
|  |                     .getResponseHeaders() | ||||||
|  |                     .put(Headers.CONTENT_TYPE, output.getContentType()); | ||||||
|  |             httpServerExchange.getResponseSender() | ||||||
|  |                     .send(ByteBuffer.wrap(render)); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @NonNull | ||||||
|  |     private OutputType getOutputType(@NonNull final HttpServerExchange httpServerExchange) { | ||||||
|  |         return RequestParameter.OUTPUT.<OutputType>getParameterValue(httpServerExchange.getQueryParameters()) | ||||||
|  |                 .getOrElse(() -> { | ||||||
|  |                     final HeaderValues accept = httpServerExchange.getRequestHeaders().get(Headers.ACCEPT); | ||||||
|  |                     if (accept.contains(OutputType.HTML.getContentType())) { | ||||||
|  |                         return OutputType.HTML; | ||||||
|  |                     } | ||||||
|  |                     return OutputType.TEXT_PLAIN; | ||||||
|  |                 }); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -1,5 +1,6 @@ | ||||||
| package ch.fritteli.labyrinth.server.handler; | package ch.fritteli.labyrinth.server.handler; | ||||||
| 
 | 
 | ||||||
|  | import ch.fritteli.labyrinth.generator.model.Position; | ||||||
| import ch.fritteli.labyrinth.server.OutputType; | import ch.fritteli.labyrinth.server.OutputType; | ||||||
| import io.vavr.Tuple2; | import io.vavr.Tuple2; | ||||||
| import io.vavr.collection.HashMap; | import io.vavr.collection.HashMap; | ||||||
|  | @ -26,7 +27,23 @@ enum RequestParameter { | ||||||
|             .toOption() |             .toOption() | ||||||
|             .onEmpty(() -> log.debug("Unparseable value for parameter 'id': '{}'", p)), "i", "id"), |             .onEmpty(() -> log.debug("Unparseable value for parameter 'id': '{}'", p)), "i", "id"), | ||||||
|     OUTPUT(p -> OutputType.ofString(p) |     OUTPUT(p -> OutputType.ofString(p) | ||||||
|             .onEmpty(() -> log.debug("Unparseable value for parameter 'output': '{}'", p)), "o", "output"); |             .onEmpty(() -> log.debug("Unparseable value for parameter 'output': '{}'", p)), "o", "output"), | ||||||
|  |     START(p -> Try.of(() -> { | ||||||
|  |                 final String[] parts = p.split(","); | ||||||
|  |                 final int x = Integer.parseInt(parts[0]); | ||||||
|  |                 final int y = Integer.parseInt(parts[1]); | ||||||
|  |                 return new Position(x, y); | ||||||
|  |             }) | ||||||
|  |             .toOption() | ||||||
|  |             .onEmpty(() -> log.debug("Unparseable value for parameter 'start': '{}'", p)), "s", "start"), | ||||||
|  |     END(p -> Try.of(() -> { | ||||||
|  |                 final String[] parts = p.split(","); | ||||||
|  |                 final int x = Integer.parseInt(parts[0]); | ||||||
|  |                 final int y = Integer.parseInt(parts[1]); | ||||||
|  |                 return new Position(x, y); | ||||||
|  |             }) | ||||||
|  |             .toOption() | ||||||
|  |             .onEmpty(() -> log.debug("Unparseable value for parameter 'end': '{}'", p)), "e", "end"); | ||||||
|     @NonNull |     @NonNull | ||||||
|     private final Function<String, Option<?>> extractor; |     private final Function<String, Option<?>> extractor; | ||||||
|     @Getter |     @Getter | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue