├── CHANGELOG.md ├── README.md └── xmrig-proxy ├── css └── app.css ├── fonts ├── Framework7Icons-Regular.eot ├── Framework7Icons-Regular.ttf ├── Framework7Icons-Regular.woff ├── Framework7Icons-Regular.woff2 ├── MaterialIcons-Regular.eot ├── MaterialIcons-Regular.svg ├── MaterialIcons-Regular.ttf ├── MaterialIcons-Regular.woff └── MaterialIcons-Regular.woff2 ├── img ├── demo.png └── icon.png ├── index.html ├── js ├── app.js ├── inobounce.min.js └── routes.js ├── pages ├── 404.html ├── ch_pool.html ├── history.html ├── login.html ├── main.html ├── settings.html └── workers.html └── php ├── config.php ├── cron.php └── get_json.php /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # v1.0 2 | - First release. 3 | 4 | # v1.1 5 | - Add app password protected 6 | - Add Multiple proxy instances 7 | - Fix cosmetics 8 | 9 | # v1.2 10 | - Fix cosmetics 11 | - Add Workers list sorting 12 | 13 | # v2.0.0 14 | - Code reworking 15 | - Workers list auto-update 16 | - Automatic changing pool (percentage and time) 17 | - History of pool change 18 | - Pool stats 19 | - Bug Fixes 20 | - Add some xmrig-proxy settings 21 | - Auto purge DB (default 180 days) 22 | - Auto purge History (default 150 records) 23 | - Auto Delete pool from jobs if not present in xmrig-proxy config.json 24 | - highlight disconnected worker in workers list 25 | - Fix app may hang if some proxies are not reachable. 26 | - Fix Graph history day back 27 | - Fix Not working on IIS7 28 | 29 | # v2.0.1 30 | - Add individual worker graph 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # XMRig-Proxy-Frontend 2 | Simple Mobile HTML Frontend for XMRig-proxy based on [Framework7](https://github.com/framework7io/framework7) 3 | 4 | -It shows all the important informations and allow change pool and settings with xmrig-proxy API. 5 | 6 | -Manage multiple proxy instances 7 | 8 | -Switch Pool Every x minutes automatically or set the percentage of time spent on each pool 9 | 10 | -Keep history of pool change with stats 11 | 12 | Compatible with IOS, Android, Desktop (Chrome, Firefox, IE) 13 | 14 | 15 | 16 | ## Installation 17 | You must have apache webserver with php 5.x or 7.x with extension sqlite3 and curl enabled. 18 | 19 | sudo apt-get install apache2 libapache2-mod-php php-sqlite3 php-curl 20 | 21 | extract directory xmrig-proxy to your webserver root 22 | 23 | Sqlite Database directory shall be owned by www-data 24 | 25 | sudo chown www-data /var/www/html/xmrig-proxy/php/ 26 | 27 | Add cronjob every 5 min to your crontab 28 | 29 | */5 * * * * /usr/bin/php /var/www/html/xmrig-proxy/php/cron.php 30 | 31 | You must set an access token and set "restricted": false to the xmrig-proxy config.json 32 | 33 | ## Settings 34 | Change http path in php/cron.php according to your webserver configuration 35 | 36 | $php_path = "http://127.0.0.1/xmrig-proxy"; 37 | 38 | Add proxies ip, port, token authorization and app_password in php/config.php 39 | 40 | $proxy_list[0] = array("ip"=>"127.0.0.1", "port"=>"8000", "token"=>"SECRET", "label"=>"YOUR PROXY 1 LABEL"); 41 | 42 | $proxy_list[1] = array("ip"=>"127.0.0.1", "port"=>"8200", "token"=>"SECRET", "label"=>"YOUR PROXY 2 LABEL"); 43 | 44 | $app_password = "SECRET"; 45 | 46 | The app_password is the password asked when you open webapp. 47 | 48 | ## Usage 49 | For pool change , add all your pools to the xmrig-proxy config.json and select one from within the webapp. 50 | 51 | Percentage change : 52 | 53 | percentage is calculate on day (1440 min) , if you put 10% on pool#1 and 90% on pool#2 then proxy will stay on pool#1 for 144 mins and on pool#2 for 1296 mins. 54 | 55 | Time change: 56 | 57 | miner stay on pool for defined hours then swap to next pools. 58 | 59 | ## Bugs 60 | If you found a Bug please let me know and create an Issue ! 61 | 62 | ## Enhancements 63 | Create an Issue with your Idea or open a Pull Request! 64 | 65 | ## WIP 66 | 67 | Automatic switching pool to mine the most profitable coin 68 | 69 | Add and remove pool from app 70 | 71 | [Cryptonote Mining Pools](http://hashing.mine.nu) 72 | 73 | * XMR: `44ZD1s12j8M6upWXGUS1R2YzXKiKpVmTzYKbrLYSp6pDWvW7C4ALfQ2VNyg6pt2tvA94Tu5kbcDLcLbTvjJBYk6zLFYmWM3` 74 | * BTC: `1F2UpGsQETpyCCnMEBLFc5whDFAhgXJVU1` 75 | -------------------------------------------------------------------------------- /xmrig-proxy/css/app.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Material Icons'; 3 | font-style: normal; 4 | font-weight: 400; 5 | src: url(../fonts/MaterialIcons-Regular.eot); /* For IE6-8 */ 6 | src: local('Material Icons'), 7 | local('MaterialIcons-Regular'), 8 | url(../fonts/MaterialIcons-Regular.woff2) format('woff2'), 9 | url(../fonts/MaterialIcons-Regular.woff) format('woff'), 10 | url(../fonts/MaterialIcons-Regular.ttf) format('truetype'); 11 | } 12 | 13 | i.icon.icon-xmrig { 14 | width: 22px; 15 | height: 22px; 16 | background-image: url("../img/icon.png"); 17 | } 18 | 19 | .material-icons { 20 | font-family: 'Material Icons'; 21 | font-weight: normal; 22 | font-style: normal; 23 | font-size: 24px; /* Preferred icon size */ 24 | display: inline-block; 25 | line-height: 1; 26 | text-transform: none; 27 | letter-spacing: normal; 28 | word-wrap: normal; 29 | white-space: nowrap; 30 | direction: ltr; 31 | 32 | /* Support for all WebKit browsers. */ 33 | -webkit-font-smoothing: antialiased; 34 | /* Support for Safari and Chrome. */ 35 | text-rendering: optimizeLegibility; 36 | 37 | /* Support for Firefox. */ 38 | -moz-osx-font-smoothing: grayscale; 39 | 40 | /* Support for IE. */ 41 | font-feature-settings: 'liga'; 42 | } 43 | 44 | @font-face { 45 | font-family: 'Framework7 Icons'; 46 | font-style: normal; 47 | font-weight: 400; 48 | src: url("../fonts/Framework7Icons-Regular.eot"); 49 | src: url("../fonts/Framework7Icons-Regular.woff2") format("woff2"), 50 | url("../fonts/Framework7Icons-Regular.woff") format("woff"), 51 | url("../fonts/Framework7Icons-Regular.ttf") format("truetype"); 52 | } 53 | 54 | .f7-icons, .framework7-icons { 55 | font-family: 'Framework7 Icons'; 56 | font-weight: normal; 57 | font-style: normal; 58 | font-size: 25px; 59 | line-height: 1; 60 | letter-spacing: normal; 61 | text-transform: none; 62 | display: inline-block; 63 | white-space: nowrap; 64 | word-wrap: normal; 65 | direction: ltr; 66 | -webkit-font-smoothing: antialiased; 67 | text-rendering: optimizeLegibility; 68 | -moz-osx-font-smoothing: grayscale; 69 | -webkit-font-feature-settings: "liga"; 70 | -moz-font-feature-settings: "liga=1"; 71 | -moz-font-feature-settings: "liga"; 72 | font-feature-settings: "liga"; 73 | text-align: center; 74 | } 75 | 76 | 77 | select option { 78 | color: black !important; 79 | background-color:#C0C0C0; 80 | } 81 | .w_sort{ 82 | padding:8px; 83 | } 84 | 85 | 86 | -------------------------------------------------------------------------------- /xmrig-proxy/fonts/Framework7Icons-Regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pcca-matrix/XMRig-Proxy-Frontend/f9df274c41e6176e3cde40acc8805868077f088a/xmrig-proxy/fonts/Framework7Icons-Regular.eot -------------------------------------------------------------------------------- /xmrig-proxy/fonts/Framework7Icons-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pcca-matrix/XMRig-Proxy-Frontend/f9df274c41e6176e3cde40acc8805868077f088a/xmrig-proxy/fonts/Framework7Icons-Regular.ttf -------------------------------------------------------------------------------- /xmrig-proxy/fonts/Framework7Icons-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pcca-matrix/XMRig-Proxy-Frontend/f9df274c41e6176e3cde40acc8805868077f088a/xmrig-proxy/fonts/Framework7Icons-Regular.woff -------------------------------------------------------------------------------- /xmrig-proxy/fonts/Framework7Icons-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pcca-matrix/XMRig-Proxy-Frontend/f9df274c41e6176e3cde40acc8805868077f088a/xmrig-proxy/fonts/Framework7Icons-Regular.woff2 -------------------------------------------------------------------------------- /xmrig-proxy/fonts/MaterialIcons-Regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pcca-matrix/XMRig-Proxy-Frontend/f9df274c41e6176e3cde40acc8805868077f088a/xmrig-proxy/fonts/MaterialIcons-Regular.eot -------------------------------------------------------------------------------- /xmrig-proxy/fonts/MaterialIcons-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pcca-matrix/XMRig-Proxy-Frontend/f9df274c41e6176e3cde40acc8805868077f088a/xmrig-proxy/fonts/MaterialIcons-Regular.ttf -------------------------------------------------------------------------------- /xmrig-proxy/fonts/MaterialIcons-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pcca-matrix/XMRig-Proxy-Frontend/f9df274c41e6176e3cde40acc8805868077f088a/xmrig-proxy/fonts/MaterialIcons-Regular.woff -------------------------------------------------------------------------------- /xmrig-proxy/fonts/MaterialIcons-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pcca-matrix/XMRig-Proxy-Frontend/f9df274c41e6176e3cde40acc8805868077f088a/xmrig-proxy/fonts/MaterialIcons-Regular.woff2 -------------------------------------------------------------------------------- /xmrig-proxy/img/demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pcca-matrix/XMRig-Proxy-Frontend/f9df274c41e6176e3cde40acc8805868077f088a/xmrig-proxy/img/demo.png -------------------------------------------------------------------------------- /xmrig-proxy/img/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pcca-matrix/XMRig-Proxy-Frontend/f9df274c41e6176e3cde40acc8805868077f088a/xmrig-proxy/img/icon.png -------------------------------------------------------------------------------- /xmrig-proxy/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | XMRig-Proxy 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 |
19 |
20 |
21 |
Menu
22 | 31 |
32 |
33 |
34 |
35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /xmrig-proxy/js/app.js: -------------------------------------------------------------------------------- 1 | // Dom7 2 | var $$ = Dom7; 3 | 4 | // Init App 5 | var app = new Framework7({ 6 | id: 'io.framework7.proxy', 7 | root: '#app', 8 | name: 'XMRig Proxy', 9 | theme: 'auto', 10 | routes: routes, 11 | notification: { 12 | title: '', 13 | titleRightText: '', 14 | subtitle: '', 15 | icon: '', 16 | closeTimeout: 3000, 17 | } 18 | }); 19 | 20 | var password = false; 21 | if(localStorage.getItem('save-pass') == "true") password = localStorage.getItem('xmrig-pass'); 22 | var mainView = app.views.create('.view-main', {url: '/'}); 23 | var proxy_id = 0; 24 | var refresh = false; 25 | var configTimer = false; 26 | var config_data = {}; 27 | var proxy_data = {}; 28 | var data_session = { "workers_set":[ {"sort_id":"12","sort_order":"asc"} ] }; 29 | var days = 1; 30 | var refresh_ms = 35000; 31 | window.onresize = function() { Plotly.Plots.resize('proxy_hashrate'); } 32 | 33 | //-- Login Page Init 34 | $$(document).on('page:init', '.page[data-name="login"]', function (e) { 35 | $('#enter_pass').on("click",function(){ 36 | password = window.btoa( $$('input[name=password]').val() ); 37 | app.request({url:'php/get_json.php', method:"POST", data:{cc:"check_password"}, headers:{'Authorization': password}, dataType:"json", 38 | success: function (data) { 39 | if(data == true){ 40 | if($$('input[name=keep_logged]').prop('checked') === true){ 41 | localStorage.setItem('save-pass', true); 42 | localStorage.setItem('xmrig-pass', password); 43 | } 44 | mainView.router.refreshPage(); 45 | }else{ 46 | app.dialog.alert('Wrong Password!'); 47 | $$('input[name=password]').val(""); 48 | } 49 | },error: function(xhr, status){ 50 | net_fail(); 51 | } 52 | }); 53 | }); 54 | }); 55 | 56 | //-- Main Page Init 57 | $$(document).on('page:init', '.page[data-name="main"]', function (e) { 58 | app.request.setup({ beforeSend() { StatsUpdate() }, headers: {'Authorization': password } }); 59 | refresh = function(){ get_data(); graph(); }; 60 | refresh(); 61 | configTimer = setInterval(function(){ refresh() }, refresh_ms); 62 | 63 | $$('#mindays').on("click", function() { 64 | if(days > 1) { days--; graph(); } 65 | $('#numdays').text(days); 66 | }); 67 | 68 | $$('#maxdays').on("click", function() { 69 | days++; graph(); 70 | $('#numdays').text(days); 71 | }); 72 | 73 | $$('#disconnect').on("click", function(){ 74 | app.dialog.confirm('Disconnect ?', 'Confirm', function () { 75 | localStorage.removeItem('save-pass'); 76 | localStorage.removeItem('xmrig-pass'); 77 | password = false; 78 | clearInterval(configTimer); 79 | mainView.router.refreshPage(); 80 | }); 81 | }); 82 | 83 | $$('#change_proxy').on("change", function(e) { 84 | proxy_id = this.value; 85 | $.each( $('.numeric-cell'), function( i ){ $(this).html(""); }); //-- clean html datas 86 | app.dialog.preloader('Changing proxy ...'); 87 | refresh(); 88 | setTimeout(function(){ app.dialog.close(); }, 2450); 89 | }); 90 | }); 91 | 92 | //-- Main Page Back Into View 93 | $$(document).on('page:afterin', '.page[data-name="main"]', function (e) { 94 | refresh = function(){ get_data(); graph(); }; 95 | }); 96 | 97 | //-- Workers page Init 98 | $$(document).on('page:init', '.page[data-name="workers"]', function (e) { 99 | $('.w_sort').on("click", function() { 100 | var si = $$(this).find("i"); 101 | if(si.hasClass("color-white")){ 102 | //$('.w_sort').each(function(i, obj) { $(this).find("i").toggleClass("color-white color-blue") }); 103 | si.toggleClass("color-white color-blue"); 104 | data_session.workers_set.sort_order = "desc"; 105 | }else{ 106 | si.toggleClass("color-blue color-white"); 107 | data_session.workers_set.sort_order = "asc"; 108 | } 109 | data_session.workers_set.sort_id = this.id.replace('sort', ''); 110 | workers_list(); 111 | }); 112 | refresh = function(){workers_list()}; 113 | refresh(); 114 | }); 115 | 116 | //-- Change pool page Init 117 | $$(document).on('page:init', '.page[data-name="ch_pool"]', function (e) { 118 | $$('.title_proxy').html("Proxy " + config_data.proxy_infos[proxy_id].label +"" ); 119 | get_job(); 120 | $.each( config_data.pools, function( i, item ){ 121 | $('select[name=pool]').append($("").attr("value",i).text(item.url)); 122 | $$('#percent_pool').append( 123 | '
'+ 124 | item.url+''+ 125 | '
'); 126 | }); 127 | $('.percent_input').on('change', function(e){ 128 | $('#submit_pool').show(); 129 | }); 130 | 131 | $('#submit_pool').on('click', function(){ 132 | var formData = app.form.convertToData('#ch_pool-form'); 133 | var job_datas = { loop_time:formData.loop_time, pools:[], pool_hashes:proxy_data.results.hashes_total, pool_shares:proxy_data.results.accepted }; 134 | var tot = 0; 135 | $.each( $('.percent_input'), function( i ){ 136 | if(this.value) tot+=parseInt(this.value); 137 | job_datas.pools[i] = {"url":this.name, "percent":this.value}; 138 | }); 139 | if( !(tot==100 || tot==0) ){ 140 | app.dialog.alert('Total must be 100% for % switching!'); 141 | return false; 142 | } 143 | if(formData.loop_time > 0 && tot != 0){ 144 | app.dialog.alert( 'You can\'t use 2 events' ); 145 | return false; 146 | } 147 | if(formData.loop_time > 0 || (tot == 0 && formData.loop_time == 0) ){ 148 | delete job_datas.pools; 149 | } 150 | app.dialog.confirm('Confirm change ?', 'Confirm', function () { 151 | app.request.post('php/get_json.php', { cc:"write_job", proxy:proxy_id, job_datas:job_datas, proxy_pool:config_data.pools[0]}, function (data) { 152 | app.notification.create({text: 'Job saved successfully'}).open(); 153 | $('#submit_pool').hide(); 154 | get_data(); 155 | //setTimeout(function(){ get_job(); }, 5000); 156 | },"json"); 157 | }); 158 | }); 159 | 160 | $('select[name=pool]').on('change', function(e){ 161 | var index = this.value; 162 | app.dialog.confirm('to '+$(this).find(":selected").text()+' ?', 'Change Pool', function () { 163 | var selected_pool = config_data.pools[index].url; 164 | app.dialog.preloader('Changing pool ...'); 165 | app.request.post('php/get_json.php', {cc:"put_data", mode:'switch', proxy:proxy_id, proxy_config_data:config_data, summary_array:proxy_data, new_pool:selected_pool}, function (data) { 166 | if(data){ 167 | app.dialog.close(); 168 | $("#act_pool").html( config_data.pools[index].url ); 169 | app.notification.create({text: 'Pool changed successfully'}).open(); 170 | get_data(); 171 | //setTimeout(function(){ get_job(); }, 5000); ne fonctionne pas 172 | } 173 | },"json"); 174 | }, function(){ 175 | $("select[name=pool]").val(0); 176 | }); 177 | }); 178 | 179 | $("input[name=loop_time]").on("change", function(){ 180 | $('#submit_pool').show(); 181 | }); 182 | }) 183 | 184 | //-- Settings page Init 185 | $$(document).on('page:init', '.page[data-name="settings"]', function (e) { 186 | get_data(); 187 | $$('.delete_file').on("click", function(e){ 188 | delete_file($(this).data().name, $(this).data().file, proxy_id) 189 | }); 190 | $$('.title_proxy').html("Proxy " + config_data.proxy_infos[proxy_id].label +"" ); 191 | $.each( config_data, function( key, val ){ 192 | if(typeof val === 'object'){ 193 | $.each( val, function( k, v ){ 194 | if(key == "pools"){ 195 | //console.log(v["url"]); 196 | } 197 | if(key == "api")$("[name='api:"+k+"']").val(v); 198 | }); 199 | }else{ 200 | if(val === true){ 201 | $("[name='"+key+"']").prop("checked",true); 202 | }else{ 203 | $("[name='"+key+"']").val(val); 204 | } 205 | } 206 | }); 207 | 208 | $("#proxy-form-settings :input").on("change",function(){ $('#submit').show() }); 209 | 210 | $('#submit').on("click", function(){ 211 | app.dialog.preloader('Sending datas...'); 212 | var formData = app.form.convertToData("#proxy-form-settings"); 213 | $.each( formData, function(key, val ){ 214 | if(Array.isArray(val)){ // for f7 checkbox 215 | if(val.length > 0) val = true; else val = false; 216 | } 217 | if(key.indexOf(':') >= 0){ 218 | config_data[key.split(":")[0] ][key.split(":")[1]] = val; 219 | }else{ 220 | config_data[key] = val; 221 | } 222 | }); 223 | 224 | app.request.post('php/get_json.php', {cc:"put_data", mode:'setting', proxy: proxy_id, proxy_config_data:config_data}, function (data) { 225 | app.dialog.close(); 226 | app.notification.create({text: 'Settings saved successfully'}).open(); 227 | $('#submit').hide(); 228 | },"json"); 229 | 230 | }); 231 | }) 232 | 233 | //-- History Page Init 234 | $$(document).on('page:init', '.page[data-name="history"]', function (e) { 235 | $$('.title_proxy').html("Proxy " + config_data.proxy_infos[proxy_id].label +"" ); 236 | app.request.post('php/get_json.php', {cc:"get_history", proxy:proxy_id}, function (data) { 237 | var history_html = ""; 238 | if(data == "false"){ 239 | history_html = "No auto pool change history!"; 240 | }else{ 241 | var tothashes = 0; var tottime = 0; var totshares = 0; 242 | $.each( data, function(i, item ){ 243 | var item_hashes = item.hashes; 244 | if(item_hashes < 0)item_hashes = 0; 245 | history_html+=''+ 246 | ''+ (item.pool != null ? item.pool.split(':')[0] : "??") +''+ 247 | ''+ new Date(item.start * 1000).getDate()+ " " +time(item.start) + ''+ 248 | ''+ secondstotime(item.time_on, true) +''+ 249 | ''+ (item_hashes > 0 ? getReadableHashRateString(item_hashes) : "----") +''+ 250 | ''+ (item.shares ? item.shares : "") +''+ 251 | ''; 252 | tothashes+=parseInt(item_hashes); 253 | tottime+=parseInt(item.time_on); 254 | totshares+=parseInt(item.shares); 255 | }); 256 | history_html+="Totals:" + data.length + ""+secondstotime(tottime, true)+""+getReadableHashRateString(tothashes)+""; 257 | history_html+=""+totshares+""; 258 | } 259 | $$("#pool_history").html(history_html); 260 | },"json"); 261 | }); 262 | 263 | //-- functions 264 | function delete_file(name, file, proxy_id){ 265 | app.dialog.confirm('Delete ' + name +' datas?', 'Delete', function () { 266 | app.request.post('php/get_json.php', {cc:"delete_file", file:file, proxy:proxy_id}, function (data) { 267 | app.notification.create({text: 'File deleted successfully'}).open(); 268 | mainView.router.refreshPage(); 269 | },"json"); 270 | }); 271 | } 272 | 273 | function net_fail(){ 274 | app.dialog.preloader('Network Error ...'); 275 | setTimeout(function () { 276 | app.dialog.close(); 277 | }, 3000); 278 | } 279 | 280 | function get_job(){ 281 | app.request.post('php/get_json.php', {cc:"get_job", proxy:proxy_id}, function (data) { 282 | if(!data) return false; 283 | var pool_elapse = proxy_data.uptime; 284 | var pool_hashes = proxy_data.results.hashes_total; 285 | var pool_shares = proxy_data.results.accepted; 286 | if(data.pool_time) pool_elapse = Math.floor(Date.now() / 1000)-parseInt(data.pool_time); 287 | if(data.pool_hashes) pool_hashes = pool_hashes-parseInt(data.pool_hashes); 288 | if(data.pool_shares) pool_shares = pool_shares-parseInt(data.pool_shares); 289 | var pool_mode = "None"; 290 | $("#pool_timeon").html(secondstotime(pool_elapse, true)); 291 | $("#pool_shares").html(pool_shares); 292 | $("input[name=loop_time]").val(data.loop_time); 293 | 294 | if(data.pools && data.pools.length > 0){ 295 | var pool_perc = data.pools[0].percent; 296 | if(pool_perc) pool_mode = "%"; 297 | $("#pool_remain").html( secondstotime( (1440/100) * pool_perc * 60 - pool_elapse, true) ); 298 | $.each(data.pools, function( i, item ){ 299 | $("input[name='"+item.url+"']").val( item.percent ); 300 | }) 301 | } 302 | 303 | if(pool_hashes < 0) pool_hashes = "----"; else pool_hashes = getReadableHashRateString(pool_hashes); 304 | $("#pool_hashes").html(pool_hashes); 305 | if(parseInt(data.loop_time) > 0){ 306 | pool_mode = "Time"; 307 | var remaining = parseInt(data.loop_time)*3600 - pool_elapse; 308 | $("#pool_remain").html( secondstotime( (remaining > 0 ? remaining : "0"), true ) ); 309 | } 310 | $("#pool_mode").html(pool_mode); 311 | },"json"); 312 | } 313 | 314 | function workers_list(){ 315 | app.request.post('php/get_json.php', {cc:"proxy_data", endpoint: 'workers', proxy: proxy_id}, function (data) { 316 | 317 | if(!data || data.error){ 318 | net_fail(); 319 | return false; 320 | } 321 | data.workers.sort( JSONSortOrder(data_session.workers_set.sort_id, data_session.workers_set.sort_order) ); 322 | var hash_list=""; 323 | $.each( data.hashrate.total, function( i, item ){ 324 | if(i<5)hash_list+=""+getReadableHashRateString(item*1000)+"/s"; 325 | }); 326 | var connected = 0; 327 | for(var i = 0; i < data.workers.length; ++i){ 328 | if(data.workers[i][2] == 1) 329 | connected++; 330 | } 331 | $$('.title_proxy').html("Proxy " + config_data.proxy_infos[proxy_id].label +" - Workers: " + connected + " / " + data.workers.length ); 332 | $$('#worker_list').html(""); 333 | var tot_hashes = 0; 334 | $.each( data.workers, function( i, item ){ 335 | $$('#worker_list').append('
  • '+ 336 | '
    '+ 337 | '
    '+ 338 | '
    '+ 339 | '
    ' + item[0].substr(0,8) +( item[0].length > 8 ? ".."+item[0].substr(-4) :"") + '
    '+ 340 | '
    ('+item[2]+') '+item[1]+'
    '+ 341 | '
    '+ 342 | '
    '+ 343 | $.timeago(new Date(item[7]).toISOString())+ 344 | ' - '+getReadableHashRateString(item[6])+' ('+item[3]+')'+' ('+item[4]+')'+' ('+item[5]+')'+ 345 | '
    '+ 346 | '
    '+ 347 | '
    1m
    '+ 348 | '
    10m
    '+ 349 | '
    1h
    '+ 350 | '
    12h
    '+ 351 | '
    24h
    '+ 352 | '
    '+ 353 | '
    '+ 354 | '
    '+getReadableHashRateString(item[8]*1000)+"/s"+'
    '+ 355 | '
    '+getReadableHashRateString(item[9]*1000)+"/s"+'
    '+ 356 | '
    '+getReadableHashRateString(item[10]*1000)+"/s"+'
    '+ 357 | '
    '+getReadableHashRateString(item[11]*1000)+"/s"+'
    '+ 358 | '
    '+getReadableHashRateString(item[12]*1000)+"/s"+'
    '+ 359 | '
    '+ 360 | '
    '+ 361 | '
    '+ 362 | '
  • ' 363 | ); 364 | tot_hashes+=item[6]; 365 | }); 366 | hash_list+=""+getReadableHashRateString(tot_hashes)+"/s"; 367 | $$('#w_hashrates').html(hash_list); 368 | 369 | $.each( data.workers, function( i, item ){ 370 | var result = $.grep(data.workers_stats, function(e){ return e.id === item[0] }); 371 | if(result.length)$('#'+item[0].replace(".","_") ).text(result[0].datas); 372 | }); 373 | 374 | $('.inlinesparkline').sparkline( 375 | 'html', 376 | { 377 | type: 'line', 378 | width: '90%', 379 | height: '40', 380 | lineColor: '#1F77B4', 381 | fillColor: '#1E4A69', 382 | spotColor: null, 383 | minSpotColor: null, 384 | maxSpotColor: null, 385 | highlightLineColor: '#1E4A69', 386 | spotRadius: 3, 387 | drawNormalOnTop: false, 388 | chartRangeMin: 0, 389 | tooltipFormat: '{{y}}, {{offset:names}}' 390 | } 391 | ); 392 | 393 | },"json"); 394 | } 395 | 396 | function graph(){ 397 | app.request.post('php/get_json.php', {cc:"read_db", proxy:proxy_id, days:days}, 398 | function (data) { 399 | var X = []; var Y = []; 400 | for (var reading = 0; reading < data.length-2; reading++) { 401 | X.push(data[reading].date); 402 | Y.push( data[reading].value/1000 ); 403 | } 404 | var trace1 = { 405 | x: X, 406 | y: Y, 407 | fill: 'tozeroy', 408 | type: 'scatter' 409 | }; 410 | var data = [trace1]; 411 | 412 | var layout = { 413 | paper_bgcolor: "#1E1E1E", 414 | plot_bgcolor: "#1E1E1E", 415 | margin: { 416 | l:40, 417 | r:20, 418 | t:10, 419 | b:30 420 | }, 421 | autosize: true, 422 | height: "260", 423 | showlegend: false, 424 | xaxis: { 425 | autorange: true, 426 | showgrid: false, 427 | zeroline: false, 428 | showline: false, 429 | autotick: true, 430 | ticks: '', 431 | showticklabels: true 432 | }, 433 | yaxis: { 434 | autorange: true, 435 | showgrid: true, 436 | zeroline: true, 437 | showline: true, 438 | autotick: true, 439 | ticks: '', 440 | tickformat: ".2f", 441 | showticklabels: true 442 | } 443 | }; 444 | Plotly.newPlot('proxy_hashrate', data, layout, {displaylogo: false, displayModeBar: false}); 445 | },"json"); 446 | } 447 | 448 | function get_data(){ 449 | app.request.post('php/get_json.php', {cc:"proxy_data", endpoint: 'summary', proxy: proxy_id}, function (data) { 450 | if(!data || data.error ){ 451 | net_fail(); 452 | return false; 453 | } 454 | proxy_data = data; // set global proxy_data 455 | if(data.config_data) config_data = data.config_data; // set global config_data 456 | var proxy_list = ""; 457 | $.each(data.config_data.proxy_infos, function( i, item ){ 458 | proxy_list+=''; 459 | }); 460 | $$("#act_pool").html( config_data.pools[0].url ); 461 | $$('#change_proxy').html(proxy_list); 462 | $$("#bar_infos").html( " - " + getReadableHashRateString( (data.results.hashes_total / data.uptime))+"/s Wrk. "+data.miners.now ); 463 | $$("#worker_id").html( data.worker_id ); 464 | $$("#uptime").html( secondstotime(data.uptime) ); 465 | $$("#workers").html( "Now: "+data.miners.now+" - Max: "+data.miners.max+""); 466 | $$("#tothash").html(getReadableHashRateString(data.results.hashes_total)); 467 | $$("#avghash").html(getReadableHashRateString( (data.results.hashes_total / data.uptime))+"/s"); 468 | $$("#accepted").html(data.results.accepted); 469 | $$("#invalid").html(data.results.invalid); 470 | $$("#rejected").html(data.results.rejected); 471 | $$("#expired").html(data.results.expired); 472 | $$("#avgT").html(data.results.avg_time+" ms"); 473 | $$("#latency").html(data.results.latency); 474 | $$("#donated").html(data.donated); 475 | $$("#donatelevel").html(data.donate_level); 476 | $$("#up_tot").html(data.upstreams.total); 477 | $$("#up_active").html(data.upstreams.active); 478 | $$("#up_error").html(data.upstreams.error); 479 | $$("#up_ratio").html(data.upstreams.ratio); 480 | $$("#up_sleep").html(data.upstreams.sleep); 481 | var best_list=""; 482 | var bl = data.results.best; 483 | $.each( bl, function( i, item ){ 484 | best_list+=''+(i+1)+''+parseInt(item)+''; 485 | }); 486 | var hash_list=""; 487 | $.each( data.hashrate.total, function( i, item ){ 488 | if(i<5)hash_list+=""+getReadableHashRateString(item*1000)+"/s"; 489 | }); 490 | setTimeout(function(){ 491 | $$("#ten_best").html(best_list); 492 | $$('#hashrate').html(hash_list); 493 | },500); 494 | },"json"); 495 | } 496 | 497 | function capitalizeFirstLetter(string) { 498 | return string.charAt(0).toUpperCase() + string.slice(1); 499 | } 500 | 501 | function time(s) { 502 | var tzoffset = new Date(s * 1e3).getTimezoneOffset()*60; 503 | return new Date((s-tzoffset) * 1e3).toISOString().slice(-13, -5); 504 | } 505 | 506 | function secondstotime(secs , mode) 507 | { 508 | var seconds = parseInt(secs, 10); 509 | var days = Math.floor(seconds / (3600*24)); 510 | seconds -= days*3600*24; 511 | var hrs = Math.floor(seconds / 3600); 512 | seconds -= hrs*3600; 513 | var mnts = Math.floor(seconds / 60); 514 | seconds -= mnts*60; 515 | if(mode) 516 | return (days >=1 ? days : "") + ( new Date(secs*1000)).toUTCString().match(/(\d\d:\d\d:\d\d)/)[0]; 517 | else 518 | return days+" days, "+hrs+" Hrs, "+mnts+" Minutes, "+seconds+" Seconds"; 519 | } 520 | 521 | 522 | function getReadableHashRateString(hashrate) { 523 | hashrates = hashrate || 0; 524 | var i = 0; 525 | var byteUnits = [' H', ' Kh', ' Mh', ' Gh', ' Th', ' Ph' ]; 526 | while(hashrates >=1000) { 527 | hashrates = hashrates / 1000; 528 | i++; 529 | } 530 | return parseFloat(hashrates).toFixed(2) + byteUnits[i]; 531 | } 532 | 533 | function JSONSortOrder(prop, order){ 534 | return function(a,b){ 535 | if( a[prop] > b[prop]){ 536 | return (order == "asc" ? 1 : -1); 537 | }else if( a[prop] < b[prop] ){ 538 | return (order == "asc" ? -1 : 1) 539 | } 540 | return 0; 541 | } 542 | } 543 | 544 | function StatsUpdate(){ 545 | var stats_update = $$(".upd_sign"); 546 | if(!stats_update) return true; 547 | $$(stats_update).css({ "transition":"opacity 100ms ease-out","opacity":"1" }); 548 | setTimeout(function(){ 549 | $$(stats_update).css({"transition":"opacity 4000ms linear","opacity":"0"}); 550 | }, 500); 551 | } 552 | -------------------------------------------------------------------------------- /xmrig-proxy/js/inobounce.min.js: -------------------------------------------------------------------------------- 1 | (function(global){var startY=0;var enabled=false;var handleTouchmove=function(evt){var el=evt.target;while(el!==document.body&&el!==document){var style=window.getComputedStyle(el);if(!style){break}if(el.nodeName==="INPUT"&&el.getAttribute("type")==="range"){return}var scrolling=style.getPropertyValue("-webkit-overflow-scrolling");var overflowY=style.getPropertyValue("overflow-y");var height=parseInt(style.getPropertyValue("height"),10);var isScrollable=scrolling==="touch"&&(overflowY==="auto"||overflowY==="scroll");var canScroll=el.scrollHeight>el.offsetHeight;if(isScrollable&&canScroll){var curY=evt.touches?evt.touches[0].screenY:evt.screenY;var isAtTop=startY<=curY&&el.scrollTop===0;var isAtBottom=startY>=curY&&el.scrollHeight-el.scrollTop===height;if(isAtTop||isAtBottom){evt.preventDefault()}return}el=el.parentNode}evt.preventDefault()};var handleTouchstart=function(evt){startY=evt.touches?evt.touches[0].screenY:evt.screenY};var enable=function(){window.addEventListener("touchstart",handleTouchstart,false);window.addEventListener("touchmove",handleTouchmove,false);enabled=true};var disable=function(){window.removeEventListener("touchstart",handleTouchstart,false);window.removeEventListener("touchmove",handleTouchmove,false);enabled=false};var isEnabled=function(){return enabled};var testDiv=document.createElement("div");document.documentElement.appendChild(testDiv);testDiv.style.WebkitOverflowScrolling="touch";var scrollSupport="getComputedStyle"in window&&window.getComputedStyle(testDiv)["-webkit-overflow-scrolling"]==="touch";document.documentElement.removeChild(testDiv);if(scrollSupport){enable()}var iNoBounce={enable:enable,disable:disable,isEnabled:isEnabled};if(typeof module!=="undefined"&&module.exports){module.exports=iNoBounce}if(typeof global.define==="function"){(function(define){define("iNoBounce",[],function(){return iNoBounce})})(global.define)}else{global.iNoBounce=iNoBounce}})(this); -------------------------------------------------------------------------------- /xmrig-proxy/js/routes.js: -------------------------------------------------------------------------------- 1 | var routes = [ 2 | // Index page 3 | { 4 | path: '/', 5 | async(routeTo, routeFrom, resolve, reject) { 6 | if (password) { 7 | resolve({ url: './pages/main.html' }) 8 | } else { 9 | resolve({ url: './pages/login.html' }) 10 | } 11 | } 12 | }, 13 | // Main page 14 | { 15 | path: '/main/', 16 | url: './pages/main.html', 17 | name: 'main', 18 | }, 19 | // Workers page 20 | { 21 | path: '/workers/', 22 | url: './pages/workers.html', 23 | name: 'workers', 24 | }, 25 | // Settings page 26 | { 27 | path: '/settings/', 28 | url: './pages/settings.html', 29 | name: 'settings', 30 | }, 31 | // Change Pool page 32 | { 33 | path: '/ch_pool/', 34 | url: './pages/ch_pool.html', 35 | name: 'ch_pool', 36 | }, 37 | // History page 38 | { 39 | path: '/history/', 40 | url: './pages/history.html', 41 | name: 'history', 42 | }, 43 | // Default route (404 page). MUST BE THE LAST 44 | { 45 | path: '(.*)', 46 | url: './pages/404.html', 47 | }, 48 | ]; 49 | -------------------------------------------------------------------------------- /xmrig-proxy/pages/404.html: -------------------------------------------------------------------------------- 1 |
    2 | 13 |
    14 |
    15 |

    Sorry

    16 |

    Requested content not found.

    17 |
    18 |
    19 |
    20 | -------------------------------------------------------------------------------- /xmrig-proxy/pages/ch_pool.html: -------------------------------------------------------------------------------- 1 |
    2 | 10 |
    11 |
    12 |
    13 |
      14 |
    • 15 |
      16 |
      17 |
      18 |
      Mode
      19 |
      Uptime
      20 |
      Remain
      21 |
      Hashes
      22 |
      Shares
      23 |
      24 |
      25 |
      26 |
      27 |
      28 |
      29 |
      30 |
      31 |
      32 |
      33 |
    • 34 |
    35 |
    36 |
    37 |
      38 |
    • 39 |
      40 |
      41 |
      Change Actual Pool
      42 |
      43 | 45 |
      46 |
      47 |
      48 |
    • 49 |
    • 50 |
      51 |
      52 |
      Switch Pool Every (Hours.)
      53 |
      54 | 55 |
      56 |
      57 |
      58 |
    • 59 |
    • 60 |
      61 |
      62 |
      Switch Pool %
      63 |
      64 |
      65 |
    • 66 |
    67 |
    68 | 69 |
    70 |
    -------------------------------------------------------------------------------- /xmrig-proxy/pages/history.html: -------------------------------------------------------------------------------- 1 |
    2 | 10 |
    11 |
    12 |
    13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
    PoolStartTimeHashesShares
    26 |
    27 |
    28 |
    -------------------------------------------------------------------------------- /xmrig-proxy/pages/login.html: -------------------------------------------------------------------------------- 1 |
    2 | 33 |
    -------------------------------------------------------------------------------- /xmrig-proxy/pages/main.html: -------------------------------------------------------------------------------- 1 |
    2 | 19 |
    20 |
    21 |
    22 |
    Proxy Stats
    23 |
    24 |
    25 |
    26 |
    H/R History for 27 | 28 | 1 29 | 30 | days 31 |
    32 |
    33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 |
    1 M10 M1 H12 H24 H
    49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 |
    Proxy Infos
    Act. Proxy 60 | 61 |
    Act. Pool
    Uptime
    Worker ID
    Workers
    Total Hashes
    Avg. Hashrate
    Latency
    Donate Level
    Donated
    101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 |
    Upstreams
    Total
    Active
    Error
    Ratio
    Sleep
    130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 |
    Shares
    Accepted
    Invalid
    Rejected
    Expired
    Avg. Time
    159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 |
    Top Ten Results
    168 |
    169 |
    170 |
    -------------------------------------------------------------------------------- /xmrig-proxy/pages/settings.html: -------------------------------------------------------------------------------- 1 |
    2 | 10 |
    11 |
    12 |
    13 |
      14 |
    • 15 |
      16 |
      Algo
      17 |
      18 | 22 |
      23 |
      24 |
    • 25 |
    • 26 |
      27 |
      Background
      28 |
      29 | 32 |
      33 |
      34 |
    • 35 |
    • 36 |
      37 |
      Colors
      38 |
      39 | 42 |
      43 |
      44 |
    • 45 |
    • 46 |
      47 |
      Custom Diff
      48 |
      49 | 50 |
      51 |
      52 |
    • 53 |
    • 54 |
      55 |
      Donate Level
      56 |
      57 | 58 |
      59 |
      60 |
    • 61 |
    • 62 |
      63 |
      Mode
      64 |
      65 | 69 |
      70 |
      71 |
    • 72 |
    • 73 |
      74 |
      Retries
      75 |
      76 | 77 |
      78 |
      79 |
    • 80 |
    • 81 |
      82 |
      Retry Pause
      83 |
      84 | 85 |
      86 |
      87 |
    • 88 |
    • 89 |
      90 |
      User Agent
      91 |
      92 | 93 |
      94 |
      95 |
    • 96 |
    • 97 |
      98 |
      Verbose
      99 |
      100 | 103 |
      104 |
      105 |
    • 106 |
    • 107 |
      108 |
      Worker id
      109 |
      110 | 111 |
      112 |
      113 |
    • 114 |
    115 |
    116 | 117 |
    118 |
    Delete Files
    119 |
    120 |

    121 | 122 | 123 | 124 |

    125 |
    126 |
    127 |
    128 |
    -------------------------------------------------------------------------------- /xmrig-proxy/pages/workers.html: -------------------------------------------------------------------------------- 1 |
    2 | 16 |
    17 |
    18 |
    19 |
    20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 40 | 46 | 52 | 58 | 64 | 70 | 71 | 72 |
    1m10m1h12h24hTot
    35 | 36 | sort 37 | sort 38 | 39 | 41 | 42 | sort 43 | sort 44 | 45 | 47 | 48 | sort 49 | sort 50 | 51 | 53 | 54 | sort 55 | sort 56 | 57 | 59 | 60 | sort 61 | sort 62 | 63 | 65 | 66 | sort 67 | sort 68 | 69 |
    73 |
    74 |
      75 |
      76 |
      77 |
      -------------------------------------------------------------------------------- /xmrig-proxy/php/config.php: -------------------------------------------------------------------------------- 1 | "127.0.0.1", "port"=>"8000", "token"=>"SECRET", "label"=>"PROXY 1 LABEL"); 8 | 9 | $max_history = 150; //-- max history records per proxy for json file 10 | $max_history_days = 180; //-- max days of graph history 11 | ?> -------------------------------------------------------------------------------- /xmrig-proxy/php/cron.php: -------------------------------------------------------------------------------- 1 | 'write_db'))); 9 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 10 | $server_output = curl_exec ($ch); 11 | curl_close ($ch); 12 | ?> -------------------------------------------------------------------------------- /xmrig-proxy/php/get_json.php: -------------------------------------------------------------------------------- 1 | $val) { 14 | if( preg_match($rx_http, $key) ) { 15 | $arh_key = preg_replace($rx_http, '', $key); 16 | $rx_matches = array(); 17 | $rx_matches = explode('_', $arh_key); 18 | if( count($rx_matches) > 0 and strlen($arh_key) > 2 ) { 19 | foreach($rx_matches as $ak_key => $ak_val) $rx_matches[$ak_key] = ucfirst($ak_val); 20 | $arh_key = implode('-', $rx_matches); 21 | } 22 | $arh[$arh_key] = $val; 23 | } 24 | } 25 | return( $arh ); 26 | } 27 | } 28 | 29 | $headers = apache_request_headers(); 30 | 31 | switch($_POST['cc']) 32 | { 33 | case 'check_password': 34 | echo json_encode(verify_password($headers)); 35 | break; 36 | 37 | case ($_POST['cc'] == 'read_db' && verify_password($headers)): 38 | $proxy_id = $_POST["proxy"]; 39 | $db = new SQLite3('proxy.db'); 40 | $db->busyTimeout(5000); 41 | $db->exec('PRAGMA journal_mode = wal;'); 42 | $days = intval($_POST["days"]); 43 | $date = time()-($days * 24 * 60 * 60); 44 | $date = date('Y-m-d H:i:s', $date); 45 | $proxy_adress = $proxy_list[$proxy_id]["ip"].":".$proxy_list[$proxy_id]["port"]; 46 | $results = $db->query("SELECT * FROM 'proxy_$proxy_adress' WHERE date >= '$date'"); 47 | $arr = array(); $i=0; 48 | while($row = $results->fetchArray()){ 49 | $arr[$i]['date'] = $row['date']; 50 | $arr[$i]['value'] = $row['value']; 51 | $i++; 52 | } 53 | $db->close(); 54 | echo json_encode($arr); 55 | break; 56 | 57 | case 'write_db': 58 | $db = new SQLite3('proxy.db'); 59 | $db->busyTimeout(5000); 60 | $db->exec('PRAGMA journal_mode = wal;'); 61 | $jobs = get_jobs(); 62 | //-- First compare proxy present in jobs.json with proxy from this php adress list 63 | $address_list = array(); 64 | foreach($proxy_list as $k=>$v) $address_list[] = $v["ip"].":".$v["port"]; 65 | foreach($jobs as $k=>$v){ 66 | $key = array_search($v["proxy"], $address_list); 67 | if($key === false){ // if proxy exist on jobs.json and not php adress list , delete datas from jobs.json 68 | unset($jobs[$k]); 69 | $jobs = array_values($jobs); 70 | $jsondata = json_encode($jobs, JSON_PRETTY_PRINT); 71 | file_put_contents("jobs.json", $jsondata); 72 | } 73 | } 74 | 75 | foreach($proxy_list as $proxy){ 76 | $proxy_address = $proxy["ip"].":".$proxy["port"]; 77 | $db->query("CREATE TABLE IF NOT EXISTS 'proxy_$proxy_address' ('id_auto' INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, 'date' DATETIME, 'value' NUMERIC);"); 78 | $summary_array = json_decode(get_curl_data($proxy["ip"], $proxy["port"], "summary", $proxy["token"]),true); 79 | if(!$summary_array) continue; // if proxy not available ! 80 | $workers_array = json_decode(get_curl_data($proxy["ip"], $proxy["port"], "workers", $proxy["token"]),true); 81 | if(!empty($workers_array["workers"])) write_workers_stats($workers_array["workers"], $proxy["ip"]."_".$proxy["port"]); 82 | $val = round($summary_array['hashrate']['total'][2]*1000,2); 83 | $date = date('Y-m-d H:i'); 84 | $db->query("INSERT INTO 'proxy_$proxy_address' ('date' ,'value') VALUES('$date', '$val')"); 85 | $date_max = date( 'Y-m-d H:i', strtotime("-$max_history_days day", strtotime($date)) ); 86 | $db->query("DELETE FROM 'proxy_$proxy_address' WHERE date(date) 0){ 96 | $pool_time = $jobs[$key]["pool_time"]; 97 | if( (time()-$pool_time)/3600 >= $jobs[$key]["loop_time"]){ 98 | swap_pool($proxy_address, $summary_array, $proxy_config_data, $proxy["token"], $jobs[$key]); 99 | } 100 | }else if(!empty($jobs[$key]["pools"])){ 101 | //-- Loop Percent 102 | $pool_lists = $jobs[$key]["pools"]; 103 | //-- first verify if pools inside config.json is the same in jobs.json else delete datas from job.json 104 | foreach($pool_lists as $kk=>$vv){ 105 | $Fkey = array_search($vv["url"], array_column($proxy_config_data["pools"], 'url')); 106 | if($Fkey === false){ 107 | unset($jobs[$key]["pools"][$kk]); 108 | $pool_lists = $jobs[$key]["pools"]; 109 | $jsondata = json_encode($jobs, JSON_PRETTY_PRINT); 110 | file_put_contents("jobs.json", $jsondata); 111 | } 112 | } 113 | $time_on = time() - $jobs[$key]["pool_time"]; 114 | foreach($pool_lists as $k=>$v){ 115 | $pool = $v["url"]; 116 | $minutes_perc = (1440/100)*$v["percent"]; 117 | if($proxy_config_data["pools"][0]["url"] == $pool && $time_on/60 >= $minutes_perc){ 118 | swap_pool($proxy_address, $summary_array, $proxy_config_data, $proxy["token"], $jobs[$key]); 119 | } 120 | } 121 | } 122 | } 123 | } 124 | } 125 | $db->close(); 126 | break; 127 | 128 | case ($_POST['cc'] == 'proxy_data' && verify_password($headers)): 129 | //endpoint --> config, workers, summary 130 | $proxy_id = $_POST["proxy"]; 131 | $endpoint = $_POST["endpoint"]; 132 | $data = get_curl_data($proxy_list[$proxy_id]["ip"], $proxy_list[$proxy_id]["port"], $endpoint, $proxy_list[$proxy_id]["token"]); 133 | if($data){ 134 | $api_data = json_decode($data, true); 135 | }else{ 136 | $api_data["error"] = 1; 137 | } 138 | if($endpoint == "summary"){ 139 | $config_data = get_proxy_configs($proxy_list[$proxy_id]["ip"], $proxy_list[$proxy_id]["port"], $proxy_list[$proxy_id]["token"]); 140 | if($config_data)$api_data["config_data"] = $config_data; 141 | $proxy_infos = array(); $i=0; 142 | foreach($GLOBALS["proxy_list"] as $k => $v){ 143 | $proxy_infos[$i]["id"] = $k; 144 | $proxy_infos[$i]["label"] = $v["label"]; 145 | $i++; 146 | } 147 | $api_data["config_data"]["proxy_infos"] = $proxy_infos; 148 | }else if($endpoint == "workers"){ 149 | $api_data["workers_stats"] = get_workers_stats($proxy_list[$proxy_id]["ip"]."_".$proxy_list[$proxy_id]["port"]); 150 | } 151 | echo json_encode($api_data); 152 | break; 153 | 154 | case ($_POST['cc'] == 'write_job' && verify_password($headers)): 155 | $proxy_id = $_POST["proxy"]; 156 | $job_datas = $_POST["job_datas"]; 157 | $proxy_pool = $_POST["proxy_pool"]; 158 | $job_datas["proxy"] = $proxy_list[$proxy_id]["ip"].":".$proxy_list[$proxy_id]["port"]; 159 | $job_infos = array("proxy_hashes" => $job_datas["pool_hashes"], "proxy_shares" => $job_datas["pool_shares"], "proxy_pool" => $proxy_pool["url"]); 160 | echo json_encode(write_job($job_datas, $job_infos)); 161 | 162 | break; 163 | 164 | case ($_POST['cc'] == 'get_job' && verify_password($headers)): 165 | $proxy_id = $_POST["proxy"]; 166 | $jobs = get_jobs($proxy_id); 167 | if(!$jobs){ 168 | echo json_encode(false); 169 | }else{ 170 | $ex = false; 171 | foreach($jobs as $k => $v){ 172 | if($v["proxy"] == $proxy_list[$proxy_id]["ip"].":".$proxy_list[$proxy_id]["port"]) $ex = $k; 173 | } 174 | if($ex !== false) echo json_encode($jobs[$ex]); else echo json_encode(false); 175 | } 176 | break; 177 | 178 | case ($_POST['cc'] == 'get_history' && verify_password($headers)): 179 | $proxy_id = $_POST["proxy"]; 180 | $datas = get_history($proxy_id); 181 | if($datas) echo json_encode($datas); else echo json_encode('false'); 182 | break; 183 | 184 | case ($_POST['cc'] == 'delete_file' && verify_password($headers)): 185 | $file = $_POST["file"]; 186 | $del = false; 187 | if(file_exists($file)) $del = unlink($file); 188 | echo json_encode($del); 189 | break; 190 | 191 | case ($_POST['cc'] == 'put_data' && verify_password($headers)): 192 | $proxy_id = $_POST["proxy"]; 193 | $mode = $_POST["mode"]; 194 | $url = "http://".$proxy_list[$proxy_id]["ip"].":".$proxy_list[$proxy_id]["port"]."/1/config"; 195 | $proxy_config_data = $_POST["proxy_config_data"]; 196 | if($mode == "switch"){ 197 | $summary_array = $_POST["summary_array"]; 198 | $new_pool = $_POST["new_pool"]; 199 | $pool_index = array_search($new_pool, array_column($proxy_config_data["pools"], 'url')); 200 | $proxy_address = $proxy_list[$proxy_id]["ip"].":".$proxy_list[$proxy_id]["port"]; 201 | 202 | $jobs = get_jobs($proxy_id); 203 | $key = array_search($proxy_list[$proxy_id]["ip"].":".$proxy_list[$proxy_id]["port"], array_column($jobs, 'proxy')); 204 | 205 | if($key === false){ 206 | $job = array("loop_time" => "", "pools" => array(), "proxy" => $proxy_address); 207 | }else{ 208 | $job = $jobs[$key]; 209 | } 210 | $response = switch_to_pool($proxy_address, $summary_array, $proxy_config_data, $proxy_list[$proxy_id]["token"], $job, $pool_index); 211 | }else{ 212 | $response = write_config($url, $proxy_config_data, $proxy_list[$proxy_id]["token"]); 213 | } 214 | echo json_encode(true); 215 | break; 216 | 217 | } 218 | 219 | /******************************************************************/ 220 | /* FUNCTIONS */ 221 | /******************************************************************/ 222 | function get_workers_stats($proxy){ 223 | $myFile = "workers_$proxy.json"; 224 | if (file_exists($myFile)) $data = file_get_contents($myFile); else return false; 225 | if(!isJson($data)) return false; 226 | $data = json_decode($data ,true); 227 | return $data; 228 | } 229 | 230 | function write_workers_stats($stats_array, $proxy){ 231 | $myFile = "workers_$proxy.json"; 232 | if(!file_exists($myFile)){ 233 | $create = json_encode(array(), JSON_PRETTY_PRINT); 234 | file_put_contents($myFile, $create); 235 | } 236 | $jsondata = file_get_contents($myFile); 237 | 238 | if(!isJson($jsondata)){ 239 | $create = json_encode(array(), JSON_PRETTY_PRINT); 240 | file_put_contents($myFile, $create); 241 | $jsondata = json_encode(array()); 242 | } 243 | if( time()-filemtime($myFile) < 3600 && empty($create) ) return false; //write stats only each hour 244 | 245 | $workers_stats = json_decode($jsondata, true); 246 | foreach($stats_array as $k => $v){ 247 | $id = trim($v[0]); 248 | $hashes = $v[12]; 249 | $key = array_search($id, array_column($workers_stats, 'id')); 250 | if($key !== false){ 251 | $temp_arr = explode(',', $workers_stats[$key]["datas"]); 252 | array_push($temp_arr, $hashes); 253 | if(sizeof($temp_arr) >= 24) { unset($temp_arr[0]); $temp_arr = array_values($temp_arr); } 254 | $workers_stats[$key]["datas"] = implode(",", $temp_arr); 255 | if ( array_sum($temp_arr) == 0 ){ unset($workers_stats[$key]); $workers_stats = array_values($workers_stats); } // delete old workers 256 | }else{ 257 | $new_stats = array("id"=>$id, "datas"=>$hashes); 258 | array_push($workers_stats, $new_stats); 259 | } 260 | 261 | } 262 | $jsondata = json_encode($workers_stats, JSON_PRETTY_PRINT); 263 | file_put_contents($myFile, $jsondata); 264 | } 265 | 266 | function get_proxy_configs($proxy_ip, $proxy_port, $token){ 267 | $data = get_curl_data($proxy_ip, $proxy_port, "config", $token); 268 | if($data) return json_decode($data, true); 269 | } 270 | function switch_to_pool($proxy_address, $summary_array, $proxy_config_data, $token, $job, $new_pool){ 271 | $proxy_url = "http://".$proxy_address."/1/config"; 272 | $prev_pool = $proxy_config_data["pools"][0]; 273 | array_move($proxy_config_data["pools"], 0, $new_pool); 274 | $response = write_config($proxy_url, $proxy_config_data, $token); 275 | $job_infos = array("proxy_hashes" => $summary_array["results"]["hashes_total"], "proxy_shares" => $summary_array["results"]["accepted"], "proxy_pool" => $prev_pool["url"]); 276 | write_job($job, $job_infos); 277 | } 278 | 279 | function swap_pool($proxy_address, $summary_array, $proxy_config_data, $token, $job){ 280 | $proxy_url = "http://".$proxy_address."/1/config"; 281 | $prev_pool = $proxy_config_data["pools"][0]; 282 | unset($proxy_config_data["pools"][0]); 283 | array_push($proxy_config_data["pools"], $prev_pool); 284 | $proxy_config_data["pools"] = array_values($proxy_config_data["pools"]); 285 | $response = write_config($proxy_url, $proxy_config_data, $token); 286 | $job_infos = array("proxy_hashes" => $summary_array["results"]["hashes_total"], "proxy_shares" => $summary_array["results"]["accepted"], "proxy_pool" => $prev_pool["url"]); 287 | write_job($job, $job_infos); 288 | return json_encode(true); 289 | } 290 | 291 | 292 | function history_write($datas){ 293 | $myFile = "history.json"; 294 | if(!file_exists($myFile)){ 295 | $create = json_encode(array(), JSON_PRETTY_PRINT); 296 | file_put_contents($myFile, $create); 297 | } 298 | $jsondata = file_get_contents($myFile); 299 | if(!isJson($jsondata)){ 300 | return false; 301 | } 302 | $arr_data = json_decode($jsondata, true); 303 | $key = array_search($datas["proxy"], array_column($arr_data, 'proxy')); 304 | 305 | if($key === false){ 306 | array_push($arr_data, $datas); 307 | }else{ 308 | if( sizeof($arr_data[$key]["history"]) >= $GLOBALS["max_history"] ) unset($arr_data[$key]["history"][0]); 309 | $arr_data[$key]["history"] = array_values($arr_data[$key]["history"]); 310 | array_push( $arr_data[$key]["history"], $datas["history"][0]); 311 | } 312 | $jsondata = json_encode($arr_data, JSON_PRETTY_PRINT); 313 | file_put_contents($myFile, $jsondata); 314 | } 315 | 316 | 317 | function write_job($new_job, $infos){ 318 | $myFile = "jobs.json"; 319 | $new_job["pool_time"] = time(); 320 | $new_job["pool_hashes"] = $infos["proxy_hashes"]; 321 | $new_job["pool_shares"] = $infos["proxy_shares"]; 322 | $hist_datas = array("proxy"=>$new_job["proxy"]); 323 | if(!file_exists($myFile)){ 324 | $create = json_encode(array(), JSON_PRETTY_PRINT); 325 | file_put_contents($myFile, $create); 326 | } 327 | $jsondata = file_get_contents($myFile); 328 | 329 | if(!isJson($jsondata)){ 330 | $create = json_encode(array(), JSON_PRETTY_PRINT); 331 | file_put_contents($myFile, $create); 332 | $jsondata = json_encode(array()); 333 | } 334 | $jobs_data = json_decode($jsondata, true); 335 | 336 | 337 | $key = array_search($new_job["proxy"], array_column($jobs_data, 'proxy')); 338 | 339 | if($key === false){ 340 | array_push($jobs_data, $new_job); 341 | }else{ 342 | $time_on = time()-$jobs_data[$key]["pool_time"]; 343 | $hashes_on = $infos["proxy_hashes"]-$jobs_data[$key]["pool_hashes"]; 344 | $shares = $infos["proxy_shares"]-$jobs_data[$key]["pool_shares"]; 345 | $hist_datas["history"][0] = array("pool"=>$infos["proxy_pool"], "hashes"=>$hashes_on, "start"=>$jobs_data[$key]["pool_time"], "time_on"=>$time_on, "shares"=>$shares) ; 346 | history_write($hist_datas); 347 | $jobs_data[$key] = $new_job; 348 | } 349 | $jsondata = json_encode($jobs_data, JSON_PRETTY_PRINT); 350 | file_put_contents($myFile, $jsondata); 351 | return true; 352 | } 353 | 354 | //-- Write to XMRIG-Proxy config.json 355 | function write_config($url, $proxy_config_data, $token){ 356 | foreach($proxy_config_data as $k=>$v){ 357 | if(is_array($v)){ 358 | foreach($v as $kk=>$vv){ 359 | if($vv == "false") $proxy_config_data[$k][$kk] = false; if($vv == "true")$proxy_config_data[$k][$kk] = true; 360 | } 361 | }else{ 362 | if($v == "false") $proxy_config_data[$k] = false; if($v == "true")$proxy_config_data[$k] = true; 363 | } 364 | } 365 | $proxy_config_data = json_encode($proxy_config_data); 366 | $authorization = "Authorization: Bearer ".$token; 367 | $ch = curl_init(); 368 | curl_setopt($ch, CURLOPT_HTTPHEADER, array( 369 | 'Content-Type: application/json', 370 | 'Content-Length: ' . strlen($proxy_config_data), 371 | $authorization) 372 | ); 373 | curl_setopt($ch, CURLOPT_URL, $url); 374 | curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT'); 375 | curl_setopt($ch, CURLOPT_POSTFIELDS, $proxy_config_data); 376 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 377 | curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 6); 378 | $response = curl_exec($ch); 379 | curl_close($ch); 380 | return $response; 381 | } 382 | 383 | //-- Get History JSON 384 | function get_history($proxy_id){ 385 | $myFile = "history.json"; 386 | if (file_exists($myFile)) $data = file_get_contents($myFile); else return false; 387 | if(!isJson($data)) return false; 388 | $data = json_decode($data,true); 389 | $proxy_adress = $GLOBALS["proxy_list"][$proxy_id]["ip"].":".$GLOBALS["proxy_list"][$proxy_id]["port"]; 390 | $history = array(); 391 | $key = array_search($proxy_adress, array_column($data, 'proxy')); 392 | if($key !== false) $history = $data[$key]["history"]; 393 | return array_reverse($history); 394 | } 395 | 396 | //-- Get Jobs From JSON 397 | function get_jobs(){ 398 | $myFile = 'jobs.json'; 399 | if (file_exists($myFile)) $data = file_get_contents($myFile); else return false; 400 | if(!isJson($data)) return false; 401 | return json_decode($data, true); 402 | } 403 | 404 | function array_move(&$array,$swap_a,$swap_b){ 405 | list($array[$swap_a],$array[$swap_b]) = array($array[$swap_b],$array[$swap_a]); 406 | } 407 | 408 | function isJson($string){ 409 | return is_string($string) && is_array(json_decode($string, true)) && (json_last_error() == JSON_ERROR_NONE) ? true : false; 410 | } 411 | 412 | function verify_password($headers){ 413 | $token = $headers['Authorization']; 414 | $password = base64_decode($token); 415 | if($GLOBALS["app_password"] != trim($password)) return false; else return true; 416 | } 417 | 418 | function get_curl_data($ip, $port, $endpoint, $token){ 419 | $ch = curl_init(); 420 | $authorization = "Authorization: Bearer ".$token; 421 | curl_setopt ($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json' , $authorization )); 422 | curl_setopt ($ch, CURLOPT_URL, "http://$ip:$port/1/$endpoint"); 423 | curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1); 424 | curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, 6); 425 | $response = curl_exec($ch); 426 | curl_close ($ch); 427 | return($response); 428 | } 429 | ?> 430 | --------------------------------------------------------------------------------