fix: merge jte extension refactor with static serving features
- Move JteStaticServing to dev.relism.flash package - Fix imports in HttpStatus and test files - Add fluent config methods to JteExtension (templateRoot, serveStatics, staticPrefix, etc.) - Implement routes() for static asset serving with HEAD support - Include Main.java entry point
This commit is contained in:
BIN
Binary file not shown.
+5
-5
@@ -6,19 +6,19 @@ public final class JtehomeGenerated {
|
|||||||
public static final String JTE_NAME = "pages/home.jte";
|
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 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<String, Object> global) {
|
public static void render(gg.jte.html.HtmlTemplateOutput jteOutput, gg.jte.html.HtmlInterceptor jteHtmlInterceptor, HomePage page, String build, Map<String, Object> global) {
|
||||||
jteOutput.writeContent("\r\n<h1>");
|
jteOutput.writeContent("\n<h1>");
|
||||||
jteOutput.setContext("h1", null);
|
jteOutput.setContext("h1", null);
|
||||||
jteOutput.writeUserContent(page.title());
|
jteOutput.writeUserContent(page.title());
|
||||||
jteOutput.writeContent("</h1>\r\n<p>");
|
jteOutput.writeContent("</h1>\n<p>");
|
||||||
jteOutput.setContext("p", null);
|
jteOutput.setContext("p", null);
|
||||||
jteOutput.writeUserContent(page.author());
|
jteOutput.writeUserContent(page.author());
|
||||||
jteOutput.writeContent("</p>\r\n<small>");
|
jteOutput.writeContent("</p>\n<small>");
|
||||||
jteOutput.setContext("small", null);
|
jteOutput.setContext("small", null);
|
||||||
jteOutput.writeUserContent(build);
|
jteOutput.writeUserContent(build);
|
||||||
jteOutput.writeContent("</small>\r\n<small>");
|
jteOutput.writeContent("</small>\n<small>");
|
||||||
jteOutput.setContext("small", null);
|
jteOutput.setContext("small", null);
|
||||||
jteOutput.writeUserContent((String) global.get("appName"));
|
jteOutput.writeUserContent((String) global.get("appName"));
|
||||||
jteOutput.writeContent("</small>\r\n");
|
jteOutput.writeContent("</small>\n");
|
||||||
}
|
}
|
||||||
public static void renderMap(gg.jte.html.HtmlTemplateOutput jteOutput, gg.jte.html.HtmlInterceptor jteHtmlInterceptor, java.util.Map<String, Object> params) {
|
public static void renderMap(gg.jte.html.HtmlTemplateOutput jteOutput, gg.jte.html.HtmlInterceptor jteHtmlInterceptor, java.util.Map<String, Object> params) {
|
||||||
HomePage page = (HomePage)params.get("page");
|
HomePage page = (HomePage)params.get("page");
|
||||||
|
|||||||
+56
-4
@@ -1,5 +1,7 @@
|
|||||||
package dev.relism.flash.ext.view.jte;
|
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.BaseViewExtension;
|
||||||
import dev.relism.flash.ext.view.core.GlobalValue;
|
import dev.relism.flash.ext.view.core.GlobalValue;
|
||||||
import dev.relism.flash.ext.view.core.ViewRuntimeBridge;
|
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.Consumer;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
/**
|
|
||||||
* Opinionated jte SSR extension for Flash.
|
|
||||||
*/
|
|
||||||
public final class JteExtension extends BaseViewExtension<JteTarget> {
|
public final class JteExtension extends BaseViewExtension<JteTarget> {
|
||||||
private final JteSettings settings;
|
private final JteSettings settings;
|
||||||
|
|
||||||
@@ -21,7 +20,7 @@ public final class JteExtension extends BaseViewExtension<JteTarget> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public JteExtension() {
|
public JteExtension() {
|
||||||
this(JteSettings.builder().build());
|
this.settings = JteSettings.builder().build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public JteExtension(Consumer<JteSettings.Builder> customizer) {
|
public JteExtension(Consumer<JteSettings.Builder> customizer) {
|
||||||
@@ -34,6 +33,41 @@ public final class JteExtension extends BaseViewExtension<JteTarget> {
|
|||||||
this.settings = settings;
|
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<JteSettings.Builder> 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
|
@Override
|
||||||
public JteExtension addGlobal(String key, Function<Request, Object> resolver) {
|
public JteExtension addGlobal(String key, Function<Request, Object> resolver) {
|
||||||
super.addGlobal(key, resolver);
|
super.addGlobal(key, resolver);
|
||||||
@@ -60,6 +94,24 @@ public final class JteExtension extends BaseViewExtension<JteTarget> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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() {
|
private static void ensureJtePresent() {
|
||||||
try {
|
try {
|
||||||
Class.forName("gg.jte.TemplateEngine", false, JteExtension.class.getClassLoader());
|
Class.forName("gg.jte.TemplateEngine", false, JteExtension.class.getClassLoader());
|
||||||
|
|||||||
+4
-4
@@ -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.flash.http.HttpStatus;
|
||||||
import dev.relism.models.Request;
|
import dev.relism.flash.models.Request;
|
||||||
import dev.relism.models.Response;
|
import dev.relism.flash.models.Response;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
+17
-23
@@ -92,7 +92,7 @@ class JteExtensionTest {
|
|||||||
void routes_register_static_wildcard_when_enabled() {
|
void routes_register_static_wildcard_when_enabled() {
|
||||||
JteExtension ext = new JteExtension(cfg -> cfg.staticPrefix("/assets"));
|
JteExtension ext = new JteExtension(cfg -> cfg.staticPrefix("/assets"));
|
||||||
TestRegistrar app = new TestRegistrar();
|
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("GET /assets/**"));
|
||||||
assertTrue(app.routes.containsKey("HEAD /assets/**"));
|
assertTrue(app.routes.containsKey("HEAD /assets/**"));
|
||||||
}
|
}
|
||||||
@@ -101,7 +101,7 @@ class JteExtensionTest {
|
|||||||
void routes_do_not_register_static_when_disabled() {
|
void routes_do_not_register_static_when_disabled() {
|
||||||
JteExtension ext = new JteExtension().serveStatics(false);
|
JteExtension ext = new JteExtension().serveStatics(false);
|
||||||
TestRegistrar app = new TestRegistrar();
|
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());
|
assertTrue(app.routes.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,10 +111,10 @@ class JteExtensionTest {
|
|||||||
.staticPrefix("/assets")
|
.staticPrefix("/assets")
|
||||||
.largeFileThresholdBytes(1));
|
.largeFileThresholdBytes(1));
|
||||||
TestRegistrar app = new TestRegistrar();
|
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);
|
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);
|
Object out = app.routes.get("GET /assets/**").handle(req, res);
|
||||||
|
|
||||||
assertEquals(null, out);
|
assertEquals(null, out);
|
||||||
@@ -124,13 +124,7 @@ class JteExtensionTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static JteSettings readSettings(JteExtension ext) {
|
private static JteSettings readSettings(JteExtension ext) {
|
||||||
try {
|
return ext.getSettings();
|
||||||
var f = JteExtension.class.getDeclaredField("settings");
|
|
||||||
f.setAccessible(true);
|
|
||||||
return (JteSettings) f.get(ext);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void invokeValidate(JteExtension ext, Class<? extends RequestHandler> type) throws Exception {
|
private static void invokeValidate(JteExtension ext, Class<? extends RequestHandler> type) throws Exception {
|
||||||
@@ -147,39 +141,39 @@ class JteExtensionTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static Request request(String path, String query, String acceptEncoding, String origin) {
|
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";
|
String raw = "Host: localhost\r\n";
|
||||||
if (acceptEncoding != null) raw += "Accept-Encoding: " + acceptEncoding + "\r\n";
|
if (acceptEncoding != null) raw += "Accept-Encoding: " + acceptEncoding + "\r\n";
|
||||||
if (origin != null) raw += "Origin: " + origin + "\r\n";
|
if (origin != null) raw += "Origin: " + origin + "\r\n";
|
||||||
byte[] bytes = raw.getBytes(StandardCharsets.UTF_8);
|
byte[] bytes = raw.getBytes(StandardCharsets.UTF_8);
|
||||||
headers.reset(bytes, 0, bytes.length);
|
headers.reset(bytes, 0, bytes.length);
|
||||||
|
|
||||||
dev.relism.models.RequestLine line = new dev.relism.models.RequestLine(
|
dev.relism.flash.models.RequestLine line = new dev.relism.flash.models.RequestLine(
|
||||||
dev.relism.http.HttpMethod.GET,
|
dev.relism.flash.http.HttpMethod.GET,
|
||||||
new dev.relism.routing.routers.fastpathrouter.FastPathViews.StringByteView(path),
|
new dev.relism.flash.routing.routers.fastpathrouter.FastPathViews.StringByteView(path),
|
||||||
query == null ? null : new dev.relism.routing.routers.fastpathrouter.FastPathViews.StringByteView(query),
|
query == null ? null : new dev.relism.flash.routing.routers.fastpathrouter.FastPathViews.StringByteView(query),
|
||||||
new dev.relism.routing.routers.fastpathrouter.FastPathViews.StringByteView("HTTP/1.1"),
|
new dev.relism.flash.routing.routers.fastpathrouter.FastPathViews.StringByteView("HTTP/1.1"),
|
||||||
headers
|
headers
|
||||||
);
|
);
|
||||||
return new Request(line, new byte[0]);
|
return new Request(line, new byte[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class TestRegistrar extends dev.relism.extension.FlashRegistrar<TestRegistrar> {
|
private static final class TestRegistrar extends dev.relism.flash.extension.FlashRegistrar<TestRegistrar> {
|
||||||
private final Map<String, RequestHandler> routes = new HashMap<>();
|
private final Map<String, RequestHandler> routes = new HashMap<>();
|
||||||
private final List<dev.relism.routing.Middleware> mws = new ArrayList<>();
|
private final List<dev.relism.flash.routing.Middleware> mws = new ArrayList<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public dev.relism.extension.FlashContext ctx() {
|
public dev.relism.flash.extension.FlashContext ctx() {
|
||||||
return new dev.relism.extension.FlashContext();
|
return new dev.relism.flash.extension.FlashContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void addRoute(dev.relism.http.HttpMethod method, String path, RequestHandler handler, List<dev.relism.routing.Middleware> mw) {
|
protected void addRoute(dev.relism.flash.http.HttpMethod method, String path, RequestHandler handler, List<dev.relism.flash.routing.Middleware> mw) {
|
||||||
routes.put(method.name() + " " + path, handler);
|
routes.put(method.name() + " " + path, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void addMiddleware(dev.relism.routing.Middleware mw) {
|
protected void addMiddleware(dev.relism.flash.routing.Middleware mw) {
|
||||||
mws.add(mw);
|
mws.add(mw);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package dev.relism.ext.view.jte;
|
package dev.relism.flash.ext.view.jte;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,5 @@
|
|||||||
package dev.relism.flash.http;
|
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.nio.charset.StandardCharsets;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user