commit 00f55221673b9f6f5984541de51ad4f9e5fa7a70 Author: rdavidek Date: Fri Apr 23 13:28:20 2021 +0200 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..553e981 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +target +bin +.settings +.classpath +.project + diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..b1690f9 --- /dev/null +++ b/pom.xml @@ -0,0 +1,61 @@ + + 4.0.0 + cz.kamma.mining + mining-info-web + war + 1.0-SNAPSHOT + mining-info-web + http://maven.apache.org + + + 1.8 + 1.8 + UTF-8 + + + + + javax.servlet + servlet-api + 2.5 + provided + + + javax.servlet.jsp + jsp-api + 2.1 + provided + + + + org.json + json + 20171018 + + + + + ROOT + + + org.apache.maven.plugins + maven-compiler-plugin + 2.3.2 + + 1.8 + 1.8 + + + + + + + + prime-repo + Prime Repo + http://repository.primefaces.org + + + diff --git a/src/main/java/cz/kamma/mining/Constants.java b/src/main/java/cz/kamma/mining/Constants.java new file mode 100644 index 0000000..dbd3de1 --- /dev/null +++ b/src/main/java/cz/kamma/mining/Constants.java @@ -0,0 +1,8 @@ +package cz.kamma.mining; + +public interface Constants { + + public static final String APP_VERSION = "v0.4"; + public static final String COPYRIGHT = "2021"; + public static final int DEFAULT_HTTP_TIMEOUT = 2000; +} diff --git a/src/main/java/cz/kamma/mining/bean/MiningBean.java b/src/main/java/cz/kamma/mining/bean/MiningBean.java new file mode 100644 index 0000000..6c91eb5 --- /dev/null +++ b/src/main/java/cz/kamma/mining/bean/MiningBean.java @@ -0,0 +1,281 @@ +package cz.kamma.mining.bean; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +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.helper.HttpHelper; +import cz.kamma.mining.vo.KeyValue; + +public class MiningBean { + + public static String updateAll(HttpServletRequest request, HttpServletResponse response) throws Exception { + java.lang.System.setProperty("https.protocols", "TLSv1,TLSv1.1,TLSv1.2"); + List prices = new ArrayList<>(); + List workers = new ArrayList<>(); + List pool = new ArrayList<>(); + List network = new ArrayList<>(); + + String[] cryptoCur = new String[] { "btc", "ltc", "xrp", "eth" }; + double[] lastPrices = new double[] { 0, 0, 0, 0 }; + + String apikey = request.getParameter("apikey"); + String ltcWallet = request.getParameter("ltc"); + String xrpWallet = request.getParameter("xrp"); + String currency = request.getParameter("cur"); + + if (request.getParameter("apikey") == null) { + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Invalid API key"); + return null; + } + + if (currency == null || currency.equals("null") || currency.length() == 0) + currency = "usd"; + else + currency = currency.toLowerCase(); + + String curSym = "$"; + + if (currency.equals("usd")) + curSym = "$"; + else if (currency.equals("eur")) + curSym = "€"; + + workers.clear(); + prices.clear(); + network.clear(); + pool.clear(); + + String resultStr; + String restRequest; + + for (int i = 0; i < cryptoCur.length; i++) { + String ccur = cryptoCur[i]; + restRequest = HttpHelper.getStringResponse("https://www.bitstamp.net/api/v2/ticker/".concat(ccur).concat(currency)); + if (restRequest != null && restRequest.length() > 0) { + JSONObject tmp = new JSONObject(restRequest); + double res = tmp.getDouble("last"); + lastPrices[i] = res; + if (res > 0d) + resultStr = curSym + res; + else + resultStr = "Unknown"; + KeyValue wi = new KeyValue(); + wi.setKey(ccur.toUpperCase().concat("/").concat(currency.toUpperCase()).concat(" (Bitstamp)")); + wi.setValue(resultStr); + prices.add(wi); + } + } + + if (ltcWallet != null && !"null".equals(ltcWallet) && ltcWallet.length() > 0) { + restRequest = HttpHelper.getStringResponse("https://chain.so/api/v2/get_address_balance/LTC/".concat(ltcWallet)); + if (restRequest != null && restRequest.length() > 0) { + JSONObject full = new JSONObject(restRequest); + JSONObject data = (JSONObject)full.get("data"); + String confirmedBalance = (String) data.get("confirmed_balance"); + + double res = Double.parseDouble(confirmedBalance); + 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); + } + } + + if (xrpWallet != null && !"null".equals(xrpWallet) && xrpWallet.length() > 0) { + restRequest = HttpHelper.getStringResponse("https://data.ripple.com/v2/accounts/".concat(xrpWallet).concat("/balances")); + if (restRequest != null && restRequest.length() > 0) { + JSONObject full = new JSONObject(restRequest); + JSONArray balances = (JSONArray) full.get("balances"); + double res = balances.getJSONObject(0).getDouble("value"); + if (res > 0d) { + resultStr = res + " XRP " + curSym + String.format("%.2f", (res * lastPrices[2])); + } else + resultStr = "Unknown"; + KeyValue wi = new KeyValue(); + wi.setKey("My Balance XRP"); + wi.setValue(resultStr); + prices.add(wi); + } + } + + if (apikey != null && !"null".equals(apikey) && apikey.length() > 0) { + String miningJson = HttpHelper.getStringResponse("https://www.litecoinpool.org/api?api_key=".concat(apikey)); + if (miningJson != null && miningJson.length() > 0) { + JSONObject full = new JSONObject(miningJson); + JSONObject user = (JSONObject) full.get("user"); + KeyValue wi = new KeyValue(); + wi.setKey("HashRate"); + if (user.getInt("hash_rate") > 0) + wi.setValue((user.getInt("hash_rate") / 1000) + " MH/s"); + else + wi.setValue("Unknown"); + workers.add(wi); + + JSONObject workersJson = (JSONObject) full.get("workers"); + for (Iterator keys = workersJson.keys(); keys.hasNext();) { + String key = keys.next(); + JSONObject worker = (JSONObject) workersJson.get(key); + wi = new KeyValue(); + wi.setKey("HashRate " + key); + wi.setValue((worker.getInt("hash_rate") / 1000) + " MH/s"); + workers.add(wi); + } + + wi = new KeyValue(); + wi.setKey("Paid"); + if (user.getDouble("paid_rewards") > 0) + wi.setValue(user.getDouble("paid_rewards") + " LTC " + curSym + String.format("%.2f", (user.getDouble("paid_rewards") * lastPrices[1]))); + else + wi.setValue("Unknown"); + workers.add(wi); + + wi = new KeyValue(); + wi.setKey("Unpaid"); + if (user.getDouble("unpaid_rewards") > 0) + wi.setValue(user.getDouble("unpaid_rewards") + " LTC " + curSym + String.format("%.2f", (user.getDouble("unpaid_rewards") * lastPrices[1]))); + else + wi.setValue("Unknown"); + workers.add(wi); + + wi = new KeyValue(); + wi.setKey("Total"); + if (user.getDouble("total_rewards") > 0) + wi.setValue(user.getDouble("total_rewards") + " LTC " + curSym + String.format("%.2f", (user.getDouble("total_rewards") * lastPrices[1]))); + else + wi.setValue("Unknown"); + workers.add(wi); + + wi = new KeyValue(); + wi.setKey("Expected 24h"); + if (user.getDouble("expected_24h_rewards") > 0) + wi.setValue(user.getDouble("expected_24h_rewards") + " LTC " + curSym + String.format("%.2f", (user.getDouble("expected_24h_rewards") * lastPrices[1]))); + else + wi.setValue("Unknown"); + workers.add(wi); + + wi = new KeyValue(); + wi.setKey("Past 24h"); + if (user.getDouble("past_24h_rewards") > 0) + wi.setValue(user.getDouble("past_24h_rewards") + " LTC " + curSym + String.format("%.2f", (user.getDouble("past_24h_rewards") * lastPrices[1]))); + else + wi.setValue("Unknown"); + workers.add(wi); + + JSONObject net = (JSONObject) full.get("network"); + wi = new KeyValue(); + wi.setKey("Network HashRate"); + if (net.getLong("hash_rate") > 0) + wi.setValue((net.getLong("hash_rate") / 1000000) + " GH/s"); + else + wi.setValue("Unknown"); + network.add(wi); + + wi = new KeyValue(); + wi.setKey("Difficulty"); + if (net.getDouble("difficulty") > 0) + wi.setValue("" + net.getDouble("difficulty")); + else + wi.setValue("Unknown"); + network.add(wi); + + wi = new KeyValue(); + wi.setKey("Next Difficulty"); + if (net.getDouble("next_difficulty") > 0) + wi.setValue("" + net.getDouble("next_difficulty")); + else + wi.setValue("Unknown"); + network.add(wi); + + wi = new KeyValue(); + wi.setKey("Retarget time"); + if (net.getDouble("retarget_time") > 0) + wi.setValue(splitToComponentTimes(net.getInt("retarget_time"))); + else + wi.setValue("Unknown"); + network.add(wi); + + JSONObject poolJson = (JSONObject) full.get("pool"); + wi = new KeyValue(); + wi.setKey("Pool HashRate"); + if (poolJson.getLong("hash_rate") > 0) + wi.setValue((poolJson.getLong("hash_rate") / 1000000) + " GH/s"); + else + wi.setValue("Unknown"); + pool.add(wi); + + wi = new KeyValue(); + wi.setKey("Active users"); + if (poolJson.getInt("active_users") > 0) + wi.setValue("" + poolJson.getInt("active_users")); + else + wi.setValue("Unknown"); + pool.add(wi); + + wi = new KeyValue(); + wi.setKey("PPS Ratio"); + if (poolJson.getDouble("pps_ratio") > 0) + wi.setValue("" + poolJson.getDouble("pps_ratio")); + else + wi.setValue("Unknown"); + pool.add(wi); + } + } + + String res = "#PRICES##WORKERS##POOL##NETWORK#"; + + String tmp = ""; + for (KeyValue kv : prices) { + tmp = tmp.concat("").concat(kv.getKey().concat("").concat("").concat(kv.getValue()).concat("")); + } + res = res.replace("#PRICES#", tmp); + + tmp = ""; + for (KeyValue kv : workers) { + tmp = tmp.concat("").concat(kv.getKey().concat("").concat("").concat(kv.getValue()).concat("")); + } + res = res.replace("#WORKERS#", tmp); + + tmp = ""; + for (KeyValue kv : pool) { + tmp = tmp.concat("").concat(kv.getKey().concat("").concat("").concat(kv.getValue()).concat("")); + } + res = res.replace("#POOL#", tmp); + + tmp = ""; + for (KeyValue kv : network) { + tmp = tmp.concat("").concat(kv.getKey().concat("").concat("").concat(kv.getValue()).concat("")); + } + res = res.replace("#NETWORK#", tmp); + + return res; + } + + public String getVersion() { + return Constants.APP_VERSION; + } + + public static String splitToComponentTimes(int longVal) { + int days = longVal / (24 * 3600); + int remainder = longVal - (days * 24 * 3600); + int hours = remainder / 3600; + remainder = remainder - hours * 3600; + int mins = remainder / 60; + //remainder = remainder - mins * 60; + //int secs = remainder; + + return (days>0?days+"d ":"")+(hours>0?hours+"h ":"")+(mins>0?mins+"m ":""); + } + +} diff --git a/src/main/java/cz/kamma/mining/helper/HttpHelper.java b/src/main/java/cz/kamma/mining/helper/HttpHelper.java new file mode 100644 index 0000000..1baa8af --- /dev/null +++ b/src/main/java/cz/kamma/mining/helper/HttpHelper.java @@ -0,0 +1,39 @@ +package cz.kamma.mining.helper; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; + +import cz.kamma.mining.Constants; + +public class HttpHelper { + + public static String getStringResponse(String urlStr) { + return getStringResponse(urlStr, Constants.DEFAULT_HTTP_TIMEOUT); + } + + public static String getStringResponse(String urlStr, int timeout) { + String output = ""; + + try { + URL url = new URL(urlStr); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setDoInput(true); + conn.setDoOutput(false); + conn.setConnectTimeout(timeout); + conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.76 Safari/537.36"); + conn.connect(); + BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream())); + String inputLine; + while ((inputLine = in.readLine()) != null) + output += inputLine; + in.close(); + conn.disconnect(); + } catch (Exception e) { + System.out.println("Error while getting HTTP response from " + urlStr + ". Ex:" + e); + } + return output; + } + +} diff --git a/src/main/java/cz/kamma/mining/vo/KeyValue.java b/src/main/java/cz/kamma/mining/vo/KeyValue.java new file mode 100644 index 0000000..a5a1b73 --- /dev/null +++ b/src/main/java/cz/kamma/mining/vo/KeyValue.java @@ -0,0 +1,28 @@ +package cz.kamma.mining.vo; + +import java.io.Serializable; + +public class KeyValue implements Serializable { + private static final long serialVersionUID = 1L; + + String key; + String value; + + public KeyValue() { + } + + public String getKey() { + return key; + } + public void setKey(String key) { + this.key = key; + } + public String getValue() { + return value; + } + public void setValue(String value) { + this.value = value; + } + + +} diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000..141d980 --- /dev/null +++ b/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,10 @@ + + + Mining Console + + index.jsp + + diff --git a/src/main/webapp/ajaxview.jsp b/src/main/webapp/ajaxview.jsp new file mode 100644 index 0000000..58323f7 --- /dev/null +++ b/src/main/webapp/ajaxview.jsp @@ -0,0 +1,34 @@ + +<%@page contentType="text/html; charset=UTF-8" %> +<%@page import="cz.kamma.mining.Constants"%> + + + + + + +Mining Info + + + + +
+

