diff --git a/Plugins/Mineplex.Core/src/mineplex/core/MiniPlugin.java b/Plugins/Mineplex.Core/src/mineplex/core/MiniPlugin.java index dbad6fbdb..3477b742c 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/MiniPlugin.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/MiniPlugin.java @@ -1,27 +1,21 @@ package mineplex.core; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.scheduler.BukkitScheduler; -import com.google.common.util.concurrent.ThreadFactoryBuilder; import mineplex.core.command.CommandCenter; import mineplex.core.command.ICommand; import mineplex.core.common.util.F; import mineplex.core.common.util.NautHashMap; import mineplex.core.common.util.UtilTime; import mineplex.core.common.util.UtilTime.TimeUnit; +import mineplex.core.thread.ThreadPool; public abstract class MiniPlugin implements Listener { - private static final ExecutorService threadPool = Executors.newCachedThreadPool( - new ThreadFactoryBuilder().setNameFormat("MiniPlugin Async %1$d").build()); - protected String _moduleName = "Default"; protected JavaPlugin _plugin; protected NautHashMap _commands; @@ -113,7 +107,7 @@ public abstract class MiniPlugin implements Listener public void runAsync(Runnable runnable) { // Instead of using - threadPool.execute(runnable); + ThreadPool.ASYNC.execute(runnable); } public void runAsync(Runnable runnable, long time) diff --git a/Plugins/Mineplex.Core/src/mineplex/core/slack/SlackAPI.java b/Plugins/Mineplex.Core/src/mineplex/core/slack/SlackAPI.java new file mode 100644 index 000000000..9bce0f192 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/slack/SlackAPI.java @@ -0,0 +1,129 @@ +package mineplex.core.slack; + +import java.io.BufferedReader; +import java.io.DataOutputStream; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLEncoder; + +import com.google.gson.JsonObject; +import mineplex.core.thread.ThreadPool; + +/** + * An API for sending and handling Slack messages. + */ +public class SlackAPI +{ + // Default emoji. + public static final String DEFAULT_ICON = ":mineplex:"; + + // Singular instance. + private static SlackAPI _instance; + + // Don't allow instantiation elsewhere. + private SlackAPI() {} + + /** + * Sends a message asynchronously to a Slack channel. + * + * @param team The team which contains the target channel. + * @param channel The target channel for the message. + * @param message The message to be displayed. + * @param customTitle Whether or not to use a custom title for the message. + * If false the default team title is used. + */ + public void sendMessage(SlackTeam team, String channel, SlackMessage message, boolean customTitle) + { + ThreadPool.ASYNC.execute(() -> + { + // Set message title. + if (!customTitle) + { + message.setUsername(team.getTitle()); + message.setIcon(DEFAULT_ICON); + } + + // Set message channel. + JsonObject msg = message.toJson(); + msg.addProperty("channel", channel); + + // Run the call. + runWebCall(team, msg); + }); + } + + /** + * Runs a web call to a specified Slack incoming-hook. + * + * @param team The team to run the call on. + * @param call The call to be run. + */ + private String runWebCall(SlackTeam team, JsonObject call) + { + HttpURLConnection connection = null; + try + { + // Create connection. + URL url = new URL(team.getURL()); + connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("POST"); + connection.setConnectTimeout(5000); + connection.setUseCaches(false); + connection.setDoInput(true); + connection.setDoOutput(true); + + // Setup payload. + String payload = "payload=" + URLEncoder.encode(call.toString(), "UTF-8"); + + // Send request. + DataOutputStream dos = new DataOutputStream(connection.getOutputStream()); + dos.writeBytes(payload); + dos.flush(); + dos.close(); + + // Receive response. + InputStream is = connection.getInputStream(); + BufferedReader rd = new BufferedReader(new InputStreamReader(is)); + String line; + String response = ""; + while ((line = rd.readLine()) != null) + { + response += line + "\n"; + } + + rd.close(); + return response.toString(); + } + catch (Exception e) + { + e.printStackTrace(); + } + finally + { + if (connection != null) + { + // Terminate connection. + connection.disconnect(); + } + } + + return "500 Error"; + } + + /** + * Gets the singular instance of the Slack API. + * + * @return The {@link SlackAPI} instance. + */ + public static SlackAPI getInstance() + { + if (_instance == null) + { + _instance = new SlackAPI(); + } + + return _instance; + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/slack/SlackAttachment.java b/Plugins/Mineplex.Core/src/mineplex/core/slack/SlackAttachment.java new file mode 100644 index 000000000..a42d9a405 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/slack/SlackAttachment.java @@ -0,0 +1,14 @@ +package mineplex.core.slack; + +/** + * Attached content for a {@link SlackMessage}. + */ +public class SlackAttachment +{ + private String _color; + + private String _authorName; + private String _authorIcon; + + private String _title; +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/slack/SlackMessage.java b/Plugins/Mineplex.Core/src/mineplex/core/slack/SlackMessage.java new file mode 100644 index 000000000..60cd5739e --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/slack/SlackMessage.java @@ -0,0 +1,194 @@ +package mineplex.core.slack; + +import java.util.ArrayList; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; + +/** + * A message to be sent through the {@link SlackAPI}. + */ +public class SlackMessage +{ + private String _username; + private String _icon; + + private String _content; + private ArrayList _attachments; + + /** + * Class constructor. + * + * @param content The content of the message. + */ + public SlackMessage(String content) + { + _icon = SlackAPI.DEFAULT_ICON; + _content = content; + _attachments = new ArrayList<>(); + } + + /** + * Class constructor. + * + * @param username The username of the message. + * @param content The content of the message. + */ + public SlackMessage(String username, String content) + { + _username = username; + _icon = SlackAPI.DEFAULT_ICON; + _content = content; + _attachments = new ArrayList<>(); + } + + /** + * Class constructor. + * + * @param username The username of the message. + * @param icon The icon/emoji of the message. + * @param content The content of the message. + */ + public SlackMessage(String username, String icon, String content) + { + _username = username; + _icon = ":" + icon + ":"; + _content = content; + _attachments = new ArrayList<>(); + } + + /** + * Converts the message to JSON format. + * + * @return The {@link SlackMessage} in the form of a {@link JsonObject}. + */ + public JsonObject toJson() + { + JsonObject msg = new JsonObject(); + + if (_username != null) + { + msg.addProperty("username", _username); + } + + if (_icon != null) + { + msg.addProperty("icon_emoji", _icon); + } + + if (_content != null) + { + msg.addProperty("text", _content); + } + + if (!_attachments.isEmpty()) + { + JsonArray attachments = new JsonArray(); + for (SlackAttachment attachment : _attachments) + { + //attachments.add(attachment.toJson()); + //TODO + } + + msg.add("attachments", attachments); + } + + return msg; + } + + /** + * Gets the username that displays as a title. + * + * @return The username in use. + */ + public String getUsername() + { + return _username; + } + + /** + * Sets the username that displays as a title. + * + * @param username The username to use. + */ + public void setUsername(String username) + { + _username = username; + } + + /** + * Gets the icon that displays with the title. + * + * @return The icon in use. + */ + public String getIcon() + { + return _icon; + } + + /** + * Sets the icon that displays with the title. + * + * @param icon The icon to use. + */ + public void setIcon(String icon) + { + _icon = icon; + } + + /** + * Gets the content of the message. + * + * @return The content of the message. + */ + public String getContent() + { + return _content; + } + + /** + * Sets the content of the message. + * + * @param content The content of the message. + */ + public void setContent(String content) + { + _content = content; + } + + /** + * Gets the attachments of the message. + * + * @return A list of attachments. + */ + public ArrayList getAttachments() + { + return _attachments; + } + + /** + * Adds an attachment to the Slack message. + * + * @param attachment The attachment to add. + */ + public void addAttachment(SlackAttachment attachment) + { + if (!_attachments.contains(attachment)) + { + _attachments.add(attachment); + } + } + + /** + * Removes an attachment from the Slack message. + * + * @param attachment The attachment to remove. + */ + public void removeAttachment(SlackAttachment attachment) + { + if (_attachments.contains(attachment)) + { + _attachments.remove(attachment); + } + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/slack/SlackTeam.java b/Plugins/Mineplex.Core/src/mineplex/core/slack/SlackTeam.java new file mode 100644 index 000000000..965346791 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/slack/SlackTeam.java @@ -0,0 +1,79 @@ +package mineplex.core.slack; + +/** + * An enumeration of Mineplex Slack teams. + */ +public enum SlackTeam +{ + // Dev team - mineplex.slack.com + DEVELOPER("Mineplex Dev", "T045RUM7F", "B0VK6GFKN", "6GxwJsDfEpbVnQl8pYuEyq5T"), + + // QA team - mineplexqa.slack.com + QA("Mineplex QA", "todo", "todo", "todo"), // TODO: new details + + ; + + private String _title; + private String _id1; + private String _id2; + private String _token; + + SlackTeam(String title, String id1, String id2, String token) + { + _title = title; + _id1 = id1; + _id2 = id2; + _token = token; + } + + /** + * Gets the title that will be displayed that the top of each + * {@link SlackMessage}. + * + * @return The title of this team. + */ + public String getTitle() + { + return _title; + } + + /** + * Gets the first ID of this Slack team. + * + * @return The individual first ID. + */ + public String getId1() + { + return _id1; + } + + /** + * Gets the second ID of this Slack team. + * + * @return The individual second ID. + */ + public String getId2() + { + return _id2; + } + + /** + * Gets the token key of this Slack team. + * + * @return The individual and secret token. + */ + public String getToken() + { + return _token; + } + + /** + * Gets the web hook in the form of a URL. + * + * @return The URL as a string. + */ + public String getURL() + { + return "https://hooks.slack.com/services/" + getId1() + "/" + getId2() + "/" + getToken(); + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/thread/ThreadPool.java b/Plugins/Mineplex.Core/src/mineplex/core/thread/ThreadPool.java new file mode 100644 index 000000000..7e9af44b1 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/thread/ThreadPool.java @@ -0,0 +1,19 @@ +package mineplex.core.thread; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import com.google.common.util.concurrent.ThreadFactoryBuilder; + +/** + * A collection of threads for different uses. + */ +public class ThreadPool +{ + + // Async Thread + public static ExecutorService ASYNC = Executors.newCachedThreadPool( + new ThreadFactoryBuilder().setNameFormat("MiniPlugin Async %1$d").build() + ); + +}