rewritten as standalone docker app

This commit is contained in:
Radek Davidek 2025-11-19 19:07:30 +01:00
parent f5e8564f75
commit dc5095ffa3
20 changed files with 1563 additions and 1160 deletions

3
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"java.configuration.updateBuildConfiguration": "automatic"
}

14
Dockerfile Normal file
View File

@ -0,0 +1,14 @@
# Použij JDK jako základ
FROM eclipse-temurin:11-jre
# Nastav pracovní adresář
WORKDIR /app
# Přidej fat JAR do kontejneru
COPY target/mining-info-server.jar app.jar
# Exponuj port (nastav podle tvého serveru)
EXPOSE 8080
# Spusť aplikaci
ENTRYPOINT ["java", "-jar", "app.jar"]

67
pom.xml
View File

@ -4,58 +4,67 @@
<modelVersion>4.0.0</modelVersion>
<groupId>cz.kamma.mining</groupId>
<artifactId>mining-info-web</artifactId>
<packaging>war</packaging>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>mining-info-web</name>
<url>http://maven.apache.org</url>
<properties>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<maven.compiler.source>11</maven.compiler.source>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.json/json -->
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20171018</version>
<version>20250517</version>
</dependency>
</dependencies>
<build>
<finalName>ROOT</finalName>
<finalName>mining-info</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<mainClass>cz.kamma.mining.MiningApplication</mainClass>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>cz.kamma.mining.MiningApplication</mainClass>
</transformer>
</transformers>
<finalName>mining-info-server</finalName>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>prime-repo</id>
<name>Prime Repo</name>
<url>http://repository.primefaces.org</url>
</repository>
</repositories>
</project>

View File

@ -2,8 +2,8 @@ package cz.kamma.mining;
public interface Constants {
public static final String APP_VERSION = "v0.9.1";
public static final String COPYRIGHT = "2024";
public static final String APP_VERSION = "v0.9.2";
public static final String COPYRIGHT = "2025";
public static final int DEFAULT_HTTP_CONNECTION_TIMEOUT = 6000;
public static final int DEFAULT_HTTP_READ_TIMEOUT = 18000;
public static final int RELOAD_TIME = 25000;

View File

@ -0,0 +1,59 @@
package cz.kamma.mining;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import com.sun.net.httpserver.HttpServer;
import cz.kamma.mining.handler.MainPageHandler;
import cz.kamma.mining.handler.StaticFileHandler;
import cz.kamma.mining.handler.UpdateHandler;
public class MiningApplication {
private HttpServer server;
private static final int PORT = 8080;
private static final int THREAD_POOL_SIZE = 10;
public MiningApplication() throws IOException {
this.server = HttpServer.create(new InetSocketAddress("0.0.0.0", PORT), 50);
ExecutorService executorService = Executors.newFixedThreadPool(THREAD_POOL_SIZE);
server.setExecutor(executorService);
// Register handlers
server.createContext("/", new MainPageHandler());
server.createContext("/ajaxview.html", new StaticFileHandler());
server.createContext("/getupdate", new UpdateHandler());
System.out.println("Server initialized on port " + PORT);
}
public void start() {
server.start();
System.out.println("Mining Info Server started on http://0.0.0.0:" + PORT);
}
public void stop() {
server.stop(0);
System.out.println("Mining Info Server stopped");
}
public static void main(String[] args) {
try {
MiningApplication app = new MiningApplication();
app.start();
// Graceful shutdown on SIGTERM
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
System.out.println("Shutting down server...");
app.stop();
}));
} catch (IOException e) {
System.err.println("Failed to start server: " + e.getMessage());
e.printStackTrace();
}
}
}

View File

