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