mirror of
https://github.com/Qortal/qortal.git
synced 2025-02-14 11:15:49 +00:00
FATJAR packaging + block explorer changes
Switched from maven-assembly-plugin to maven-shade-plugin for building FATJAR. When running from FATJAR, class-path is ". .." to help find log4j2.properties file. Swagger-UI can now be served direct from inside FATJAR instead of requiring resources in filesystem. Default package Start now controller/Controller block-explorer.html now served via Jetty and modified to use relative URLs instead of absolute http://localhost:9085/... style Improved shutdown code in controller /admin/stop API call disabled for now Highly permissive settings.json added
This commit is contained in:
parent
ad9fa9bf9d
commit
28c2cdaf5b
@ -88,7 +88,7 @@
|
|||||||
document.body.innerHTML = html;
|
document.body.innerHTML = html;
|
||||||
|
|
||||||
XHR({
|
XHR({
|
||||||
url: "http://localhost:9085/transactions/address/" + address,
|
url: "/transactions/address/" + address,
|
||||||
onload: renderAddressTransactions,
|
onload: renderAddressTransactions,
|
||||||
responseType: "json"
|
responseType: "json"
|
||||||
});
|
});
|
||||||
@ -96,7 +96,7 @@
|
|||||||
|
|
||||||
function fetchAddressInfo(address) {
|
function fetchAddressInfo(address) {
|
||||||
XHR({
|
XHR({
|
||||||
url: "http://localhost:9085/addresses/assets/" + address,
|
url: "/addresses/assets/" + address,
|
||||||
onload: renderAddressInfo,
|
onload: renderAddressInfo,
|
||||||
responseType: "json"
|
responseType: "json"
|
||||||
});
|
});
|
||||||
@ -181,7 +181,7 @@
|
|||||||
|
|
||||||
// Fetch block's transactions
|
// Fetch block's transactions
|
||||||
XHR({
|
XHR({
|
||||||
url: "http://localhost:9085/transactions/block/" + blockData.signature,
|
url: "/transactions/block/" + blockData.signature,
|
||||||
onload: renderBlockTransactions,
|
onload: renderBlockTransactions,
|
||||||
responseType: "json"
|
responseType: "json"
|
||||||
});
|
});
|
||||||
@ -189,7 +189,7 @@
|
|||||||
|
|
||||||
function fetchBlockInfo(height) {
|
function fetchBlockInfo(height) {
|
||||||
XHR({
|
XHR({
|
||||||
url: "http://localhost:9085/blocks/byheight/" + height,
|
url: "/blocks/byheight/" + height,
|
||||||
onload: renderBlockInfo,
|
onload: renderBlockInfo,
|
||||||
responseType: "json"
|
responseType: "json"
|
||||||
});
|
});
|
||||||
@ -227,7 +227,7 @@
|
|||||||
|
|
||||||
function shutdownAPI() {
|
function shutdownAPI() {
|
||||||
XHR({
|
XHR({
|
||||||
url: "http://localhost:9085/admin/stop",
|
url: "/admin/stop",
|
||||||
onload: showShutdown,
|
onload: showShutdown,
|
||||||
responseType: "json"
|
responseType: "json"
|
||||||
});
|
});
|
||||||
@ -247,7 +247,7 @@
|
|||||||
|
|
||||||
for (var h = height; h > 0 && h >= height - 20; --h)
|
for (var h = height; h > 0 && h >= height - 20; --h)
|
||||||
XHR({
|
XHR({
|
||||||
url: "http://localhost:9085/blocks/byheight/" + h,
|
url: "/blocks/byheight/" + h,
|
||||||
onload: listBlock,
|
onload: listBlock,
|
||||||
responseType: "json"
|
responseType: "json"
|
||||||
});
|
});
|
||||||
@ -264,7 +264,7 @@
|
|||||||
|
|
||||||
function windowOnLoad() {
|
function windowOnLoad() {
|
||||||
XHR({
|
XHR({
|
||||||
url: "http://localhost:9085/blocks/height",
|
url: "/blocks/height",
|
||||||
onload: initialBlocks,
|
onload: initialBlocks,
|
||||||
responseType: "json"
|
responseType: "json"
|
||||||
});
|
});
|
||||||
|
88
pom.xml
88
pom.xml
@ -4,6 +4,7 @@
|
|||||||
<groupId>org.qora</groupId>
|
<groupId>org.qora</groupId>
|
||||||
<artifactId>qora-core</artifactId>
|
<artifactId>qora-core</artifactId>
|
||||||
<version>2.0.0-SNAPSHOT</version>
|
<version>2.0.0-SNAPSHOT</version>
|
||||||
|
<packaging>jar</packaging>
|
||||||
<properties>
|
<properties>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<swagger-ui.version>3.19.0</swagger-ui.version>
|
<swagger-ui.version>3.19.0</swagger-ui.version>
|
||||||
@ -20,36 +21,6 @@
|
|||||||
<target>1.8</target>
|
<target>1.8</target>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-assembly-plugin</artifactId>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<phase>package</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>single</goal>
|
|
||||||
</goals>
|
|
||||||
<configuration>
|
|
||||||
<archive>
|
|
||||||
<manifest>
|
|
||||||
<mainClass>
|
|
||||||
Start
|
|
||||||
</mainClass>
|
|
||||||
<addClasspath>true</addClasspath>
|
|
||||||
</manifest>
|
|
||||||
<manifestEntries>
|
|
||||||
<Class-Path>. ..</Class-Path>
|
|
||||||
</manifestEntries>
|
|
||||||
</archive>
|
|
||||||
<descriptorRefs>
|
|
||||||
<descriptorRef>jar-with-dependencies</descriptorRef>
|
|
||||||
</descriptorRefs>
|
|
||||||
<finalName>Qora</finalName>
|
|
||||||
<appendAssemblyId>false</appendAssemblyId>
|
|
||||||
</configuration>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
<!-- unpack swagger-ui to target folder -->
|
<!-- unpack swagger-ui to target folder -->
|
||||||
<plugin>
|
<plugin>
|
||||||
<artifactId>maven-dependency-plugin</artifactId>
|
<artifactId>maven-dependency-plugin</artifactId>
|
||||||
@ -118,6 +89,63 @@
|
|||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
|
<version>3.0.2</version>
|
||||||
|
<configuration>
|
||||||
|
<archive>
|
||||||
|
<manifest>
|
||||||
|
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
|
||||||
|
</manifest>
|
||||||
|
</archive>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
|
<version>2.4.3</version>
|
||||||
|
<configuration>
|
||||||
|
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||||
|
<artifactSet>
|
||||||
|
<excludes>
|
||||||
|
<!-- Don't include original swagger-UI as we're including our own modified version -->
|
||||||
|
<exclude>org.webjars:swagger-ui</exclude>
|
||||||
|
</excludes>
|
||||||
|
</artifactSet>
|
||||||
|
<filters>
|
||||||
|
<filter>
|
||||||
|
<artifact>*:*</artifact>
|
||||||
|
<excludes>
|
||||||
|
<exclude>META-INF/*.SF</exclude>
|
||||||
|
<exclude>META-INF/*.DSA</exclude>
|
||||||
|
<exclude>META-INF/*.RSA</exclude>
|
||||||
|
</excludes>
|
||||||
|
</filter>
|
||||||
|
</filters>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>shade</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<transformers>
|
||||||
|
<transformer
|
||||||
|
implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer" />
|
||||||
|
<transformer
|
||||||
|
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||||
|
<mainClass>controller.Controller</mainClass>
|
||||||
|
<manifestEntries>
|
||||||
|
<Class-Path>. ..</Class-Path>
|
||||||
|
</manifestEntries>
|
||||||
|
</transformer>
|
||||||
|
</transformers>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
<repositories>
|
<repositories>
|
||||||
|
6
settings.json
Normal file
6
settings.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"rpcallowed": [
|
||||||
|
"::/0",
|
||||||
|
"0.0.0.0/0"
|
||||||
|
]
|
||||||
|
}
|
@ -1,25 +0,0 @@
|
|||||||
|
|
||||||
import api.ApiService;
|
|
||||||
import repository.DataException;
|
|
||||||
import repository.RepositoryFactory;
|
|
||||||
import repository.RepositoryManager;
|
|
||||||
import repository.hsqldb.HSQLDBRepositoryFactory;
|
|
||||||
|
|
||||||
public class Start {
|
|
||||||
|
|
||||||
private static final String connectionUrl = "jdbc:hsqldb:file:db/test;create=true";
|
|
||||||
|
|
||||||
public static void main(String args[]) throws DataException {
|
|
||||||
RepositoryFactory repositoryFactory = new HSQLDBRepositoryFactory(connectionUrl);
|
|
||||||
RepositoryManager.setRepositoryFactory(repositoryFactory);
|
|
||||||
|
|
||||||
ApiService apiService = ApiService.getInstance();
|
|
||||||
apiService.start();
|
|
||||||
|
|
||||||
//// testing the API client
|
|
||||||
//ApiClient client = ApiClient.getInstance();
|
|
||||||
//String test = client.executeCommand("GET blocks/first");
|
|
||||||
//System.out.println(test);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -15,8 +15,8 @@ import javax.ws.rs.Path;
|
|||||||
import javax.ws.rs.Produces;
|
import javax.ws.rs.Produces;
|
||||||
import javax.ws.rs.core.Context;
|
import javax.ws.rs.core.Context;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
import repository.DataException;
|
|
||||||
import repository.RepositoryManager;
|
import controller.Controller;
|
||||||
|
|
||||||
@Path("admin")
|
@Path("admin")
|
||||||
@Produces({MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN})
|
@Produces({MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN})
|
||||||
@ -95,20 +95,14 @@ public class AdminResource {
|
|||||||
public String shutdown() {
|
public String shutdown() {
|
||||||
Security.checkApiCallAllowed("GET admin/stop", request);
|
Security.checkApiCallAllowed("GET admin/stop", request);
|
||||||
|
|
||||||
try {
|
|
||||||
RepositoryManager.closeRepositoryFactory();
|
|
||||||
} catch (DataException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
new Thread(new Runnable() {
|
new Thread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
ApiService.getInstance().stop();
|
Controller.shutdown();
|
||||||
}
|
}
|
||||||
}).start();
|
}); // disabled for now: .start();
|
||||||
|
|
||||||
return "true";
|
return "false";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package api;
|
|||||||
|
|
||||||
import io.swagger.v3.jaxrs2.integration.resources.OpenApiResource;
|
import io.swagger.v3.jaxrs2.integration.resources.OpenApiResource;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import org.eclipse.jetty.rewrite.handler.RedirectPatternRule;
|
import org.eclipse.jetty.rewrite.handler.RedirectPatternRule;
|
||||||
@ -26,32 +25,33 @@ public class ApiService {
|
|||||||
private final Set<Class<?>> resources;
|
private final Set<Class<?>> resources;
|
||||||
|
|
||||||
public ApiService() {
|
public ApiService() {
|
||||||
// resources to register
|
// Resources to register
|
||||||
this.resources = new HashSet<Class<?>>();
|
this.resources = new HashSet<Class<?>>();
|
||||||
this.resources.add(AddressesResource.class);
|
this.resources.add(AddressesResource.class);
|
||||||
this.resources.add(AdminResource.class);
|
this.resources.add(AdminResource.class);
|
||||||
this.resources.add(BlocksResource.class);
|
this.resources.add(BlocksResource.class);
|
||||||
this.resources.add(TransactionsResource.class);
|
this.resources.add(TransactionsResource.class);
|
||||||
|
this.resources.add(BlockExplorerResource.class);
|
||||||
this.resources.add(OpenApiResource.class); // swagger
|
this.resources.add(OpenApiResource.class); // swagger
|
||||||
this.resources.add(ApiDefinition.class); // for API definition
|
this.resources.add(ApiDefinition.class); // for API definition
|
||||||
this.resources.add(AnnotationPostProcessor.class); // for API resource annotations
|
this.resources.add(AnnotationPostProcessor.class); // for API resource annotations
|
||||||
ResourceConfig config = new ResourceConfig(this.resources);
|
ResourceConfig config = new ResourceConfig(this.resources);
|
||||||
|
|
||||||
// create RPC server
|
// Create RPC server
|
||||||
this.server = new Server(Settings.getInstance().getRpcPort());
|
this.server = new Server(Settings.getInstance().getRpcPort());
|
||||||
|
|
||||||
// whitelist
|
// IP address based access control
|
||||||
InetAccessHandler accessHandler = new InetAccessHandler();
|
InetAccessHandler accessHandler = new InetAccessHandler();
|
||||||
for (String pattern : Settings.getInstance().getRpcAllowed()) {
|
for (String pattern : Settings.getInstance().getRpcAllowed()) {
|
||||||
accessHandler.include(pattern);
|
accessHandler.include(pattern);
|
||||||
}
|
}
|
||||||
this.server.setHandler(accessHandler);
|
this.server.setHandler(accessHandler);
|
||||||
|
|
||||||
// url rewriting
|
// URL rewriting
|
||||||
RewriteHandler rewriteHandler = new RewriteHandler();
|
RewriteHandler rewriteHandler = new RewriteHandler();
|
||||||
accessHandler.setHandler(rewriteHandler);
|
accessHandler.setHandler(rewriteHandler);
|
||||||
|
|
||||||
// context
|
// Context
|
||||||
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.NO_SESSIONS);
|
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.NO_SESSIONS);
|
||||||
context.setContextPath("/");
|
context.setContextPath("/");
|
||||||
rewriteHandler.setHandler(context);
|
rewriteHandler.setHandler(context);
|
||||||
@ -69,9 +69,8 @@ public class ApiService {
|
|||||||
|
|
||||||
// Swagger-UI static content
|
// Swagger-UI static content
|
||||||
ClassLoader loader = this.getClass().getClassLoader();
|
ClassLoader loader = this.getClass().getClassLoader();
|
||||||
File swaggerUIResourceLocation = new File(loader.getResource("resources/swagger-ui/").getFile());
|
|
||||||
ServletHolder swaggerUIServlet = new ServletHolder("static-swagger-ui", DefaultServlet.class);
|
ServletHolder swaggerUIServlet = new ServletHolder("static-swagger-ui", DefaultServlet.class);
|
||||||
swaggerUIServlet.setInitParameter("resourceBase", swaggerUIResourceLocation.getAbsolutePath());
|
swaggerUIServlet.setInitParameter("resourceBase", loader.getResource("resources/swagger-ui/").toString());
|
||||||
swaggerUIServlet.setInitParameter("dirAllowed", "true");
|
swaggerUIServlet.setInitParameter("dirAllowed", "true");
|
||||||
swaggerUIServlet.setInitParameter("pathInfoOnly", "true");
|
swaggerUIServlet.setInitParameter("pathInfoOnly", "true");
|
||||||
context.addServlet(swaggerUIServlet, "/api-documentation/*");
|
context.addServlet(swaggerUIServlet, "/api-documentation/*");
|
||||||
@ -96,19 +95,20 @@ public class ApiService {
|
|||||||
|
|
||||||
public void start() {
|
public void start() {
|
||||||
try {
|
try {
|
||||||
// START RPC
|
// Start server
|
||||||
server.start();
|
server.start();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// FAILED TO START RPC
|
// Failed to start
|
||||||
|
throw new RuntimeException("Failed to start API", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stop() {
|
public void stop() {
|
||||||
try {
|
try {
|
||||||
// STOP RPC
|
// Stop server
|
||||||
server.stop();
|
server.stop();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// FAILED TO STOP RPC
|
// Failed to stop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
35
src/api/BlockExplorerResource.java
Normal file
35
src/api/BlockExplorerResource.java
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
package api;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.FileSystems;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.ws.rs.GET;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.Produces;
|
||||||
|
import javax.ws.rs.core.Context;
|
||||||
|
import javax.ws.rs.core.MediaType;
|
||||||
|
|
||||||
|
@Path("/")
|
||||||
|
@Produces({ MediaType.TEXT_HTML })
|
||||||
|
public class BlockExplorerResource {
|
||||||
|
|
||||||
|
@Context
|
||||||
|
HttpServletRequest request;
|
||||||
|
|
||||||
|
public BlockExplorerResource() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("/block-explorer.html")
|
||||||
|
public String getBlockExplorer() {
|
||||||
|
try {
|
||||||
|
byte[] htmlBytes = Files.readAllBytes(FileSystems.getDefault().getPath("block-explorer.html"));
|
||||||
|
return new String(htmlBytes, "UTF-8");
|
||||||
|
} catch (IOException e) {
|
||||||
|
return "block-explorer.html not found";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
59
src/controller/Controller.java
Normal file
59
src/controller/Controller.java
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
package controller;
|
||||||
|
|
||||||
|
import api.ApiService;
|
||||||
|
import repository.DataException;
|
||||||
|
import repository.RepositoryFactory;
|
||||||
|
import repository.RepositoryManager;
|
||||||
|
import repository.hsqldb.HSQLDBRepositoryFactory;
|
||||||
|
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
|
public class Controller {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LogManager.getLogger(Controller.class);
|
||||||
|
|
||||||
|
private static final String connectionUrl = "jdbc:hsqldb:file:db/test;create=true";
|
||||||
|
private static final Object shutdownLock = new Object();
|
||||||
|
private static boolean isStopping = false;
|
||||||
|
|
||||||
|
public static void main(String args[]) throws DataException {
|
||||||
|
LOGGER.info("Starting up...");
|
||||||
|
|
||||||
|
LOGGER.info("Starting repository");
|
||||||
|
RepositoryFactory repositoryFactory = new HSQLDBRepositoryFactory(connectionUrl);
|
||||||
|
RepositoryManager.setRepositoryFactory(repositoryFactory);
|
||||||
|
|
||||||
|
LOGGER.info("Starting API");
|
||||||
|
ApiService apiService = ApiService.getInstance();
|
||||||
|
apiService.start();
|
||||||
|
|
||||||
|
Runtime.getRuntime().addShutdownHook(new Thread() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Controller.shutdown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void shutdown() {
|
||||||
|
synchronized (shutdownLock) {
|
||||||
|
if (!isStopping) {
|
||||||
|
isStopping = true;
|
||||||
|
|
||||||
|
LOGGER.info("Shutting down API");
|
||||||
|
ApiService.getInstance().stop();
|
||||||
|
|
||||||
|
try {
|
||||||
|
LOGGER.info("Shutting down repository");
|
||||||
|
RepositoryManager.closeRepositoryFactory();
|
||||||
|
} catch (DataException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGGER.info("Shutdown complete!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user