From 9b7c0d4deb3f35a214c5f1dadbdb9a1711b0e873 Mon Sep 17 00:00:00 2001 From: cnaude Date: Sun, 15 Nov 2015 17:25:26 -0700 Subject: [PATCH] Add file tailer. Tail your server.log and send output to user or channel. --- pom.xml | 8 +- .../java/com/cnaude/purpleirc/LogTailer.java | 113 ++++++++++++++++++ .../java/com/cnaude/purpleirc/PurpleBot.java | 34 +++++- .../java/com/cnaude/purpleirc/PurpleIRC.java | 1 + src/main/resources/SampleBot.yml | 6 + 5 files changed, 156 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/cnaude/purpleirc/LogTailer.java diff --git a/pom.xml b/pom.xml index ba78f59..b13662e 100644 --- a/pom.xml +++ b/pom.xml @@ -103,7 +103,13 @@ commons-codec commons-codec - 1.10 + 1.9 + + + + commons-io + commons-io + 2.4 diff --git a/src/main/java/com/cnaude/purpleirc/LogTailer.java b/src/main/java/com/cnaude/purpleirc/LogTailer.java new file mode 100644 index 0000000..343fecd --- /dev/null +++ b/src/main/java/com/cnaude/purpleirc/LogTailer.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2014 cnaude + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.cnaude.purpleirc; + +import java.io.File; +import org.apache.commons.io.input.Tailer; +import org.apache.commons.io.input.TailerListener; +import org.apache.commons.io.input.TailerListenerAdapter; + +/** + * + * @author Chris Naude Poll the command queue and dispatch to Bukkit + */ +public class LogTailer { + + private final PurpleIRC plugin; + private final PurpleBot ircBot; + private final String target; + private final boolean ctcp; + private static final int SLEEP = 500; + private final File file; + private Tailer tailer; + private Thread thread; + private TailerListener listener; + + /** + * + * @param plugin + * @param ircBot + * @param target + * @param ctcp + * @param fileName + */ + public LogTailer(final PurpleBot ircBot, final PurpleIRC plugin, final String target, final boolean ctcp, final String fileName) { + this.plugin = plugin; + this.ircBot = ircBot; + this.target = target; + this.ctcp = ctcp; + this.file = new File(fileName); + if (file.exists()) { + startWatcher(); + } else { + plugin.logError("No such file: " + fileName); + } + } + + private void startWatcher() { + plugin.getServer().getScheduler().runTaskLaterAsynchronously(plugin, new Runnable() { + @Override + public void run() { + plugin.logInfo("Tailing file: " + file.getName()); + listener = new MyTailerListener(); + tailer = new Tailer(file, listener, SLEEP); + thread = new Thread(tailer); + thread.setDaemon(true); // optional + thread.start(); + } + }, 0); + } + + public class MyTailerListener extends TailerListenerAdapter { + + @Override + public void handle(String line) { + if (ctcp) { + blockingCTCPMessage(target, line); + } else { + blockingIRCMessage(target, line); + } + } + + } + + private void blockingIRCMessage(final String target, final String message) { + if (!ircBot.isConnected()) { + return; + } + plugin.logDebug("[blockingIRCMessage] About to send IRC message to " + target + ": " + message); + ircBot.bot.sendIRC().message(target, message); + plugin.logDebug("[blockingIRCMessage] Message sent to " + target + ": " + message); + } + + private void blockingCTCPMessage(final String target, final String message) { + if (!ircBot.isConnected()) { + return; + } + plugin.logDebug("[blockingCTCPMessage] About to send IRC message to " + target + ": " + message); + ircBot.bot.sendIRC().ctcpResponse(target, message); + plugin.logDebug("[blockingCTCPMessage] Message sent to " + target + ": " + message); + } + + protected void stopTailer() { + if (tailer != null) { + plugin.logInfo("Stoping tailer."); + tailer.stop(); + } + } + +} diff --git a/src/main/java/com/cnaude/purpleirc/PurpleBot.java b/src/main/java/com/cnaude/purpleirc/PurpleBot.java index f16b46d..0dcbad9 100644 --- a/src/main/java/com/cnaude/purpleirc/PurpleBot.java +++ b/src/main/java/com/cnaude/purpleirc/PurpleBot.java @@ -59,6 +59,7 @@ import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import me.botsko.prism.actionlibs.QueryParameters; import me.botsko.prism.events.BlockStateChange; +import org.apache.commons.io.input.Tailer; import org.bukkit.Achievement; import org.bukkit.ChatColor; import org.bukkit.GameMode; @@ -188,6 +189,11 @@ public final class PurpleBot { public CaseInsensitiveMap linkRequests; public CaseInsensitiveMap> remotePlayers; public CaseInsensitiveMap> remoteServerInfo; + private LogTailer tailer; + private boolean tailerEnabled; + private String tailerFile; + private String tailerRecipient; + private boolean tailerCtcp; /** * @@ -275,6 +281,9 @@ public final class PurpleBot { } public void buildBot(boolean reload) { + if (tailer != null) { + tailer.stopTailer(); + } Configuration.Builder configBuilder = new Configuration.Builder() .setName(botNick) .setLogin(botLogin) @@ -354,6 +363,15 @@ public final class PurpleBot { plugin.logInfo("Auto-connect is disabled. To connect: /irc connect " + bot.getNick()); } plugin.logDebug("Max line length: " + configBuilder.getMaxLineLength()); + if (tailerEnabled && !tailerFile.isEmpty() && !tailerRecipient.isEmpty()) { + tailer = new LogTailer(this, plugin, tailerRecipient, tailerCtcp, tailerFile); + } + } + + protected void stopTailer() { + if (tailer != null) { + tailer.stopTailer(); + } } private void addListeners() { @@ -777,6 +795,12 @@ public final class PurpleBot { plugin.logInfo(" No command recipients defined."); } + // load tailer settings + tailerEnabled = config.getBoolean("file-tailer.enabled", false); + tailerFile = config.getString("file-tailer.file", "server.log"); + tailerRecipient = config.getString("file-tailer.recipient", ""); + tailerCtcp = config.getBoolean("file-tailer.ctcp", false); + // build command notify ignore list for (String command : config.getStringList("command-notify.ignore")) { if (!channelCmdNotifyIgnore.contains(command)) { @@ -875,7 +899,7 @@ public final class PurpleBot { if (opsList.isEmpty()) { plugin.logInfo("No channel ops defined."); } - + // build channel ban list Collection cBans = new ArrayList<>(); for (String channelBan : config.getStringList("channels." + enChannelName + ".banlist")) { @@ -1865,7 +1889,7 @@ public final class PurpleBot { } saveConfig("channels." + encodeChannel(getConfigChannelName(channelName)) + ".ops", opsList.get(channelName)); } - + /** * * @param channelName @@ -1919,7 +1943,7 @@ public final class PurpleBot { } saveConfig("channels." + encodeChannel(getConfigChannelName(channelName)) + ".ops", opsList.get(channelName)); } - + /** * * @param channelName @@ -2071,7 +2095,7 @@ public final class PurpleBot { } } } - + /** * * @param channelName @@ -2463,7 +2487,7 @@ public final class PurpleBot { } } } - + /** * * @param channel diff --git a/src/main/java/com/cnaude/purpleirc/PurpleIRC.java b/src/main/java/com/cnaude/purpleirc/PurpleIRC.java index ba5c2b1..d28e158 100644 --- a/src/main/java/com/cnaude/purpleirc/PurpleIRC.java +++ b/src/main/java/com/cnaude/purpleirc/PurpleIRC.java @@ -346,6 +346,7 @@ public class PurpleIRC extends JavaPlugin { logInfo("Disconnecting IRC bots."); for (PurpleBot ircBot : ircBots.values()) { commandQueue.cancel(); + ircBot.stopTailer(); ircBot.saveConfig(getServer().getConsoleSender()); ircBot.quit(); } diff --git a/src/main/resources/SampleBot.yml b/src/main/resources/SampleBot.yml index 3959a74..c60c5a9 100644 --- a/src/main/resources/SampleBot.yml +++ b/src/main/resources/SampleBot.yml @@ -66,6 +66,12 @@ command-notify: - example ignore: - /example +# File tailer +file-tailer: + enabled: false + file: 'server.log' + recipient: '#minecraft-test' + ctcp: false # Messaging flood control (game and IRC) flood-control: # Enable or disable flood control