Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

📅 Action Scheduler #57

Merged
merged 62 commits into from
Sep 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
3fd3b78
Updated the WorldManager.java
gnmyt Sep 3, 2023
e7942aa
Created the ScheduleActionType enum
gnmyt Sep 6, 2023
b6b9bb2
Created the ScheduleFrequency enum
gnmyt Sep 6, 2023
283fb22
Created the ScheduleAction.java
gnmyt Sep 6, 2023
b4fe8e1
Created the ScheduleExecution.java
gnmyt Sep 6, 2023
15279d3
Created the Schedule.java entity
gnmyt Sep 6, 2023
9917eea
Created the ScheduleController.java
gnmyt Sep 6, 2023
90638af
Created the ScheduleManager.java
gnmyt Sep 6, 2023
0ef1fc2
Extracted the mode string function in the BackupRoute.java
gnmyt Sep 6, 2023
ab86ef2
Removed semicolon from the ScheduleFrequency enum
gnmyt Sep 6, 2023
fb95dd4
Created the ScheduleRoute.java
gnmyt Sep 6, 2023
c78f676
Created the ScheduleActionRoute.java
gnmyt Sep 6, 2023
d8f1999
Created the ScheduleExecutionRoute.java
gnmyt Sep 6, 2023
c3333f6
Created the ScheduleNameRoute.java
gnmyt Sep 6, 2023
14a14ac
Implemented the ScheduleManager into the MinecraftDashboard.java
gnmyt Sep 6, 2023
65e81a7
Added the background > card color to the dark.js
gnmyt Sep 6, 2023
1b84b50
Added the background > card color to the light.js
gnmyt Sep 6, 2023
362c3e6
Fixed a bug in the BackupItem.jsx
gnmyt Sep 6, 2023
2c819ce
Implemented action editing in the BackupCreationDialog.jsx
gnmyt Sep 6, 2023
b3c436a
Created the EditActionDialog.jsx
gnmyt Sep 6, 2023
a797110
Created the EditActionDialog index.js
gnmyt Sep 6, 2023
1ea0d9f
Created the Action.jsx
gnmyt Sep 6, 2023
39b56bb
Created the Action index.js
gnmyt Sep 6, 2023
02ef8c2
Created the mappings.jsx
gnmyt Sep 6, 2023
ee02d22
Created the CreateActionDialog.jsx
gnmyt Sep 6, 2023
7325623
Created the CreateActionDialog index.js
gnmyt Sep 6, 2023
fd94cd8
Created the CreateScheduleDialog.jsx
gnmyt Sep 6, 2023
449471b
Created the CreateScheduleDialog index.js
gnmyt Sep 6, 2023
e13b96a
Created the Schedule.jsx
gnmyt Sep 6, 2023
f14c9a3
Created the Schedule index.js
gnmyt Sep 6, 2023
6d84cb7
Created the SchedulesContext.jsx
gnmyt Sep 6, 2023
a116149
Created the SchedulesContext index.js
gnmyt Sep 6, 2023
51c7dd7
Created the Scheduler.jsx page
gnmyt Sep 6, 2023
ab7d270
Created the Scheduler index.js
gnmyt Sep 6, 2023
709331a
Added the scheduler route to the server.jsx
gnmyt Sep 6, 2023
4c2a807
Added all schedule translations in the en.json
gnmyt Sep 6, 2023
6d5c7fb
Fixed a bug in the ScheduleController.java
gnmyt Sep 7, 2023
ff1981e
Extracted getDays from the CreateScheduleDialog.jsx
gnmyt Sep 7, 2023
b65eacf
Created the Schedule utils.js
gnmyt Sep 7, 2023
8aca689
Updated the Schedule.jsx
gnmyt Sep 7, 2023
137dc87
Added schedule translations to the en.json
gnmyt Sep 7, 2023
ed60899
Added "none found" to the Scheduler.jsx
gnmyt Sep 7, 2023
40de238
Added the none_created translation to the en.json
gnmyt Sep 7, 2023
fc17fda
Fixed the Scheduler.jsx
gnmyt Sep 7, 2023
f8822f9
Integrated editing in the CreateScheduleDialog.jsx
gnmyt Sep 7, 2023
78c80e2
Added the "Edit" translations to the en.json
gnmyt Sep 7, 2023
449a9ff
Added the edit button in the Schedule.jsx
gnmyt Sep 7, 2023
d708d18
Fixed a bug in the CreateScheduleDialog.jsx
gnmyt Sep 7, 2023
bf9fd9d
Added the KICK_ALL_PLAYERS type
gnmyt Sep 7, 2023
267654d
Integrated the KICK_ALL_PLAYERS logic
gnmyt Sep 7, 2023
ed11135
Updated the EditActionDialog.jsx
gnmyt Sep 7, 2023
c43261d
Updated the EditActionDialog mapping.jsx
gnmyt Sep 7, 2023
7d98cb4
Updated the CreateActionDialog.jsx
gnmyt Sep 7, 2023
943c0b5
Added the schedules.types.kick translation to the en.json
gnmyt Sep 7, 2023
a774b89
Updated the action translations in the en.json
gnmyt Sep 7, 2023
4fdb7ba
Updated the EditActionDialog.jsx
gnmyt Sep 7, 2023
c1f0f91
Updated the CreateActionDialog.jsx
gnmyt Sep 7, 2023
af6b87a
Optimized the Schedule.jsx for mobile devices
gnmyt Sep 7, 2023
2833cf6
Updated the Scheduler.jsx
gnmyt Sep 7, 2023
ce3bc2f
Fixed a bug in the Scheduler.jsx
gnmyt Sep 7, 2023
a2ebe10
Fixed a bug in the ScheduleController.java
gnmyt Sep 7, 2023
a1b2e4f
Fixed a bug in the ScheduleController.java
gnmyt Sep 7, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/main/java/de/gnmyt/mcdash/MinecraftDashboard.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public class MinecraftDashboard extends JavaPlugin {
private static AccountManager accountManager;
private static WorldManager worldManager;
private static SSHManager sshManager;
private static ScheduleManager scheduleManager;
private static MinecraftDashboard instance;
private static HttpServer server;

Expand All @@ -37,6 +38,7 @@ public void onEnable() {
worldManager = new WorldManager(instance);
config = new ConfigurationManager(instance);
backupController = new BackupController();
scheduleManager = new ScheduleManager(instance);
if (!config.configExists()) config.generateDefault();
metrics = new Metrics(this, 18915);

Expand Down Expand Up @@ -182,4 +184,12 @@ public static ScheduledExecutorService getExecutor() {
public static UpdateManager getUpdateManager() {
return updateManager;
}

/**
* Gets the schedule manager
* @return the schedule manager
*/
public static ScheduleManager getScheduleManager() {
return scheduleManager;
}
}
158 changes: 158 additions & 0 deletions src/main/java/de/gnmyt/mcdash/api/config/ScheduleManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
package de.gnmyt.mcdash.api.config;

import de.gnmyt.mcdash.MinecraftDashboard;
import de.gnmyt.mcdash.api.controller.ScheduleController;
import de.gnmyt.mcdash.api.entities.*;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class ScheduleManager {

private final File file;
private final FileConfiguration config;
private final ScheduleController controller;

/**
* Basic constructor of the {@link ScheduleManager}
* Loads the schedules.yml file
*/
public ScheduleManager(MinecraftDashboard api) {
file = new File("plugins//" + api.getName() + "//schedules.yml");

config = YamlConfiguration.loadConfiguration(file);
controller = new ScheduleController(this);

if (!config.contains("schedules")) {
config.set("schedules", new ArrayList<>());
saveConfig();
} else {
controller.startTasks();
}
}

/**
* Gets a schedule by its name
*
* @param name The name of the schedule
* @return the schedule
*/
public Schedule getScheduleByName(String name) {
if (!config.contains("schedules." + name)) return null;
String execute = config.getString("schedules." + name + ".execute");

ScheduleExecution execution = new ScheduleExecution(ScheduleFrequency.valueOf(execute.split("@")[0].toUpperCase()),
Integer.parseInt(execute.split("@")[1]));

ArrayList<ScheduleAction> actions = new ArrayList<>();
for (String action : config.getStringList("schedules." + name + ".actions")) {
if (action.contains("@")) {
actions.add(new ScheduleAction(ScheduleActionType.getById(Integer.parseInt(action.split("@")[0])),
action.split("@")[1]));
} else {
actions.add(new ScheduleAction(ScheduleActionType.getById(Integer.parseInt(action))));
}
}

return new Schedule(name, execution, actions);
}

/**
* Gets all schedules
*
* @return the schedules
*/
public ArrayList<Schedule> getSchedules() {
ArrayList<Schedule> schedules = new ArrayList<>();
if (config.getConfigurationSection("schedules") == null) return schedules;
for (String schedule : config.getConfigurationSection("schedules").getKeys(false))
schedules.add(getScheduleByName(schedule));
return schedules;
}

/**
* Adds a new schedule
*
* @param name The name of the schedule
* @param execution The execution of the schedule
* @param actions The actions of the schedule
*/
public void addSchedule(String name, ScheduleExecution execution, ScheduleAction... actions) {
String execute = execution.getFrequency().name() + "@" + execution.getTime();
List<String> actionList = Stream.of(actions)
.map(action -> action.getType().getId() + (action.getPayload() != null ? "@" + action.getPayload() : ""))
.collect(Collectors.toList());

config.set("schedules." + name + ".execute", execute);
config.set("schedules." + name + ".actions", actionList);
saveConfig();
}

/**
* Updates the name of a schedule
*
* @param name The name of the schedule
* @param newName The new name of the schedule
*/
public void renameSchedule(String name, String newName) {
config.set("schedules." + name + ".execute", config.getString("schedules." + name + ".execute"));
config.set("schedules." + name + ".actions", config.getStringList("schedules." + name + ".actions"));
config.set("schedules." + newName, config.getConfigurationSection("schedules." + name));
config.set("schedules." + name, null);
saveConfig();
}

/**
* Updates the execution of a schedule
*
* @param name The name of the schedule
* @param execution The new execution of the schedule
*/
public void setExecution(String name, ScheduleExecution execution) {
config.set("schedules." + name + ".execute", execution.getFrequency().name() + "@" + execution.getTime());
saveConfig();
}

/**
* Updates the actions of a schedule
*
* @param name The name of the schedule
* @param actions The new actions of the schedule
*/
public void setActions(String name, ScheduleAction... actions) {
ArrayList<String> actionList = new ArrayList<>();
for (ScheduleAction action : actions)
actionList.add(action.getType().getId() + (action.getPayload() != null ? "@" + action.getPayload() : ""));
config.set("schedules." + name + ".actions", actionList);
saveConfig();
}

/**
* Removes a schedule
*
* @param name The name of the schedule
*/
public void removeSchedule(String name) {
config.set("schedules." + name, null);
saveConfig();
}


/**
* Saves the configuration
*/
private void saveConfig() {
try {
config.save(file);
controller.restartTasks();
} catch (IOException ignored) {
}
}

}
4 changes: 2 additions & 2 deletions src/main/java/de/gnmyt/mcdash/api/config/WorldManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ public class WorldManager {
private final FileConfiguration config;

/**
* Basic constructor of the {@link AccountManager}
* Loads the accounts.yml file
* Basic constructor of the {@link WorldManager}
* Loads the worlds.yml file
*/
public WorldManager(MinecraftDashboard api) {
file = new File("plugins//"+api.getName()+"//worlds.yml");
Expand Down
172 changes: 172 additions & 0 deletions src/main/java/de/gnmyt/mcdash/api/controller/ScheduleController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
package de.gnmyt.mcdash.api.controller;

import de.gnmyt.mcdash.MinecraftDashboard;
import de.gnmyt.mcdash.api.config.ScheduleManager;
import de.gnmyt.mcdash.api.entities.Schedule;
import de.gnmyt.mcdash.api.entities.ScheduleAction;
import de.gnmyt.mcdash.api.entities.ScheduleExecution;
import de.gnmyt.mcdash.api.entities.ScheduleFrequency;
import de.gnmyt.mcdash.panel.routes.backups.BackupRoute;
import org.bukkit.Bukkit;

import java.io.File;
import java.util.Calendar;
import java.util.Date;
import java.util.TimerTask;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class ScheduleController {

private final ScheduleManager manager;
private ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);

/**
* Basic constructor of the {@link ScheduleController}
*
* @param manager The {@link ScheduleManager} instance
*/
public ScheduleController(ScheduleManager manager) {
this.manager = manager;
}

/**
* Starts all tasks from the {@link ScheduleManager}
*/
public void startTasks() {
for (Schedule schedule : manager.getSchedules()) {
ScheduleExecution execution = schedule.getExecution();
Calendar calendar = calculateNextExecutionTime(execution);

scheduleTask(schedule, calendar);
}
}

/**
* Calculates the next execution time of a {@link ScheduleExecution}
*
* @param execution The {@link ScheduleExecution} you want to calculate
* @return the next execution time
*/
private Calendar calculateNextExecutionTime(ScheduleExecution execution) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date());
calendar.set(Calendar.SECOND, 0);

if (execution.getFrequency() == ScheduleFrequency.MONTHLY) {
calendar.set(Calendar.DAY_OF_MONTH, execution.getTime());
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
} else if (execution.getFrequency() == ScheduleFrequency.WEEKLY) {
calendar.set(Calendar.DAY_OF_WEEK, (execution.getTime() + 1) > 7 ? 1 : execution.getTime() + 1);
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
} else if (execution.getFrequency() == ScheduleFrequency.DAILY) {
calendar.set(Calendar.HOUR_OF_DAY, execution.getHours());
calendar.set(Calendar.MINUTE, execution.getMinutes());
} else if (execution.getFrequency() == ScheduleFrequency.HOURLY) {
calendar.set(Calendar.MINUTE, execution.getTime());
}

if (calendar.getTime().before(new Date())) advanceToNextOccurrence(calendar, execution.getFrequency());

return calendar;
}

/**
* Advances the calendar to the next occurrence
* @param calendar The calendar you want to advance
* @param frequency The frequency of the schedule
*/
private void advanceToNextOccurrence(Calendar calendar, ScheduleFrequency frequency) {
switch (frequency) {
case MONTHLY:
calendar.add(Calendar.MONTH, 1);
break;
case WEEKLY:
calendar.add(Calendar.WEEK_OF_YEAR, 1);
break;
case DAILY:
calendar.add(Calendar.DAY_OF_YEAR, 1);
break;
case HOURLY:
calendar.add(Calendar.HOUR_OF_DAY, 1);
break;
}
}

/**
* Schedules a task
*
* @param schedule The {@link Schedule} you want to schedule
* @param calendar The time on which the task should be executed
*/
private void scheduleTask(Schedule schedule, Calendar calendar) {
TimerTask task = new TimerTask() {
@Override
public void run() {
for (ScheduleAction action : schedule.getActions()) {
try {
Thread.sleep(1000);

switch (action.getType()) {
case COMMAND:
Bukkit.getScheduler().callSyncMethod(MinecraftDashboard.getInstance(), () ->
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), action.getPayload()));
break;
case BROADCAST:
MinecraftDashboard.getInstance().getServer().broadcastMessage(action.getPayload());
break;
case RELOAD_SERVER:
MinecraftDashboard.getInstance().getServer().reload();
break;
case STOP_SERVER:
MinecraftDashboard.getInstance().getServer().shutdown();
break;
case CREATE_BACKUP:
MinecraftDashboard.getBackupController().createBackup(action.getPayload(),
BackupRoute.getBackupDirectories(action.getPayload()).toArray(new File[0]));
break;
case KICK_ALL_PLAYERS:
Bukkit.getScheduler().callSyncMethod(MinecraftDashboard.getInstance(), () -> {
MinecraftDashboard.getInstance().getServer().getOnlinePlayers().forEach(player ->
player.kickPlayer(action.getPayload()));
return null;
});
break;
}
} catch (Exception e) {
Bukkit.getLogger().warning("An error occurred while executing a schedule action: "
+ e.getMessage());
}
}

advanceToNextOccurrence(calendar, schedule.getExecution().getFrequency());
scheduleTask(schedule, calendar);
}
};

scheduler.schedule(task, calendar.getTimeInMillis() - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
}

/**
* Restarts all tasks
* <p>
* This method is used to restart all tasks after the config has been reloaded
* or the plugin has been reloaded
* <br>
* This method will shutdown the current scheduler, cancel all currently running tasks and start a new scheduler
* </p>
*/
public void restartTasks() {
scheduler.shutdownNow();
try {
scheduler.awaitTermination(3, TimeUnit.SECONDS);
} catch (InterruptedException ignored) {
}
scheduler = Executors.newScheduledThreadPool(1);
startTasks();
}

}
Loading