package tterrag.tppibot.reactions; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import lombok.Value; import org.pircbotx.Channel; import org.pircbotx.User; import org.pircbotx.hooks.events.MessageEvent; import com.google.common.base.Joiner; import tterrag.tppibot.Main; import tterrag.tppibot.interfaces.IReaction; import tterrag.tppibot.reactions.CharacterSpam.SpamReasons; import tterrag.tppibot.util.ThreadUtils; public class FloodSpam implements IReaction { public static final int EXPIRE_TIME = 10000; // ms public static final int MAX_MSGS = 5; public static class MessageCount { @Value private class Message { private String msg; private long time; @Override public String toString() { return msg; } } public final User user; public final Channel channel; private List<Message> msgs; public MessageCount(User user, Channel channel, String msg, long time) { this.user = user; this.channel = channel; msgs = new ArrayList<Message>(); msg(msg, time); } public void msg(String msg, long time) { msgs.add(new Message(msg, time)); } public void tick() { Iterator<Message> iter = msgs.iterator(); while (iter.hasNext()) { Message m = iter.next(); if (System.currentTimeMillis() - m.time > EXPIRE_TIME) { iter.remove(); } } } public boolean isValid() { return msgs.size() > 1; } public boolean equals(MessageEvent<?> event) { return this.user.equals(event.getUser()) && this.channel.equals(event.getChannel()); } public boolean breakinDaLaw() { return msgs.size() >= MAX_MSGS; } } private List<MessageCount> counts = new ArrayList<MessageCount>(); private Runnable ticker = new Runnable() { @Override public void run() { while (true) { synchronized (counts) { for (MessageCount c : counts) { c.tick(); } } if (counts.size() > 100) { counts.clear(); } ThreadUtils.sleep(1000); } } }; public FloodSpam() { Thread thread = new Thread(ticker); thread.start(); } @Override public void onMessage(MessageEvent<?> event) { boolean found = false; Iterator<MessageCount> iter = counts.iterator(); if (Main.spamFilter.filtersEnabled(event.getChannel().getName())) { synchronized (counts) { while (iter.hasNext()) { MessageCount count = iter.next(); if (count != null && count.equals(event)) { count.msg(event.getMessage(), event.getTimestamp()); found = true; if (count.breakinDaLaw()) { timeout(count); iter.remove(); } break; } } } if (!found) { counts.add(new MessageCount(event.getUser(), event.getChannel(), event.getMessage(), event.getTimestamp())); } } } private void timeout(MessageCount msg) { Main.spamFilter.finish(Main.spamFilter.timeout(Main.bot, msg.user, msg.channel, SpamReasons.FLOOD) ? msg.user : null, SpamReasons.FLOOD, "\"" + Joiner.on("\", \"").join(msg.msgs) + "\""); } }