Skip to content

Commit

Permalink
add stakepoolfinder and caching infrastructure (#5)
Browse files Browse the repository at this point in the history
  • Loading branch information
jolan committed May 31, 2016
1 parent 1b17a2d commit c70f545
Show file tree
Hide file tree
Showing 29 changed files with 576 additions and 71 deletions.
203 changes: 203 additions & 0 deletions api/index.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
<?php

$GLOBALS["clearcache"] = 0;
$GLOBALS["debug"] = 0;

if ($GLOBALS["clearcache"]) {
apcu_clear_cache();
}

$spdata = array(
"Bravo" => array(
"launchedEpoch" => strtotime("Sun May 22 17:54:00 CDT 2016"),
"lastAttempt" => 0,
"lastUpdated" => 0,
"url" => "https://dcr.stakepool.net",
),
"Delta" => array(
"launchedEpoch" => strtotime("Thu May 19 10:19:00 CDT 2016"),
"lastAttempt" => 0,
"lastUpdated" => 0,
"url" => "https://dcr.stakeminer.com",
),
"Echo" => array(
"launchedEpoch" => strtotime("Mon May 23 12:59:00 CDT 2016"),
"lastAttempt" => 0,
"lastUpdated" => 0,
"url" => "http://pool.d3c.red",
),
"Golf" => array(
"launchedEpoch" => strtotime("Wed May 25 04:09:00 CDT 2016"),
"lastAttempt" => 0,
"lastUpdated" => 0,
"url" => "https://stakepool.dcrstats.com",
),
"India" => array(
"launchedEpoch" => strtotime("Sun May 22 13:58:00 CDT 2016"),
"lastAttempt" => 0,
"lastUpdated" => 0,
"url" => "http://stakepool.eu",
)
);

foreach ($spdata as $i => $d) {
apcu_add("spcache-{$i}", $d);
}

switch ($_REQUEST["c"]) {
// clear cache
case "cc":
if ($_SERVER["REMOTE_ADDR"] == "127.0.0.1" || $_SERVER["REMOTE_ADDR"] == "::1") {
apcu_clear_cache();
print "cache cleared\n";
} else {
print "unauthorized\n";
}
break;
// get insight status;
case "gis":
$status = getInsightStatus();
print $status;
break;
// get downloads image
case "gdi":
header("Content-type: image/png");
$png = getDownloadsImage();
print $png;
break;
// get stakepool data
case "gsd":
getStakepoolData($spdata);
$allpooldata = array();
foreach (array_keys($spdata) as $i) {
$allpooldata[$i] = apcu_fetch("spcache-{$i}");
}
print json_encode($allpooldata);
break;
}

function debugLog($s) {
if ($GLOBALS["debug"]) {
error_log($s);
}
}

function getDownloadsImage() {
$cacheTTL = 24 * 60 * 60;
$timeOut = 3;
$png = file_get_contents("../content/images/total.png");
$url = "https://img.shields.io/github/downloads/decred/decred-release/total.png";

$curPng = apcu_fetch("gdi");
if (empty($curPng)) {
$c = curl_init($url);
curl_setopt($c, CURLOPT_CONNECTTIMEOUT, $timeOut);
curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($c, CURLOPT_TIMEOUT, $timeOut);
$r = curl_exec($c);
if ($r === false) {
error_log("curl error: " . curl_error($c) . " (errno: " . curl_errno($c) . ") while scraping {$url}");
} else {
// XXX PHP image validation functions seem to require a file
if (!empty($r)) {
apcu_store("gdi", $r, $cacheTTL);
}
$png = $r;
}
} else {
$png = $curPng;
}

return $png;
}

function getInsightStatus() {
$cacheTTL = 60;
$timeOut = 1;
$status = '{"info":{"blocks":"-"}}';
$url = "https://mainnet.decred.org/api/status";

$curStatus = apcu_fetch("gsi");

if (empty($curStatus)) {
$c = curl_init($url);
curl_setopt($c, CURLOPT_CONNECTTIMEOUT, $timeOut);
curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($c, CURLOPT_TIMEOUT, $timeOut);
$r = curl_exec($c);
if ($r === false) {
error_log("curl error: " . curl_error($c) . " (errno: " . curl_errno($c) . ") while scraping {$url}");
} else {
$jd = json_decode($r, true);
if (!empty($jd)) {
apcu_store("gsi", $r, $cacheTTL);
}
$status = $r;
}
} else {
$status = $curStatus;
}

return $status;
}

function getStakepoolData($spdata) {
$interval = 20 * 60;
$timeOut = 2;

foreach (array_keys($spdata) as $i) {
$d = apcu_fetch("spcache-{$i}");
if (isset($d["lastUpdated"]) && time() - $d["lastUpdated"] > $interval && time() - $d["lastAttempt"] > $interval) {
debugLog("updating $i: {$d["url"]}");
$d["lastAttempt"] = time();
$c = curl_init("{$d["url"]}/stats");
curl_setopt($c, CURLOPT_CONNECTTIMEOUT, $timeOut);
curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
// XXX if getstakeinfo isn't cached then this takes a long time
// XXX should probably be parallelized
curl_setopt($c, CURLOPT_TIMEOUT, $timeOut*3);
$r = curl_exec($c);
curl_close($c);
if ($r === false) {
apcu_store("spcache-{$i}", $d);
error_log("curl error: " . curl_error($c) . " (errno: " . curl_errno($c) . ") while scraping {$d["url"]}/stats");
} else {
$nd = array(
"Immature" => "",
"Live" => "",
"Voted" => "",
"Missed" => "",
"PoolFees" => "",
"UserCount" => "",
"PoolStatus" => "",
);
foreach (array_keys($nd) as $k) {
if (preg_match("/\<span id=\"{$k}\"\>(.*?)\<\/span\>/m", $r, $m)) {
$nd[$k] = $m[1];
}
}
foreach ($nd as $k => $v) {
if ($v == "") {
$nd[$k] = "N/A";
$nd["PoolStatus"] = "Unknown";
}
}
foreach ($nd as $k => $v) {
// don't cache failed reads
if (array_key_exists($k, $d) && $d[$k] != "N/A" && $v == "N/A") {
continue;
}
$d[$k] = $v;
}
$d["lastAttempt"] = time();
$d["lastUpdated"] = time();
apcu_store("spcache-{$i}", $d);
debugLog("updated $i");
}
} else {
debugLog("no updates required for {$i}");
}
}
}

?>
7 changes: 7 additions & 0 deletions content/css/jquery-ui.min.css

Large diffs are not rendered by default.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added content/images/stable.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added content/images/total.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
159 changes: 130 additions & 29 deletions content/scripts/scripts.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,130 @@
document.onload = ajaxGet(null,"ghcommits","https://api.github.com/repos/decred/dcrd/stats/commit_activity");

function ajaxGet(param,container,page){
var xmlhttp;

if(window.XMLHttpRequest){// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}else{// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}

xmlhttp.onreadystatechange=function(){
if(xmlhttp.readyState==4 && xmlhttp.status==200){
var jsonResult = JSON.parse(xmlhttp.responseText);
var commits = 0;

for(var j in jsonResult){
commits += jsonResult[j]['total'];
console.log(commits);
}

document.getElementById(container).innerHTML=commits;
}
}

xmlhttp.open("GET",page,true);
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlhttp.send(null);
}
(function ($) {
$.fn.styleTable = function (options) {
var defaults = {
css: 'styleTable'
};
options = $.extend(defaults, options);

return this.each(function () {

input = $(this);
input.addClass(options.css);

input.find("tr").on('mouseover mouseout', function (event) {
if (event.type == 'mouseover') {
$(this).children("td").addClass("ui-state-hover");
} else {
$(this).children("td").removeClass("ui-state-hover");
}
});

input.find("th").addClass("ui-state-default");
input.find("td").addClass("ui-widget-content");

input.find("tr").each(function () {
$(this).children("td:not(:first)").addClass("first");
$(this).children("th:not(:first)").addClass("first");
});
});
};
})(jQuery);

var stakepoolFinder = function() {
var fields = ["PoolFees", "PoolStatus", "Voted", "Missed", "Live", "Immature", "UserCount"];

tableMarkup = '<table id="pooldata" class="datatables ui-widget ui-widget-content">' +
'<thead>' +
'<tr class="ui-widget-header">' +
'<th>Launch Date</th>' +
'<th>Pool ID</th>' +
'<th>URL</th>' +
'<th>Last Updated</th>';
$.each(fields, function(i, field) {
tableMarkup += '<th>' + field + '</th>';
});

tableMarkup += '</tr></thead><tbody>';

$("#stakepool-data").html("Loading...");
$.ajax({
url: "./api/",
data: { c: "gsd"},
dataType: "json",
error: function (jqXHR, textStatus, errorThrown) {
errorMarkup ='<div class="ui-widget"><div class="ui-state-error ui-corner-all">' +
'<p><span class="ui-icon ui-icon-alert" style="float: left; margin-right: .3em;"></span>' +
'<strong>Error:</strong> ' + textStatus + ": " + errorThrown + '</p></div></div>';
},
success: function(data, textStatus) {
$.each(data, function(poolName, poolData ) {
tableMarkup += '<tr>';
tableMarkup += '<td><span>' + moment.unix(poolData["launchedEpoch"]).format("MMMM Do YYYY, HH:mm:ss") + '</span></td>';
tableMarkup += '<td>' + poolName + '</td>';
tableMarkup += '<td><a href="' + poolData["url"] + '">' + poolData["url"] + '</a></td>';
tableMarkup += '<td>' + moment.unix(poolData["lastUpdated"]).format("MMMM Do YYYY, HH:mm:ss") + '</td>';

$.each(fields, function(i, field) {
if (poolData.hasOwnProperty(field)) {
var value = poolData[field]
if (field == "PoolFees") {
if (value.substr(-1) != "%") {
value += "%";
}
}
tableMarkup += '<td>' + value + '</td>';
} else {
tableMarkup += '<td>N/A</td>';
}
});

tableMarkup += '</tr>';
});

tableMarkup += '</tbody></table>';
$("#stakepool-data").html(tableMarkup);
$("#pooldata").DataTable({
"jQueryUI": true,
"order": [[ 5, 'asc' ], [ 0, 'asc' ]],
"paging": false,
"searching": false,
});
$("#pooldata").styleTable();
},
});

$("#stakepool-dialog").dialog({
height: 400,
width: $(window).width() - 180,
modal: false,
buttons: {
Close: function() {
$(this).dialog("close");
}
}
});
};

$(document).ready(function() {
var blockexplorer = $.PeriodicalUpdater("./api/?c=gis", {
method: 'get',
maxCalls: 0,
autoStop: 0,
minTimeout: 5000,
maxTimeout: 60000,
multiplier: 2,
runatonce: true,
type: "text",
verbose: 0
}, function(response, success, xhr, handle) {
if (success) {
var json = $.parseJSON(response);
$("#blockheight").text(json["info"]["blocks"]);
// just use connections until we have a proper node counter
//$("#nodes").text(json["info"]["connections"]);
} else {
$("#blockheight").text("-");
$("#nodes").text("-");
blockexplorer.stop();
}
});
});
9 changes: 9 additions & 0 deletions content/scripts/vendor/dataTables.jqueryui.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions content/scripts/vendor/jquery-1.12.4.min.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions content/scripts/vendor/jquery-1.12.4.min.map

Large diffs are not rendered by default.

4 changes: 0 additions & 4 deletions content/scripts/vendor/jquery-2.1.4.min.js

This file was deleted.

9 changes: 9 additions & 0 deletions content/scripts/vendor/jquery-ui.min.js

Large diffs are not rendered by default.

Loading

0 comments on commit c70f545

Please sign in to comment.