package com.juick.xmpp.s2s; import com.juick.JuickApplication; import com.juick.JuickComponent; import com.juick.User; import com.juick.server.MessagesQueries; import com.juick.server.SubscriptionsQueries; import com.juick.server.UserQueries; import com.juick.xmpp.*; import com.juick.xmpp.extensions.JuickMessage; import com.juick.xmpp.extensions.Nickname; import com.juick.xmpp.extensions.XOOB; import org.springframework.jdbc.core.JdbcTemplate; import java.io.IOException; import java.util.*; import java.util.concurrent.ExecutorService; import java.util.logging.Logger; /** * * @author ugnich */ public class S2SComponent implements JuickComponent { private static final Logger LOGGER = Logger.getLogger(S2SComponent.class.getName()); ExecutorService executorService; public static String HOSTNAME = null; public static String componentName = null; public static String STATSFILE = null; static final List inConnections = Collections.synchronizedList(new ArrayList<>()); static final List outConnections = Collections.synchronizedList(new ArrayList<>()); static final List outCache = Collections.synchronizedList(new ArrayList<>()); JdbcTemplate sql; JuickBot bot; final public static HashMap childParsers = new HashMap<>(); public static void addConnectionIn(ConnectionIn c) { synchronized (inConnections) { inConnections.add(c); } } public static void addConnectionOut(ConnectionOut c) { synchronized (outConnections) { outConnections.add(c); } } public static void removeConnectionIn(ConnectionIn c) { synchronized (inConnections) { inConnections.remove(c); } } public static void removeConnectionOut(ConnectionOut c) { synchronized (outConnections) { outConnections.remove(c); } } public static String getFromCache(String hostname) { CacheEntry ret = null; synchronized (outCache) { for (Iterator i = outCache.iterator(); i.hasNext();) { CacheEntry c = i.next(); if (c.hostname != null && c.hostname.equals(hostname)) { ret = c; i.remove(); break; } } } return (ret != null) ? ret.xml : null; } public static ConnectionOut getConnectionOut(String hostname, boolean needReady) { synchronized (outConnections) { for (ConnectionOut c : outConnections) { if (c.to != null && c.to.equals(hostname) && (!needReady || c.streamReady)) { return c; } } } return null; } public static ConnectionIn getConnectionIn(String streamID) { synchronized (inConnections) { for (ConnectionIn c : inConnections) { if (c.streamID != null && c.streamID.equals(streamID)) { return c; } } } return null; } public void sendOut(Stanza s) { sendOut(s.to.Host, s.toString()); } public void sendOut(String hostname, String xml) { boolean haveAnyConn = false; ConnectionOut connOut = null; synchronized (outConnections) { for (ConnectionOut c : outConnections) { if (c.to != null && c.to.equals(hostname)) { if (c.streamReady) { connOut = c; break; } else { haveAnyConn = true; break; } } } } if (connOut != null) { try { connOut.sendStanza(xml); } catch (IOException e) { LOGGER.warning("STREAM TO " + connOut.to + " " + connOut.streamID + " ERROR: " + e.toString()); } return; } boolean haveCache = false; synchronized (outCache) { for (CacheEntry c : outCache) { if (c.hostname != null && c.hostname.equals(hostname)) { c.xml += xml; c.tsUpdated = System.currentTimeMillis(); haveCache = true; break; } } if (!haveCache) { outCache.add(new CacheEntry(hostname, xml)); } } if (!haveAnyConn) { ConnectionOut connectionOut = new ConnectionOut(hostname); connectionOut.parseStream(); } } public S2SComponent(JuickApplication application, Properties conf) { LOGGER.info("component initialized"); HOSTNAME = conf.getProperty("hostname", "juick.com"); componentName = conf.getProperty("componentname", "s2s"); STATSFILE = conf.getProperty("statsfile"); this.sql = application.getSql(); this.executorService = application.getExecutorService(); this.bot = new JuickBot(application, this); executorService.submit(new ConnectionListener(application, bot)); executorService.submit(new CleaningUp()); } @Override public void messageReceived(Message xmsg) { JID jid = xmsg.to; if (jid.Host.equals(componentName)) { LOGGER.info("STREAM ROUTER (PROCESS): " + xmsg.toString()); JuickMessage jmsg = (JuickMessage) xmsg.getChild(JuickMessage.XMLNS); if (jmsg != null) { if (jid.Username != null && jid.Username.equals("recomm")) { sendJuickRecommendation(jmsg); } else { if (jmsg.getRID() > 0) { sendJuickComment(jmsg); } else if (jmsg.getMID() > 0) { sendJuickMessage(jmsg); } } } } } public void sendJuickMessage(JuickMessage jmsg) { List users; if (jmsg.FriendsOnly) { users = SubscriptionsQueries.getUsersSubscribedToUser(sql, jmsg.getUser().getUID(), jmsg.FriendsOnly); } else { users = SubscriptionsQueries.getSubscribedUsers(sql, jmsg.getUser().getUID(), jmsg.getMID()); } String txt = "@" + jmsg.getUser().getUName() + ":" + jmsg.getTagsString() + "\n"; String attachment = jmsg.getAttachmentURL(); if (attachment != null) { txt += attachment + "\n"; } txt += jmsg.getText() + "\n\n"; txt += "#" + jmsg.getMID() + " http://juick.com/" + jmsg.getMID(); Nickname nick = new Nickname(); nick.Nickname = "@" + jmsg.getUser().getUName(); com.juick.xmpp.Message msg = new com.juick.xmpp.Message(); msg.from = JuickBot.JuickJID; msg.body = txt; msg.type = Message.Type.chat; msg.thread = "juick-" + jmsg.getMID(); msg.addChild(jmsg); msg.addChild(nick); if (attachment != null) { XOOB oob = new XOOB(); oob.URL = attachment; msg.addChild(oob); } for (User user : users) { for (String jid : UserQueries.getActiveJIDs(sql, user)) { msg.to = new JID(jid); sendOut(msg); } } } public void sendJuickComment(JuickMessage jmsg) { String replyQuote; List users = SubscriptionsQueries.getSubscribedUsers(sql, jmsg.getUser().getUID(), jmsg.getMID()); replyQuote = getReplyQuote(sql, jmsg.getMID(), jmsg.ReplyTo); String txt = "Reply by @" + jmsg.getUser().getUName() + ":\n" + replyQuote + "\n"; String attachment = jmsg.getAttachmentURL(); if (attachment != null) { txt += attachment + "\n"; } txt += jmsg.getText() + "\n\n" + "#" + jmsg.getMID() + "/" + jmsg.getRID() + " http://juick.com/" + jmsg.getMID() + "#" + jmsg.getRID(); com.juick.xmpp.Message msg = new com.juick.xmpp.Message(); msg.from = JuickBot.JuickJID; msg.body = txt; msg.type = Message.Type.chat; msg.addChild(jmsg); for (User user : users) { // TODO: make single query for (String jid : UserQueries.getActiveJIDs(sql, user)) { msg.to = new JID(jid); sendOut(msg); } } } private String getReplyQuote(JdbcTemplate sql, int MID, int ReplyTo) { String quote = ""; if (ReplyTo > 0) { com.juick.Message q = MessagesQueries.getReply(sql, MID, ReplyTo); if (q != null) { quote = q.getText(); } } else { com.juick.Message q = MessagesQueries.getMessage(sql, MID); if (q != null) { quote = q.getText(); } } if (quote.length() > 50) { quote = ">" + quote.substring(0, 47).replace('\n', ' ') + "...\n"; } else if (quote.length() > 0) { quote = ">" + quote.replace('\n', ' ') + "\n"; } return quote; } public void sendJuickRecommendation(JuickMessage recomm) { JuickMessage jmsg; jmsg = new JuickMessage(MessagesQueries.getMessage(sql, recomm.getMID())); List users = SubscriptionsQueries.getUsersSubscribedToComments(sql, recomm.getMID(), jmsg.getUser().getUID()); String txt = "Recommended by @" + recomm.getUser().getUName() + ":\n"; txt += "@" + jmsg.getUser().getUName() + ":" + jmsg.getTagsString() + "\n"; String attachment = jmsg.getAttachmentURL(); if (attachment != null) { txt += attachment + "\n"; } txt += jmsg.getText() + "\n\n"; txt += "#" + jmsg.getMID(); if (jmsg.Replies > 0) { if (jmsg.Replies % 10 == 1 && jmsg.Replies % 100 != 11) { txt += " (" + jmsg.Replies + " reply)"; } else { txt += " (" + jmsg.Replies + " replies)"; } } txt += " http://juick.com/" + jmsg.getMID(); Nickname nick = new Nickname(); nick.Nickname = "@" + jmsg.getUser().getUName(); com.juick.xmpp.Message msg = new com.juick.xmpp.Message(); msg.from = JuickBot.JuickJID; msg.body = txt; msg.type = Message.Type.chat; msg.thread = "juick-" + jmsg.getMID(); msg.addChild(jmsg); msg.addChild(nick); if (attachment != null) { XOOB oob = new XOOB(); oob.URL = attachment; msg.addChild(oob); } for (User user : users) { for (String jid : UserQueries.getActiveJIDs(sql, user)) { msg.to = new JID(jid); sendOut(msg); } } } }