@ -13,13 +13,11 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.json.JSONArray;
import org.json.JSONObject;
import cz.kamma.mining.Constants;
import cz.kamma.mining.handler.RequestParams;
import cz.kamma.mining.vo.KeyValue;
public class MiningBean {
@ -35,7 +33,7 @@ public class MiningBean {
String restRequest;
int finished = 0b0;
public String updateAll(HttpServletRequest request, HttpServletResponse response) throws Exception {
public String updateAll(RequestParams request) throws Exception {
SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss");
java.lang.System.setProperty("https.protocols", "TLSv1,TLSv1.1,TLSv1.2");
List<KeyValue> prices = new ArrayList<>();
@ -109,20 +107,24 @@ public class MiningBean {
try {
if (ltcWallet != null && !"null".equals(ltcWallet) && ltcWallet.length() > 0) {
restRequest = getStringResponse(
"https://api.blockcypher.com/v1/ltc/main/addrs/".concat(ltcWallet).concat("/balance"));
"https://litecoinblockexplorer.net/api/v2/address/".concat(ltcWallet), 10000, 10000, null);
if (restRequest != null && restRequest.length() > 0) {
JSONObject full = new JSONObject(restRequest);
String balance = (String) full.get("final_balance").toString();
try {
JSONObject full = new JSONObject(restRequest);
String balance = full.getString("balance");
double res = Double.parseDouble(balance) / 100000000;
if (res > 0d) {
; resultStr = res + " LTC " + curSym + String.format("%.2f", (res * lastPrices[1]));
} else
resultStr = "Unknown";
KeyValue wi = new KeyValue();
wi.setKey("My Balance LTC");
wi.setValue(resultStr);
prices.add(wi);
double res = Double.parseDouble(balance) / 100000000.0;
if (res > 0d) {
resultStr = res + " LTC " + curSym + String.format("%.2f", (res * lastPrices[1]));
} else
resultStr = "Unknown";
KeyValue wi = new KeyValue();
wi.setKey("My Balance LTC");
wi.setValue(resultStr);
prices.add(wi);
} catch (Exception e) {
System.out.println("Error parsing LTC balance: " + e.getMessage());
}
}
}
} catch (Exception e) {
@ -174,22 +176,25 @@ public class MiningBean {
try {
if (ethWallet != null && !"null".equals(ethWallet) && ethWallet.length() > 0) {
restRequest = getStringResponse(
"https://api.etherscan.io/api?module=account&action=balance&address=" + ethWallet
+ "&tag=latest&apikey=N54NVXSVSISMQ4QIM2JVKJW56KHCKMU5T4");
"https://eth.blockscout.com/api/v2/addresses/" + ethWallet, 10000, 10000, null);
if (restRequest != null && restRequest.length() > 0) {
JSONObject full = new JSONObject(restRequest);
String confirmedBalance = (String) full.get("result");
try {
JSONObject full = new JSONObject(restRequest);
String balanceStr = full.getString("coin_balance");
double res = Double.parseDouble(confirmedBalance);
res = res * 0.000000000000000001;
if (res > 0d) {
resultStr = res + " ETH " + curSym + String.format("%.2f", (res * lastPrices[3]));
} else
resultStr = "Unknown";
KeyValue wi = new KeyValue();
wi.setKey("My Balance ETH");
wi.setValue(resultStr);
prices.add(wi);
double res = Double.parseDouble(balanceStr);
res = res * 0.000000000000000001;
if (res > 0d) {
resultStr = res + " ETH " + curSym + String.format("%.2f", (res * lastPrices[3]));
} else
resultStr = "Unknown";
KeyValue wi = new KeyValue();
wi.setKey("My Balance ETH");
wi.setValue(resultStr);
prices.add(wi);
} catch (Exception e) {
System.out.println("Error parsing ETH balance: " + e.getMessage());
}
}
}
} catch (Exception e) {
@ -669,12 +674,11 @@ public class MiningBean {
try {
if (ltcWallet != null && !"null".equals(ltcWallet) && ltcWallet.length() > 0) {
restRequest = getStringResponse(
"https://api.blockcypher.com/v1/ltc/main/addrs/".concat(ltcWallet).concat("/balance"));
"https://litecoinblockexplorer.net/api/v2/address/".concat(ltcWallet), 10000, 10000, null);
if (restRequest != null && restRequest.length() > 0) {
JSONObject full = new JSONObject(restRequest);
String balance = (String) full.get("final_balance").toString();
double res = Double.parseDouble(balance) / 100000000;
String balance = full.getString("balance");
double res = Double.parseDouble(balance) / 100000000.0;
String curSym = "$";
String resultStr = "";
if (res > 0d) {

View File

@ -0,0 +1,38 @@
package cz.kamma.mining.handler;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
public class MainPageHandler implements HttpHandler {
@Override
public void handle(HttpExchange exchange) throws IOException {
if ("GET".equals(exchange.getRequestMethod())) {
try {
// Read index.html from src/main/webapp/
Path filePath = Paths.get("src/main/webapp/index.html").normalize();
if (Files.exists(filePath) && !Files.isDirectory(filePath)) {
byte[] fileContent = Files.readAllBytes(filePath);
exchange.getResponseHeaders().set("Content-Type", "text/html; charset=UTF-8");
exchange.sendResponseHeaders(200, fileContent.length);
OutputStream os = exchange.getResponseBody();
os.write(fileContent);
os.close();
} else {
exchange.sendResponseHeaders(404, -1);
}
} catch (Exception e) {
exchange.sendResponseHeaders(500, -1);
}
} else {
exchange.sendResponseHeaders(405, -1);
}
}
}

View File

@ -0,0 +1,23 @@
package cz.kamma.mining.handler;
import java.util.Map;
/**
* Simple request parameters container without servlet API dependency
*/
public class RequestParams {
private Map<String, String> parameters;
public RequestParams(Map<String, String> parameters) {
this.parameters = parameters;
}
public String getParameter(String name) {
return parameters.get(name);
}
public Map<String, String> getParameterMap() {
return parameters;
}
}

View File

@ -0,0 +1,77 @@
package cz.kamma.mining.handler;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
public class StaticFileHandler implements HttpHandler {
public StaticFileHandler() {
// staticDir is informational, actual path is resolved from classpath
}
@Override
public void handle(HttpExchange exchange) throws IOException {
if ("GET".equals(exchange.getRequestMethod())) {
String path = exchange.getRequestURI().getPath();
// Remove leading slash
if (path.startsWith("/")) {
path = path.substring(1);
}
try {
// Security: prevent directory traversal
if (path.contains("..")) {
exchange.sendResponseHeaders(403, -1);
return;
}
InputStream resourceStream = getClass().getClassLoader().getResourceAsStream(path);
if (resourceStream != null) {
byte[] fileContent = resourceStream.readAllBytes();
resourceStream.close();
String contentType = getContentType(path);
exchange.getResponseHeaders().set("Content-Type", contentType);
exchange.sendResponseHeaders(200, fileContent.length);
OutputStream os = exchange.getResponseBody();
os.write(fileContent);
os.close();
} else {
exchange.sendResponseHeaders(404, -1);
}
} catch (Exception e) {
exchange.sendResponseHeaders(500, -1);
}
} else {
exchange.sendResponseHeaders(405, -1);
}
}
private String getContentType(String path) {
if (path.endsWith(".css")) {
return "text/css; charset=UTF-8";
} else if (path.endsWith(".js")) {
return "application/javascript; charset=UTF-8";
} else if (path.endsWith(".html")) {
return "text/html; charset=UTF-8";
} else if (path.endsWith(".xml")) {
return "text/xml; charset=UTF-8";
} else if (path.endsWith(".png")) {
return "image/png";
} else if (path.endsWith(".jpg") || path.endsWith(".jpeg")) {
return "image/jpeg";
} else if (path.endsWith(".gif")) {
return "image/gif";
} else if (path.endsWith(".svg")) {
return "image/svg+xml";
}
return "application/octet-stream";
}
}

View File

@ -0,0 +1,80 @@
package cz.kamma.mining.handler;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import cz.kamma.mining.bean.MiningBean;
public class UpdateHandler implements HttpHandler {
@Override
public void handle(HttpExchange exchange) throws IOException {
if ("POST".equals(exchange.getRequestMethod())) {
// Parse POST parameters
byte[] buffer = new byte[exchange.getRequestBody().available()];
exchange.getRequestBody().read(buffer);
String postData = new String(buffer, StandardCharsets.UTF_8);
Map<String, String> params = parsePostData(postData);
// Create RequestParams object
try {
MiningBean bean = new MiningBean();
RequestParams request = new RequestParams(params);
String result = bean.updateAll(request);
exchange.getResponseHeaders().set("Content-Type", "text/xml; charset=UTF-8");
exchange.sendResponseHeaders(200, result.getBytes(StandardCharsets.UTF_8).length);
OutputStream os = exchange.getResponseBody();
os.write(result.getBytes(StandardCharsets.UTF_8));
os.close();
} catch (Exception e) {
String errorResponse = "<response><error>" + escapeXml(e.getMessage()) + "</error></response>";
exchange.getResponseHeaders().set("Content-Type", "text/xml; charset=UTF-8");
exchange.sendResponseHeaders(500, errorResponse.getBytes(StandardCharsets.UTF_8).length);
OutputStream os = exchange.getResponseBody();
os.write(errorResponse.getBytes(StandardCharsets.UTF_8));
os.close();
}
} else {
exchange.sendResponseHeaders(405, -1);
}
}
private Map<String, String> parsePostData(String postData) {
Map<String, String> params = new HashMap<>();
if (postData == null || postData.isEmpty()) {
return params;
}
String[] pairs = postData.split("&");
for (String pair : pairs) {
int idx = pair.indexOf('=');
if (idx > 0) {
String key = pair.substring(0, idx);
String value = idx + 1 < pair.length() ? pair.substring(idx + 1) : "";
try {
params.put(java.net.URLDecoder.decode(key, "UTF-8"),
java.net.URLDecoder.decode(value, "UTF-8"));
} catch (Exception e) {
params.put(key, value);
}
}
}
return params;
}
private String escapeXml(String str) {
if (str == null) {
return "";
}
return str.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")
.replace("\"", "&quot;").replace("'", "&apos;");
}
}

View File

@ -0,0 +1,305 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon"
href="https://cdn2.iconfinder.com/data/icons/bitcoin-and-mining/44/trade-24.png">
<title>Mining Info</title>
<style>
* {
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: #1a1a1a;
color: #ddd;
margin: 0;
padding: 0;
line-height: 1.5;
}
h2 {
background: #2d5a6e;
color: #fff;
padding: 15px;
margin: 0;
text-align: center;
font-size: 1.3em;
font-weight: 600;
}
table {
width: 100%;
border-collapse: separate;
border-spacing: 0;
margin-top: 0;
}
tr {
display: table-row;
}
td {
padding: 12px;
border-bottom: 1px solid #333;
vertical-align: middle;
}
tr:last-child td {
border-bottom: none;
}
.label {
color: #4caf50;
font-weight: 600;
text-decoration: none;
word-wrap: break-word;
}
.label:hover {
color: #66bb6a;
}
.label a {
text-decoration: none;
color: inherit;
font-weight: 600;
}
.value {
color: #4caf50;
text-align: right;
font-weight: 600;
word-wrap: break-word;
}
.section {
background: #333;
font-weight: 600;
color: #999;
padding: 12px !important;
}
.section td {
padding: 12px !important;
border-bottom: 2px solid #555 !important;
}
/* Desktop styles */
@media (min-width: 768px) {
body {
font-size: 1em;
}
h2 {
font-size: 1.5em;
padding: 20px;
}
td {
padding: 12px 16px;
}
table {
margin-top: 10px;
}
}
/* Mobile styles */
@media (max-width: 767px) {
body {
font-size: 0.95em;
padding: 0;
}
h2 {
font-size: 1.1em;
padding: 12px;
}
table {
display: table;
width: 100%;
}
td {
padding: 10px 12px;
font-size: 0.95em;
}
.label {
font-weight: 600;
}
.value {
font-weight: 600;
}
.section {
font-size: 0.9em;
}
}
/* Small phones */
@media (max-width: 480px) {
body {
font-size: 0.9em;
}
h2 {
font-size: 1em;
padding: 10px;
}
td {
padding: 8px 10px;
}
.label {
font-size: 0.95em;
}
.value {
font-size: 0.95em;
}
}
.loading-container {
display: flex;
justify-content: center;
align-items: center;
padding: 40px 20px;
flex-direction: column;
gap: 15px;
}
.spinner {
width: 40px;
height: 40px;
border: 4px solid #333;
border-top-color: #4caf50;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
.loading-text {
color: #999;
font-size: 0.95em;
letter-spacing: 2px;
}
</style>
</head>
<body>
<h2>Mining Info</h2>
<div id="overview">
<div class="loading-container">
<div class="spinner"></div>
<div class="loading-text">LOADING</div>
</div>
</div>
<script language=javascript type='text/javascript'>
// Get query parameters from URL
function getQueryParam(name) {
var url = window.location.href;
name = name.replace(/[\[\]]/g, '\\$&');
var regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)');
var results = regex.exec(url);
if (!results) return "";
if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/g, ' '));
}
function AX_asynchUpdate(ltcapikey, dogapikey, ltc, eth, xrp, cur) {
var data = 'ajaxMethod=asynchUpdate&ltcapikey=' + encodeURIComponent(ltcapikey) +
'&dogapikey=' + encodeURIComponent(dogapikey) +
'&ltc=' + encodeURIComponent(ltc) +
'&eth=' + encodeURIComponent(eth) +
'&xrp=' + encodeURIComponent(xrp) +
'&cur=' + encodeURIComponent(cur);
var xhr = new XMLHttpRequest();
xhr.open('POST', '/getupdate', true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
AX_asynchUpdateResponse(xhr.responseXML);
}
};
xhr.send(data);
}
function AX_asynchUpdateResponse(xmlDocument) {
if (!xmlDocument) return;
var prices = xmlDocument.getElementsByTagName("prices")[0];
var workers = xmlDocument.getElementsByTagName("workers")[0];
var pool = xmlDocument.getElementsByTagName("pool")[0];
var network = xmlDocument.getElementsByTagName("network")[0];
var resStr = "<table>";
// Prices section
if (prices) {
var pairsList = prices.getElementsByTagName("pair");
resStr = resStr + "<tr class='section'><td colspan='2'>Prices</td></tr>";
for (var i = 0; i < pairsList.length; i++) {
var color = pairsList[i].getElementsByTagName("color")[0];
var colorValue = color ? color.firstChild.data : "#4caf50";
var key = pairsList[i].getElementsByTagName("key")[0].firstChild.data;
var value = pairsList[i].getElementsByTagName("value")[0].firstChild.data;
resStr = resStr + "<tr><td class='label'>" + key + "</td><td class='value' style='color:" + colorValue + ";'>" + value + "</td></tr>";
}
}
if (workers) {
var workersList = workers.getElementsByTagName("pair");
if (workersList.length > 0) {
resStr = resStr + "<tr class='section'><td colspan='2'>Workers</td></tr>";
for (var i = 0; i < workersList.length; i++) {
var key = workersList[i].getElementsByTagName("key")[0].firstChild.data;
var value = workersList[i].getElementsByTagName("value")[0].firstChild.data;
resStr = resStr + "<tr><td class='label'>" + key + "</td><td class='value'>" + value + "</td></tr>";
}
}
}
if (pool) {
var poolList = pool.getElementsByTagName("pair");
if (poolList.length > 0) {
resStr = resStr + "<tr class='section'><td colspan='2'>Pool</td></tr>";
for (var i = 0; i < poolList.length; i++) {
var key = poolList[i].getElementsByTagName("key")[0].firstChild.data;
var value = poolList[i].getElementsByTagName("value")[0].firstChild.data;
resStr = resStr + "<tr><td class='label'>" + key + "</td><td class='value'>" + value + "</td></tr>";
}
}
}
if (network) {
var networkList = network.getElementsByTagName("pair");
if (networkList.length > 0) {
resStr = resStr + "<tr class='section'><td colspan='2'>Network</td></tr>";
for (var i = 0; i < networkList.length; i++) {
var key = networkList[i].getElementsByTagName("key")[0].firstChild.data;
var value = networkList[i].getElementsByTagName("value")[0].firstChild.data;
resStr = resStr + "<tr><td class='label'>" + key + "</td><td class='value'>" + value + "</td></tr>";
}
}
}
resStr = resStr + "</table>";
document.getElementById('overview').innerHTML = resStr;
}
function asynchUpdate() {
var ltcapikey = getQueryParam('ltcapikey');
var dogapikey = getQueryParam('dogapikey');
var ltc = getQueryParam('ltc');
var eth = getQueryParam('eth');
var xrp = getQueryParam('xrp');
var cur = getQueryParam('cur') || 'usd';
AX_asynchUpdate(ltcapikey, dogapikey, ltc, eth, xrp, cur);
setTimeout('asynchUpdate();', 25000);
}
asynchUpdate();
</script>
</body>
</html>

View File

@ -0,0 +1,149 @@
<!DOCTYPE html>
<html>
<head>
<link rel="icon"
href="https://cdn2.iconfinder.com/data/icons/bitcoin-and-mining/44/trade-24.png">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Mining Info</title>
<style>
* {
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: #1a1a1a;
color: #ddd;
margin: 0;
padding: 20px;
line-height: 1.5;
}
h1 {
color: #fff;
text-align: center;
margin-bottom: 30px;
}
form {
max-width: 800px;
margin: 0 auto;
}
table {
width: 100%;
border-collapse: collapse;
}
tr {
display: table-row;
}
td {
padding: 15px;
border-bottom: 1px solid #333;
}
tr:last-child td {
border-bottom: none;
}
.group {
background: #2d5a6e;
color: #fff;
font-weight: 600;
padding: 15px;
}
input[type="text"],
select {
padding: 8px 12px;
background: #333;
color: #ddd;
border: 1px solid #555;
border-radius: 4px;
font-family: inherit;
font-size: 1em;
}
input[type="text"]:focus,
select:focus {
outline: none;
border-color: #4caf50;
box-shadow: 0 0 5px rgba(76, 175, 80, 0.3);
}
input[type="submit"] {
padding: 10px 30px;
background: #4caf50;
color: #fff;
border: none;
border-radius: 4px;
font-size: 1em;
font-weight: 600;
cursor: pointer;
transition: background 0.3s;
}
input[type="submit"]:hover {
background: #45a049;
}
h5 {
color: #999;
font-size: 0.9em;
margin-top: 20px;
}
</style>
</head>
<body>
<h1>Mining Info</h1>
<form action="ajaxview.html" method="GET">
<table>
<tr>
<td class='group'>litecoinpool.org LTC API key (optional)</td>
<td align="right" class='group'><input
type="text" name="ltcapikey" size="40" /></td>
</tr>
<tr>
<td class='group'>aikapool.org DOGE API key (optional)</td>
<td align="right" class='group'><input
type="text" name="dogapikey" size="40" /></td>
</tr>
<tr>
<td class='group'>Litecoin wallet address (optional)</td>
<td align="right" class='group'><input
type="text" name="ltc" size="40" /></td>
</tr>
<tr>
<td class='group'>Ethereum wallet address (optional)</td>
<td align="right" class='group'><input
type="text" name="eth" size="40" /></td>
</tr>
<tr>
<td class='group'>Ripple wallet address (optional)</td>
<td align="right" class='group'><input
type="text" name="xrp" size="40" /></td>
</tr>
<tr>
<td class='group'>Fiat currency</td>
<td align="right" class='group'><select
name="cur"><option value="usd" selected>USD ($)</option>
<option value="eur">EUR (€)</option></select></td>
</tr>
<tr>
<td class='group' colspan="2"><div align="center">
<input type="submit" value="Show" />
</div></td>
</tr>
<tr>
<td colspan="2"></td>
</tr>
<tr>
<td colspan="2" align="center"><h5>mining-info.eu v0.9.1 ©2024<br/>LTC: LgQU1Pf96Bip67bpUrTw6K1goayWjPwfay</h5></td>
</tr>
</table>
</form>
</body>
</html>

View File

@ -1,3 +0,0 @@
Manifest-Version: 1.0
Class-Path:

View File

@ -1,10 +0,0 @@
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<display-name>Mining Console</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>

View File

@ -1,34 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@page contentType="text/html; charset=UTF-8" %>
<%@page import="cz.kamma.mining.Constants"%>
<html lang="en">
<head>
<link rel="icon"
href="https://cdn2.iconfinder.com/data/icons/bitcoin-and-mining/44/trade-24.png">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="format-detection" content="telephone=no">
<meta name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<title>Mining Info</title>
<link rel="stylesheet" type="text/css" href="./css/default-theme.css?ver=<%=System.currentTimeMillis()%>">
<script type="text/javascript"
src="client.js?ver=<%=System.currentTimeMillis()%>"></script>
</head>
<body class="landscape">
<div class="toolbar">
<h1>Mining Info</h1>
</div>
<ul id="overview">
<li>LOADING...</li>
</ul>
<script language=javascript type='text/javascript'>
function asynchUpdate() {
AX_asynchUpdate("<%=request.getParameter("ltcapikey")%>", "<%=request.getParameter("dogapikey")%>", "<%=request.getParameter("ltc")%>", "<%=request.getParameter("eth")%>", "<%=request.getParameter("xrp")%>", "<%=request.getParameter("cur")%>");
setTimeout('asynchUpdate();', <%=Constants.RELOAD_TIME%>);
}
asynchUpdate();
</script>
</body>
</html>

View File

@ -1,145 +0,0 @@
var URLsuffix = '/getupdate.jsp';
//var URLsuffix = '/mining-console/getupdate.jsp';
var ajaxHttp = getAjaxLibrary();
function getAjaxLibrary() {
var activexmodes = [ "Msxml2.XMLHTTP", "Microsoft.XMLHTTP" ] // activeX
// versions
// to check
// for in IE
if (window.ActiveXObject) { // Test for support for ActiveXObject in IE
// first (as XMLHttpRequest in IE7 is broken)
for (var i = 0; i < activexmodes.length; i++) {
try {
return new ActiveXObject(activexmodes[i])
} catch (e) {
// suppress error
}
}
} else if (window.XMLHttpRequest) // if Mozilla, Safari etc
return new XMLHttpRequest()
else
return false
}
/*******************************************************************************
* F U N C T I O N S
******************************************************************************/
function getHost() {
var url = "" + window.location;
var prot = url.split('//')[0];
var urlparts = url.split('//')[1].split('/');
return urlparts[0];
}
function getProt() {
var url = "" + window.location;
return url.split('//')[0];
}
function ajaxSendRequest(data, onReadyStateChange) {
var URL = getProt() + '//' + getHost() + URLsuffix;
// if (ajaxHttp.overrideMimeType)
// ajaxHttp.overrideMimeType('text/xml')
ajaxHttp.open("POST", URL, true);
ajaxHttp.onreadystatechange = onReadyStateChange;
ajaxHttp.setRequestHeader('Content-Type',
'application/x-www-form-urlencoded');
ajaxHttp.send(data);
}
function ajaxResponseReady() {
if (ajaxHttp.readyState == 4) {
/* received */
if (ajaxHttp.status == 200
|| window.location.href.indexOf("http") == -1) {
/* response is ok */
return true;
} else {
return false;
}
}
return false;
}
function ajaxGetXmlResponse() {
if (ajaxHttp.responseXML && ajaxHttp.responseXML.parseError
&& (ajaxHttp.responseXML.parseError.errorCode != 0)) {
ajaxGetXmlError(true);
return null;
} else {
return ajaxHttp.responseXML;
}
}
function AX_asynchUpdate(ltcapikey, dogapikey, ltc, eth, xrp, cur) {
var data = 'ajaxMethod=asynchUpdate&ltcapikey=' + ltcapikey + '&dogapikey=' + dogapikey + '&ltc=' + ltc + '&eth=' + eth
+ '&xrp=' + xrp+ '&cur=' + cur;
ajaxSendRequest(data, AX_asynchUpdateResponse);
}
function AX_asynchUpdateResponse() {
if (ajaxResponseReady()) {
if (ajaxHttp.responseText.indexOf('invalid') == -1) {
var xmlDocument = ajaxGetXmlResponse();
var prices = xmlDocument.getElementsByTagName("prices")[0]
.getElementsByTagName("pair");
var workers = xmlDocument.getElementsByTagName("workers")[0]
.getElementsByTagName("pair");
var pool = xmlDocument.getElementsByTagName("pool")[0]
.getElementsByTagName("pair");
var network = xmlDocument.getElementsByTagName("network")[0]
.getElementsByTagName("pair");
var resStr = "<li class='group' id='prices'>Prices</li>";
for (var i = 0; i <= (prices.length - 1); i++) {
var color = prices[i].getElementsByTagName("color")[0].firstChild.data;
if (color==null)
color = "GREEN";
resStr = resStr
+ "<li>"
+ prices[i].getElementsByTagName("key")[0].firstChild.data
+ " <span class='value' style='transition: text-shadow 0.7s ease-in-out; color:"+color+";'>"
+ prices[i].getElementsByTagName("value")[0].firstChild.data
+ "</span></li>";
}
if (workers.length > 0) {
resStr = resStr + "<li class='group' id='workers'>Workers</li>";
for (var i = 0; i <= (workers.length - 1); i++) {
resStr = resStr
+ "<li>"
+ workers[i].getElementsByTagName("key")[0].firstChild.data
+ " <span class='value' style='transition: text-shadow 0.7s ease-in-out;'>"
+ workers[i].getElementsByTagName("value")[0].firstChild.data
+ "</span></li>";
}
}
if (pool.length > 0) {
resStr = resStr + "<li class='group' id='pool'>Pool</li>";
for (var i = 0; i <= (pool.length - 1); i++) {
resStr = resStr
+ "<li>"
+ pool[i].getElementsByTagName("key")[0].firstChild.data
+ " <span class='value' style='transition: text-shadow 0.7s ease-in-out;'>"
+ pool[i].getElementsByTagName("value")[0].firstChild.data
+ "</span></li>";
}
}
if (network.length > 0) {
resStr = resStr + "<li class='group' id='network'>Network</li>";
for (var i = 0; i <= (network.length - 1); i++) {
resStr = resStr
+ "<li>"
+ network[i].getElementsByTagName("key")[0].firstChild.data
+ " <span class='value' style='transition: text-shadow 0.7s ease-in-out;'>"
+ network[i].getElementsByTagName("value")[0].firstChild.data
+ "</span></li>";
}
}
document.getElementById('overview').innerHTML = resStr;
}
}
}

View File

@ -1,83 +0,0 @@
body {
margin: 0;
font-family: Helvetica;
background: #424242;
color: rgb(202, 202, 0);
overflow-x: hidden;
}
body>*:not(.toolbar) {
position: absolute;
margin: 0;
padding: 0;
left: 0;
top: 45px;
width: 100%;
height: auto;
min-height: 415px;
}
/************************************************************************************************/
body>.toolbar {
box-sizing: border-box;
border-bottom: 1px solid #2d3642;
border-top: 1px solid #6d84a2;
padding: 0 10px 10px 10px;
height: 45px;
background: #6d84a2 repeat-x;
}
.toolbar>h1 {
position: absolute;
overflow: hidden;
left: 0%;
margin: 1px 0 0 -1px;
padding-top: 10px;
height: 45px;
font-size: 20px;
width: 100%;
font-weight: bold;
text-shadow: rgba(0, 0, 0, 0.4) 0px -1px 0;
text-align: center;
text-overflow: ellipsis;
white-space: nowrap;
color: #FFFFFF;
}
/************************************************************************************************/
body>ul>li {
position: relative;
margin: 0;
border-bottom: 1px solid #E0E0E0;
padding: 8px 0 8px 10px;
font-size: 17px;
font-weight: bold;
list-style: none;
}
a {
color: rgb(3, 203, 33);
font-weight: bold;
font-style: normal;
text-decoration: none;
}
.group {
position: relative;
top: -1px;
margin-bottom: -2px;
border-top: 1px solid #7d7d7d;
border-bottom: 1px solid #999999;
padding: 1px 10px;
font-weight: bold;
text-shadow: rgba(0, 0, 0, 0.4) 0 1px 0;
color: #FFFFFF;
opacity: 0.7;
background: #c8c8c8 repeat-x;
}
.value {
color: #55AA55;
float: right;
padding: 0 8px;
}

View File

@ -1,13 +0,0 @@
<%@page import="cz.kamma.mining.bean.MiningBean"%>
<%@page import="java.util.Date"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
MiningBean mb = new MiningBean();
String res = mb.updateAll(request, response);
response.setContentType("text/xml; charset=UTF-8");
response.setHeader("Cache-Control", "no-cache");
response.getWriter().write(res);
response.getWriter().flush();
%>

View File

@ -1,70 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@page contentType="text/html; charset=UTF-8" %>
<%@page import="cz.kamma.mining.Constants"%>
<html>
<head>
<link rel="icon"
href="https://cdn2.iconfinder.com/data/icons/bitcoin-and-mining/44/trade-24.png">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Mining Info</title>
<link rel="stylesheet" type="text/css" href="./css/default-theme.css">
</head>
<body>
<div class="toolbar">
<h1>Mining Info</h1>
</div>
<form action="ajaxview.jsp" method="GET">
<table border="0" width="100%">
<tr>
<td class='group'>litecoinpool.org LTC API key (optional)</td>
<td align="right" class='group'
style='transition: text-shadow 0.7s ease-in-out;'><input
type="text" name="ltcapikey" size="40" /></td>
</tr>
<tr>
<td class='group'>aikapool.org DOGE API key (optional)</td>
<td align="right" class='group'
style='transition: text-shadow 0.7s ease-in-out;'><input
type="text" name="dogapikey" size="40" /></td>
</tr>
<tr>
<td class='group'>Litecoin wallet address (optional)</td>
<td align="right" class='group'
style='transition: text-shadow 0.7s ease-in-out;'><input
type="text" name="ltc" size="40" /></td>
</tr>
<tr>
<td class='group'>Ethereum wallet address (optional)</td>
<td align="right" class='group'
style='transition: text-shadow 0.7s ease-in-out;'><input
type="text" name="eth" size="40" /></td>
</tr>
<tr>
<td class='group'>Ripple wallet address (optional)</td>
<td align="right" class='group'
style='transition: text-shadow 0.7s ease-in-out;'><input
type="text" name="xrp" size="40" /></td>
</tr>
<tr>
<td class='group'>Fiat currency</td>
<td align="right" class='group'
style='transition: text-shadow 0.7s ease-in-out;'><select
name="cur"><option value="usd" selected>USD ($)</option>
<option value="eur">EUR (€)</option></select></td>
</tr>
<tr>
<td class='group' colspan="2"><div align="center">
<input type="submit" value="Show" />
</div></td>
</tr>
<tr>
<td colspan="2"></td>
</tr>
<tr>
<td colspan="2" align="center"><h5>mining-info.eu <%=Constants.APP_VERSION%> ©<%=Constants.COPYRIGHT%><br/>LTC: LgQU1Pf96Bip67bpUrTw6K1goayWjPwfay</h5></td>
</tr>
</table>
</form>
</body>
</html>