package org.freecode.irc; import org.freecode.irc.event.internal.*; import java.io.*; import java.net.Socket; import java.util.LinkedList; import java.util.List; import java.util.concurrent.*; /** * User: Shivam * Date: 16/06/13 * Time: 22:30 */ public class IrcConnection implements Runnable { private BufferedReader reader; private BufferedWriter writer; private Socket socket; private String host; private int port; private volatile List<RawIrcListener> listeners; private volatile List<DelegateListener> delegateListeners; private ScheduledExecutorService executor; private Future readerFuture; public static final int ERR_NICKNAMEINUSE = 433; private ConcurrentLinkedQueue<String> rawLines = new ConcurrentLinkedQueue<>(); private final ScheduledFuture<?> writerFuture; public IrcConnection(final String host, final int port) throws IOException { this.host = host; this.port = port; this.socket = new Socket(host, port); reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); listeners = new LinkedList<>(); delegateListeners = new LinkedList<>(); executor = Executors.newScheduledThreadPool(2); addListener(new RawPrivateMessageProcessor(this)); addListener(new RawNoticeProcessor(this)); addListener(new RawJoinProcessor(this)); readerFuture = executor.scheduleAtFixedRate(this, 100L, 100L, TimeUnit.MILLISECONDS); writerFuture = executor.scheduleAtFixedRate(new Runnable() { @Override public void run() { if (socket.isOutputShutdown()) { writerFuture.cancel(true); return; } if (!rawLines.isEmpty()) { String s = rawLines.poll(); System.out.println("Out: " + s); try { writer.write(s); writer.newLine(); writer.flush(); } catch (IOException e) { e.printStackTrace(); } } } }, 100L, 100L, TimeUnit.MILLISECONDS); } public void joinChannel(String channel) { try { sendRaw("JOIN :" + channel); } catch (IOException e) { e.printStackTrace(); } } public void addListener(final DelegateListener listener) { delegateListeners.add(listener); } public void removeListener(final DelegateListener listener) { delegateListeners.remove(listener); } public void addListener(final RawIrcListener listener) { listeners.add(listener); } public void removeListener(final RawIrcListener listener) { listeners.remove(listener); } public void register(final String nick, final String user, final String realName) throws IOException { sendRaw("NICK " + nick); sendRaw("USER " + user + " 0 * :" + realName); } public <T> List<T> getDelegates(Class<T> type) { List<T> list = new LinkedList<>(); for (DelegateListener l : delegateListeners) { if (type.isAssignableFrom(l.getClass())) { list.add(type.cast(l)); } } return list; } public void sendMessage(String target, String message) { try { sendRaw(String.format("PRIVMSG %s :%s", target, message)); } catch (IOException e) { e.printStackTrace(); } } public void sendRaw(String s) throws IOException { if (s.endsWith("\n")) { s = s.replaceAll("[\n\r]", ""); } if (!socket.isOutputShutdown()) { rawLines.offer(s); } } public void run() { if (socket.isInputShutdown()) { readerFuture.cancel(true); } else { try { String raw = reader.readLine(); System.out.println(raw); if (!Character.isLetterOrDigit(raw.charAt(0))) { raw = raw.substring(1); } if (raw.startsWith("PING ")) { sendRaw(raw.replaceFirst("PING", "PONG")); } else { for (RawIrcListener listener : listeners) { if (listener.qualifies(raw)) { listener.execute(raw); } } } } catch (IOException e) { e.printStackTrace(); } } } public void send(final Transmittable transmittable) { try { sendRaw(transmittable.getRaw()); } catch (IOException e) { e.printStackTrace(); } } public void sendNotice(String target, String message) { try { sendRaw(String.format("NOTICE %s :%s", target, message)); } catch (IOException e) { e.printStackTrace(); } } public BufferedWriter getWriter() { return writer; } }