/** * Licensed to Cloudera, Inc. under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. Cloudera, Inc. licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.cloudera.flume.handlers.irc; import java.io.IOException; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import org.schwering.irc.lib.IRCConnection; import org.schwering.irc.lib.IRCEventListener; import org.schwering.irc.lib.IRCModeParser; import org.schwering.irc.lib.IRCUser; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.cloudera.flume.conf.FlumeConfiguration; import com.cloudera.flume.conf.SourceFactory.SourceBuilder; import com.cloudera.flume.core.Event; import com.cloudera.flume.core.EventImpl; import com.cloudera.flume.core.EventSource; import com.google.common.base.Preconditions; /** * This logs in and listens to a irc server. * * TODO (jon) share the connection to support multiple channels and to support * an IrcSink. */ public class IrcSource extends EventSource.Base { static final Logger LOG = LoggerFactory.getLogger(IrcSource.class); private IRCConnection conn; String host; int port; String nick; String pass; String user; String name; String chan; boolean ssl; // later iteraton BlockingQueue<Event> q = new LinkedBlockingQueue<Event>(); public IrcSource(String host, int port, String nick, String pass, String user, String name, String chan, boolean ssl) { this.host = host; this.port = port; this.nick = nick; this.pass = pass; this.user = user; this.name = name; this.chan = chan; this.ssl = ssl; } public IrcSource(String host, int port, String nick, String chan) { this(host, port, nick, null, null, null, chan, false); } @Override public void open() throws IOException { // TODO (jon) check if the nick usage was successful or not conn = new IRCConnection(host, new int[] { port }, pass, nick, user, name); conn.addIRCEventListener(new Listener()); conn.setEncoding(FlumeConfiguration.get().getFlurkerEncoding()); conn.setPong(true); conn.setDaemon(false); conn.setColors(false); conn.connect(); conn.send("join " + chan); // TODO(jon) check if channel join was successful or not } @Override public void close() throws IOException { conn.close(); } private void append(String s) { if (s == null) { LOG.error("null append!"); return; } q.add(new EventImpl(s.getBytes())); } // Need to pick which call backs should be "sources" and which are "sinks". /** * Treats IRC events. The most of them are just printed. * * TODO (jon) since we have fields, we can use store this as structured data. */ public class Listener implements IRCEventListener { public void onRegistered() { append("Connected"); } public void onDisconnected() { append("Disconnected"); } public void onError(String msg) { append("Error: " + msg); } public void onError(int num, String msg) { append("Error #" + num + ": " + msg); } public void onInvite(String chan, IRCUser u, String nickPass) { append(chan + "> " + u.getNick() + " invites " + nickPass); } public void onJoin(String chan, IRCUser u) { append(chan + "> " + u.getNick() + " joins"); } public void onKick(String chan, IRCUser u, String nickPass, String msg) { append(chan + "> " + u.getNick() + " kicks " + nickPass); } public void onMode(IRCUser u, String nickPass, String mode) { append("Mode: " + u.getNick() + " sets modes " + mode + " " + nickPass); } public void onMode(String chan, IRCUser u, IRCModeParser mp) { append(chan + "> " + u.getNick() + " sets mode: " + mp.getLine()); } public void onNick(IRCUser u, String nickNew) { append("Nick: " + u.getNick() + " is now known as " + nickNew); } public void onNotice(String target, IRCUser u, String msg) { append(target + "> " + u.getNick() + " (notice): " + msg); } public void onPart(String chan, IRCUser u, String msg) { append(chan + "> " + u.getNick() + " parts"); } public void onPrivmsg(String chan, IRCUser u, String msg) { append(chan + "> " + u.getNick() + ": " + msg); } public void onQuit(IRCUser u, String msg) { append("Quit: " + u.getNick()); } public void onReply(int num, String value, String msg) { append("Reply #" + num + ": " + value + " " + msg); } public void onTopic(String chan, IRCUser u, String topic) { append(chan + "> " + u.getNick() + " changes topic into: " + topic); } public void onPing(String p) { } public void unknown(String a, String b, String c, String d) { append("UNKNOWN: " + a + " b " + c + " " + d); } } @Override public Event next() throws IOException { try { Event e = q.take(); updateEventProcessingStats(e); return e; } catch (InterruptedException e) { LOG.error("IrcSource interrupted", e); throw new IOException(e); } } public static SourceBuilder builder() { return new SourceBuilder() { @Override public EventSource build(String... argv) { Preconditions.checkArgument(argv.length == 4, "usage: ircSource(server, port, nick, chan)"); String server = argv[0]; int port = Integer.parseInt(argv[1]); String nick = argv[2]; String chan = argv[3]; return new IrcSource(server, port, nick, chan); } }; } /** * A simple irc client using the source irc source interface. */ public static void main(String[] argv) throws IOException { if (argv.length != 4) { System.err.println("Usage: IrcSource server port nick #channel"); System.exit(-1); } String server = argv[0]; int port = 0; try { port = Integer.parseInt(argv[1]); } catch (Exception e) { System.err.println("Problem parsing port number: " + argv[1]); System.exit(-1); } String nick = argv[2]; String chan = argv[3]; final IrcSource src = new IrcSource(server, port, nick, chan); new Thread() { public void run() { try { while (true) { System.out.println(src.next()); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }.start(); src.open(); } }