diff --git a/client/pom.xml b/client/pom.xml
index 751cca31..abca8e98 100644
--- a/client/pom.xml
+++ b/client/pom.xml
@@ -82,6 +82,21 @@
org.openjfx
javafx-media
+
+ org.eclipse.jetty
+ jetty-server
+ [9.3.24.v20180605,)
+
+
+ org.eclipse.jetty
+ jetty-servlet
+ [9.3.24.v20180605,)
+
+
+ com.vladsch.flexmark
+ flexmark-all
+ 0.40.34
+
diff --git a/client/src/main/java/ctbrec/docs/DocServer.java b/client/src/main/java/ctbrec/docs/DocServer.java
new file mode 100644
index 00000000..1d1057e9
--- /dev/null
+++ b/client/src/main/java/ctbrec/docs/DocServer.java
@@ -0,0 +1,56 @@
+package ctbrec.docs;
+
+import java.net.BindException;
+
+import org.eclipse.jetty.server.Handler;
+import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.server.HttpConnectionFactory;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.server.handler.HandlerList;
+import org.eclipse.jetty.servlet.ServletHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DocServer {
+ private static final transient Logger LOG = LoggerFactory.getLogger(DocServer.class);
+
+ private static Server server = new Server();
+ private static volatile boolean started = false;
+
+ public synchronized static void start() throws Exception {
+ if(started) {
+ return;
+ }
+
+ server = new Server();
+
+ HttpConfiguration config = new HttpConfiguration();
+ config.setSendServerVersion(false);
+ ServerConnector http = new ServerConnector(server, new HttpConnectionFactory(config));
+ http.setPort(5689);
+ server.addConnector(http);
+
+ ServletHandler handler = new ServletHandler();
+ server.setHandler(handler);
+ HandlerList handlers = new HandlerList();
+ handlers.setHandlers(new Handler[] { handler });
+ server.setHandler(handlers);
+
+ MarkdownServlet markdownServlet = new MarkdownServlet();
+ ServletHolder holder = new ServletHolder(markdownServlet);
+ handler.addServletWithMapping(holder, "/docs/*");
+ StaticFileServlet staticFileServlet = new StaticFileServlet();
+ holder = new ServletHolder(staticFileServlet);
+ handler.addServletWithMapping(holder, "/static/*");
+
+ try {
+ server.start();
+ started = true;
+ server.join();
+ } catch (BindException e) {
+ LOG.error("Port {} is already in use", http.getPort(), e);
+ }
+ }
+}
diff --git a/client/src/main/java/ctbrec/docs/MarkdownServlet.java b/client/src/main/java/ctbrec/docs/MarkdownServlet.java
new file mode 100644
index 00000000..c93e7535
--- /dev/null
+++ b/client/src/main/java/ctbrec/docs/MarkdownServlet.java
@@ -0,0 +1,79 @@
+package ctbrec.docs;
+
+import java.io.ByteArrayOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.vladsch.flexmark.html.HtmlRenderer;
+import com.vladsch.flexmark.parser.Parser;
+import com.vladsch.flexmark.util.ast.Node;
+import com.vladsch.flexmark.util.options.MutableDataSet;
+
+public class MarkdownServlet extends HttpServlet {
+
+ private static final transient Logger LOG = LoggerFactory.getLogger(MarkdownServlet.class);
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ String path = req.getRequestURI();
+ LOG.debug("Path: [{}]", path);
+ try {
+ String md = loadMarkdown(path);
+ String html = markdownToHtml(md);
+ resp.setStatus(HttpServletResponse.SC_OK);
+ resp.getWriter().println(getHeader());
+ resp.getWriter().println(html);
+ resp.getWriter().println(getFooter());
+ } catch (FileNotFoundException e) {
+ resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
+ resp.setContentType("text/plain");
+ resp.getWriter().println("Hö?");
+ resp.getWriter().println();
+ }
+ }
+
+ private String markdownToHtml(String markdown) {
+ MutableDataSet options = new MutableDataSet();
+ Parser parser = Parser.builder(options).build();
+ HtmlRenderer renderer = HtmlRenderer.builder(options).build();
+ Node document = parser.parse(markdown);
+ String html = renderer.render(document);
+ return html;
+ }
+
+ private String loadMarkdown(String path) throws IOException {
+ String resource = "/html" + path;
+ return loadFile(resource);
+ }
+
+ private String loadFile(String resource) throws IOException {
+ InputStream resourceAsStream = getClass().getResourceAsStream(resource);
+ if(resourceAsStream == null) {
+ throw new FileNotFoundException();
+ }
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ int length = 0;
+ byte[] buffer = new byte[1024];
+ while( (length = resourceAsStream.read(buffer)) >= 0 ) {
+ out.write(buffer, 0, length);
+ }
+ return new String(out.toByteArray(), "utf-8");
+ }
+
+ private String getHeader() throws IOException {
+ return loadFile("/html/docs/header.html");
+ }
+
+ private String getFooter() throws IOException {
+ return loadFile("/html/docs/footer.html");
+ }
+}
diff --git a/client/src/main/java/ctbrec/docs/StaticFileServlet.java b/client/src/main/java/ctbrec/docs/StaticFileServlet.java
new file mode 100644
index 00000000..b195a3db
--- /dev/null
+++ b/client/src/main/java/ctbrec/docs/StaticFileServlet.java
@@ -0,0 +1,37 @@
+package ctbrec.docs;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+public class StaticFileServlet extends HttpServlet {
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ String request = req.getRequestURI();
+ serveFile(request, resp);
+ }
+
+ @Override
+ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ doGet(req, resp);
+ }
+
+ private void serveFile(String resource, HttpServletResponse resp) throws IOException {
+ InputStream resourceAsStream = getClass().getResourceAsStream("/html" + resource);
+ if(resourceAsStream == null) {
+ throw new FileNotFoundException();
+ }
+ OutputStream out = resp.getOutputStream();
+ int length = 0;
+ byte[] buffer = new byte[1024];
+ while( (length = resourceAsStream.read(buffer)) >= 0 ) {
+ out.write(buffer, 0, length);
+ }
+ }
+}
diff --git a/client/src/main/java/ctbrec/ui/CamrecApplication.java b/client/src/main/java/ctbrec/ui/CamrecApplication.java
index ab111385..59165e9a 100644
--- a/client/src/main/java/ctbrec/ui/CamrecApplication.java
+++ b/client/src/main/java/ctbrec/ui/CamrecApplication.java
@@ -26,6 +26,7 @@ import ctbrec.Config;
import ctbrec.Model;
import ctbrec.StringUtil;
import ctbrec.Version;
+import ctbrec.docs.DocServer;
import ctbrec.event.Event;
import ctbrec.event.EventBusHolder;
import ctbrec.event.EventHandler;
@@ -108,6 +109,14 @@ public class CamrecApplication extends Application {
}
createGui(primaryStage);
checkForUpdates();
+
+ new Thread(() -> {
+ try {
+ DocServer.start();
+ } catch (Exception e) {
+ LOG.error("Couldn't start documentation server", e);
+ }
+ }).start();
}
private void logEnvironment() {
diff --git a/client/src/main/resources/html/docs/RunningTheServer.md b/client/src/main/resources/html/docs/RunningTheServer.md
new file mode 100644
index 00000000..ca8b294b
--- /dev/null
+++ b/client/src/main/resources/html/docs/RunningTheServer.md
@@ -0,0 +1,11 @@
+How To Run The Server
+=======================
+The archive you downloaded contains a `server.bat` or `server.sh`, which can be used to start the server. On the first start, the server uses a default configuration. Once you terminate the server by pressing ctrl + c, the config is stored in your user home.
+
+On Windows that is `C:\Users\{your user name}\AppData\Roaming\ctbrec\server.json`
+
+On Linux it is `~/.config/ctbrec/server.json`
+
+On macOS it is `/Users/{your user name}/Library/Preferences/ctbrec`
+
+You can open this file in a text editor and change it to your likings. You probably only want to change httpPort and recordingsDir. Most of the other stuff is irrelevant since the server and CTB Recorder use the same config file format. When the server is running, you can connect to it with CTB Recorder by changing the setting "Record location" to "Remote".
\ No newline at end of file
diff --git a/client/src/main/resources/html/docs/footer.html b/client/src/main/resources/html/docs/footer.html
new file mode 100644
index 00000000..96fba82e
--- /dev/null
+++ b/client/src/main/resources/html/docs/footer.html
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+