com.danielflower.apprunner.web.WebServer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of app-runner Show documentation
Show all versions of app-runner Show documentation
A self-hosted platform-as-a-service that hosts web apps written in Java, Clojure, NodeJS, Python, golang and Scala.
package com.danielflower.apprunner.web;
import com.danielflower.apprunner.Config;
import com.danielflower.apprunner.problems.AppRunnerException;
import com.danielflower.apprunner.web.v1.AppResource;
import com.danielflower.apprunner.web.v1.SystemResource;
import io.muserver.ContentTypes;
import io.muserver.Method;
import io.muserver.MuServer;
import io.muserver.MuServerBuilder;
import io.muserver.openapi.OpenAPIObjectBuilder;
import io.muserver.rest.RestHandlerBuilder;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.http.HttpClientTransportOverHTTP;
import org.eclipse.jetty.util.HttpCookieStore;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.net.ServerSocket;
import static io.muserver.ContextHandlerBuilder.context;
import static io.muserver.openapi.InfoObjectBuilder.infoObject;
public class WebServer implements AutoCloseable {
public static final Logger log = LoggerFactory.getLogger(WebServer.class);
private final ProxyMap proxyMap;
private final int httpPort;
private final int httpsPort;
private final SSLContext sslContext;
private MuServer muServer;
private final String defaultAppName;
private final SystemResource systemResource;
private final AppResource appResource;
private final int idleTimeout;
private final int totalTimeout;
private HttpClient rpClient;
public WebServer(int httpPort, int httpsPort, SSLContext sslContext, ProxyMap proxyMap, String defaultAppName, SystemResource systemResource, AppResource appResource, int idleTimeout, int totalTimeout) {
this.httpPort = httpPort;
this.httpsPort = httpsPort;
this.sslContext = sslContext;
this.proxyMap = proxyMap;
this.defaultAppName = defaultAppName;
this.systemResource = systemResource;
this.appResource = appResource;
this.idleTimeout = idleTimeout;
this.totalTimeout = totalTimeout;
}
public static int getAFreePort() {
try {
try (ServerSocket serverSocket = new ServerSocket(0)) {
return serverSocket.getLocalPort();
}
} catch (IOException e) {
throw new AppRunnerException("Unable to get a port", e);
}
}
public void start() throws Exception {
rpClient = createClient();
muServer = MuServerBuilder.muServer()
.withHttpPort(httpPort)
.withHttpsPort(httpsPort)
.withHttpsConfig(sslContext)
.addHandler(Method.GET, "/", (request, response, pathParams) -> {
if (StringUtils.isNotEmpty(defaultAppName)) {
response.redirect("/" + defaultAppName);
} else {
response.status(400);
response.contentType(ContentTypes.TEXT_PLAIN);
response.write("You can set a default app by setting the " + Config.DEFAULT_APP_NAME + " property.");
}
})
.addHandler(context("api")
.addHandler((request, response) -> {
response.headers().set("Access-Control-Allow-Origin", "*");
response.headers().set("Access-Control-Allow-Headers",
"origin, content-type, accept, authorization");
response.headers().set("Access-Control-Allow-Credentials", "true");
response.headers().set("Access-Control-Allow-Methods",
"GET, POST, PUT, DELETE, OPTIONS, HEAD");
return false;
})
.addHandler(context("v1")
.addHandler(
RestHandlerBuilder.restHandler(systemResource, appResource)
.withOpenApiJsonUrl("swagger.json")
.withOpenApiHtmlUrl("api.html")
.withOpenApiDocument(OpenAPIObjectBuilder.openAPIObject()
.withInfo(infoObject()
.withTitle("App Runner")
.withDescription("The REST API for App Runner which is used for registering apps, deploying apps, viewing logs etc.")
.withVersion("1.0")
.build())
)
)
))
.addHandler(null, "/{appName : [^/?]+}{ignored:(.*)}", new AppReverseProxy(rpClient, proxyMap, totalTimeout))
.start();
log.info("Started web server at " + muServer.httpsUri() + " / " + muServer.httpUri());
}
private HttpClient createClient() throws Exception {
int selectors = Math.max(1, Runtime.getRuntime().availableProcessors() / 2);
HttpClient client = new HttpClient(new HttpClientTransportOverHTTP(selectors), new SslContextFactory(true));
client.setFollowRedirects(false);
client.setCookieStore(new HttpCookieStore.Empty());
client.setMaxConnectionsPerDestination(256);
client.setAddressResolutionTimeout(15000);
client.setConnectTimeout(15000);
client.setIdleTimeout(idleTimeout);
client.setUserAgentField(null);
client.start();
client.getContentDecoderFactories().clear();
return client;
}
public void close() throws Exception {
if (muServer != null) {
muServer.stop();
muServer = null;
}
if (rpClient != null) {
rpClient.stop();
rpClient = null;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy