mirror of
https://github.com/plan-player-analytics/Plan.git
synced 2025-01-18 06:02:41 +01:00
Initial version of standalone
- Prompts settings on enable - Runs with MySQL pretending to be a new game server in the database - Works pretty well for first attempt at it. A lot of inspiration was taken from the mock version of the system used during tests. TODO: - Doesn't have commands implemented yet - Doesn't log errors properly - Doesn't log console contents to a file - Network page needs to be accessible if proxy server is in database
This commit is contained in:
parent
3b09fd8da2
commit
925906bec6
@ -48,7 +48,6 @@ public abstract class ServerInfo implements SubSystem {
|
||||
}
|
||||
|
||||
public ServerIdentifier getServerIdentifier() {
|
||||
Server server = getServer();
|
||||
return new ServerIdentifier(server.getUuid(), server.getIdentifiableName());
|
||||
}
|
||||
|
||||
|
@ -8,18 +8,21 @@ dependencies {
|
||||
shadow project(path: ":sponge")
|
||||
shadow project(path: ":bungeecord")
|
||||
shadow project(path: ":velocity")
|
||||
shadow project(path: ":standalone")
|
||||
testImplementation project(path: ":common", configuration: 'testArtifacts')
|
||||
testImplementation project(path: ":bukkit", configuration: 'testArtifacts')
|
||||
testImplementation project(path: ":nukkit", configuration: 'testArtifacts')
|
||||
testImplementation project(path: ":sponge", configuration: 'testArtifacts')
|
||||
testImplementation project(path: ":bungeecord", configuration: 'testArtifacts')
|
||||
testImplementation project(path: ":velocity", configuration: 'testArtifacts')
|
||||
testImplementation project(path: ":standalone", configuration: 'testArtifacts')
|
||||
}
|
||||
|
||||
jar {
|
||||
// Add the sponge mixin into the manifest
|
||||
manifest.attributes([
|
||||
'MixinConfigs': 'plan-sponge.mixins.json'
|
||||
'MixinConfigs': 'plan-sponge.mixins.json',
|
||||
'Main-Class' : 'net.playeranalytics.plan.PlanStandalone'
|
||||
])
|
||||
}
|
||||
|
||||
|
@ -1,14 +1,10 @@
|
||||
plugins {
|
||||
id "net.kyori.blossom" version "1.3.0"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly project(":common")
|
||||
implementation project(path: ":common", configuration: 'shadow')
|
||||
compileOnly project(":api")
|
||||
implementation project(":api")
|
||||
implementation project(":common")
|
||||
|
||||
testImplementation project(path: ":common", configuration: 'testArtifacts')
|
||||
shadow "net.playeranalytics:platform-abstraction-layer-api:$palVersion"
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
configurations = [project.configurations.shadow]
|
||||
}
|
@ -1,14 +1,173 @@
|
||||
package net.playeranalytics.plan;
|
||||
|
||||
import com.djrapitops.plan.PlanPlugin;
|
||||
import com.djrapitops.plan.PlanSystem;
|
||||
import com.djrapitops.plan.commands.use.ColorScheme;
|
||||
import com.djrapitops.plan.commands.use.Subcommand;
|
||||
import com.djrapitops.plan.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.settings.config.paths.*;
|
||||
import com.djrapitops.plan.settings.config.paths.key.Setting;
|
||||
import net.playeranalytics.plugin.StandalonePlatformAbstractionLayer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.LogManager;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class PlanStandalone {
|
||||
public class PlanStandalone implements PlanPlugin {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger("Plan");
|
||||
private static final Logger LOGGER = Logger.getGlobal();
|
||||
|
||||
public static void main(String[] args) {
|
||||
private static final ScannerPrompter SCANNER_PROMPTER = new ScannerPrompter();
|
||||
private static final ExecutorService EXECUTOR_SERVICE = Executors.newSingleThreadExecutor();
|
||||
|
||||
private static PlanStandalone pluginInstance;
|
||||
|
||||
private PlanSystem system;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
LogManager.getLogManager().readConfiguration(PlanStandalone.class.getResourceAsStream("/logging.properties"));
|
||||
|
||||
LOGGER.info("Starting Plan..");
|
||||
LOGGER.info("Type 'exit' at any time to stop the program.");
|
||||
LOGGER.info(() -> "Java version: " + System.getProperty("java.version"));
|
||||
LOGGER.info("");
|
||||
pluginInstance = new PlanStandalone();
|
||||
EXECUTOR_SERVICE.submit(pluginInstance::onEnable);
|
||||
|
||||
// Blocks and waits user input to the console
|
||||
SCANNER_PROMPTER.enable();
|
||||
}
|
||||
|
||||
public static void shutdown(int status) {
|
||||
LOGGER.info("Stopping the program...");
|
||||
if (pluginInstance != null) pluginInstance.onDisable();
|
||||
SCANNER_PROMPTER.disable();
|
||||
EXECUTOR_SERVICE.shutdown();
|
||||
try {
|
||||
if (!EXECUTOR_SERVICE.awaitTermination(5, TimeUnit.SECONDS)) {
|
||||
EXECUTOR_SERVICE.shutdownNow();
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
LOGGER.info("Press enter to exit..");
|
||||
System.exit(131);
|
||||
Thread.currentThread().interrupt();
|
||||
return;
|
||||
}
|
||||
if (status != 0) LOGGER.info("Press enter to exit..");
|
||||
System.exit(status);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getResource(String resource) {
|
||||
try {
|
||||
return pluginInstance.getSystem().getPlanFiles().getResourceFromJar(resource).asInputStream();
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ColorScheme getColorScheme() {
|
||||
return new ColorScheme("", "", "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlanSystem getSystem() {
|
||||
return system;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerCommand(Subcommand command) {
|
||||
// no-op, unused
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
try {
|
||||
PlanStandaloneComponent component = DaggerPlanStandaloneComponent.builder()
|
||||
.plan(this)
|
||||
.abstractionLayer(new StandalonePlatformAbstractionLayer(LOGGER))
|
||||
.build();
|
||||
|
||||
system = component.system();
|
||||
system.enableForCommands();
|
||||
|
||||
PlanConfig config = system.getConfigSystem().getConfig();
|
||||
|
||||
config.set(WebserverSettings.DISABLED, false);
|
||||
config.set(DataGatheringSettings.GEOLOCATIONS, false);
|
||||
config.set(DataGatheringSettings.DISK_SPACE, false);
|
||||
config.set(DataGatheringSettings.PING, false);
|
||||
|
||||
String ip = config.get(ProxySettings.IP);
|
||||
if ("0.0.0.0".equals(ip)) {
|
||||
// First installation, prompt for settings
|
||||
LOGGER.info("\n--------------\n");
|
||||
promptSetting(config, ProxySettings.IP, "Please enter IP / address to access this server");
|
||||
promptSetting(config, DatabaseSettings.MYSQL_HOST, "Please enter MySQL address");
|
||||
promptSetting(config, DatabaseSettings.MYSQL_PORT, "Please enter MySQL port");
|
||||
promptSetting(config, DatabaseSettings.MYSQL_DATABASE, "Please enter MySQL database name/schema name");
|
||||
promptSetting(config, DatabaseSettings.MYSQL_USER, "Please enter MySQL user");
|
||||
promptSetting(config, DatabaseSettings.MYSQL_PASS, "Please enter MySQL password");
|
||||
promptSettingInt(config, WebserverSettings.PORT, "Please enter Webserver port to use");
|
||||
config.set(PluginSettings.SERVER_NAME, "Standalone Plan Instance");
|
||||
LOGGER.info("Saving config..");
|
||||
config.save();
|
||||
LOGGER.info("\n--------------\n");
|
||||
LOGGER.info("Config saved - proceeding with plugin enable..");
|
||||
}
|
||||
|
||||
SCANNER_PROMPTER.insertCommands(component.planCommand());
|
||||
|
||||
} catch (Exception | Error e) {
|
||||
LOGGER.log(Level.SEVERE, "Failed to enable commands" + e + ", program will exit\n", e);
|
||||
shutdown(1);
|
||||
}
|
||||
try {
|
||||
system.enable();
|
||||
LOGGER.info("-- Startup complete, Plan enabled successfully!");
|
||||
} catch (Exception | Error e) {
|
||||
LOGGER.log(Level.SEVERE, "Failed to enable plugin " + e + ", you can try 'plan reload' after changing config settings.\n", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void promptSetting(PlanConfig config, Setting<String> setting, String prompt) {
|
||||
LOGGER.info(() -> prompt + " (" + setting.getPath() + " setting):");
|
||||
String inputValue = SCANNER_PROMPTER.waitAndGetInput()
|
||||
.orElseThrow(() -> new IllegalStateException("KeyboardInterrupt"));
|
||||
config.set(setting, inputValue);
|
||||
LOGGER.info(() -> "Set '" + setting.getPath() + "' as '" + inputValue + "'");
|
||||
}
|
||||
|
||||
private void promptSettingInt(PlanConfig config, Setting<Integer> setting, String prompt) {
|
||||
LOGGER.info(() -> prompt + " (" + setting.getPath() + " setting):");
|
||||
String inputValue = SCANNER_PROMPTER.waitAndGetInput()
|
||||
.orElseThrow(() -> new IllegalStateException("KeyboardInterrupt"));
|
||||
|
||||
try {
|
||||
config.set(setting, Integer.parseInt(inputValue));
|
||||
} catch (NumberFormatException invalid) {
|
||||
LOGGER.warning("'" + inputValue + "' is not a valid number, try again");
|
||||
promptSettingInt(config, setting, prompt);
|
||||
return;
|
||||
}
|
||||
LOGGER.info(() -> "Set '" + setting.getPath() + "' as '" + inputValue + "'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
if (system != null) system.disable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getDataFolder() {
|
||||
return pluginInstance.getSystem().getPlanFiles().getDataFolder();
|
||||
}
|
||||
}
|
||||
|
@ -2,9 +2,26 @@ package net.playeranalytics.plan;
|
||||
|
||||
import com.djrapitops.plan.PlanSystem;
|
||||
import com.djrapitops.plan.commands.PlanCommand;
|
||||
import com.djrapitops.plan.modules.FiltersModule;
|
||||
import com.djrapitops.plan.modules.PlatformAbstractionLayerModule;
|
||||
import dagger.BindsInstance;
|
||||
import dagger.Component;
|
||||
import net.playeranalytics.plan.module.StandaloneBindingModule;
|
||||
import net.playeranalytics.plan.module.StandaloneProvidingModule;
|
||||
import net.playeranalytics.plan.module.StandaloneServerPropertiesModule;
|
||||
import net.playeranalytics.plugin.PlatformAbstractionLayer;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
@Singleton
|
||||
@Component(modules = {
|
||||
PlatformAbstractionLayerModule.class,
|
||||
FiltersModule.class,
|
||||
|
||||
StandaloneBindingModule.class,
|
||||
StandaloneProvidingModule.class,
|
||||
StandaloneServerPropertiesModule.class
|
||||
})
|
||||
public interface PlanStandaloneComponent {
|
||||
|
||||
PlanCommand planCommand();
|
||||
@ -17,6 +34,9 @@ public interface PlanStandaloneComponent {
|
||||
@BindsInstance
|
||||
Builder plan(PlanStandalone plan);
|
||||
|
||||
@BindsInstance
|
||||
Builder abstractionLayer(PlatformAbstractionLayer abstractionLayer);
|
||||
|
||||
PlanStandaloneComponent build();
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.playeranalytics.plan;
|
||||
|
||||
import com.djrapitops.plan.SubSystem;
|
||||
import com.djrapitops.plan.commands.PlanCommand;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.Scanner;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* @author AuroraLS3
|
||||
*/
|
||||
public class ScannerPrompter implements SubSystem {
|
||||
|
||||
private final AtomicBoolean shutdown = new AtomicBoolean(false);
|
||||
private final AtomicReference<String> scannedLine = new AtomicReference<>();
|
||||
private Scanner scanner;
|
||||
|
||||
@Override
|
||||
public void enable() {
|
||||
scanner = new Scanner(System.in);
|
||||
while (!shutdown.get() && scanner.hasNext()) {
|
||||
synchronized (scannedLine) {
|
||||
String scanned = scanner.nextLine();
|
||||
|
||||
if (StringUtils.equalsAny(scanned, "stop", "end", "quit", "exit")) {
|
||||
PlanStandalone.shutdown(0);
|
||||
return; // Ends the loop
|
||||
}
|
||||
|
||||
scannedLine.set(scanned);
|
||||
scannedLine.notify();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disable() {
|
||||
scanner.close();
|
||||
shutdown.set(true);
|
||||
}
|
||||
|
||||
public Optional<String> waitAndGetInput() {
|
||||
try {
|
||||
String scanned = "";
|
||||
while (scanned.trim().isEmpty()) {
|
||||
synchronized (scannedLine) {
|
||||
scannedLine.wait();
|
||||
scanned = scannedLine.get();
|
||||
}
|
||||
}
|
||||
return Optional.of(scanned);
|
||||
} catch (InterruptedException e) {
|
||||
PlanStandalone.shutdown(132);
|
||||
Thread.currentThread().interrupt();
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
public void insertCommands(PlanCommand planCommand) {
|
||||
// TODO enable commands
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.playeranalytics.plan.gathering;
|
||||
|
||||
import com.djrapitops.plan.PlanPlugin;
|
||||
import com.djrapitops.plan.gathering.listeners.ListenerSystem;
|
||||
|
||||
/**
|
||||
* @author AuroraLS3
|
||||
*/
|
||||
public class NoOpListenerSystem extends ListenerSystem {
|
||||
|
||||
@Override
|
||||
protected void registerListeners() {
|
||||
// no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void unregisterListeners() {
|
||||
// no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public void callEnableEvent(PlanPlugin plugin) {
|
||||
// no-op
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.playeranalytics.plan.gathering;
|
||||
|
||||
import com.djrapitops.plan.gathering.ServerSensor;
|
||||
|
||||
/**
|
||||
* @author AuroraLS3
|
||||
*/
|
||||
public class NoOpServerSensor implements ServerSensor<Object> {
|
||||
|
||||
@Override
|
||||
public boolean supportsDirectTPS() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOnlinePlayerCount() {
|
||||
return 0;
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.playeranalytics.plan.module;
|
||||
|
||||
import com.djrapitops.plan.PlanPlugin;
|
||||
import com.djrapitops.plan.delivery.webserver.cache.JSONFileStorage;
|
||||
import com.djrapitops.plan.delivery.webserver.cache.JSONStorage;
|
||||
import com.djrapitops.plan.delivery.webserver.http.JettyWebserver;
|
||||
import com.djrapitops.plan.delivery.webserver.http.WebServer;
|
||||
import com.djrapitops.plan.identification.ServerInfo;
|
||||
import com.djrapitops.plan.identification.ServerServerInfo;
|
||||
import com.djrapitops.plan.settings.ConfigSystem;
|
||||
import com.djrapitops.plan.settings.ProxyConfigSystem;
|
||||
import com.djrapitops.plan.utilities.logging.ErrorLogger;
|
||||
import dagger.Binds;
|
||||
import dagger.Module;
|
||||
import net.playeranalytics.plan.PlanStandalone;
|
||||
import net.playeranalytics.plan.utilities.logging.StandaloneErrorLogger;
|
||||
|
||||
/**
|
||||
* @author AuroraLS3
|
||||
*/
|
||||
@Module
|
||||
public interface StandaloneBindingModule {
|
||||
|
||||
@Binds
|
||||
PlanPlugin bindPlugin(PlanStandalone plugin);
|
||||
|
||||
@Binds
|
||||
ServerInfo bindServerInfo(ServerServerInfo serverServerInfo);
|
||||
|
||||
@Binds
|
||||
ConfigSystem bindConfigSystem(ProxyConfigSystem configSystem);
|
||||
|
||||
@Binds
|
||||
JSONStorage bindJSONStorage(JSONFileStorage jsonFileStorage);
|
||||
|
||||
@Binds
|
||||
WebServer bindWebserver(JettyWebserver webServer);
|
||||
|
||||
@Binds
|
||||
ErrorLogger bindErrorLogger(StandaloneErrorLogger standaloneErrorLogger);
|
||||
}
|
@ -0,0 +1,142 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.playeranalytics.plan.module;
|
||||
|
||||
import com.djrapitops.plan.TaskSystem;
|
||||
import com.djrapitops.plan.gathering.ServerSensor;
|
||||
import com.djrapitops.plan.gathering.importing.importers.Importer;
|
||||
import com.djrapitops.plan.gathering.listeners.ListenerSystem;
|
||||
import com.djrapitops.plan.settings.config.ExtensionSettings;
|
||||
import com.djrapitops.plan.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.settings.locale.Locale;
|
||||
import com.djrapitops.plan.settings.locale.LocaleSystem;
|
||||
import com.djrapitops.plan.storage.database.DBSystem;
|
||||
import com.djrapitops.plan.storage.database.DBType;
|
||||
import com.djrapitops.plan.storage.database.MySQLDB;
|
||||
import com.djrapitops.plan.storage.database.SQLiteDB;
|
||||
import com.djrapitops.plan.storage.file.JarResource;
|
||||
import com.google.gson.Gson;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import dagger.multibindings.ElementsIntoSet;
|
||||
import net.playeranalytics.plan.gathering.NoOpListenerSystem;
|
||||
import net.playeranalytics.plan.gathering.NoOpServerSensor;
|
||||
import net.playeranalytics.plugin.PluginInformation;
|
||||
import net.playeranalytics.plugin.server.PluginLogger;
|
||||
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
import java.io.File;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* @author AuroraLS3
|
||||
*/
|
||||
@Module
|
||||
public class StandaloneProvidingModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
DBSystem provideDatabaseSystem(
|
||||
PlanConfig config,
|
||||
Locale locale,
|
||||
SQLiteDB.Factory sqLiteDB,
|
||||
MySQLDB mySQLDB,
|
||||
PluginLogger logger
|
||||
) {
|
||||
return new DBSystem(config, locale, sqLiteDB, logger) {
|
||||
@Override
|
||||
public void enable() {
|
||||
databases.add(mySQLDB);
|
||||
db = getActiveDatabaseByName(DBType.MYSQL.getConfigName());
|
||||
super.enable();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ElementsIntoSet
|
||||
Set<Importer> provideEmptyImporterSet() {
|
||||
return new HashSet<>();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ElementsIntoSet
|
||||
Set<TaskSystem.Task> provideEmptyTaskSet() {
|
||||
return new HashSet<>();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
ListenerSystem provideListenerSystem() {
|
||||
return new NoOpListenerSystem();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
ServerSensor<?> provideServerSensor() {
|
||||
return new NoOpServerSensor();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@Named("mainCommandName")
|
||||
String provideMainCommandName() {
|
||||
return "plan";
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
Gson provideGson() {
|
||||
return new Gson();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
Locale provideLocale(LocaleSystem localeSystem) {
|
||||
return localeSystem.getLocale();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
ExtensionSettings providePluginsConfigSection(PlanConfig config) {
|
||||
return config.getExtensionSettings();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@Named("isExtensionEnabled")
|
||||
Predicate<String> provideExtensionEnabledConfigCheck(PlanConfig config) {
|
||||
return config.getExtensionSettings()::isEnabled;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
JarResource.StreamFunction provideJarStreamFunction(PluginInformation information) {
|
||||
return information::getResourceFromJar;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@Named("dataFolder")
|
||||
File provideDataFolder(PluginInformation information) {
|
||||
return information.getDataFolder();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.playeranalytics.plan.module;
|
||||
|
||||
import com.djrapitops.plan.identification.properties.ServerProperties;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
/**
|
||||
* @author AuroraLS3
|
||||
*/
|
||||
@Module
|
||||
public class StandaloneServerPropertiesModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
ServerProperties provideServerProperties() {
|
||||
return new ServerProperties(
|
||||
"Standalone Java",
|
||||
0,
|
||||
"Java " + System.getProperty("java.version"),
|
||||
"",
|
||||
() -> new InetSocketAddress(25565).getAddress().getHostAddress(),
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.playeranalytics.plan.utilities.logging;
|
||||
|
||||
import com.djrapitops.plan.utilities.logging.ErrorContext;
|
||||
import com.djrapitops.plan.utilities.logging.ErrorLogger;
|
||||
import net.playeranalytics.plan.PlanStandalone;
|
||||
import net.playeranalytics.plugin.server.PluginLogger;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
/**
|
||||
* @author AuroraLS3
|
||||
*/
|
||||
@Singleton
|
||||
public class StandaloneErrorLogger implements ErrorLogger {
|
||||
|
||||
private final PluginLogger logger;
|
||||
|
||||
@Inject
|
||||
public StandaloneErrorLogger(PluginLogger logger) {
|
||||
this.logger = logger;
|
||||
// TODO Extract file logging properties of PluginErrorLogger without PlanPlugin as dependency.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void critical(Throwable throwable, ErrorContext context) {
|
||||
error(throwable, context);
|
||||
PlanStandalone.shutdown(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(Throwable throwable, ErrorContext context) {
|
||||
logger.error("", throwable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(Throwable throwable, ErrorContext context) {
|
||||
logger.warn("", throwable);
|
||||
}
|
||||
}
|
@ -1,23 +1,36 @@
|
||||
package net.playeranalytics.plugin;
|
||||
|
||||
import net.playeranalytics.plugin.information.StandalonePluginInformation;
|
||||
import net.playeranalytics.plugin.scheduling.RunnableFactory;
|
||||
import net.playeranalytics.plugin.scheduling.StandaloneRunnableFactory;
|
||||
import net.playeranalytics.plugin.server.JavaUtilPluginLogger;
|
||||
import net.playeranalytics.plugin.server.Listeners;
|
||||
import net.playeranalytics.plugin.server.PluginLogger;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class StandalonePlatformAbstractionLayer implements PlatformAbstractionLayer {
|
||||
|
||||
private final PluginLogger logger;
|
||||
private final StandaloneRunnableFactory runnableFactory;
|
||||
private final StandalonePluginInformation pluginInformation;
|
||||
private final Listeners listeners;
|
||||
|
||||
public StandalonePlatformAbstractionLayer(Logger logger) {this.logger = new JavaUtilPluginLogger(logger);}
|
||||
public StandalonePlatformAbstractionLayer(Logger logger) {
|
||||
this.logger = new JavaUtilPluginLogger(logger);
|
||||
runnableFactory = new StandaloneRunnableFactory();
|
||||
pluginInformation = new StandalonePluginInformation();
|
||||
listeners = new Listeners() {
|
||||
@Override
|
||||
public void registerListener(Object o) {/*no-op*/}
|
||||
|
||||
@Override
|
||||
public void unregisterListener(Object o) {/*no-op*/}
|
||||
|
||||
@Override
|
||||
public void unregisterListeners() {/*no-op*/}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public PluginLogger getPluginLogger() {
|
||||
@ -26,53 +39,16 @@ public class StandalonePlatformAbstractionLayer implements PlatformAbstractionLa
|
||||
|
||||
@Override
|
||||
public Listeners getListeners() {
|
||||
return new Listeners() {
|
||||
@Override
|
||||
public void registerListener(Object o) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterListener(Object o) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterListeners() {
|
||||
}
|
||||
};
|
||||
return listeners;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RunnableFactory getRunnableFactory() {
|
||||
return null;
|
||||
return runnableFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PluginInformation getPluginInformation() {
|
||||
return new PluginInformation() {
|
||||
@Override
|
||||
public InputStream getResourceFromJar(String s) {
|
||||
return getClass().getResourceAsStream(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getDataFolder() {
|
||||
return new File("Plan");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVersion() {
|
||||
try {
|
||||
return readVersionFromPluginYml();
|
||||
} catch (IOException | URISyntaxException e) {
|
||||
return e.toString();
|
||||
}
|
||||
}
|
||||
|
||||
private String readVersionFromPluginYml() throws IOException, URISyntaxException {
|
||||
String pluginYmlContents = new String(Files.readAllBytes(new File(getClass().getResource("plugin.yml").toURI()).toPath()));
|
||||
String versionHalf = StringUtils.split(pluginYmlContents, "version:")[1];
|
||||
return StringUtils.split(versionHalf, "\n")[0];
|
||||
}
|
||||
};
|
||||
return pluginInformation;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.playeranalytics.plugin.information;
|
||||
|
||||
import net.playeranalytics.plugin.PluginInformation;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* @author AuroraLS3
|
||||
*/
|
||||
public class StandalonePluginInformation implements PluginInformation {
|
||||
|
||||
@Override
|
||||
public InputStream getResourceFromJar(String resourceName) {
|
||||
return getClass().getResourceAsStream("/" + resourceName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getDataFolder() {
|
||||
return new File("Plan");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVersion() {
|
||||
return readVersionFromPluginYml();
|
||||
}
|
||||
|
||||
private String readVersionFromPluginYml() {
|
||||
String pluginYmlContents = readAllBytes("plugin.yml");
|
||||
for (String line : StringUtils.split(pluginYmlContents, "\n")) {
|
||||
if (line.contains("version")) {
|
||||
return StringUtils.split(line, ":")[1].trim();
|
||||
}
|
||||
}
|
||||
return "Missing plugin.yml";
|
||||
}
|
||||
|
||||
private String readAllBytes(String resource) {
|
||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||
try (InputStream inStream = getResourceFromJar(resource); buffer) {
|
||||
int nRead;
|
||||
byte[] data = new byte[16384];
|
||||
|
||||
while ((nRead = inStream.read(data, 0, data.length)) != -1) {
|
||||
buffer.write(data, 0, nRead);
|
||||
}
|
||||
buffer.flush();
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
return buffer.toString(StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.playeranalytics.plugin.scheduling;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
public class StandaloneRunnableFactory implements RunnableFactory {
|
||||
|
||||
private final Set<StandaloneTask> tasks;
|
||||
private ScheduledExecutorService executorService;
|
||||
|
||||
public StandaloneRunnableFactory() {
|
||||
this.executorService = Executors.newScheduledThreadPool(8);
|
||||
this.tasks = Collections.newSetFromMap(new ConcurrentHashMap<>());
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnscheduledTask create(Runnable runnable) {
|
||||
return new UnscheduledStandaloneTask(getExecutorService(), runnable, task -> {
|
||||
});
|
||||
}
|
||||
|
||||
private ScheduledExecutorService getExecutorService() {
|
||||
if (executorService.isShutdown() || executorService.isTerminated()) {
|
||||
// Hacky way of fixing tasks when plugin is disabled, leaks one thread every reload.
|
||||
executorService = Executors.newSingleThreadScheduledExecutor();
|
||||
}
|
||||
return executorService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnscheduledTask create(PluginRunnable runnable) {
|
||||
return new UnscheduledStandaloneTask(getExecutorService(), runnable, runnable::setCancellable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelAllKnownTasks() {
|
||||
this.tasks.forEach(Task::cancel);
|
||||
this.tasks.clear();
|
||||
executorService.shutdown();
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.playeranalytics.plugin.scheduling;
|
||||
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
public class StandaloneTask implements Task {
|
||||
|
||||
private final Future<?> task;
|
||||
|
||||
public StandaloneTask(Future<?> task) {
|
||||
this.task = task;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGameThread() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
task.cancel(false);
|
||||
}
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.playeranalytics.plugin.scheduling;
|
||||
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class UnscheduledStandaloneTask implements UnscheduledTask {
|
||||
|
||||
private final ScheduledExecutorService scheduler;
|
||||
private final Runnable runnable;
|
||||
private final Consumer<Task> cancellableConsumer;
|
||||
|
||||
public UnscheduledStandaloneTask(ScheduledExecutorService scheduler, Runnable runnable, Consumer<Task> cancellableConsumer) {
|
||||
this.scheduler = scheduler;
|
||||
this.runnable = runnable;
|
||||
this.cancellableConsumer = cancellableConsumer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Task runTaskAsynchronously() {
|
||||
StandaloneTask task = new StandaloneTask(this.scheduler.submit(this.runnable));
|
||||
cancellableConsumer.accept(task);
|
||||
return task;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Task runTaskLaterAsynchronously(long delayTicks) {
|
||||
StandaloneTask task = new StandaloneTask(this.scheduler.schedule(
|
||||
this.runnable,
|
||||
delayTicks * 50,
|
||||
TimeUnit.MILLISECONDS
|
||||
));
|
||||
cancellableConsumer.accept(task);
|
||||
return task;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Task runTaskTimerAsynchronously(long delayTicks, long periodTicks) {
|
||||
StandaloneTask task = new StandaloneTask(this.scheduler.scheduleAtFixedRate(
|
||||
runnable,
|
||||
delayTicks * 50,
|
||||
periodTicks * 50,
|
||||
TimeUnit.MILLISECONDS
|
||||
));
|
||||
cancellableConsumer.accept(task);
|
||||
return task;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Task runTask() {
|
||||
return runTaskAsynchronously();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Task runTaskLater(long delayTicks) {
|
||||
return runTaskLaterAsynchronously(delayTicks);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Task runTaskTimer(long delayTicks, long periodTicks) {
|
||||
return runTaskTimerAsynchronously(delayTicks, periodTicks);
|
||||
}
|
||||
}
|
5
Plan/standalone/src/main/resources/logging.properties
Normal file
5
Plan/standalone/src/main/resources/logging.properties
Normal file
@ -0,0 +1,5 @@
|
||||
handlers=java.util.logging.ConsoleHandler
|
||||
.level=INFO
|
||||
java.util.logging.ConsoleHandler.level=INFO
|
||||
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
|
||||
java.util.logging.SimpleFormatter.format=[%1$tF %1$tT] %4$-7s : %5$s %n
|
Loading…
Reference in New Issue
Block a user