mirror of
https://github.com/xmrig/xmrig-proxy.git
synced 2026-02-09 02:59:17 +08:00
Initial import.
This commit is contained in:
12
.editorconfig
Normal file
12
.editorconfig
Normal file
@@ -0,0 +1,12 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.json]
|
||||
insert_final_newline = false
|
||||
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/node_modules
|
||||
/.idea
|
||||
41
app.sh
Executable file
41
app.sh
Executable file
@@ -0,0 +1,41 @@
|
||||
#!/bin/bash -e
|
||||
APP_NAME=xmrig-proxy
|
||||
ACTION=$1
|
||||
. "$NVM_DIR/nvm.sh"
|
||||
|
||||
start() {
|
||||
NODE_ENV=production pm2 start index.js --interpreter=`nvm which stable` --name ${APP_NAME} --log log/${APP_NAME}.log --output log/${APP_NAME}.out --error log/${APP_NAME}.err
|
||||
}
|
||||
|
||||
stop() {
|
||||
pm2 stop ${APP_NAME}
|
||||
}
|
||||
|
||||
restart() {
|
||||
pm2 restart ${APP_NAME}
|
||||
}
|
||||
|
||||
update() {
|
||||
git pull
|
||||
stop
|
||||
start
|
||||
}
|
||||
|
||||
case "${ACTION}" in
|
||||
start)
|
||||
start
|
||||
;;
|
||||
stop)
|
||||
stop
|
||||
;;
|
||||
restart)
|
||||
restart
|
||||
;;
|
||||
update)
|
||||
update
|
||||
;;
|
||||
*)
|
||||
echo $"Usage: $0 {start|stop|restart|update}"
|
||||
exit 1
|
||||
esac
|
||||
exit 0
|
||||
88
app/Proxy.js
Normal file
88
app/Proxy.js
Normal file
@@ -0,0 +1,88 @@
|
||||
'use strict';
|
||||
|
||||
const Promise = require('bluebird');
|
||||
const uuid = require('uuid');
|
||||
const net = require('net');
|
||||
const readline = require('readline');
|
||||
const log = require('./log');
|
||||
|
||||
const READY = 0;
|
||||
const WAIT_LOGIN = 1;
|
||||
const WAIT_CLOSE = 2;
|
||||
|
||||
|
||||
class Proxy {
|
||||
constructor(options, onLogin) {
|
||||
this.host = options.host;
|
||||
this.port = options.port;
|
||||
this.onLogin = onLogin;
|
||||
|
||||
this.server = net.createServer(this.onConnection.bind(this));
|
||||
}
|
||||
|
||||
|
||||
listen(options) {
|
||||
return Promise.promisify(this.server.listen, { context: this.server })(options);
|
||||
}
|
||||
|
||||
|
||||
onConnection(socket) {
|
||||
socket.id = uuid.v4();
|
||||
|
||||
_setupSocket(socket);
|
||||
socket.state = WAIT_LOGIN;
|
||||
|
||||
const upstream = _setupSocket(new net.Socket());
|
||||
upstream.connect({ host: this.host, port: this.port });
|
||||
|
||||
const i = readline.createInterface({ input: socket, terminal: false });
|
||||
i.on('line', line => {
|
||||
if (line === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (socket.state === WAIT_LOGIN) {
|
||||
try {
|
||||
upstream.write(this.onLogin(socket, line));
|
||||
socket.state = READY;
|
||||
}
|
||||
catch (e) {
|
||||
socket.state = WAIT_CLOSE;
|
||||
log.error(`[login] "${e.message}"`);
|
||||
socket.end();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// console.log('<<<', line);
|
||||
upstream.write(line + '\n');
|
||||
});
|
||||
|
||||
upstream.on('data', data => {
|
||||
// console.log('>>>', data.toString());
|
||||
socket.write(data)
|
||||
});
|
||||
|
||||
socket.on('close', had_error => {
|
||||
upstream.end();
|
||||
});
|
||||
|
||||
upstream.on('close', had_error => {
|
||||
socket.end();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function _setupSocket(socket) {
|
||||
socket.setNoDelay(true);
|
||||
socket.setKeepAlive(true, 120);
|
||||
|
||||
socket.on('error', err => {});
|
||||
|
||||
return socket;
|
||||
}
|
||||
|
||||
|
||||
module.exports = Proxy;
|
||||
24
app/config.js
Normal file
24
app/config.js
Normal file
@@ -0,0 +1,24 @@
|
||||
'use strict';
|
||||
|
||||
const Promise = require('bluebird');
|
||||
const nconf = require('nconf');
|
||||
const path = require('path');
|
||||
|
||||
|
||||
let suffix = '-dev';
|
||||
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
suffix = '';
|
||||
}
|
||||
else if (process.env.NODE_ENV === 'test') {
|
||||
suffix = '-test';
|
||||
}
|
||||
|
||||
|
||||
nconf.file(path.join(__dirname, `/../config/app${suffix}.json`));
|
||||
nconf.file('default', path.join(__dirname, '/../config/default.json'));
|
||||
|
||||
|
||||
module.exports.save = function() {
|
||||
return Promise.promisify(nconf.save, {context: nconf})();
|
||||
};
|
||||
20
app/log.js
Normal file
20
app/log.js
Normal file
@@ -0,0 +1,20 @@
|
||||
'use strict';
|
||||
|
||||
const winston = require('winston');
|
||||
|
||||
|
||||
const logger = new (winston.Logger)({
|
||||
transports: [
|
||||
new winston.transports.File({ filename: __dirname + '/../log/app.log', json: false })
|
||||
],
|
||||
exitOnError: true
|
||||
});
|
||||
|
||||
|
||||
/* istanbul ignore next */
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
logger.add(winston.transports.Console, { colorize: true, timestamp: true, level: 'debug' });
|
||||
}
|
||||
|
||||
|
||||
module.exports = logger;
|
||||
49
app/login.js
Normal file
49
app/login.js
Normal file
@@ -0,0 +1,49 @@
|
||||
'use strict';
|
||||
|
||||
const nconf = require('nconf');
|
||||
const rigs = require('./rigs');
|
||||
|
||||
const BYPASS_WORKER_ID = nconf.get('bypass_worker_id');
|
||||
const BYPASS_WALLET = nconf.get('bypass_wallet');
|
||||
const WALLET_ADDRESS = nconf.get('wallet');
|
||||
const PASSWORD = nconf.get('password');
|
||||
const USER_AGENT = nconf.get('agent');
|
||||
|
||||
|
||||
function login(socket, line) {
|
||||
if (line.charAt(0) !== '{') {
|
||||
throw new Error(line);
|
||||
}
|
||||
|
||||
const packet = JSON.parse(line);
|
||||
if (packet.method !== 'login') {
|
||||
throw new Error('Invalid method');
|
||||
}
|
||||
|
||||
rigs.add(socket, packet.params);
|
||||
packet.params.login = getLogin(packet.params.login);
|
||||
packet.params.agent = USER_AGENT;
|
||||
|
||||
if (PASSWORD) {
|
||||
packet.params.pass = PASSWORD;
|
||||
}
|
||||
|
||||
return JSON.stringify(packet) + '\n';
|
||||
}
|
||||
|
||||
|
||||
function getLogin(login) {
|
||||
login = login.split('.');
|
||||
if (!BYPASS_WALLET || login[0].length < 95) {
|
||||
login[0] = WALLET_ADDRESS;
|
||||
}
|
||||
|
||||
if (!BYPASS_WORKER_ID || login.length < 2) {
|
||||
return login[0]
|
||||
}
|
||||
|
||||
return login.join('.');
|
||||
}
|
||||
|
||||
|
||||
module.exports = login;
|
||||
47
app/rigs.js
Normal file
47
app/rigs.js
Normal file
@@ -0,0 +1,47 @@
|
||||
'use strict';
|
||||
|
||||
const log = require('./log');
|
||||
|
||||
|
||||
const STORE = new Map();
|
||||
|
||||
|
||||
/**
|
||||
* Add new rig.
|
||||
*
|
||||
* @param {Object} socket
|
||||
* @param {Object} params
|
||||
*/
|
||||
function add(socket, params) {
|
||||
STORE.set(socket.id, { id: socket.id, ip: socket.remoteAddress, login: params.login, ua: params.agent, datetime: +new Date() });
|
||||
|
||||
socket.on('close', had_error => {
|
||||
remove(socket.id, had_error);
|
||||
});
|
||||
|
||||
log.info(socket.remoteAddress, `login: "${params.login}", ua: "${params.agent}", count: ${STORE.size}`);
|
||||
}
|
||||
|
||||
|
||||
function remove(socket_id, had_error) {
|
||||
const info = STORE.get(socket_id);
|
||||
if (!info) {
|
||||
return;
|
||||
}
|
||||
|
||||
STORE.delete(socket_id);
|
||||
log.info(info.ip, `close: "${info.login}", had_error: ${had_error}, count: ${STORE.size}`);
|
||||
}
|
||||
|
||||
|
||||
function report() {
|
||||
return {
|
||||
rigsCount: STORE.size,
|
||||
rigs: Array.from(STORE.values())
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
module.exports.add = add;
|
||||
module.exports.remove = remove;
|
||||
module.exports.report = report;
|
||||
21
config/default.json
Normal file
21
config/default.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"wallet": "48edfHu7V9Z84YzzMa6fUueoELZ9ZRXq9VetWzYGzKt52XU5xvqgzYnDK9URnRoJMk1j8nLwEVsaSWJ4fhdUyZijBGUicoD",
|
||||
"bypass_worker_id": true,
|
||||
"bypass_wallet": true,
|
||||
"password": "",
|
||||
"agent": "cpuminer-multi/0.1",
|
||||
"upstream": {
|
||||
"host": "xmr-eu.dwarfpool.com",
|
||||
"port": 8005
|
||||
},
|
||||
"proxy": [
|
||||
{
|
||||
"host": "0.0.0.0",
|
||||
"port": 80
|
||||
},
|
||||
{
|
||||
"host": "0.0.0.0",
|
||||
"port": 443
|
||||
}
|
||||
]
|
||||
}
|
||||
22
index.js
Normal file
22
index.js
Normal file
@@ -0,0 +1,22 @@
|
||||
'use strict';
|
||||
|
||||
const config = require('./app/config');
|
||||
const nconf = require('nconf');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const Proxy = require('./app/Proxy');
|
||||
const log = require('./app/log');
|
||||
const login = require('./app/login');
|
||||
const rigs = require('./app/rigs');
|
||||
|
||||
|
||||
nconf.get('proxy').forEach(listen => {
|
||||
const proxy = new Proxy(nconf.get('upstream'), login);
|
||||
proxy.listen(listen)
|
||||
.then(() => log.info('[app] listen:', listen));
|
||||
});
|
||||
|
||||
|
||||
setInterval(() => {
|
||||
fs.writeFile(path.join(__dirname, `log/report.json`), JSON.stringify(rigs.report(), null, 2), err => {})
|
||||
}, 60000);
|
||||
2
log/.gitignore
vendored
Normal file
2
log/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
29
package.json
Normal file
29
package.json
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "xmrig-proxy",
|
||||
"version": "0.1.0",
|
||||
"description": "XMRig Proxy",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"start": "bash app.sh start",
|
||||
"stop": "bash app.sh stop",
|
||||
"restart": "bash app.sh stop && bash app.sh start",
|
||||
"update": "bash app.sh update",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/xmrig/xmrig-proxy.git"
|
||||
},
|
||||
"author": "XMRig <support@xmrig.com> (https://xmrig.com)",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/xmrig/xmrig-proxy/issues"
|
||||
},
|
||||
"homepage": "https://github.com/xmrig/xmrig-proxy#readme",
|
||||
"dependencies": {
|
||||
"bluebird": "3.5.0",
|
||||
"nconf": "0.8.4",
|
||||
"uuid": "3.0.1",
|
||||
"winston": "2.3.1"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user