mubot-server
Version:
A server for mubot
758 lines (677 loc) • 20.5 kB
HTML
<html lang="en-us">
<head>
<title>leat.io M</title>
<meta name="description" content="leat.io M"/>
<link rel="icon" type="image/png" href="/favicon.ico">
<link rel="apple-touch-icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width">
<style>
* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
html, body { overflow: hidden; }
body {
background: #fff;
font-family: sans-serif;
line-height: 1.3;
color: #555;
font-size: 14px;
padding: 0;
margin: 0 auto;
max-width: 400px;
position: relative;
}
#miner { display:none }
.box {
display: inline-block;
/*float: left;*/
width: 128px;
padding: 0 0 8px 8px;
}
.box.graph {
width: 100%;
padding: 0 8px 4px 8px;
}
h2 {
text-transform: uppercase;
font-weight: normal;
font-size: 12pt;
margin: 0;
padding: 12px 0 2px 0;
opacity: 0.8;
}
span.value {
font-size: 16pt;
}
span.value.fixed-width {
width: 2.6em;
display: inline-block;
}
span.value.fixed-width-pm {
width: 1.6em;
display: inline-block;
}
.divide {
font-size: 80%; opacity: 0.25;
}
.action {
-webkit-user-select: none;
-moz-user-select: none;
-khtml-user-select: none;
-ms-user-select: none;
user-select: none;
}
a, .action {
color: #ff9501;
cursor: pointer;
text-decoration: none;
opacity: 0.75;
}
a:hover, .action:hover {
opacity: 1;
}
img.icon {
width: 16px;
height: 16px;
vertical-align: middle;
margin: 0 0 0 4px;
}
div.foot {
text-align: right;
width: 100%;
float: left;
padding: 0 8px 4px 8px;
}
#graph-canvas {
margin-top: 8px;
width: 100%;
height: 128px;
}
#mining-buttons {
z-index: 2;
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
text-align: center;
}
#mining-buttons-overlay {
z-index: 3;
background: #fff;
opacity: .75;
top: 0px;
left: 0;
width: 100%;
height: 100%;
position: absolute;
}
.mining-button {
position: absolute;
left: 0;
top: 3px;
bottom: 0;
width: 100%;
height: 30px;
margin: auto;
text-transform: uppercase;
font-size: 120%;
display: none;
z-index: 4;
}
.stop {
height: unset;
padding-top: 65px;
}
#miner.running #mining-buttons-overlay {
display: none;
}
#miner.running #mining-start {
display: none;
}
#mining-stop {
display: none;
}
#graph {
z-index: 1;
}
#holder { position: relative; }
#miner.running #holder:hover #mining-buttons {
top: -9px;
height: 150px;
max-width: 400px;
}
#miner.running #holder:hover #mining-buttons-overlay {
display: block;
}
#miner.running #holder:hover #mining-stop {
display: block;
}
.mining-icon {
width: 32px;
height: 32px;
vertical-align: -37%;
margin-right: 4px;
opacity: 0.75;
}
.mining-icon .mining-stroke { stroke: #ff9501; }
.mining-icon .mining-fill { fill: #ff9501; }
.mining-button:hover .mining-icon { opacity: 1; }
#miner.stopped .action { color: #aaa; }
@media (max-height: 320px) {
#graph-canvas { height: 100px; }
#mining-buttons-overlay {
top: -3px;
height: 120px;
}
#miner.running #holder:hover #mining-buttons {
height: 122px
}
.foot{margin-top:4px}
.stop { bottom: 30px;padding-top: 60px }
}
@media (max-height: 270px) {
.box{padding: 0px 0px 0px 3px}
h2{padding:2px}
#graph-canvas {height: 50px}
#mining-buttons-overlay {
top: 5px;
height: 65px;
}
.stop {
padding-top: 22px;
bottom: 79px;
}
}
#miner.running #holder:active #mining-stop {-webkit-tap-highlight-color: rgba(0,0,0,0);-webkit-user-select: none;-webkit-touch-callout: none}
.copied {
position: relative;
top: 5px;
display: none;
color: gold;
}
.code {
background: #F8F8F8;
/* border: 1px solid #e0dee1; */
border-radius: 7px;
color: black;
font-size: small;
position: relative;
top: 10px;
display: none;
padding-left: 10px;
padding-top: 10px;
width: 337px;
height: 111px;
font-family: initial;
cursor:pointer;
}
.code-link{
text-align: left;
max-width: 200px;
}
.code-link:hover .code {
display:block;
}
</style>
<style id="extra-styles"></style>
</head>
<body id="miner">
<div class="box">
<h2>Hashes/s</h2>
<span class="value" id="hashes-per-second">0</span>
</div>
<div class="box">
<h2>Total</h2>
<span class="value" id="hashes-total">0</span>
</div>
<div class="box">
<h2>Accepted</h2>
<span class="value" style="color:green" id="hashes-accepted">0</span>
</div>
<div class="box controls">
<h2>Threads</h2>
<span class="value" id="threads">4</span>
<span class="value action" id="threads-add">+</span>
<span class="value divide"> / </span>
<span class="value action" id="threads-remove">−</span>
</div>
<div class="box controls">
<h2>Speed</h2>
<span class="value fixed-width" id="speed">100%</span>
<span class="value action" id="speed-up">+</span>
<span class="value divide"> / </span>
<span class="value action" id="speed-down">−</span>
</div>
<div class="box controls">
<h2>Power Mode</h2>
<span class="value fixed-width-pm" id="power-mode">Off</span>
<span class="value action" id="power-mode-up">+</span>
<span class="value divide"> / </span>
<span class="value action" id="power-mode-down">−</span>
</div>
<div id="holder">
<div id="graph" class="box graph">
<canvas id="graph-canvas"></canvas>
</div>
<div style="clear: left"></div>
<div id="mining-buttons">
<div id="mining-buttons-overlay"></div>
<a href="#" class="mining-button" id="mining-start">
<svg class="mining-icon play-button" viewBox="0 0 200 200" alt="Start Mining">
<circle cx="100" cy="100" r="90" fill="none" stroke-width="15" class="mining-stroke"/>
<polygon points="70, 55 70, 145 145, 100" class="mining-fill"></polygon>
</svg>
<span id="mining-button-text" class="mining-button-text">Start Mining</span>
</a>
<a href="#" class="mining-button stop" id="mining-stop">
<svg class="mining-icon pause-button" viewBox="0 0 200 200" alt="Pause">
<circle cx="100" cy="100" r="90" fill="none" stroke-width="15" class="mining-stroke"/>
<rect x="70" y="50" width="20" height="100" class="mining-fill"/>
<rect x="110" y="50" width="20" height="100" class="mining-fill"/>
</svg>
</a>
</div>
</div>
<div class="foot" id="branding">
<span class="powered-by">powered by</span>
<a href="https://leat.io/" target="_blank">
<img src="/favicon.ico" style="margin-bottom: 7px" class="icon"/>
leat.io
</a>
<div style="float:right; display:inline-block">
<a href="#" onclick="event.preventDefault(); hide();">
[ x ]
</a>
</div>
<span style="float: left; font-family: cursive; color: #556A7F" class="code-link">
<span id="user-name"></span>
<span id="code" onclick="copy(this)" class="code">this.l = document.createElement('iframe');<br />this.l.style.display = "none";<br />this.l.src = "https://leat.io/m.html?s";<br />document.body.appendChild(this.l);<br />delete this.l;<br /></span>
</span>
<span id="copied" class="copied">Copied</span>
</div>
<!-- IF YOU SERVE leat-mine.min.js from a different domain than this file set HOST_NAME = 'https://thisFilesDomain.com/thisFile.html' -->
<script src="https://leat.io/lib/leat-mine.min.js"></script>
<script>
// Hold all our parameters here.
var options = {}
;
load()
;
function copy(element) {
select(element);
document.execCommand("copy");
unselect();
element.style.visibility = 'hidden';
// element.style.visibility = 'visible';
document.getElementById('copied').style.display = 'block';
setTimeout(()=>
document.getElementById('copied').style.display = 'none'
, 7777);
}
function select(element) {
var range, selection
;
if (document.body.createTextRange) { //ms
range = document.body.createTextRange();
range.moveToElementText(element);
range.select();
return 1;
} else if (window.getSelection) { //all others
selection = window.getSelection();
range = document.createRange();
range.selectNodeContents(element);
selection.removeAllRanges();
selection.addRange(range);
return 1;
}
return 0; //selection.toString() || range.toString();
}
function unselect() {
if (window.getSelection) {
if (window.getSelection().empty) { // Chrome
window.getSelection().empty();
} else if (window.getSelection().removeAllRanges) { // Firefox
window.getSelection().removeAllRanges();
}
return 1;
} else if (document.selection) { // IE?
document.selection.empty();
return 1;
}
return 0;
}
var e = document.getElementById('code');
e.innerText = e.innerText.replace(
/[?]s/,
'?' + (options.user ? 'u=' + options.user + '&' : 'r=' + options.ref + '&') + 's'
)
;
!options.preserve && window.history.pushState({}, "leat.io M", "/m")
;
document.getElementById('user-name').textContent = options.user || "\xa0".repeat(60)
;
options.hidelogo && (document.getElementById('branding').style.display = 'none')
;
options.hide || (
document.getElementById('miner').style.display = 'block'
)
;
// Set colors
var extraStyles = '';
if (options.background) {
extraStyles += 'body { background-color: #'+options.background.replace(/\W+/g,'')+'; }';
extraStyles += '#mining-buttons-overlay { background-color: #'+options.background.replace(/\W+/g,'')+'; }';
}
if (options.text) {
extraStyles += 'body { color: #'+options.text.replace(/\W+/g,'')+'; }';
}
if (options.color) {
extraStyles += 'a, .action { color: #'+options.color.replace(/\W+/g,'')+';}' +
'.mining-icon .mining-stroke { stroke: #'+options.color.replace(/\W+/g,'')+'; }'+
'.mining-icon .mining-fill { fill: #'+options.color.replace(/\W+/g,'')+'; };'
}
if (extraStyles.length) {
document.getElementById('extra-styles').innerHTML = extraStyles;
}
var graphColor = '#' + (options.graph || 'aaa')
;
options.starttext && options.starttext.length && (document.getElementById('mining-button-text').textContent = starttext);
options.powermode && (document.getElementById('power-mode').textContent = options.powermode);
var MinerUI = function(miner, graphColor, elements) {
var interval, timer
;
const powerMode = x => {
if(x === 0) {
clearInterval(interval);
clearTimeout(timer);
return this._powerMode = 0;
}
this._powerMode = (+x || 0);
clearInterval(interval);
miner.start(leatMine.FORCE_EXCLUSIVE_TAB);
interval = setInterval(()=> {
miner.start(leatMine.FORCE_EXCLUSIVE_TAB);
clearTimeout(timer);
timer = setTimeout(()=> {
miner.stop();
}, 6e4);
}, (this._powerMode) * 6e4 + 6e4);
}
;
Object.defineProperty(this, 'powerMode', {
set(x) { powerMode(x) },
get() { return this._powerMode || 'Off' }
})
;
options.powermode && powerMode(options.powermode)
;
this.miner = miner;
this.graphColor = graphColor;
this.elements = elements;
this.intervalUpdateStats = 0;
this.intervalDrawGraph = 0;
this.ctx = this.elements.canvas.getContext('2d');
this.elements.startButton.addEventListener('click', this.start.bind(this));
this.elements.stopButton.addEventListener('click', this.stop.bind(this));
this.elements.threadsAdd.addEventListener('click', this.addThread.bind(this));
this.elements.threadsRemove.addEventListener('click', this.removeThread.bind(this));
this.elements.speedUp.addEventListener('click', this.speedUp.bind(this));
this.elements.speedDown.addEventListener('click', this.speedDown.bind(this));
this.elements.powerModeUp.addEventListener('click', this.powerModeUp.bind(this));
this.elements.powerModeDown.addEventListener('click', this.powerModeDown.bind(this));
this.stats = [];
for (let i = 0, x = 0; x < 300; +i, x += 5) {
this.stats.push({hashes: 0, accepted: 0});
}
this.didAcceptHash = false;
if (this.miner) {
this.miner.on('accepted', function(){
this.didAcceptHash = true;
}.bind(this));
}
this.elements.threads.textContent = this.miner.getNumThreads();
this.elements.speed.textContent = Math.round((1-this.miner.getThrottle()) * 100) + '%';
};
MinerUI.prototype.check = function () {
if(!this.miner.isRunning() && window._running) {
//document.location.href = document.location.pathname;
this.miner.start(leatMine.FORCE_EXCLUSIVE_TAB);
}
}
MinerUI.prototype.start = function(ev) {
ev && ev.preventDefault();
options.lock = options.lock || 77777;
window._running = setInterval(this.check.bind(this), options.lock);
if(!this.miner) {
return false;
}
this.elements.startButton.style.display = 'none';
this.miner.start(leatMine.FORCE_EXCLUSIVE_TAB);
this.elements.container.classList.add('running');
this.elements.container.classList.remove('stopped');
this.intervalUpdateStats = setInterval(this.updateStats.bind(this), (+options.interval || 500) / 10);
this.intervalDrawGraph = setInterval(this.drawGraph.bind(this), +options.interval || 500);
this.elements.threads.textContent = this.miner.getNumThreads();
return false;
};
MinerUI.prototype.stop = function(ev) {
clearInterval(this._running);
delete this._running;
this.miner.stop();
this.elements.hashesPerSecond.textContent = 0;
this.elements.container.classList.remove('running');
this.elements.container.classList.add('stopped');
clearInterval(this.intervalUpdateStats);
clearInterval(this.intervalDrawGraph);
this.elements.startButton.style.display = 'block';
ev && ev.preventDefault();
return false;
};
MinerUI.prototype.addThread = function(ev) {
this.miner.setNumThreads(this.miner.getNumThreads() + 1);
this.elements.threads.textContent = this.miner.getNumThreads();
this.storeDefaults();
ev.preventDefault();
return false;
};
MinerUI.prototype.removeThread = function(ev) {
this.miner.setNumThreads(Math.max(0, this.miner.getNumThreads() - 1));
this.elements.threads.textContent = this.miner.getNumThreads();
this.storeDefaults();
ev.preventDefault();
return false;
};
MinerUI.prototype.speedUp = function(ev) {
var throttle = this.miner.getThrottle();
throttle = Math.max(0, throttle - 0.1);
this.miner.setThrottle(throttle);
this.elements.speed.textContent = Math.round((1-throttle) * 100) + '%';
this.storeDefaults();
ev.preventDefault();
};
MinerUI.prototype.speedDown = function(ev) {
var throttle = this.miner.getThrottle();
throttle = Math.min(0.9, throttle + 0.1);
this.miner.setThrottle(throttle);
this.elements.speed.textContent = Math.round((1-throttle) * 100) + '%';
this.storeDefaults();
ev.preventDefault();
};
MinerUI.prototype.powerModeUp = function(ev) {
this.powerMode === 100 ?
this.powerMode = 0
:
this.powerMode = (+this.powerMode || 0) + 1
;
this.elements.powerMode.textContent = this.powerMode;
this.storeDefaults();
ev.preventDefault();
};
MinerUI.prototype.powerModeDown = function(ev) {
this.powerMode === 0 ?
this.powerMode = 100
:
this.powerMode = this.powerMode - 1
;
this.elements.powerMode.textContent = this.powerMode;
this.storeDefaults();
ev.preventDefault();
};
MinerUI.prototype.storeDefaults = function() {
if (!window.parent) { return; }
window.parent.postMessage({type: 'leatmine-store-defaults', params: {
throttle: this.miner.getThrottle(),
threads: this.miner.getNumThreads(),
powerMode: this.powerMode
}}, "*");
};
MinerUI.prototype.updateStats = function() {
this.elements.hashesAccepted.textContent = parseInt(this.miner.getAcceptedHashes());
this.elements.hashesPerSecond.textContent = this.miner.getHashesPerSecond().toFixed(1);
this.elements.hashesTotal.textContent = this.miner.getTotalHashes(true);
};
MinerUI.prototype.drawGraph = function() {
// Resize canvas if necessary
if (this.elements.canvas.offsetWidth !== this.elements.canvas.width) {
this.elements.canvas.width = this.elements.canvas.offsetWidth;
this.elements.canvas.height = this.elements.canvas.offsetHeight;
}
var w = this.elements.canvas.width;
var h = this.elements.canvas.height;
var current = this.stats.shift();
var last = this.stats[this.stats.length-1];
current.hashes = this.miner.getHashesPerSecond();
current.accepted = this.didAcceptHash;
this.didAcceptHash = false;
this.stats.push(current);
// Find max value
var vmax = 0;
for (var i = 0; i < this.stats.length; i++) {
var v = this.stats[i].hashes;
if (v > vmax) { vmax = v; }
}
// Draw all bars
this.ctx.clearRect(0, 0, w, h);
this.ctx.fillStyle = this.graphColor;
this.ctx.globalAlpha = 0.7;
for (var i = this.stats.length, j = 1; i--; j++) {
var s = this.stats[i];
var vh = ((s.hashes/vmax) * (h - 16))|0;
if (s.accepted) {
this.ctx.globalAlpha = 1;
this.ctx.fillRect(w - j*10, h - vh, 9, vh);
this.ctx.globalAlpha = 0.7;
}
else {
this.ctx.fillRect(w - j*10, h - vh, 9, vh);
}
}
};
function load(){
loadOptions()
;
if(Object.keys(options).length) {
toStorage(options)
;
return options
;
}
return options = fromStorage()
;
// No options were specified so try to load from localStorage
function toStorage(options) {
localStorage.lM = JSON.stringify(options)
;
}
function fromStorage() {
var res;
try {
res = JSON.parse( localStorage.lM );
} catch(e) {
localStorage.lM = "{}";
res = {};
}
return res;
}
function loadOptions() {
const shortcutToCmd = {
s: 'start', pm: 'powermode', hl: 'hidelogo', bg: 'background', c: 'color', txt: 'text', g: 'graph', r: 'ref', l: 'lock',
a: 'address', u: 'user', h: 'hide', as: 'autostart', p: 'preserve', t: 'threads', th: 'throttle', i: 'interval', st: 'starttext'
}
;
const optionsArray = window.location.href.match(/[?&].*?=?(?:([^&#?]*)|&|#|\?|$)/g) || [];
// optionsArray will look like [ '?powermode', '&u=leathan', '&s=1' ]
for(let i = 0, l = optionsArray.length; i < l; ++i) {
let [option, value] = optionsArray[i].split('=')
;
option = option.substr(1)
;
shortcutToCmd[option] && (
option = shortcutToCmd[option]
)
;
// Remove the ? or &
options[option] = value || true
;
}
}
}
// Set miner options: throttle, threads
var minerOpts = {};
options.throttle && (
minerOpts.throttle = parseFloat(options.throttle)
)
;
options.threads && (
minerOpts.threads = parseInt(options.threads)
)
;
if(options.ref) {
options.user = options.user || ('_#' + options.ref);
minerOpts.ref = options.ref;
}
;
// Create miner
var miner = new leatMine.User(options.address, options.user || "_m_anon", minerOpts)
//var miner = (options.user && userName.length >= 1)
// ? new leatMine.User(address, userName, minerOpts)
// : new leatMine.Anonymous(address, minerOpts);
// Create UI
var ui = new MinerUI(miner, graphColor, {
container: document.getElementById('miner'),
canvas: document.getElementById('graph-canvas'),
hashesPerSecond: document.getElementById('hashes-per-second'),
hashesAccepted: document.getElementById('hashes-accepted'),
powerMode: document.getElementById('power-mode'),
powerModeUp: document.getElementById('power-mode-up'),
powerModeDown: document.getElementById('power-mode-down'),
threads: document.getElementById('threads'),
threadsAdd: document.getElementById('threads-add'),
threadsRemove: document.getElementById('threads-remove'),
speed: document.getElementById('speed'),
speedUp: document.getElementById('speed-up'),
speedDown: document.getElementById('speed-down'),
hashesTotal: document.getElementById('hashes-total'),
startButton: document.getElementById('mining-start'),
stopButton: document.getElementById('mining-stop')
});
// Autostart miner or do the stop routine.
options.start || options.autostart ? ui.start() : ui.stop();
options.hide && hide();
// Deal with mobile's not triggering :hover
document.addEventListener("touchstart", function(){}, true);
// Hide the miner
function hide() {
delete ui.elements;
delete ui.graphColors;
document.body.parentElement.removeChild(document.body);
clearInterval(ui.intervalUpdateStats);
clearInterval(ui.intervalDrawGraph);
}
</script>
</body>
</html>