/*jshint esversion: 6*/
//load database
var Datastore = require ( 'nedb' ) ;
var db = new Datastore ( { filename : _ _dirname + '/crontabs/crontab.db' } ) ;
db . loadDatabase ( function ( err ) {
if ( err ) throw err ; // no hope, just terminate
} ) ;
var exec = require ( 'child_process' ) . exec ;
var fs = require ( 'fs' ) ;
var cron _parser = require ( "cron-parser" ) ;
var os = require ( "os" ) ;
exports . log _folder = _ _dirname + '/crontabs/logs' ;
exports . env _file = _ _dirname + '/crontabs/env.db' ;
crontab = function ( name , command , schedule , stopped , logging ) {
var data = { } ;
data . name = name ;
data . command = command ;
data . schedule = schedule ;
if ( stopped !== null ) {
data . stopped = stopped ;
}
data . timestamp = ( new Date ( ) ) . toString ( ) ;
data . logging = logging ;
return data ;
} ;
exports . create _new = function ( name , command , schedule , logging ) {
var tab = crontab ( name , command , schedule , false , logging ) ;
tab . created = new Date ( ) . valueOf ( ) ;
db . insert ( tab ) ;
} ;
exports . update = function ( data ) {
db . update ( { _id : data . _id } , crontab ( data . name , data . command , data . schedule , null , data . logging ) ) ;
} ;
exports . status = function ( _id , stopped ) {
db . update ( { _id : _id } , { $set : { stopped : stopped } } ) ;
} ;
exports . remove = function ( _id ) {
db . remove ( { _id : _id } , { } ) ;
} ;
exports . crontabs = function ( callback ) {
db . find ( { } ) . sort ( { created : - 1 } ) . exec ( function ( err , docs ) {
for ( var i = 0 ; i < docs . length ; i ++ ) {
if ( docs [ i ] . schedule == "@reboot" )
docs [ i ] . next = "Next Reboot" ;
else
docs [ i ] . next = cron _parser . parseExpression ( docs [ i ] . schedule ) . next ( ) . toString ( ) ;
}
callback ( docs ) ;
} ) ;
} ;
exports . set _crontab = function ( env _vars , callback ) {
exports . crontabs ( function ( tabs ) {
var crontab _string = "" ;
if ( env _vars ) {
crontab _string = env _vars + "\n" ;
}
tabs . forEach ( function ( tab ) {
if ( ! tab . stopped ) {
if ( tab . logging && tab . logging == "true" ) {
let tmp _log = "/tmp/" + tab . _id + ".log" ;
let log _file = exports . log _folder + "/" + tab . _id + ".log" ;
if ( tab . command [ tab . command . length - 1 ] != ";" ) // add semicolon
tab . command += ";" ;
// hook is in beta
if ( tab . hook ) {
let tmp _hook = "/tmp/" + tab . _id + ".hook" ;
crontab _string += tab . schedule + " ({ " + tab . command + " } | tee " + tmp _hook + ") 3>&1 1>&2 2>&3 | tee " + tmp _log + "; if test -f " + tmp _log + "; then date >> " + log _file + "; cat " + tmp _log + " >> " + log _file + "; rm " + tmp _log + "; fi; if test -f " + tmp _hook + "; then " + tab . hook + " < " + tmp _hook + "; rm " + tmp _hook + "; fi \n" ;
} else {
crontab _string += tab . schedule + " { " + tab . command + " } 2> " + tmp _log + "; if test -f " + tmp _log + "; then date >> " + log _file + "; cat " + tmp _log + " >> " + log _file + "; rm " + tmp _log + "; fi \n" ;
}
}
else {
crontab _string += tab . schedule + " " + tab . command + "\n" ;
}
}
} ) ;
fs . writeFile ( exports . env _file , env _vars , function ( err ) {
if ( err ) callback ( err ) ;
fs . writeFile ( "/tmp/crontab" , crontab _string , function ( err ) {
if ( err ) return callback ( err ) ;
exec ( "crontab /tmp/crontab" , function ( err ) {
if ( err ) return callback ( err ) ;
else callback ( ) ;
} ) ;
} ) ;
} ) ;
} ) ;
} ;
exports . get _backup _names = function ( ) {
var backups = [ ] ;
fs . readdirSync ( _ _dirname + '/crontabs' ) . forEach ( function ( file ) {
// file name begins with backup
if ( file . indexOf ( "backup" ) === 0 ) {
backups . push ( file ) ;
}
} ) ;
// Sort by date. Newest on top
for ( var i = 0 ; i < backups . length ; i ++ ) {
var Ti = backups [ i ] . split ( "backup" ) [ 1 ] ;
Ti = new Date ( Ti . substring ( 0 , Ti . length - 3 ) ) . valueOf ( ) ;
for ( var j = 0 ; j < i ; j ++ ) {
var Tj = backups [ j ] . split ( "backup" ) [ 1 ] ;
Tj = new Date ( Tj . substring ( 0 , Tj . length - 3 ) ) . valueOf ( ) ;
if ( Ti > Tj ) {
var temp = backups [ i ] ;
backups [ i ] = backups [ j ] ;
backups [ j ] = temp ;
}
}
}
return backups ;
} ;
exports . backup = function ( ) {
//TODO check if it failed
fs . createReadStream ( _ _dirname + '/crontabs/crontab.db' ) . pipe ( fs . createWriteStream ( _ _dirname + '/crontabs/backup ' + ( new Date ( ) ) . toString ( ) . replace ( "+" , " " ) + '.db' ) ) ;
} ;
exports . restore = function ( db _name ) {
fs . createReadStream ( _ _dirname + '/crontabs/' + db _name ) . pipe ( fs . createWriteStream ( _ _dirname + '/crontabs/crontab.db' ) ) ;
db . loadDatabase ( ) ; // reload the database
} ;
exports . reload _db = function ( ) {
db . loadDatabase ( ) ;
} ;
exports . get _env = function ( ) {
if ( fs . existsSync ( exports . env _file ) ) {
return fs . readFileSync ( exports . env _file , 'utf8' ) . replace ( "\n" , "\n" ) ;
}
return "" ;
} ;
exports . import _crontab = function ( ) {
exec ( "crontab -l" , function ( error , stdout , stderr ) {
var lines = stdout . split ( "\n" ) ;
var namePrefix = new Date ( ) . getTime ( ) ;
lines . forEach ( function ( line , index ) {
var regex = /^((\@[a-zA-Z]+\s)|(([^\s]+)\s([^\s]+)\s([^\s]+)\s([^\s]+)\s([^\s]+)\s))/ ;
var command = line . replace ( regex , '' ) . trim ( ) ;
var schedule = line . replace ( command , '' ) . trim ( ) ;
var is _valid = false ;
try { is _valid = cron _parser . parseString ( line ) . expressions . length > 0 ; } catch ( e ) { }
if ( command && schedule && is _valid ) {
var name = namePrefix + '_' + index ;
db . findOne ( { command : command , schedule : schedule } , function ( err , doc ) {
if ( err ) {
throw err ;
}
if ( ! doc ) {
exports . create _new ( name , command , schedule , null ) ;
}
else {
doc . command = command ;
doc . schedule = schedule ;
exports . update ( doc ) ;
}
} ) ;
}
} ) ;
} ) ;
} ;
exports . autosave _crontab = function ( callback ) {
let env _vars = exports . get _env ( ) ;
exports . set _crontab ( env _vars , callback ) ;
} ;