@ -0,0 +1,152 @@
package name.nathanmcrae.numbersstation ;
import com.leakyabstractions.result.api.Result ;
import com.leakyabstractions.result.core.Results ;
import java.io.IOException ;
import java.io.OutputStreamWriter ;
import java.io.Writer ;
import java.nio.charset.StandardCharsets ;
import java.nio.file.Files ;
import java.nio.file.Path ;
import java.nio.file.Paths ;
import java.util.concurrent.TimeUnit ;
import java.util.logging.Level ;
import java.util.logging.Logger ;
import java.util.regex.Matcher ;
import java.util.regex.Pattern ;
import javafx.util.Pair ;
public class LinuxScheduler {
private static final Logger logger = Logger . getLogger ( Main . class . getName ( ) ) ;
public static Result < Boolean , String > registerSchedule ( StationSettings settings ) {
try {
String taskName = " numbers-station-main_ " + settings . getName ( ) ;
// TODO: assume it's on the PATH
Process listProcess = new ProcessBuilder ( " /usr/bin/crontab " , " -l " ) . start ( ) ;
if ( ! listProcess . waitFor ( 5 , TimeUnit . SECONDS ) ) {
String message = " Failed to query " + taskName + " task: process timed out " ;
logger . log ( Level . SEVERE , message ) ;
return Results . failure ( message ) ;
}
Pair < String , String > output = WindowsScheduler . captureProcessOutput ( listProcess ) ;
if ( listProcess . exitValue ( ) ! = 0 ) {
String message = " Failed to get user id. Exit code: " + listProcess . exitValue ( ) + " . stdout: " + output . getKey ( ) + " \ n \ tstderr: " + output . getValue ( ) ;
logger . log ( Level . SEVERE , message ) ;
return Results . failure ( message ) ;
}
String currentCrontab = output . getKey ( ) ;
String cronEntry = " # " + taskName + " \ n " + cronExpression ( settings ) + " \ n \ n " ;
Pattern pattern = Pattern . compile ( " # " + taskName + " \\ n[^ \\ n]+ \\ n \\ n " ) ;
Matcher matcher = pattern . matcher ( currentCrontab ) ;
StringBuilder sb = new StringBuilder ( ) ;
if ( matcher . find ( ) ) {
matcher . appendReplacement ( sb , cronEntry ) ;
boolean foundMultiple = false ;
while ( matcher . find ( ) ) {
foundMultiple = true ;
matcher . appendReplacement ( sb , " " ) ;
}
matcher . appendTail ( sb ) ;
} else {
sb . append ( currentCrontab ) ;
sb . append ( cronEntry ) ;
}
String newCrontab = sb . toString ( ) ;
// TODO: assume it's on the PATH
Process addProcess = new ProcessBuilder ( " /usr/bin/crontab " , " - " ) . start ( ) ;
Writer w = new OutputStreamWriter ( addProcess . getOutputStream ( ) , " UTF-8 " ) ;
System . out . println ( newCrontab ) ;
w . write ( newCrontab ) ;
w . flush ( ) ;
w . close ( ) ;
if ( ! addProcess . waitFor ( 5 , TimeUnit . SECONDS ) ) {
String message = " Failed to register " + taskName + " task: process timed out " ;
logger . log ( Level . SEVERE , message ) ;
return Results . failure ( message ) ;
}
if ( addProcess . exitValue ( ) ! = 0 ) {
Pair < String , String > addOutput = WindowsScheduler . captureProcessOutput ( addProcess ) ;
String message = " Failed to get user id. Exit code: " + addProcess . exitValue ( ) + " . stdout: " + addOutput . getKey ( ) + " . stderr: " + addOutput . getValue ( ) ;
logger . log ( Level . SEVERE , message ) ;
return Results . failure ( message ) ;
}
} catch ( CronExpressionException | IOException | InterruptedException e ) {
String message = " Exception while registering schedule " ;
logger . log ( Level . SEVERE , message , e ) ;
return Results . failure ( message ) ;
}
// Path cronDPath = Paths.get("/etc/cron.d");
// if (!Files.exists(cronDPath)) {
// String message = "/etc/cron.d does not exist, cannot create cron entry. Select 'Manage schedule externally' and set up scheduling as desired.";
// logger.log(Level.SEVERE, message);
// return Results.failure(message);
// }
// Path cronPath = cronDPath.resolve(settings.safeName());
// try {
// Files.write(cronPath, cronEntry(settings).getBytes(StandardCharsets.UTF_8));
// } catch (Exception e) {
// String message = "Failed to write cron file at '" + cronPath.toString() + "'";
// logger.log(Level.SEVERE, message, e);
// return Results.failure(message);
// }
return Results . success ( true ) ;
}
/**
* * * * * * {command to execute}
* | | | | |
* | | | | day of the week (0– 6) (Sunday to Saturday;
* | | | month (1– 12) 7 is also Sunday on some systems)
* | | day of the month (1– 31)
* | hour (0– 23)
* minute (0– 59)
*/
public static String cronExpression ( StationSettings settings ) throws CronExpressionException {
String minute = Integer . toString ( settings . getScheduleStartTime ( ) . getMinute ( ) ) ;
String hour = Integer . toString ( settings . getScheduleStartTime ( ) . getHour ( ) ) ;
String dayOfMonth = Integer . toString ( settings . getScheduleStartDate ( ) . getDayOfMonth ( ) ) ;
String dayOfWeek = Integer . toString ( settings . getScheduleStartDate ( ) . getDayOfMonth ( ) ) ;
String scheduleString = " " ;
switch ( settings . getMessagePeriod ( ) ) {
case DAILY :
scheduleString = minute + " " + hour + " * * * " ;
break ;
case WEEKLY :
scheduleString = minute + " " + hour + " * * " + dayOfWeek ;
break ;
case MONTHLY :
scheduleString = minute + " " + hour + " " + dayOfMonth + " * * " ;
break ;
default :
throw new CronExpressionException ( " Message period not implemented: ' " + settings . getMessagePeriod ( ) + " ' " ) ;
}
// TODO: figure out actual invocation
return scheduleString + " /home/nathanmcrae/personal_root/projects/numbers-station/run.sh --station \" " + settings . getName ( ) + " \" " ;
}
public static class CronExpressionException extends Exception {
public CronExpressionException ( String message ) {
super ( message ) ;
}
}
}