Skip to content

Commit

Permalink
closes asciidoctor#468: adds first life refresh in http mojo
Browse files Browse the repository at this point in the history
  • Loading branch information
abelsromero committed Sep 6, 2020
1 parent 14e0635 commit 2e75af5
Show file tree
Hide file tree
Showing 6 changed files with 512 additions and 92 deletions.
58 changes: 4 additions & 54 deletions src/main/java/org/asciidoctor/maven/AsciidoctorHttpMojo.java
Original file line number Diff line number Diff line change
@@ -1,18 +1,10 @@
package org.asciidoctor.maven;

import org.apache.commons.io.IOUtils;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.asciidoctor.Asciidoctor;
import org.asciidoctor.maven.http.AsciidoctorHttpServer;
import org.asciidoctor.maven.io.IO;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.Map;

@Mojo(name = "http")
public class AsciidoctorHttpMojo extends AsciidoctorRefreshMojo {
Expand All @@ -25,60 +17,18 @@ public class AsciidoctorHttpMojo extends AsciidoctorRefreshMojo {
@Parameter(property = PREFIX + "home", defaultValue = "index")
protected String home;

@Parameter(property = PREFIX + "reload-interval", defaultValue = "0")
protected int autoReloadInterval;


@Override
public void execute() throws MojoExecutionException, MojoFailureException {

final AsciidoctorHttpServer server = new AsciidoctorHttpServer(getLog(), port, outputDirectory, home);

startPolling();
server.start();
doWork();
doWait();
server.stop();
}

@Override
protected void convertFile(final Asciidoctor asciidoctorInstance, final Map<String, Object> options, final File f) {
asciidoctorInstance.convertFile(f, options);
logConvertedFile(f);

if (autoReloadInterval > 0 && backend.toLowerCase().startsWith("html")) {
final String filename = f.getName();
final File out = new File(outputDirectory, filename.substring(0, filename.lastIndexOf(".")) + ".html");
if (out.exists()) {

String content = null;

{ // read
FileInputStream fis = null;
try {
fis = new FileInputStream(out); // java asciidoctor render() doesn't work ATM so read the converted file instead of doing it in memory
content = IO.slurp(fis);
} catch (final Exception e) {
getLog().error(e);
} finally {
IOUtils.closeQuietly(fis);
}
}

if (content != null) { // convert + write
FileOutputStream fos = null;
try {
fos = new FileOutputStream(out);
fos.write(addRefreshing(content).getBytes());
} catch (final Exception e) {
getLog().error(e);
} finally {
IOUtils.closeQuietly(fos);
}
}
}
}
}

private String addRefreshing(final String html) {
return html.replace("</body>", "<script>setTimeout(\"location.reload(true);\"," + autoReloadInterval + ");</script>\n</body>");
stopMonitors();
}

public String getHome() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ private void showWaitMessage() {
getLog().info("Type [exit|quit] to exit and [refresh] to force a manual re-conversion.");
}

private void stopMonitors() throws MojoExecutionException {
protected void stopMonitors() throws MojoExecutionException {
if (monitors != null) {
for (final FileAlterationMonitor monitor : monitors) {
try {
Expand All @@ -88,7 +88,7 @@ private void stopMonitors() throws MojoExecutionException {
}
}

private void startPolling() throws MojoExecutionException {
protected void startPolling() throws MojoExecutionException {

// TODO avoid duplication with AsciidoctorMojo
final Optional<File> sourceDirectoryCandidate = findSourceDirectory(sourceDirectory, project.getBasedir());
Expand Down
82 changes: 48 additions & 34 deletions src/main/java/org/asciidoctor/maven/http/AsciidoctorHandler.java
Original file line number Diff line number Diff line change
@@ -1,24 +1,22 @@
package org.asciidoctor.maven.http;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.*;
import io.netty.util.CharsetUtil;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.nio.charset.StandardCharsets;

public class AsciidoctorHandler extends SimpleChannelInboundHandler<FullHttpRequest> {

private static final String HTML_MEDIA_TYPE = "text/html";
public static final String HTML_EXTENSION = ".html";

Expand All @@ -37,40 +35,57 @@ public AsciidoctorHandler(final File workDir, final String defaultPage) {

@Override
public void channelRead0(final ChannelHandlerContext ctx, final FullHttpRequest msg) throws Exception {
if (msg.getMethod() != HttpMethod.GET) {
final DefaultFullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
HttpResponseStatus.METHOD_NOT_ALLOWED,
Unpooled.copiedBuffer("<html><body>Only GET method allowed</body></html>", CharsetUtil.UTF_8));

if (msg.getMethod() != HttpMethod.GET && msg.getMethod() != HttpMethod.HEAD) {
send(ctx, new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.METHOD_NOT_ALLOWED));
return;
}

final File file = deduceFile(msg.getUri());

if (!file.exists()) {
final ByteBuf body = Unpooled.copiedBuffer("<body><html>File not found: " + file.getPath() + "<body></html>", CharsetUtil.UTF_8);
final DefaultFullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NOT_FOUND, body);
response.headers().set(HttpHeaders.Names.CONTENT_TYPE, HTML_MEDIA_TYPE);
send(ctx, response);
return;
}

final File file = deduceFile(msg.getUri());
// HEAD means we already loaded the page, so we know is HTML
if (msg.getMethod() == HttpMethod.HEAD) {
final DefaultFullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.RESET_CONTENT);

final HttpHeaders headers = response.headers();
// Test if retuning any size works
headers.set(HttpHeaders.Names.CONTENT_LENGTH, file.length());
headers.set(HttpHeaders.Names.EXPIRES, 0);
headers.set(HttpHeaders.Names.CONTENT_TYPE, HTML_MEDIA_TYPE);
send(ctx, response);
return;
}

final HttpResponseStatus status;
final ByteBuf body;
final String mediaType;
if (file.exists()) {

if (file.getName().endsWith("html")) {
final String content = FileUtils.readFileToString(file, StandardCharsets.UTF_8);
body = Unpooled.copiedBuffer(addRefreshing(content), CharsetUtil.UTF_8);
} else {
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
final FileInputStream fileInputStream = new FileInputStream(file);
IOUtils.copy(fileInputStream, baos);
body = Unpooled.copiedBuffer(baos.toByteArray());
body = Unpooled.copiedBuffer(FileUtils.readFileToByteArray(file));
IOUtils.closeQuietly(fileInputStream);

mediaType = mediaType(file.getName());
status = HttpResponseStatus.OK;
} else {
body = Unpooled.copiedBuffer("<body><html>File not found: " + file.getPath() + "<body></html>", CharsetUtil.UTF_8);
status = HttpResponseStatus.NOT_FOUND;
mediaType = HTML_MEDIA_TYPE;
}

final DefaultFullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status, body);
response.headers().set(HttpHeaders.Names.CONTENT_TYPE, mediaType);
final DefaultFullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, body);
response.headers().set(HttpHeaders.Names.CONTENT_TYPE, mediaType(file.getName()));
send(ctx, response);
}

private String addRefreshing(final String html) {
return html.replace("</body>", "<script src=\"http://livejs.com/live.js#html\"></script></body>");
}

private void send(final ChannelHandlerContext ctx, final DefaultFullHttpResponse response) {
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
}
Expand All @@ -80,18 +95,17 @@ private File deduceFile(final String path) {
return new File(directory, defaultPage);
}

if (!path.contains(".")) {
return new File(directory, addDefaultExtension(path));
}

return new File(directory, path);
return new File(directory, path.contains(".") ? path : addDefaultExtension(path));
}

private static String addDefaultExtension(String path) {
return path + HTML_EXTENSION;
}

private static String mediaType(final String name) {
if (name.endsWith(".html")) {
return HTML_MEDIA_TYPE;
}
if (name.endsWith(".js")) {
return "text/javascript";
}
Expand All @@ -107,6 +121,6 @@ private static String mediaType(final String name) {
if (name.endsWith(".jpeg") || name.endsWith(".jpg")) {
return "image/jpeg";
}
return HTML_MEDIA_TYPE;
return "application/octet-stream";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public AsciidoctorHttpServer(final Log logger, final int port, final File output
this.defaultPage = defaultPage;
}

public void start() {
public AsciidoctorHttpServer start() {
final AtomicInteger threadId = new AtomicInteger(1);
workerGroup = new NioEventLoopGroup(THREAD_NUMBER, new ThreadFactory() {
@Override
Expand Down Expand Up @@ -89,6 +89,7 @@ public void operationComplete(final ChannelFuture future) throws Exception {
} catch (final InterruptedException e) {
logger.error(e.getMessage(), e);
}
return this;
}

public void stop() {
Expand Down
Loading

0 comments on commit 2e75af5

Please sign in to comment.