Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- var irc = require('irc')
- , winston = require('winston')
- , fs = require('fs')
- , yaml = require('js-yaml')
- , coin = require('node-cannacoin')
- , crypto = require('crypto')
- , request = require('request')
- , webadmin = require('../lib/webadmin/app')
- , async = require('async');
- //Locks & lsat active for rain.
- var last_active = {};
- var locks = [];
- // check if the config file exists
- if(!fs.existsSync('./config/config.yml')) {
- winston.error('Configuration file doesn\'t exist! Please read the README.md file first.');
- process.exit(1);
- }
- // load settings
- var settings = yaml.load(fs.readFileSync('./config/config.yml', 'utf-8'));
- // handle sigint
- process.on('exit', function() {
- winston.info('Exiting...');
- if(client != null) {
- client.disconnect('My master ordered me to leave.');
- }
- });
- // load winston's cli defaults
- winston.cli();
- // write logs to file
- if(settings.log.file) {
- winston.add(winston.transports.File, {
- filename: settings.log.file,
- level: 'info'
- });
- }
- // connect to coin json-rpc
- winston.info('Connecting to ' + settings.coin.full_name + ' daemon...');
- var coin = coin({
- host: settings.rpc.host,
- port: settings.rpc.port,
- user: settings.rpc.user,
- pass: settings.rpc.pass
- });
- coin.getBalance(function(err, balance) {
- if(err) {
- winston.error('Could not connect to %s RPC API! ', settings.coin.full_name, err);
- // process.exit(1);
- return;
- }
- var balance = typeof(balance) == 'object' ? balance.result : balance;
- winston.info('Connected to JSON RPC API. Current total balance is %d' + settings.coin.short_name, balance);
- })
- // run webadmin
- if(settings.webadmin.enabled){
- winston.info('Running webadmin on port %d', settings.webadmin.port);
- webadmin.app(settings.webadmin.port, coin, settings, winston);
- }
- // connect to the server
- winston.info('Connecting to ' + settings.connection.host + '...');
- // create new client object
- var client = new irc.Client(settings.connection.host, settings.login.nickname, {
- port: settings.connection.port,
- secure: settings.connection.secure,
- channels: settings.channels,
- userName: settings.login.username,
- realName: settings.login.realname,
- debug: settings.connection.debug
- });
- // gets user's login status
- irc.Client.prototype.isIdentified = function(nickname, callback) {
- // request login status
- this.say('NickServ', 'ACC ' + nickname);
- // wait for response
- var listener = function(from, to, message) {
- // proceed only on NickServ's ACC response
- var regexp = new RegExp('^(\\S+) ACC (\\d)');
- if(from != undefined && from.toLowerCase() == 'nickserv' && regexp.test(message)) {
- var match = message.match(regexp);
- var user = match[1];
- var level = match[2];
- // if the right response, call the callback and remove this listener
- if(user.toLowerCase() == nickname.toLowerCase()) {
- callback(level == 3);
- this.removeListener('notice', listener);
- }
- }
- }
- this.addListener('notice', listener);
- }
- irc.Client.prototype.getNames = function(channel, callback) {
- client.send('NAMES', channel);
- var listener = function(nicks) {
- var names = [];
- for(name in nicks) {
- names.push(name);
- }
- callback(names);
- this.removeListener('names' + channel, listener);
- }
- this.addListener('names' + channel, listener);
- }
- // gets a empty coin address
- irc.Client.prototype.getAddress = function(nickname, callback) {
- winston.debug('Requesting address for %s', nickname);
- coin.send('getaccountaddress', nickname.toLowerCase(), function(err, address) {
- if(err) {
- winston.error('Something went wrong while getting address. ' + err);
- callback(err);
- return false;
- }
- callback(false, address);
- });
- }
- String.prototype.expand = function(values) {
- var global = {
- nick: client.nick
- }
- return this.replace(/%([a-zA-Z_]+)%/g, function(str, variable) {
- return typeof(values[variable]) == 'undefined' ?
- (typeof(settings.coin[variable]) == 'undefined' ?
- (typeof(global[variable]) == 'undefined' ?
- str : global[variable]) : settings.coin[variable]) : values[variable];
- });
- }
- // 420 Watch
- date = new Date();
- if ( date.getHours() === 4 || date.getHours() === 16 && date.getMinutes() === 20 && date.getSeconds() === 0) {
- client.say(settings.broadcast.cannacoin, "The time is now 4:20 PST, light em up!");
- }
- // basic client listeners
- client.addListener('registered', function(message) {
- winston.info('Connected to %s.', message.server);
- client.say('NickServ', 'IDENTIFY ' + settings.login.nickserv_password);
- });
- client.addListener('error', function(message) {
- winston.error('Received an error from IRC network: ', message);
- });
- client.addListener('message', function(from, channel, message) {
- last_active[from] = Date.now();
- var match = message.toLowerCase().match(/^(!?)(\S+)/);
- if(match == null) return;
- var prefix = match[1];
- var command = match[2];
- if(settings.commands[command]) {
- if(channel == client.nick && settings.commands[command].pm === false) return;
- if(channel != client.nick && (settings.commands[command].channel === false || prefix != '!')) return;
- }
- else {
- return;
- }
- // if pms, make sure to respond to pms instead to itself
- if(channel == client.nick) channel = from;
- // comands that don't require identifying
- if(command == 'help'.toLowerCase() || command == 'terms'.toLowerCase()){
- for(var i = 0; i < settings.messages[command].length; i++) {
- var message = settings.messages[command][i];
- client.say(channel, message.expand({}));
- }
- return;
- }
- // if not that, message will be undefined for some reason
- // todo: find a fix for that
- var msg = message;
- client.isIdentified(from, function(status) {
- var message = msg;
- // check if the sending user is logged in (identified) with nickserv
- if(!status) {
- winston.info('%s tried to use command `%s`, but is not identified.', from, message);
- client.say(channel, settings.messages.not_identified.expand({name: from}));
- return;
- }
- switch(command) {
- case 'rain':
- var match = message.match(/^.?rain ([\d\.]+) ?(\d+)?/);
- if(match == null || !match[1]) {
- client.say(channel, 'Usage: !rain <amount> [max people]');
- return;
- }
- var amount = Number(match[1]);
- var max = Number(match[2]);
- if(isNaN(amount)) {
- client.say(channel, settings.messages.invalid_amount.expand({name: from, amount: match[2]}));
- return;
- }
- if(isNaN(max) || max < 1) {
- max = false;
- } else {
- max = Math.floor(max);
- }
- //If user is locked, return (do not tip).
- if(locks.indexOf(from.toLowerCase()) > -1) {
- client.say(channel, settings.messages.locked.expand({name: from}));
- return;
- }
- // Enable lock
- locks.push(from.toLowerCase());
- coin.getBalance(settings.rpc.prefix + from.toLowerCase(), settings.coin.min_confirmations, function(err, balance) {
- if(err) {
- locks.splice(locks.indexOf(from.toLowerCase()),1);
- winston.error('Error in !rain command.', err);
- client.say(channel, settings.messages.error.expand({name: from}));
- return;
- }
- var balance = typeof(balance) == 'object' ? balance.result : balance;
- if(balance >= amount) {
- client.getNames(channel, function(names) {
- // rain only on nicknames active within the last x seconds
- if(settings.commands.rain.rain_on_last_active) {
- for (var i = names.length - 1; i >= 0; i--) {
- if(!last_active.hasOwnProperty(names[i]) || last_active[names[i]] + settings.commands.rain.rain_on_last_active * 1000 < Date.now()) {
- names.splice(i, 1);
- }
- };
- }
- // remove tipper from the list
- names.splice(names.indexOf(from), 1);
- // shuffle the array
- for(var j, x, i = names.length; i; j = Math.floor(Math.random() * i), x = names[--i], names[i] = names[j], names[j] = x);
- max = max ? Math.min(max, names.length) : names.length;
- if(max == 0) return;
- var whole_channel = false;
- if(max == names.length) whole_channel = true;
- names = names.slice(0, max);
- if(amount / max < settings.coin.min_rain) {
- locks.splice(locks.indexOf(from.toLowerCase()),1);
- client.say(channel, settings.messages.rain_too_small.expand({from: from, amount: amount, min_rain: settings.coin.min_rain * max}));
- return;
- }
- for (var i = 0; i < names.length; i++) {
- coin.move(settings.rpc.prefix + from.toLowerCase(), settings.rpc.prefix + names[i].toLowerCase(), amount / max, function(err, reply) {
- if(i == names.length) locks.splice(locks.indexOf(from.toLowerCase()),1);
- if(err || !reply) {
- winston.error('Error in !rain command', err);
- return;
- }
- });
- }
- client.say(channel, settings.messages.rain.expand({name: from, amount: parseFloat((amount / max).toFixed(8)), list: (whole_channel && !settings.commands.rain.rain_on_last_active) ? 'the whole channel' : names.join(', ')}));
- });
- } else {
- locks.splice(locks.indexOf(from.toLowerCase()),1);
- client.say(channel, settings.messages.no_funds.expand({name: from, balance: balance, short: amount - balance, amount: amount}));
- }
- })
- break;
- case 'flip':
- var match = message.match(/^.?flip ([\d\.]+)/);
- if(match == null || !match[1]) {
- client.say(channel, 'Usage: !flip <amount>');
- return;
- }
- var amount = Number(match[1]);
- var max = 1;
- if(isNaN(amount)) {
- client.say(channel, settings.messages.invalid_amount.expand({name: from, amount: match[2]}));
- return;
- }
- //If user is locked, return (do not tip).
- if(locks.indexOf(from.toLowerCase()) > -1) {
- client.say(channel, settings.messages.locked.expand({name: from}));
- return;
- }
- // Enable lock
- locks.push(from.toLowerCase());
- coin.getBalance(settings.rpc.prefix + from.toLowerCase(), settings.coin.min_confirmations, function(err, balance) {
- if(err) {
- locks.splice(locks.indexOf(from.toLowerCase()),1);
- winston.error('Error in !tip command.', err);
- client.say(channel, settings.messages.error.expand({name: from}));
- return;
- }
- var balance = typeof(balance) == 'object' ? balance.result : balance;
- if(balance >= amount) {
- client.getNames(channel, function(names) {
- // rain only on nicknames active within the last x seconds
- if(settings.commands.rain.rain_on_last_active) {
- for (var i = names.length - 1; i >= 0; i--) {
- if(!last_active.hasOwnProperty(names[i]) || last_active[names[i]] + settings.commands.rain.rain_on_last_active * 1000 < Date.now()) {
- names.splice(i, 1);
- }
- };
- }
- // remove tipper from the list
- names.splice(names.indexOf(from), 1);
- // shuffle the array
- for(var j, x, i = names.length; i; j = Math.floor(Math.random() * i), x = names[--i], names[i] = names[j], names[j] = x);
- max = max ? Math.min(max, names.length) : names.length;
- if(max == 0) return;
- var whole_channel = false;
- if(max == names.length) whole_channel = true;
- names = names.slice(0, max);
- if(amount / max < settings.coin.min_rain) {
- locks.splice(locks.indexOf(from.toLowerCase()),1);
- client.say(channel, settings.messages.rain_too_small.expand({from: from, amount: amount, min_rain: settings.coin.min_rain * max}));
- return;
- }
- for (var i = 0; i < names.length; i++) {
- coin.move(settings.rpc.prefix + from.toLowerCase(), settings.rpc.prefix + names[i].toLowerCase(), amount / max, function(err, reply) {
- if(i == names.length) locks.splice(locks.indexOf(from.toLowerCase()),1);
- if(err || !reply) {
- winston.error('Error in !tip command', err);
- return;
- }
- });
- }
- client.say(channel, settings.messages.rain.expand({name: from, amount: parseFloat((amount / max).toFixed(8)), list: (whole_channel && !settings.commands.rain.rain_on_last_active) ? 'the whole channel' : names.join(', ')}));
- });
- } else {
- client.say(channel, settings.messages.no_funds.expand({name: from, balance: balance, short: amount - balance, amount: amount}));
- }
- })
- break;
- case 'tip':
- var match = message.match(/^.?tip (\S+) ([\d\.]+)/);
- if(match == null || match.length < 3) {
- client.say(channel, 'Usage: !tip <nickname> <amount>')
- return;
- }
- var to = match[1];
- var amount = Number(match[2]);
- //If user is locked, return (do not tip).
- if(locks.indexOf(from.toLowerCase()) > -1) {
- client.say(channel, settings.messages.locked.expand({name: from}));
- return;
- }
- // Enable lock
- locks.push(from.toLowerCase());
- if(isNaN(amount)) {
- locks.splice(locks.indexOf(from.toLowerCase()),1);
- client.say(channel, settings.messages.invalid_amount.expand({name: from, amount: match[2]}));
- return;
- }
- if("irc_"+to.toLowerCase() == "irc_"+from.toLowerCase()) {
- //Reset user lock
- locks.splice(locks.indexOf(from.toLowerCase()),1);
- client.say(channel, settings.messages.tip_self.expand({name: from}));
- return;
- }
- if(amount < settings.coin.min_tip) {
- //Reset lock
- locks.splice(locks.indexOf(from.toLowerCase()),1);
- client.say(channel, settings.messages.tip_too_small.expand({from: from, to: to, amount: amount}));
- return;
- }
- // check balance with min. 5 confirmations
- coin.getBalance("irc_"+from.toLowerCase(), settings.coin.min_confirmations, function(err, balance) {
- if(err) {
- //Reset lock
- locks.splice(locks.indexOf(from.toLowerCase()),1);
- winston.error('Error in !tip command.', err);
- client.say(channel, settings.messages.error.expand({name: from}));
- return;
- }
- var balance = typeof(balance) == 'object' ? balance.result : balance;
- if(balance >= amount) {
- client.isIdentified(to, function(status) {
- var message = msg;
- // check if the sending user is logged in (identified) with nickserv
- if(!status) {
- locks.splice(locks.indexOf(from.toLowerCase()),1);
- client.say(channel, settings.messages.tip_not_identified.expand({name: to}));
- return;
- }
- coin.send('move', "irc_"+from.toLowerCase(), "irc_"+to.toLowerCase(), amount, function(err, reply) {
- if(err || !reply) {
- locks.splice(locks.indexOf(from.toLowerCase()),1);
- winston.error('Error in !tip command', err);
- client.say(channel, settings.messages.error.expand({name: from}));
- return;
- }
- locks.splice(locks.indexOf(from.toLowerCase()),1);
- client.say(channel, settings.messages.tipped.expand({from: from, to: to, amount: amount}));
- });
- });
- } else {
- locks.splice(locks.indexOf(from.toLowerCase()),1);
- client.say(channel, settings.messages.no_funds.expand({name: from, balance: balance, short: amount - balance, amount: amount}));
- }
- });
- break;
- case 'withdraw':
- var match = message.match(/^.?withdraw (\S+)$/);
- if(match == null) {
- client.say(channel, 'Usage: !withdraw <' + settings.coin.full_name + ' address>');
- return;
- }
- var address = match[1];
- //If user is locked, return (do not tip).
- if(locks.indexOf(from.toLowerCase()) > -1) {
- client.say(channel, settings.messages.locked.expand({name: from}));
- return;
- }
- // Enable lock
- locks.push(from.toLowerCase());
- coin.validateAddress(address, function(err, reply) {
- if(err) {
- locks.splice(locks.indexOf(from.toLowerCase()),1);
- winston.error('Error in !withdraw command', err);
- client.say(channel, settings.messages.error.expand({name: from}));
- return;
- }
- if(reply.isvalid) {
- coin.getBalance(settings.rpc.prefix + from.toLowerCase(), settings.coin.min_confirmations, function(err, balance) {
- if(err) {
- locks.splice(locks.indexOf(from.toLowerCase()),1);
- winston.error('Error in !withdraw command', err);
- client.say(channel, settings.messages.error.expand({name: from}));
- return;
- }
- var balance = typeof(balance) == 'object' ? balance.result : balance;
- if(balance < settings.coin.min_withdraw) {
- locks.splice(locks.indexOf(from.toLowerCase()),1);
- winston.warn('%s tried to withdraw %d, but min is set to %d', from, balance, settings.coin.min_withdraw);
- client.say(channel, settings.messages.withdraw_too_small.expand({name: from, balance: balance}));
- return;
- }
- coin.sendFrom(settings.rpc.prefix + from.toLowerCase(), address, balance - settings.coin.withdrawal_fee, function(err, reply) {
- if(err) {
- locks.splice(locks.indexOf(from.toLowerCase()),1);
- winston.error('Error in !withdraw command', err);
- client.say(channel, settings.messages.error.expand({name: from}));
- return;
- }
- locks.splice(locks.indexOf(from.toLowerCase()),1);
- var values = {name: from, address: address, balance: balance, amount: balance - settings.coin.withdrawal_fee, transaction: reply}
- for(var i = 0; i < settings.messages.withdraw_success.length; i++) {
- var msg = settings.messages.withdraw_success[i];
- client.say(channel, msg.expand(values));
- };
- });
- });
- } else {
- winston.warn('%s tried to withdraw to an invalid address', from);
- client.say(channel, settings.messages.invalid_address.expand({address: address, name: from}));
- }
- });
- break;
- }
- });
- });
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement