207 lines
7.9 KiB
Java
207 lines
7.9 KiB
Java
package io.gitlab.jfronny.libjf.web.impl;
|
|
|
|
import io.gitlab.jfronny.libjf.LibJf;
|
|
import io.gitlab.jfronny.libjf.web.api.*;
|
|
import io.gitlab.jfronny.libjf.web.impl.util.WebPaths;
|
|
import io.gitlab.jfronny.libjf.web.impl.util.bluemapcore.*;
|
|
import net.fabricmc.loader.api.FabricLoader;
|
|
|
|
import javax.management.openmbean.KeyAlreadyExistsException;
|
|
import java.io.*;
|
|
import java.nio.file.Files;
|
|
import java.nio.file.Path;
|
|
import java.util.Objects;
|
|
import java.util.stream.Stream;
|
|
|
|
public class JfWebServer implements WebServer {
|
|
private HttpServer server = null;
|
|
private final RequestHandler handler = new RequestHandler();
|
|
private final int port;
|
|
private final int maxConnections;
|
|
private final DefaultFileHost dfh = new DefaultFileHost();
|
|
public JfWebServer(int port, int maxConnections) {
|
|
this.port = port;
|
|
this.maxConnections = maxConnections;
|
|
}
|
|
|
|
@Override
|
|
public String register(String webPath, ContentProvider provider) {
|
|
webPath = WebPaths.simplify(webPath);
|
|
if (handler.contentProviders.containsKey(webPath))
|
|
throw new KeyAlreadyExistsException("A ContentProvider already exists at that address (" + handler.contentProviders.get(webPath).getClass() + ")");
|
|
handler.contentProviders.put(webPath, provider);
|
|
return WebPaths.concat(getServerRoot(), webPath);
|
|
}
|
|
|
|
@Override
|
|
public String registerFile(String webPath, Path file, Boolean readOnSend) throws IOException {
|
|
if (readOnSend) {
|
|
if (!Files.exists(file))
|
|
throw new FileNotFoundException();
|
|
register(webPath, s -> {
|
|
HttpResponse resp = new HttpResponse(HttpStatusCode.OK);
|
|
resp.addHeader("Content-Type", Files.probeContentType(file));
|
|
resp.addHeader("Content-Length", String.valueOf(Files.size(file)));
|
|
FileInputStream fs = new FileInputStream(file.toFile());
|
|
resp.setData(fs);
|
|
return resp;
|
|
});
|
|
return WebPaths.concat(getServerRoot(), webPath);
|
|
}
|
|
else {
|
|
return registerFile(webPath, Files.readAllBytes(file), Files.probeContentType(file));
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public String registerFile(String webPath, byte[] data, String contentType) {
|
|
return register(webPath, s -> {
|
|
HttpResponse resp = new HttpResponse(HttpStatusCode.OK);
|
|
resp.addHeader("Content-Type", contentType);
|
|
resp.addHeader("Content-Length", String.valueOf(data.length));
|
|
ByteArrayInputStream fs = new ByteArrayInputStream(data);
|
|
resp.setData(fs);
|
|
return resp;
|
|
});
|
|
}
|
|
|
|
@Override
|
|
public String registerDir(String webPath, Path dir, Boolean readOnSend) throws IOException {
|
|
try (Stream<Path> contentPath = Files.walk(dir)) {
|
|
if (readOnSend) {
|
|
return registerSubServer(webPath, (s, t) -> {
|
|
final boolean[] c = {false};
|
|
final Path[] p_f = new Path[1];
|
|
contentPath.filter(Files::isRegularFile)
|
|
.filter(Files::isReadable)
|
|
.forEach(q -> {
|
|
if (c[0])
|
|
return;
|
|
Path p = dir.toAbsolutePath().relativize(q.toAbsolutePath());
|
|
String wp = webPath;
|
|
for (Path path : p) {
|
|
wp = WebPaths.concat(wp, path.toString());
|
|
}
|
|
if (Objects.equals(WebPaths.simplify(wp), WebPaths.simplify(WebPaths.concat(t)))) {
|
|
p_f[0] = q;
|
|
c[0] = true;
|
|
}
|
|
});
|
|
HttpResponse resp;
|
|
if (c[0]) {
|
|
resp = new HttpResponse(HttpStatusCode.OK);
|
|
resp.addHeader("Content-Type", Files.probeContentType(p_f[0]));
|
|
resp.addHeader("Content-Length", String.valueOf(Files.size(p_f[0])));
|
|
FileInputStream fs = new FileInputStream(p_f[0].toFile());
|
|
resp.setData(fs);
|
|
} else {
|
|
resp = new HttpResponse(HttpStatusCode.NOT_FOUND);
|
|
}
|
|
return resp;
|
|
});
|
|
} else {
|
|
contentPath.filter(Files::isRegularFile)
|
|
.filter(Files::isReadable)
|
|
.forEach(s -> {
|
|
Path p = dir.toAbsolutePath().relativize(s.toAbsolutePath());
|
|
String wp = webPath;
|
|
for (Path path : p) wp = WebPaths.concat(wp, path.toString());
|
|
try {
|
|
registerFile(wp, s, false);
|
|
} catch (IOException e) {
|
|
LibJf.LOGGER.error("Could not register static file", e);
|
|
}
|
|
});
|
|
}
|
|
return WebPaths.concat(getServerRoot(), webPath);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public String registerSubServer(String webPath, SubServer subServer) {
|
|
return registerSubServer(webPath, new AdvancedSubServer() {
|
|
@Override
|
|
public void onStop() {
|
|
|
|
}
|
|
|
|
@Override
|
|
public void onStart() {
|
|
|
|
}
|
|
|
|
@Override
|
|
public HttpResponse handle(HttpRequest request, String[] segments) throws IOException {
|
|
return subServer.handle(request, segments);
|
|
}
|
|
});
|
|
}
|
|
|
|
@Override
|
|
public String registerSubServer(String webPath, AdvancedSubServer subServer) {
|
|
webPath = WebPaths.simplify(webPath);
|
|
if (handler.subServers.containsKey(webPath))
|
|
throw new KeyAlreadyExistsException("A Subserver already exists at that address (" + handler.subServers.get(webPath).getClass() + ")");
|
|
handler.subServers.put(webPath, subServer);
|
|
return WebPaths.concat(getServerRoot(), webPath);
|
|
}
|
|
|
|
@Override
|
|
public String getServerRoot() {
|
|
String ip = JfWebConfig.serverIp;
|
|
if (!ip.startsWith("http"))
|
|
ip = "http://" + ip;
|
|
if (JfWebConfig.portOverride != -1) {
|
|
return WebPaths.simplify(ip) + ":" + JfWebConfig.portOverride;
|
|
}
|
|
return WebPaths.simplify(ip) + ":" + JfWebConfig.port;
|
|
}
|
|
|
|
@Override
|
|
public synchronized void stop() {
|
|
for (AdvancedSubServer subServer : handler.subServers.values()) subServer.onStop();
|
|
if (server != null) {
|
|
try {
|
|
server.close();
|
|
server.join();
|
|
}
|
|
catch (InterruptedException e) {
|
|
//It is most likely already dead
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public synchronized void restart() {
|
|
JfWebConfig.ensureValidPort();
|
|
int tmpPort = port;
|
|
if (server != null) {
|
|
tmpPort = server.getPort();
|
|
stop();
|
|
}
|
|
handler.clear();
|
|
server = new HttpServer(null, tmpPort, maxConnections, handler, () -> {
|
|
if (JfWebConfig.enableFileHost) dfh.register(this);
|
|
FabricLoader.getInstance().getEntrypointContainers(LibJf.MOD_ID + ":web", WebInit.class).forEach(entrypoint -> {
|
|
WebInit init = entrypoint.getEntrypoint();
|
|
init.register(this);
|
|
});
|
|
});
|
|
server.start();
|
|
try {
|
|
server.waitUntilReady();
|
|
} catch (InterruptedException e) {
|
|
stop();
|
|
LibJf.LOGGER.error("Server could not be readied", e);
|
|
}
|
|
for (AdvancedSubServer subServer : handler.subServers.values()) {
|
|
subServer.onStart();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean isActive() {
|
|
return server != null && server.isAlive();
|
|
}
|
|
}
|