From b75258ee5ed84510579050b5dba1edb904a09dfa Mon Sep 17 00:00:00 2001 From: Vitaly Takmazov Date: Sat, 12 Nov 2016 21:39:19 +0300 Subject: initial babbler-based xmpp bot --- .../com/juick/server/protocol/JuickProtocol.java | 6 +- juick-xmpp-bot/build.gradle | 33 ++++++++ .../main/java/com/juick/components/XMPPBot.java | 91 +++++++++++++++++++++ .../configuration/BotAppConfiguration.java | 38 +++++++++ .../components/configuration/BotInitializer.java | 40 +++++++++ .../configuration/BotMvcConfiguration.java | 33 ++++++++ .../components/controllers/StatusController.java | 30 +++++++ juick-xmpp-bot/src/main/resources/vCard.png | Bin 0 -> 5558 bytes settings.gradle | 2 +- 9 files changed, 269 insertions(+), 4 deletions(-) create mode 100644 juick-xmpp-bot/build.gradle create mode 100644 juick-xmpp-bot/src/main/java/com/juick/components/XMPPBot.java create mode 100644 juick-xmpp-bot/src/main/java/com/juick/components/configuration/BotAppConfiguration.java create mode 100644 juick-xmpp-bot/src/main/java/com/juick/components/configuration/BotInitializer.java create mode 100644 juick-xmpp-bot/src/main/java/com/juick/components/configuration/BotMvcConfiguration.java create mode 100644 juick-xmpp-bot/src/main/java/com/juick/components/controllers/StatusController.java create mode 100644 juick-xmpp-bot/src/main/resources/vCard.png diff --git a/juick-core/src/main/java/com/juick/server/protocol/JuickProtocol.java b/juick-core/src/main/java/com/juick/server/protocol/JuickProtocol.java index aff8010a..5faddd3a 100644 --- a/juick-core/src/main/java/com/juick/server/protocol/JuickProtocol.java +++ b/juick-core/src/main/java/com/juick/server/protocol/JuickProtocol.java @@ -1,12 +1,12 @@ package com.juick.server.protocol; -import com.juick.*; import com.juick.Message; +import com.juick.Tag; +import com.juick.User; import com.juick.formatters.PlainTextFormatter; import com.juick.json.MessageSerializer; import com.juick.server.*; import com.juick.server.protocol.annotation.UserCommand; -import com.juick.xmpp.*; import com.juick.xmpp.extensions.JuickMessage; import org.springframework.jdbc.core.JdbcTemplate; @@ -449,7 +449,7 @@ public class JuickProtocol { @UserCommand(pattern = "^\\s*help\\s*$", patternFlags = Pattern.CASE_INSENSITIVE, help = "HELP - returns this help message") public ProtocolReply commandHelp(User user, String[] input) { - List commandsHelp = Arrays.asList(getClass().getDeclaredMethods()).stream() + List commandsHelp = Arrays.stream(getClass().getDeclaredMethods()) .filter(m -> m.isAnnotationPresent(UserCommand.class)) .map(m -> m.getAnnotation(UserCommand.class).help()) .collect(Collectors.toList()); diff --git a/juick-xmpp-bot/build.gradle b/juick-xmpp-bot/build.gradle new file mode 100644 index 00000000..2950d081 --- /dev/null +++ b/juick-xmpp-bot/build.gradle @@ -0,0 +1,33 @@ +apply plugin: 'java' +apply plugin: 'war' +apply plugin: 'org.akhikhl.gretty' +apply plugin: 'com.github.ben-manes.versions' + +repositories { + mavenCentral() + maven { url "https://jitpack.io" } +} + +def springFrameworkVersion = '4.3.4.RELEASE' + +dependencies { + compile project(':juick-core') + compile "org.springframework:spring-webmvc:${springFrameworkVersion}" + compile 'com.mitchellbosecke:pebble-spring4:2.2.3' + compile 'org.bitbucket.sco0ter.babbler:xmpp-core-client:279e488e51' + compile 'org.bitbucket.sco0ter.babbler:xmpp-extensions-client:279e488e51' + providedRuntime 'mysql:mysql-connector-java:5.1.40' +} + +compileJava.options.encoding = 'UTF-8' + +gretty { + httpPort = 8080 + contextPath = '' + servletContainer = 'tomcat8' +} + +configurations { + all*.exclude module: 'commons-logging' +} + diff --git a/juick-xmpp-bot/src/main/java/com/juick/components/XMPPBot.java b/juick-xmpp-bot/src/main/java/com/juick/components/XMPPBot.java new file mode 100644 index 00000000..c95c94e3 --- /dev/null +++ b/juick-xmpp-bot/src/main/java/com/juick/components/XMPPBot.java @@ -0,0 +1,91 @@ +package com.juick.components; + +import com.juick.User; +import com.juick.server.UserQueries; +import com.juick.server.helpers.UserInfo; +import com.juick.server.protocol.JuickProtocol; +import com.juick.server.protocol.ProtocolReply; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.math.NumberUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.env.Environment; +import org.springframework.jdbc.core.JdbcTemplate; +import rocks.xmpp.addr.Jid; +import rocks.xmpp.core.XmppException; +import rocks.xmpp.core.stanza.model.Message; +import rocks.xmpp.extensions.component.accept.ExternalComponent; +import rocks.xmpp.extensions.vcard.temp.VCardManager; +import rocks.xmpp.extensions.vcard.temp.model.VCard; +import rocks.xmpp.extensions.version.SoftwareVersionManager; +import rocks.xmpp.extensions.version.model.SoftwareVersion; + +import javax.inject.Inject; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.net.URL; + +/** + * Created by vt on 12/11/2016. + */ +public class XMPPBot { + private static final Logger logger = LoggerFactory.getLogger(XMPPBot.class); + @Inject + JdbcTemplate jdbc; + + public XMPPBot(Environment env) { + ExternalComponent component = ExternalComponent.create(env.getProperty("component_name", "juick.com"), + env.getProperty("component_password", "secret"), env.getProperty("component_host", "localhost"), + NumberUtils.toInt(env.getProperty("component_port", "5347"), 5347)); + Jid juickJid = Jid.of(env.getProperty("xmppbot_jid", "juick@juick.com/Juick")); + try { + SoftwareVersionManager softwareVersionManager = component.getManager(SoftwareVersionManager.class); + softwareVersionManager.setSoftwareVersion(new SoftwareVersion("Juick", "git", System.getProperty("os.name", "generic"))); + VCardManager vCardManager = component.getManager(VCardManager.class); + vCardManager.setEnabled(true); + VCard ownVCard = new VCard(); + ownVCard.setNickname("Juick"); + ownVCard.setUrl(new URL("http://juick.com/")); + ownVCard.setPhoto(new VCard.Image("image/png", IOUtils.toByteArray(getClass().getClassLoader().getResourceAsStream("vCard.png")))); + vCardManager.setVCard(ownVCard); + JuickProtocol protocol = new JuickProtocol(jdbc, "http://juick.com/"); + component.addInboundMessageListener(e -> { + Message message = e.getMessage(); + if (message.getType().equals(Message.Type.ERROR) || message.getType().equals(Message.Type.GROUPCHAT)) { + return; + } + String text = message.getBody().trim(); + String command = text.toUpperCase(); + User user = UserQueries.getUserByJID(jdbc, message.getFrom().asBareJid().toString()); + if (command.equals("VCARD")) { + try { + VCard vCard = vCardManager.getVCard(message.getFrom().asBareJid()).getResult(); + UserInfo info = new UserInfo(); + info.setFullName(vCard.getFormattedName()); + info.setCountry(vCard.getAddresses().get(0).getCountry()); + info.setUrl(vCard.getUrl().toString()); + UserQueries.updateUserInfo(jdbc, user, info); + component.sendMessage(new Message(message.getFrom(), Message.Type.CHAT, "vCard updated")); + } catch (XmppException vce) { + logger.warn("vcard exception", vce); + } + } else { + try { + ProtocolReply reply = protocol.getReply(user, text); + Message replyMessage = new Message(message.getFrom(), Message.Type.CHAT); + replyMessage.setBody(reply.getDescription()); + replyMessage.setFrom(juickJid); + component.send(replyMessage); + } catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException ex) { + logger.warn("unhandled error", ex); + } + } + }); + component.connect(); + } catch (XmppException e) { + logger.error("bot connection error", e); + } catch (IOException e) { + logger.error("bot initialization error", e); + } + } +} diff --git a/juick-xmpp-bot/src/main/java/com/juick/components/configuration/BotAppConfiguration.java b/juick-xmpp-bot/src/main/java/com/juick/components/configuration/BotAppConfiguration.java new file mode 100644 index 00000000..8eb45170 --- /dev/null +++ b/juick-xmpp-bot/src/main/java/com/juick/components/configuration/BotAppConfiguration.java @@ -0,0 +1,38 @@ +package com.juick.components.configuration; + +import com.juick.components.XMPPBot; +import com.juick.configuration.DataConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.context.annotation.PropertySource; +import org.springframework.core.env.Environment; +import org.springframework.jdbc.core.JdbcTemplate; + +import javax.inject.Inject; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * Created by aalexeev on 11/12/16. + */ +@Configuration +@PropertySource("classpath:juick.conf") +@Import(DataConfiguration.class) +public class BotAppConfiguration { + @Inject + private Environment env; + @Inject + private JdbcTemplate jdbc; + + @Bean + public XMPPBot xmpp() { + return new XMPPBot(env); + } + + @Bean + public ExecutorService service() { + return Executors.newCachedThreadPool(); + } + +} diff --git a/juick-xmpp-bot/src/main/java/com/juick/components/configuration/BotInitializer.java b/juick-xmpp-bot/src/main/java/com/juick/components/configuration/BotInitializer.java new file mode 100644 index 00000000..1b8dd249 --- /dev/null +++ b/juick-xmpp-bot/src/main/java/com/juick/components/configuration/BotInitializer.java @@ -0,0 +1,40 @@ +package com.juick.components.configuration; + +import com.juick.configuration.DataConfiguration; +import org.springframework.web.filter.CharacterEncodingFilter; +import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; + +import javax.servlet.Filter; + +/** + * Created by vt on 09/02/16. + */ +public class BotInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { + + @Override + protected Class[] getRootConfigClasses() { + return new Class[]{BotAppConfiguration.class, DataConfiguration.class}; + } + + @Override + protected Class[] getServletConfigClasses() { + return new Class[]{BotMvcConfiguration.class}; + } + + @Override + protected String[] getServletMappings() { + return new String[]{"/"}; + } + + @Override + protected Filter[] getServletFilters() { + CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter(); + characterEncodingFilter.setEncoding("UTF-8"); + return new Filter[]{characterEncodingFilter}; + } + + @Override + protected String getServletName() { + return "Bot dispatcher servlet"; + } +} diff --git a/juick-xmpp-bot/src/main/java/com/juick/components/configuration/BotMvcConfiguration.java b/juick-xmpp-bot/src/main/java/com/juick/components/configuration/BotMvcConfiguration.java new file mode 100644 index 00000000..2c55c0ce --- /dev/null +++ b/juick-xmpp-bot/src/main/java/com/juick/components/configuration/BotMvcConfiguration.java @@ -0,0 +1,33 @@ +package com.juick.components.configuration; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; + +import java.util.List; + +/** + * Created by vitalyster on 28.06.2016. + */ +@Configuration +@ComponentScan(basePackages = {"com.juick.components.controllers"}) +public class BotMvcConfiguration extends WebMvcConfigurationSupport { + + @Override + protected void configureMessageConverters(List> converters) { + Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder() + .serializationInclusion(JsonInclude.Include.NON_DEFAULT) + .serializationInclusion(JsonInclude.Include.NON_NULL) + .serializationInclusion(JsonInclude.Include.NON_ABSENT) + .serializationInclusion(JsonInclude.Include.NON_EMPTY); + MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(builder.build()); + converter.getObjectMapper().registerModule(new Jdk8Module()); + converters.add(converter); + super.configureMessageConverters(converters); + } +} diff --git a/juick-xmpp-bot/src/main/java/com/juick/components/controllers/StatusController.java b/juick-xmpp-bot/src/main/java/com/juick/components/controllers/StatusController.java new file mode 100644 index 00000000..d30a906d --- /dev/null +++ b/juick-xmpp-bot/src/main/java/com/juick/components/controllers/StatusController.java @@ -0,0 +1,30 @@ +package com.juick.components.controllers; + +import com.juick.components.XMPPBot; +import com.juick.server.helpers.Status; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; + +import javax.inject.Inject; + +/** + * Created by vitalyster on 24.10.2016. + */ +@Controller +@ResponseBody +public class StatusController { + @Inject + XMPPBot xmpp; + + @RequestMapping(method = RequestMethod.GET, value = "/", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + public Status status() { + if (xmpp != null) { + String status = "OK"; + return new Status(status); + } + return new Status("Error"); + } +} diff --git a/juick-xmpp-bot/src/main/resources/vCard.png b/juick-xmpp-bot/src/main/resources/vCard.png new file mode 100644 index 00000000..5ed5336a Binary files /dev/null and b/juick-xmpp-bot/src/main/resources/vCard.png differ diff --git a/settings.gradle b/settings.gradle index 78a7c7de..96d89576 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1 @@ -include ':deps:com.juick.xmpp', ':juick-core', ':juick-api', ':juick-www', ':juick-rss', ':juick-ws', ':juick-demo', ':juick-notifications', ':juick-crosspost', ':juick-xmpp', ':juick-xmpp-ft' +include ':deps:com.juick.xmpp', ':juick-core', ':juick-api', ':juick-www', ':juick-rss', ':juick-ws', ':juick-demo', ':juick-notifications', ':juick-crosspost', ':juick-xmpp', ':juick-xmpp-ft', ':juick-xmpp-bot' -- cgit v1.2.3