Clojure newbie - переписывание кода Java на Clojure
У меня есть простой рабочий код Java, который использует библиотеку SMACK xmmp, которая отвечает на входящие сообщения и принимает приглашения в многопользовательский чат. Я пытаюсь преобразовать это clojure. бот входит в систему, но не отвечает на сообщения.
public class bot {
public static void main(String[] args) {
System.out.println("Starting session...");
try {
String server = "chat.hipchat.com";
XMPPConnection con = new XMPPConnection(server);
con.connect();
String username = "username";
String password = "password";
con.login(username, password,"bot");
System.out.println("Connected");
ChatManager chatManager = con.getChatManager();
final MyMessageListener messageListener = new MyMessageListener();
ChatManagerListener chatManagerListener = new ChatManagerListener() {
public void chatCreated(Chat chat, boolean createdLocally) {
chat.addMessageListener(messageListener);
}
};
chatManager.addChatListener(chatManagerListener);
MultiUserChat.addInvitationListener(con, new InvitationListener() {
public void invitationReceived(XMPPConnection con,
String room, String arg2, String arg3, String arg4,
Message arg5) {
MultiUserChat muc2 = new MultiUserChat(con, room);
try {
muc2.join("Bot");
} catch (XMPPException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
// Thread.currentThread();
Thread.sleep(10000);
// Disconnect from the server
con.disconnect();
} catch (XMPPException e) {
e.printStackTrace();
}
catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Ended session...");
}
}
public class MyMessageListener implements MessageListener {
public void processMessage(Chat chat, Message message) {
System.out.println("Received message: " + message.getBody());
try {
chat.sendMessage("Smack> Message sent via API.");
} catch (XMPPException e) {
e.printStackTrace();
}
}
}
(ns mybot.core
(:import [org.jivesoftware.smack
Chat ChatManager MessageListener ChatManagerListener XMPPConnection XMPPException]
[org.jivesoftware.smack.packet
Message Presence]
[org.jivesoftware.smackx.muc InvitationListener MultiUserChat] ))
(def con (XMPPConnection. "chat.hipchat.com"))
(defrecord MyMessageListener []
MessageListener
(processMessage [this chat message] ( println "Received Message" )))
(def myMessageListner ( MyMessageListener. ))
(defn add-chatManagerListener
[connection]
(println "Adding a chat manager lister")
(.addChatListener (.getChatManager connection)
(proxy [ChatManagerListener] []
(chatCreated [chat locally]
(.addMessageListner chat myMessageListner )
)
)))
(defn -main [& args]
(println "Starting bot")
(.connect con)
(.login con "username" "pwd" "bot")
(println (.isAuthenticated con))
(add-chatManagerListener con))
2 ответа
Хотя это не то, что вы просите, я бы порекомендовал использовать для этого библиотеку.
Бесстыдный плагин, есть clj-xmpp, из которого я сделал форк https://github.com/slipset/xmpp-clj/ который, вероятно, отвечает вашим потребностям.
Я настоятельно рекомендую не использовать (def ...)
поддерживать глобальное состояние, если вам не нужно. Это всегда неприятные последствия. Но, возможно, это какой-то личный вкус.
Записи в Clojure используются в качестве компонентов, и я уверен, что вы не сможете использовать их для реализации методов на интерфейсах. Определение таково: (defrecord name [& fields] & opts+specs)
где fields
список имен полей, а не имен методов
Для создания экземпляров интерфейсов Java или протоколов Clojure вы должны использовать reify
, proxy
макрос должен использоваться для расширения абстрактных классов или переопределения функций в классах. Но MessageListener
а также ChatManagerListener
являются только интерфейсом, поэтому с моей точки зрения reify
должен быть первым выбором.
Я приложил свою версию вашего источника, но я не смог проверить это правильно, поэтому обращайтесь с осторожностью.
(ns mybot.core
(:import [org.jivesoftware.smack
Chat ChatManager MessageListener ChatManagerListener XMPPConnection XMPPException]
[org.jivesoftware.smack.packet
Message Presence]
[org.jivesoftware.smackx.muc InvitationListener MultiUserChat] ))
(defn connect [host username password]
(doto (XMPPConnection. "chat.hipchat.com")
(.login username password "bot")))
(defn add-listener [connection callback]
(let [chat-manager (.getChatManager connection)
message-listener (reify
MessageListener
(processMessage [_ chat message] (callback chat message))
)
chat-listener (reify
ChatManagerListener
(chatCreated [_ chat _]
(.addMessageListner chat message-listener)))
]
(.addChatListener chat-manager chat-listener)
connection
))
(def -main [& args]
(let [con (connect "chat.hipchat.com" "username" "pwd")]
(println (.isAuthenticated con))
(add-listener con (fn [_ message] (println "Received Message:" message)))
(Thread/sleep 10000)))
Распространенным шаблоном Clojure является передача функций обратного вызова в качестве слушателей, что я и сделал для add-listener
функция. Это обеспечивает хорошее разделение и скрывает все неприятные вещи ОО.