diff --git a/flash-extensions/flash-ext-routeviewer/src/main/resources/routeviewer/index.html b/flash-extensions/flash-ext-routeviewer/src/main/resources/routeviewer/index.html index 720f499..bab0ef8 100644 --- a/flash-extensions/flash-ext-routeviewer/src/main/resources/routeviewer/index.html +++ b/flash-extensions/flash-ext-routeviewer/src/main/resources/routeviewer/index.html @@ -1,13 +1,13 @@ - - - - - - Flash Route Viewer + + + + + + Flash Route Viewer - - -
- - + + +
+ + diff --git a/flash-extensions/flash-ext-view-jte/jte-classes/gg/jte/generated/ondemand/pages/JtehomeGenerated.class b/flash-extensions/flash-ext-view-jte/jte-classes/gg/jte/generated/ondemand/pages/JtehomeGenerated.class index 64f788b..22995af 100644 Binary files a/flash-extensions/flash-ext-view-jte/jte-classes/gg/jte/generated/ondemand/pages/JtehomeGenerated.class and b/flash-extensions/flash-ext-view-jte/jte-classes/gg/jte/generated/ondemand/pages/JtehomeGenerated.class differ diff --git a/flash-extensions/flash-ext-view-jte/jte-classes/gg/jte/generated/ondemand/pages/JtehomeGenerated.java b/flash-extensions/flash-ext-view-jte/jte-classes/gg/jte/generated/ondemand/pages/JtehomeGenerated.java index 421290c..9fb39b4 100644 --- a/flash-extensions/flash-ext-view-jte/jte-classes/gg/jte/generated/ondemand/pages/JtehomeGenerated.java +++ b/flash-extensions/flash-ext-view-jte/jte-classes/gg/jte/generated/ondemand/pages/JtehomeGenerated.java @@ -6,19 +6,19 @@ public final class JtehomeGenerated { public static final String JTE_NAME = "pages/home.jte"; public static final int[] JTE_LINE_INFO = {0,0,1,2,2,2,2,6,6,6,6,7,7,7,8,8,8,9,9,9,10,10,10,2,3,4,4,4,4}; public static void render(gg.jte.html.HtmlTemplateOutput jteOutput, gg.jte.html.HtmlInterceptor jteHtmlInterceptor, HomePage page, String build, Map global) { - jteOutput.writeContent("\r\n

"); + jteOutput.writeContent("\n

"); jteOutput.setContext("h1", null); jteOutput.writeUserContent(page.title()); - jteOutput.writeContent("

\r\n

"); + jteOutput.writeContent("\n

"); jteOutput.setContext("p", null); jteOutput.writeUserContent(page.author()); - jteOutput.writeContent("

\r\n"); + jteOutput.writeContent("

\n"); jteOutput.setContext("small", null); jteOutput.writeUserContent(build); - jteOutput.writeContent("\r\n"); + jteOutput.writeContent("\n"); jteOutput.setContext("small", null); jteOutput.writeUserContent((String) global.get("appName")); - jteOutput.writeContent("\r\n"); + jteOutput.writeContent("
\n"); } public static void renderMap(gg.jte.html.HtmlTemplateOutput jteOutput, gg.jte.html.HtmlInterceptor jteHtmlInterceptor, java.util.Map params) { HomePage page = (HomePage)params.get("page"); diff --git a/flash-extensions/flash-ext-view-jte/src/main/java/dev/relism/flash/ext/view/jte/JteExtension.java b/flash-extensions/flash-ext-view-jte/src/main/java/dev/relism/flash/ext/view/jte/JteExtension.java index 6ff638c..d7cbf7f 100644 --- a/flash-extensions/flash-ext-view-jte/src/main/java/dev/relism/flash/ext/view/jte/JteExtension.java +++ b/flash-extensions/flash-ext-view-jte/src/main/java/dev/relism/flash/ext/view/jte/JteExtension.java @@ -1,5 +1,7 @@ package dev.relism.flash.ext.view.jte; +import dev.relism.flash.extension.FlashContext; +import dev.relism.flash.extension.FlashRegistrar; import dev.relism.flash.ext.view.core.BaseViewExtension; import dev.relism.flash.ext.view.core.GlobalValue; import dev.relism.flash.ext.view.core.ViewRuntimeBridge; @@ -10,9 +12,6 @@ import java.util.List; import java.util.function.Consumer; import java.util.function.Function; -/** - * Opinionated jte SSR extension for Flash. - */ public final class JteExtension extends BaseViewExtension { private final JteSettings settings; @@ -21,7 +20,7 @@ public final class JteExtension extends BaseViewExtension { } public JteExtension() { - this(JteSettings.builder().build()); + this.settings = JteSettings.builder().build(); } public JteExtension(Consumer customizer) { @@ -34,6 +33,41 @@ public final class JteExtension extends BaseViewExtension { this.settings = settings; } + public JteExtension templateRoot(String templateRoot) { + return new JteExtension(settings.toBuilder().templateRoot(templateRoot).build()); + } + + public JteExtension serveStatics(boolean serveStatics) { + return new JteExtension(settings.toBuilder().serveStatics(serveStatics).build()); + } + + public JteExtension staticPrefix(String staticPrefix) { + return new JteExtension(settings.toBuilder().staticPrefix(staticPrefix).build()); + } + + public JteExtension withStaticCors() { + return new JteExtension(settings.toBuilder().enableStaticCors(true).build()); + } + + public JteExtension staticCors(Consumer corsConfig) { + JteSettings.Builder builder = settings.toBuilder(); + builder.enableStaticCors(true); + corsConfig.accept(builder); + return new JteExtension(builder.build()); + } + + @Override + public void routes(FlashRegistrar app, FlashContext ctx) { + if (!settings.serveStatics()) return; + JteStaticServing staticServing = JteStaticServing.load(settings); + if (staticServing == null) return; + + String wildcard = settings.staticPrefix() + "/**"; + StaticJteHandler handler = new StaticJteHandler(staticServing); + app.get(wildcard, handler::handle); + app.head(wildcard, (req, res) -> { staticServing.serve(req, res, true); return null; }); + } + @Override public JteExtension addGlobal(String key, Function resolver) { super.addGlobal(key, resolver); @@ -60,6 +94,24 @@ public final class JteExtension extends BaseViewExtension { } } + JteSettings getSettings() { + return settings; + } + + private static final class StaticJteHandler extends dev.relism.flash.models.RequestHandler { + private final JteStaticServing serving; + + StaticJteHandler(JteStaticServing serving) { + this.serving = serving; + } + + @Override + public Object handle(dev.relism.flash.models.Request req, dev.relism.flash.models.Response res) { + serving.serve(req, res, false); + return null; + } + } + private static void ensureJtePresent() { try { Class.forName("gg.jte.TemplateEngine", false, JteExtension.class.getClassLoader()); diff --git a/flash-extensions/flash-ext-view-jte/src/main/java/dev/relism/ext/view/jte/JteStaticServing.java b/flash-extensions/flash-ext-view-jte/src/main/java/dev/relism/flash/ext/view/jte/JteStaticServing.java similarity index 98% rename from flash-extensions/flash-ext-view-jte/src/main/java/dev/relism/ext/view/jte/JteStaticServing.java rename to flash-extensions/flash-ext-view-jte/src/main/java/dev/relism/flash/ext/view/jte/JteStaticServing.java index 16a0f7c..b0a8dee 100644 --- a/flash-extensions/flash-ext-view-jte/src/main/java/dev/relism/ext/view/jte/JteStaticServing.java +++ b/flash-extensions/flash-ext-view-jte/src/main/java/dev/relism/flash/ext/view/jte/JteStaticServing.java @@ -1,8 +1,8 @@ -package dev.relism.ext.view.jte; +package dev.relism.flash.ext.view.jte; -import dev.relism.http.HttpStatus; -import dev.relism.models.Request; -import dev.relism.models.Response; +import dev.relism.flash.http.HttpStatus; +import dev.relism.flash.models.Request; +import dev.relism.flash.models.Response; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -202,4 +202,4 @@ final class JteStaticServing { } private record RangeSlice(int start, int end, int length) {} -} +} \ No newline at end of file diff --git a/flash-extensions/flash-ext-view-jte/src/test/java/dev/relism/flash/ext/view/jte/JteExtensionTest.java b/flash-extensions/flash-ext-view-jte/src/test/java/dev/relism/flash/ext/view/jte/JteExtensionTest.java index 0f8e2c6..4a9d129 100644 --- a/flash-extensions/flash-ext-view-jte/src/test/java/dev/relism/flash/ext/view/jte/JteExtensionTest.java +++ b/flash-extensions/flash-ext-view-jte/src/test/java/dev/relism/flash/ext/view/jte/JteExtensionTest.java @@ -92,7 +92,7 @@ class JteExtensionTest { void routes_register_static_wildcard_when_enabled() { JteExtension ext = new JteExtension(cfg -> cfg.staticPrefix("/assets")); TestRegistrar app = new TestRegistrar(); - ext.routes(app, new dev.relism.extension.FlashContext()); + ext.routes(app, new dev.relism.flash.extension.FlashContext()); assertTrue(app.routes.containsKey("GET /assets/**")); assertTrue(app.routes.containsKey("HEAD /assets/**")); } @@ -101,7 +101,7 @@ class JteExtensionTest { void routes_do_not_register_static_when_disabled() { JteExtension ext = new JteExtension().serveStatics(false); TestRegistrar app = new TestRegistrar(); - ext.routes(app, new dev.relism.extension.FlashContext()); + ext.routes(app, new dev.relism.flash.extension.FlashContext()); assertTrue(app.routes.isEmpty()); } @@ -111,10 +111,10 @@ class JteExtensionTest { .staticPrefix("/assets") .largeFileThresholdBytes(1)); TestRegistrar app = new TestRegistrar(); - ext.routes(app, new dev.relism.extension.FlashContext()); + ext.routes(app, new dev.relism.flash.extension.FlashContext()); Request req = request("/assets/sample.css", null, null, null); - Response res = new Response(200, dev.relism.http.ContentType.TEXT_PLAIN); + Response res = new Response(200, dev.relism.flash.http.ContentType.TEXT_PLAIN); Object out = app.routes.get("GET /assets/**").handle(req, res); assertEquals(null, out); @@ -124,13 +124,7 @@ class JteExtensionTest { } private static JteSettings readSettings(JteExtension ext) { - try { - var f = JteExtension.class.getDeclaredField("settings"); - f.setAccessible(true); - return (JteSettings) f.get(ext); - } catch (Exception e) { - throw new RuntimeException(e); - } + return ext.getSettings(); } private static void invokeValidate(JteExtension ext, Class type) throws Exception { @@ -147,39 +141,39 @@ class JteExtensionTest { } private static Request request(String path, String query, String acceptEncoding, String origin) { - dev.relism.models.HeaderMap headers = new dev.relism.models.HeaderMap(); + dev.relism.flash.models.HeaderMap headers = new dev.relism.flash.models.HeaderMap(); String raw = "Host: localhost\r\n"; if (acceptEncoding != null) raw += "Accept-Encoding: " + acceptEncoding + "\r\n"; if (origin != null) raw += "Origin: " + origin + "\r\n"; byte[] bytes = raw.getBytes(StandardCharsets.UTF_8); headers.reset(bytes, 0, bytes.length); - dev.relism.models.RequestLine line = new dev.relism.models.RequestLine( - dev.relism.http.HttpMethod.GET, - new dev.relism.routing.routers.fastpathrouter.FastPathViews.StringByteView(path), - query == null ? null : new dev.relism.routing.routers.fastpathrouter.FastPathViews.StringByteView(query), - new dev.relism.routing.routers.fastpathrouter.FastPathViews.StringByteView("HTTP/1.1"), + dev.relism.flash.models.RequestLine line = new dev.relism.flash.models.RequestLine( + dev.relism.flash.http.HttpMethod.GET, + new dev.relism.flash.routing.routers.fastpathrouter.FastPathViews.StringByteView(path), + query == null ? null : new dev.relism.flash.routing.routers.fastpathrouter.FastPathViews.StringByteView(query), + new dev.relism.flash.routing.routers.fastpathrouter.FastPathViews.StringByteView("HTTP/1.1"), headers ); return new Request(line, new byte[0]); } - private static final class TestRegistrar extends dev.relism.extension.FlashRegistrar { + private static final class TestRegistrar extends dev.relism.flash.extension.FlashRegistrar { private final Map routes = new HashMap<>(); - private final List mws = new ArrayList<>(); + private final List mws = new ArrayList<>(); @Override - public dev.relism.extension.FlashContext ctx() { - return new dev.relism.extension.FlashContext(); + public dev.relism.flash.extension.FlashContext ctx() { + return new dev.relism.flash.extension.FlashContext(); } @Override - protected void addRoute(dev.relism.http.HttpMethod method, String path, RequestHandler handler, List mw) { + protected void addRoute(dev.relism.flash.http.HttpMethod method, String path, RequestHandler handler, List mw) { routes.put(method.name() + " " + path, handler); } @Override - protected void addMiddleware(dev.relism.routing.Middleware mw) { + protected void addMiddleware(dev.relism.flash.routing.Middleware mw) { mws.add(mw); } } diff --git a/flash-extensions/flash-ext-view-jte/src/test/java/dev/relism/ext/view/jte/JteStaticServingTest.java b/flash-extensions/flash-ext-view-jte/src/test/java/dev/relism/flash/ext/view/jte/JteStaticServingTest.java similarity index 98% rename from flash-extensions/flash-ext-view-jte/src/test/java/dev/relism/ext/view/jte/JteStaticServingTest.java rename to flash-extensions/flash-ext-view-jte/src/test/java/dev/relism/flash/ext/view/jte/JteStaticServingTest.java index 405e7d1..3060cff 100644 --- a/flash-extensions/flash-ext-view-jte/src/test/java/dev/relism/ext/view/jte/JteStaticServingTest.java +++ b/flash-extensions/flash-ext-view-jte/src/test/java/dev/relism/flash/ext/view/jte/JteStaticServingTest.java @@ -1,4 +1,4 @@ -package dev.relism.ext.view.jte; +package dev.relism.flash.ext.view.jte; import org.junit.jupiter.api.Test; @@ -47,4 +47,4 @@ class JteStaticServingTest { assertEquals(-1, JteStaticServing.rangeLength("bytes=100-120", 100)); assertEquals(-1, JteStaticServing.rangeLength("invalid", 100)); } -} +} \ No newline at end of file diff --git a/flash/src/main/java/dev/relism/flash/Main.java b/flash/src/main/java/dev/relism/flash/Main.java new file mode 100644 index 0000000..f4c5813 --- /dev/null +++ b/flash/src/main/java/dev/relism/flash/Main.java @@ -0,0 +1,48 @@ +package dev.relism.flash; + +import dev.relism.flash.extension.FlashApp; +import dev.relism.flash.http.ContentType; +import dev.relism.flash.http.HttpMethod; +import dev.relism.flash.routing.Middleware; +import lombok.extern.slf4j.Slf4j; + +import java.nio.file.Files; +import java.nio.file.Path; + +@Slf4j +public class Main { + + private static final int PORT = 8080; + private static final Path UPLOAD_DIR = Path.of(System.getProperty("java.io.tmpdir"), "flash-uploads"); + + private static final Middleware CORS = next -> (req, res) -> { + res + .header("Access-Control-Allow-Origin", "*") + .header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS") + .header("Access-Control-Allow-Headers", "Content-Type, Authorization"); + if (req.method() == HttpMethod.OPTIONS) { res.status(204); return null; } + return next.handle(req, res); + }; + + private static final Middleware ACCESS_LOG = next -> (req, res) -> { + long start = System.nanoTime(); + try { + return next.handle(req, res); + } finally { + log.info("{} {} -> {}ms", req.method(), req.path(), + (System.nanoTime() - start) / 1_000_000.0); + } + }; + + + public static void main(String[] args) throws Exception { + Files.createDirectories(UPLOAD_DIR); + + FlashApp.create(PORT) + .get("/plaintext", (req, res) -> { + res.type(ContentType.TEXT_PLAIN); + return "Hello, World!"; + }, ACCESS_LOG, CORS) + .startAndBlock(); + } +} diff --git a/flash/src/main/java/dev/relism/flash/http/HttpStatus.java b/flash/src/main/java/dev/relism/flash/http/HttpStatus.java index 9d3f3ca..58bafba 100644 --- a/flash/src/main/java/dev/relism/flash/http/HttpStatus.java +++ b/flash/src/main/java/dev/relism/flash/http/HttpStatus.java @@ -1,10 +1,5 @@ package dev.relism.flash.http; -import dev.relism.models.Request; -import dev.relism.models.Response; -import dev.relism.routing.GET; -import dev.relism.routing.Route; - import java.nio.charset.StandardCharsets; import java.util.List;