forked from Qortal/qortal
Include NTP checking/reconfigure tools + bump version to 1.3.1
SysTray pop-up menu now includes entry for launching https://time.is so node owners can check their system clocks against internet time. Windows installs also have additional systray menu entry which runs ntpcfg.bat script, included in resources. Also available as download via node-UI servlet, e.g. http://localhost:9880/downloads/ntpcfg.bat ntpcfg.bat reconfigures Windows Time Service with many NTP servers, restarts the service, and also makes sure it auto-starts on boot. Added DEBUG-level logging when rejecting nodes due to excessive time difference (during PROOF handshake stage). Bumped default settings values for minOutboundPeers from 10 to 20. Bumped default settings values for maxPeers from 30 to 50.
This commit is contained in:
parent
9ee12f3e45
commit
7042dd819f
@ -9,7 +9,15 @@ import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.awt.event.WindowFocusListener;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JMenuItem;
|
||||
@ -23,11 +31,13 @@ import org.apache.logging.log4j.Logger;
|
||||
import org.qora.controller.Controller;
|
||||
import org.qora.globalization.Translator;
|
||||
import org.qora.settings.Settings;
|
||||
import org.qora.ui.UiService;
|
||||
import org.qora.utils.URLViewer;
|
||||
|
||||
public class SysTray {
|
||||
|
||||
protected static final Logger LOGGER = LogManager.getLogger(SplashFrame.class);
|
||||
private static final String NTP_SCRIPT = "ntpcfg.bat";
|
||||
|
||||
private static SysTray instance;
|
||||
private TrayIcon trayIcon = null;
|
||||
@ -145,6 +155,35 @@ public class SysTray {
|
||||
});
|
||||
menu.add(openUi);
|
||||
|
||||
JMenuItem openTimeCheck = new JMenuItem(Translator.INSTANCE.translate("SysTray", "CHECK_TIME_ACCURACY"));
|
||||
openTimeCheck.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
destroyHiddenDialog();
|
||||
|
||||
try {
|
||||
URLViewer.openWebpage(new URL("https://time.is"));
|
||||
} catch (Exception e1) {
|
||||
LOGGER.error("Unable to open time-check website in browser");
|
||||
}
|
||||
}
|
||||
});
|
||||
menu.add(openTimeCheck);
|
||||
|
||||
// Only for Windows users
|
||||
if (System.getProperty("os.name").toLowerCase().contains("win")) {
|
||||
JMenuItem syncTime = new JMenuItem(Translator.INSTANCE.translate("SysTray", "SYNCHRONIZE_CLOCK"));
|
||||
syncTime.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
destroyHiddenDialog();
|
||||
|
||||
new SynchronizeWorker().execute();
|
||||
}
|
||||
});
|
||||
menu.add(syncTime);
|
||||
}
|
||||
|
||||
JMenuItem exit = new JMenuItem(Translator.INSTANCE.translate("SysTray", "EXIT"));
|
||||
exit.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
@ -159,6 +198,34 @@ public class SysTray {
|
||||
return menu;
|
||||
}
|
||||
|
||||
class SynchronizeWorker extends SwingWorker<Void, Void> {
|
||||
@Override
|
||||
protected Void doInBackground() {
|
||||
// Extract reconfiguration script from resources
|
||||
String resourceName = "/" + UiService.DOWNLOADS_RESOURCE_PATH + "/" + NTP_SCRIPT;
|
||||
Path scriptPath = Paths.get(NTP_SCRIPT);
|
||||
|
||||
try (InputStream in = SysTray.class.getResourceAsStream(resourceName)) {
|
||||
Files.copy(in, scriptPath, StandardCopyOption.REPLACE_EXISTING);
|
||||
} catch (IllegalArgumentException | IOException e) {
|
||||
LOGGER.warn(String.format("Couldn't locate NTP configuration resource: %s", resourceName));
|
||||
return null;
|
||||
}
|
||||
|
||||
// Now execute extracted script
|
||||
List<String> scriptCmd = Arrays.asList(NTP_SCRIPT);
|
||||
LOGGER.info(String.format("Running NTP configuration script: %s", String.join(" ", scriptCmd)));
|
||||
try {
|
||||
new ProcessBuilder(scriptCmd).start();
|
||||
} catch (IOException e) {
|
||||
LOGGER.warn(String.format("Failed to execute NTP configuration script: %s", e.getMessage()));
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class ClosingWorker extends SwingWorker<Void, Void> {
|
||||
@Override
|
||||
protected Void doInBackground() {
|
||||
|
@ -101,8 +101,10 @@ public enum Handshake {
|
||||
ProofMessage proofMessage = (ProofMessage) message;
|
||||
|
||||
// Check peer's timestamp is within acceptable bounds
|
||||
if (Math.abs(proofMessage.getTimestamp() - peer.getConnectionTimestamp()) > MAX_TIMESTAMP_DELTA)
|
||||
if (Math.abs(proofMessage.getTimestamp() - peer.getConnectionTimestamp()) > MAX_TIMESTAMP_DELTA) {
|
||||
LOGGER.debug(String.format("Rejecting PROOF from %s as timestamp delta %d greater than max %d", peer, Math.abs(proofMessage.getTimestamp() - peer.getConnectionTimestamp()), MAX_TIMESTAMP_DELTA));
|
||||
return null;
|
||||
}
|
||||
|
||||
// If we connected outbound to peer, then this is a faked confirmation response, so we're good
|
||||
if (peer.isOutbound())
|
||||
|
@ -75,9 +75,9 @@ public class Settings {
|
||||
/** Minimum number of peers to allow block generation / synchronization. */
|
||||
private int minBlockchainPeers = 3;
|
||||
/** Target number of outbound connections to peers we should make. */
|
||||
private int minOutboundPeers = 10;
|
||||
private int minOutboundPeers = 20;
|
||||
/** Maximum number of peer connections we allow. */
|
||||
private int maxPeers = 30;
|
||||
private int maxPeers = 50;
|
||||
|
||||
// Which blockchains this node is running
|
||||
private String blockchainConfig = null; // use default from resources
|
||||
|
46
src/main/java/org/qora/ui/DownloadResourceService.java
Normal file
46
src/main/java/org/qora/ui/DownloadResourceService.java
Normal file
@ -0,0 +1,46 @@
|
||||
package org.qora.ui;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Enumeration;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.http.HttpContent;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.server.ResourceService;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
|
||||
/**
|
||||
* Replace ResourceService that delivers content as "attachments", typically forcing download instead of rendering.
|
||||
* <p>
|
||||
* Sets <tt>Content-Type</tt> header to <tt>application/octet-stream</tt><br>
|
||||
* Sets <tt>Content-Disposition</tt> header to <tt>attachment; filename="<i>basename</i>"</tt><br>
|
||||
* where <i>basename</i> is that last component of requested URI path.
|
||||
* <p>
|
||||
* Example usage:<br>
|
||||
* <br>
|
||||
* <tt>... = new ServletHolder("servlet-name", new DefaultServlet(new DownloadResourceService()));</tt>
|
||||
*/
|
||||
public class DownloadResourceService extends ResourceService {
|
||||
|
||||
@Override
|
||||
protected boolean sendData(HttpServletRequest request, HttpServletResponse response, boolean include, final HttpContent content, Enumeration<String> reqRanges) throws IOException {
|
||||
final boolean _pathInfoOnly = super.isPathInfoOnly();
|
||||
String servletPath = _pathInfoOnly ? "/" : request.getServletPath();
|
||||
String pathInfo = request.getPathInfo();
|
||||
String pathInContext = URIUtil.addPaths(servletPath,pathInfo);
|
||||
|
||||
// Find basename of requested content
|
||||
final int slashIndex = pathInContext.lastIndexOf(URIUtil.SLASH);
|
||||
if (slashIndex != -1)
|
||||
pathInContext = pathInContext.substring(slashIndex + 1);
|
||||
|
||||
// Add appropriate headers
|
||||
response.setHeader(HttpHeader.CONTENT_TYPE.asString(), "application/octet-stream");
|
||||
response.setHeader("Content-Disposition", "attachment; filename=\"" + pathInContext + "\"");
|
||||
|
||||
return super.sendData(request, response, include, content, reqRanges);
|
||||
}
|
||||
|
||||
}
|
@ -13,6 +13,8 @@ import org.qora.settings.Settings;
|
||||
|
||||
public class UiService {
|
||||
|
||||
public static final String DOWNLOADS_RESOURCE_PATH = "node-ui-downloads";
|
||||
|
||||
private final Server server;
|
||||
|
||||
public UiService() {
|
||||
@ -42,9 +44,17 @@ public class UiService {
|
||||
corsFilterHolder.setInitParameter(CrossOriginFilter.CHAIN_PREFLIGHT_PARAM, "false");
|
||||
context.addFilter(corsFilterHolder, "/*", null);
|
||||
|
||||
ClassLoader loader = this.getClass().getClassLoader();
|
||||
|
||||
// Node management UI download servlet
|
||||
ServletHolder uiDownloadServlet = new ServletHolder("node-ui-download", new DefaultServlet(new DownloadResourceService()));
|
||||
uiDownloadServlet.setInitParameter("resourceBase", loader.getResource(DOWNLOADS_RESOURCE_PATH + "/").toString());
|
||||
uiDownloadServlet.setInitParameter("dirAllowed", "true");
|
||||
uiDownloadServlet.setInitParameter("pathInfoOnly", "true");
|
||||
context.addServlet(uiDownloadServlet, "/downloads/*");
|
||||
|
||||
// Node management UI static content servlet
|
||||
ServletHolder uiServlet = new ServletHolder("node-management-ui", DefaultServlet.class);
|
||||
ClassLoader loader = this.getClass().getClassLoader();
|
||||
uiServlet.setInitParameter("resourceBase", loader.getResource("node-management-ui/").toString());
|
||||
uiServlet.setInitParameter("dirAllowed", "true");
|
||||
uiServlet.setInitParameter("pathInfoOnly", "true");
|
||||
|
@ -1,7 +1,15 @@
|
||||
#Generated by ResourceBundle Editor (http://essiembre.github.io/eclipse-rbe/)
|
||||
# SysTray pop-up menu
|
||||
OPEN_NODE_UI=Open Node UI
|
||||
EXIT=Exit
|
||||
|
||||
CHECK_TIME_ACCURACY = Check time accuracy
|
||||
|
||||
EXIT = Exit
|
||||
|
||||
# Nagging about lack of NTP time sync
|
||||
NTP_NAG_CAPTION=No connections?
|
||||
NTP_NAG_TEXT=Please enable Windows automatic time synchronization
|
||||
NTP_NAG_CAPTION = No connections?
|
||||
|
||||
NTP_NAG_TEXT = Please enable Windows automatic time synchronization
|
||||
|
||||
OPEN_NODE_UI = Open Node UI
|
||||
|
||||
SYNCHRONIZE_CLOCK = Synchronize clock
|
||||
|
@ -1,7 +1,15 @@
|
||||
#Generated by ResourceBundle Editor (http://essiembre.github.io/eclipse-rbe/)
|
||||
# SysTray pop-up menu
|
||||
OPEN_NODE_UI=\u5F00\u542F\u754C\u9762
|
||||
EXIT=\u9000\u51FA\u8F6F\u4EF6
|
||||
|
||||
CHECK_TIME_ACCURACY = \u68C0\u67E5\u65F6\u95F4\u51C6\u786E\u6027
|
||||
|
||||
EXIT = \u9000\u51FA\u8F6F\u4EF6
|
||||
|
||||
# Nagging about lack of NTP time sync
|
||||
NTP_NAG_CAPTION=\u6CA1\u6709\u8FDE\u63A5\u4E0A\u8282\u70B9\uFF1F
|
||||
NTP_NAG_TEXT=\u8BF7\u542F\u7528Windows\u81EA\u52A8\u65F6\u95F4\u540C\u6B65\u3002
|
||||
NTP_NAG_CAPTION = \u6CA1\u6709\u8FDE\u63A5\u4E0A\u8282\u70B9\uFF1F
|
||||
|
||||
NTP_NAG_TEXT = \u8BF7\u542F\u7528Windows\u81EA\u52A8\u65F6\u95F4\u540C\u6B65\u3002
|
||||
|
||||
OPEN_NODE_UI = \u5F00\u542F\u754C\u9762
|
||||
|
||||
SYNCHRONIZE_CLOCK = \u540C\u6B65\u65F6\u949F
|
||||
|
33
src/main/resources/node-ui-downloads/ntpcfg.bat
Executable file
33
src/main/resources/node-ui-downloads/ntpcfg.bat
Executable file
@ -0,0 +1,33 @@
|
||||
@echo off
|
||||
|
||||
:: BatchGotAdmin
|
||||
:-------------------------------------
|
||||
REM --> Check for permissions
|
||||
>nul 2>&1 "%SYSTEMROOT%\system32\cacls.exe" "%SYSTEMROOT%\system32\config\system"
|
||||
|
||||
REM --> If error flag set, we do not have admin.
|
||||
if '%errorlevel%' NEQ '0' (
|
||||
echo Requesting administrative privileges...
|
||||
goto UACPrompt
|
||||
) else ( goto gotAdmin )
|
||||
|
||||
:UACPrompt
|
||||
echo Set UAC = CreateObject^("Shell.Application"^) > "%temp%\getadmin.vbs"
|
||||
echo UAC.ShellExecute "%~s0", "", "", "runas", 1 >> "%temp%\getadmin.vbs"
|
||||
|
||||
"%temp%\getadmin.vbs"
|
||||
exit /B
|
||||
|
||||
:gotAdmin
|
||||
if exist "%temp%\getadmin.vbs" ( del "%temp%\getadmin.vbs" )
|
||||
pushd "%CD%"
|
||||
CD /D "%~dp0"
|
||||
:--------------------------------------
|
||||
|
||||
net stop "Windows Time"
|
||||
|
||||
w32tm /config "/manualpeerlist:pool.ntp.org 0.pool.ntp.org 1.pool.ntp.org 2.pool.ntp.org 3.pool.ntp.org cn.pool.ntp.org 0.cn.pool.ntp.org 1.cn.pool.ntp.org 2.cn.pool.ntp.org 3.cn.pool.ntp.org"
|
||||
|
||||
net start "Windows Time"
|
||||
|
||||
sc config w32time start= auto
|
Loading…
Reference in New Issue
Block a user