Mining Info

+
+
    +
  • LOADING...
  • +
+ + + + + \ No newline at end of file diff --git a/src/main/webapp/client.js b/src/main/webapp/client.js new file mode 100644 index 0000000..4c91358 --- /dev/null +++ b/src/main/webapp/client.js @@ -0,0 +1,142 @@ +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(apikey, ltc, xrp, cur) { + var data = 'ajaxMethod=asynchUpdate&apikey=' + apikey + '<c=' + ltc + + '&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 = "
  • Prices
  • "; + for (var i = 0; i <= (prices.length - 1); i++) { + resStr = resStr + + "
  • " + + prices[i].getElementsByTagName("key")[0].firstChild.data + + " " + + prices[i].getElementsByTagName("value")[0].firstChild.data + + "
  • "; + } + + if (workers.length > 0) { + resStr = resStr + "
  • Workers
  • "; + for (var i = 0; i <= (workers.length - 1); i++) { + resStr = resStr + + "
  • " + + workers[i].getElementsByTagName("key")[0].firstChild.data + + " " + + workers[i].getElementsByTagName("value")[0].firstChild.data + + "
  • "; + } + } + if (pool.length > 0) { + resStr = resStr + "
  • Pool
  • "; + for (var i = 0; i <= (pool.length - 1); i++) { + resStr = resStr + + "
  • " + + pool[i].getElementsByTagName("key")[0].firstChild.data + + " " + + pool[i].getElementsByTagName("value")[0].firstChild.data + + "
  • "; + } + } + if (network.length > 0) { + resStr = resStr + "
  • Network
  • "; + for (var i = 0; i <= (network.length - 1); i++) { + resStr = resStr + + "
  • " + + network[i].getElementsByTagName("key")[0].firstChild.data + + " " + + network[i].getElementsByTagName("value")[0].firstChild.data + + "
  • "; + } + } + document.getElementById('overview').innerHTML = resStr; + } + } +} \ No newline at end of file diff --git a/src/main/webapp/css/default-theme.css b/src/main/webapp/css/default-theme.css new file mode 100644 index 0000000..f696e7a --- /dev/null +++ b/src/main/webapp/css/default-theme.css @@ -0,0 +1,79 @@ +body { + margin: 0; + font-family: Helvetica; + background: #FFFFFF; + color: #000000; + 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; +} + +.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; +} \ No newline at end of file diff --git a/src/main/webapp/getupdate.jsp b/src/main/webapp/getupdate.jsp new file mode 100644 index 0000000..e66679d --- /dev/null +++ b/src/main/webapp/getupdate.jsp @@ -0,0 +1,12 @@ +<%@page import="cz.kamma.mining.bean.MiningBean"%> +<%@page import="java.util.Date"%> +<%@ page language="java" contentType="text/html; charset=UTF-8" + pageEncoding="UTF-8"%> +<% + String res = MiningBean.updateAll(request, response); + + response.setContentType("text/xml; charset=UTF-8"); + response.setHeader("Cache-Control", "no-cache"); + response.getWriter().write(res); + response.getWriter().flush(); +%> \ No newline at end of file diff --git a/src/main/webapp/index.jsp b/src/main/webapp/index.jsp new file mode 100644 index 0000000..66d68a4 --- /dev/null +++ b/src/main/webapp/index.jsp @@ -0,0 +1,58 @@ + +<%@page contentType="text/html; charset=UTF-8" %> +<%@page import="cz.kamma.mining.Constants"%> + + + + +Mining Info + + + +
    +

    Mining Info

    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    litecoinpool.org API key (mandatory)
    Litecoin wallet address (optional)
    Ripple wallet address (optional)
    Fiat currency
    + +
    mining-info.eu <%=Constants.APP_VERSION%> ©<%=Constants.COPYRIGHT%>
    LTC: LgQU1Pf96Bip67bpUrTw6K1goayWjPwfay
    +
    + + \ No newline at end of file