/* Dumps the redis DB to rdb, then uploads that to S3.
 * Configure below, and provide upkeep/credentials.json.
 */

var AWS = require('aws-sdk'),
    config = require('../config'),
    crypto = require('crypto'),
    db = require('../db'),
    fs = require('fs');

var BUCKET = 'backupbucket';
var ACL = 'bucket-owner-full-control';
var RDB_PATH = '/Users/lalc/dump.rdb';
var BGSAVE_TIMEOUT = 5*60;

var r, s3;

function dump_rdb(cb) {
	console.log('Dumping rdb...');
	r.lastsave(function (err, lastSave) {
		if (err) return err;
		r.bgsave(function (err)	{
			if (err) return err;
			setTimeout(poll_for_lastsave_after.bind(null,
					lastSave, 0, cb), 200);
		});
	});
}

function poll_for_lastsave_after(lastSave, seconds, cb) {
	// Will take slightly longer than BGSAVE_TIMEOUT seconds since
	// we're waiting for a lastsave command between each second
	if (seconds > BGSAVE_TIMEOUT)
		return cb("bgsave timeout");

	r.lastsave(function (err, newSave) {
		if (err)
			return cb(err);
		if (newSave > lastSave) {
			console.log('Obtained dump after', seconds, 'sec');
			check_mtime(RDB_PATH, newSave, cb);
			return;
		}
		if (newSave < lastSave)
			return cb("Time travel");
		setTimeout(poll_for_lastsave_after.bind(null,
				lastSave, seconds+1, cb), 1000);
	});
}

function check_mtime(path, lastsave, cb) {
	console.log('  redis lastsave:', lastsave);
	fs.stat(path, function (err, stat) {
		if (err)
			return cb(err);
		var mtime = Math.floor(stat.mtime.getTime() / 1000);
		console.log('  ' + path + ' mtime:', mtime);
		if (Math.abs(mtime - lastsave) > 1000)
			return cb("Bad mtime: "+lastsave+" != "+mtime);
		cb(null);
	});
}

function upload(kind, filename, cb) {
	var now = new Date();
	var random = crypto.randomBytes(8).toString('hex');
	var dir = now.getUTCFullYear() + '-' + pad2(now.getUTCMonth()+1);
	var name = dir+'-'+pad2(now.getUTCDate()) + '-' + kind + '-' + random;
	var key = dir + '/' + name;

	var stream = fs.createReadStream(filename);
	var params = {
		ACL: ACL,
		Bucket: BUCKET,
		Key: key,
		Body: stream,
	};

	process.stdout.write('Writing s3://'+BUCKET+'/'+key+' ...');
	s3.putObject(params, function (err, data) {
		if (err) {
			console.log('failed!');
			return cb(err);
		}
		console.log('done.');
		console.log('ETag:', data.ETag);
		cb(null);
	});
}

function pad2(n) {
	return (n < 10 ? '0' : '') + n;
}

if (require.main == module) {
	s3 = new AWS.S3().client;
	s3.config.loadFromPath('upkeep/credentials.json');
	r = db.redis_client();

	dump_rdb(function (err) {
		if (err)
			throw err;
		upload('dump.rdb', RDB_PATH, function (err) {
			if (err)
				throw err;
			process.exit(0);
		});
	});
}
