From 876f07840f6fa73e6f2ca0350d4ca8922c869075 Mon Sep 17 00:00:00 2001 From: Vitaly Takmazov Date: Wed, 14 Mar 2018 09:12:53 +0300 Subject: reorganize project structure --- .../com/juick/server/protocol/JuickProtocol.java | 188 +++++++++++++++++++++ .../juick/server/protocol/ProtocolListener.java | 30 ++++ .../server/protocol/annotation/UserCommand.java | 50 ++++++ .../xmpp/core/session/debug/LogbackDebugger.java | 57 +++++++ 4 files changed, 325 insertions(+) create mode 100644 juick-server-web/src/main/java/com/juick/server/protocol/JuickProtocol.java create mode 100644 juick-server-web/src/main/java/com/juick/server/protocol/ProtocolListener.java create mode 100644 juick-server-web/src/main/java/com/juick/server/protocol/annotation/UserCommand.java create mode 100644 juick-server-web/src/main/java/rocks/xmpp/core/session/debug/LogbackDebugger.java (limited to 'juick-server-web/src') diff --git a/juick-server-web/src/main/java/com/juick/server/protocol/JuickProtocol.java b/juick-server-web/src/main/java/com/juick/server/protocol/JuickProtocol.java new file mode 100644 index 00000000..1be34a3f --- /dev/null +++ b/juick-server-web/src/main/java/com/juick/server/protocol/JuickProtocol.java @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2008-2017, Juick + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.juick.server.protocol; + +import com.juick.Message; +import com.juick.Tag; +import com.juick.User; +import com.juick.formatters.PlainTextFormatter; +import com.juick.server.protocol.annotation.UserCommand; +import com.juick.server.util.TagUtils; +import com.juick.service.*; +import org.apache.commons.lang3.math.NumberUtils; +import org.apache.commons.lang3.reflect.MethodUtils; + +import javax.inject.Inject; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +/** + * Created by oxpa on 22.03.16. + */ + +public class JuickProtocol { + + private String baseUri; + private ProtocolListener listener; + + @Inject + UserService userService; + @Inject + TagService tagService; + @Inject + MessagesService messagesService; + @Inject + SubscriptionService subscriptionService; + @Inject + PMQueriesService pmQueriesService; + @Inject + PrivacyQueriesService privacyQueriesService; + @Inject + ShowQueriesService showQueriesService; + + public JuickProtocol(String baseUri) { + this.baseUri = baseUri; + } + + /** + * find command by pattern and invoke + * @param user who send command + * @param userInput given by user + * @return command result + * @throws InvocationTargetException + * @throws IllegalAccessException + * @throws NoSuchMethodException + */ + public String getReply(User user, String userInput) throws InvocationTargetException, + IllegalAccessException, NoSuchMethodException { + Optional cmd = MethodUtils.getMethodsListWithAnnotation(getClass(), UserCommand.class).stream() + .filter(m -> Pattern.compile(m.getAnnotation(UserCommand.class).pattern(), + m.getAnnotation(UserCommand.class).patternFlags()).matcher(userInput).matches()) + .findFirst(); + if (!cmd.isPresent()) { + // default command - post as new message + return postMessage(user, userInput.trim()); + } else { + Matcher matcher = Pattern.compile(cmd.get().getAnnotation(UserCommand.class).pattern(), + cmd.get().getAnnotation(UserCommand.class).patternFlags()).matcher(userInput.trim()); + List groups = new ArrayList<>(); + while (matcher.find()) { + for (int i = 1; i <= matcher.groupCount(); i++) { + groups.add(matcher.group(i)); + } + } + return (String) getClass().getMethod(cmd.get().getName(), User.class, String[].class) + .invoke(this, user, groups.toArray(new String[groups.size()])); + } + } + + public String postMessage(User user, String input) { + List tags = tagService.fromString(input, false); + String body = input.substring(TagUtils.toString(tags).length()); + int mid = messagesService.createMessage(user.getUid(), body, null, tags); + subscriptionService.subscribeMessage(mid, user.getUid()); + listener.messagePosted(messagesService.getMessage(mid)); + return "New message posted.\n#" + mid + " " + baseUri + mid; + } + + + + + @UserCommand(pattern = "^d\\s*\\#([0-9]+)$", patternFlags = Pattern.CASE_INSENSITIVE, + help = "D #12345 - delete the message") + public String commandDel(User user, String... args) { + int mid = NumberUtils.toInt(args[0], 0); + if (messagesService.deleteMessage(user.getUid(), mid)) { + return String.format("Message %s deleted", mid); + } + return "Error"; + } + + + @UserCommand(pattern = "^(#+)$", help = "# - Show last messages from your feed (## - second page, ...)") + public String commandMyFeed(User user, String... arguments) { + // number of # is the page count + int page = arguments[0].length() - 1; + List mids = messagesService.getMyFeed(user.getUid(), page, false); + List messages = messagesService.getMessages(mids); + // TODO: add instructions for empty feed + return "Your feed: \n" + String.join("\n", + messages.stream().map(PlainTextFormatter::formatPost).collect(Collectors.toList())); + } + @UserCommand(pattern = "^(#|\\.)(\\d+)((\\.|\\-|\\/)(\\d+))?\\s([\\s\\S]+)", + help = "#1234 *tag *tag2 - edit tags\n#1234 text - reply to message") + public String EditOrReply(User user, String... args) { + int mid = NumberUtils.toInt(args[1]); + int rid = NumberUtils.toInt(args[4], 0); + String txt = args[5]; + List messageTags = tagService.fromString(txt, true); + if (messageTags.size() > 0) { + if (user.getUid() != messagesService.getMessageAuthor(mid).getUid()) { + return "It is not your message"; + } + tagService.updateTags(mid, messageTags); + return "Tags are updated"; + } else { + int newrid = messagesService.createReply(mid, rid, user.getUid(), txt, null); + listener.messagePosted(messagesService.getReply(mid, newrid)); + return "Reply posted.\n#" + mid + "/" + newrid + " " + + baseUri + mid + "#" + newrid; + } + } + + + @UserCommand(pattern = "^(s|u)\\s+\\@(\\S+)$", help = "S @user - subscribe to user's posts", + patternFlags = Pattern.CASE_INSENSITIVE) + public String commandSubscribeUser(User user, String... args) { + boolean subscribe = args[0].equalsIgnoreCase("s"); + User toUser = userService.getUserByName(args[1]); + if (toUser.getUid() > 0) { + if (subscribe) { + if (subscriptionService.subscribeUser(user, toUser)) { + listener.userSubscribed(user, toUser); + return "Subscribed"; + // TODO: already subscribed case + } + } else { + if (subscriptionService.unSubscribeUser(user, toUser)) { + return "Unsubscribed from @" + toUser.getName(); + } + return "You was not subscribed to @" + toUser.getName(); + } + } + return "Error"; + } + + public String getBaseUri() { + return baseUri; + } + + public ProtocolListener getListener() { + return listener; + } + + public void setListener(ProtocolListener listener) { + this.listener = listener; + } +} diff --git a/juick-server-web/src/main/java/com/juick/server/protocol/ProtocolListener.java b/juick-server-web/src/main/java/com/juick/server/protocol/ProtocolListener.java new file mode 100644 index 00000000..f051e6d0 --- /dev/null +++ b/juick-server-web/src/main/java/com/juick/server/protocol/ProtocolListener.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2008-2017, Juick + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.juick.server.protocol; + +import com.juick.Message; +import com.juick.User; + +/** + * Created by vitalyster on 19.12.2016. + */ +public interface ProtocolListener { + void privateMessage(User from, User to, String body); + void userSubscribed(User from, User to); + void messagePosted(Message msg); +} diff --git a/juick-server-web/src/main/java/com/juick/server/protocol/annotation/UserCommand.java b/juick-server-web/src/main/java/com/juick/server/protocol/annotation/UserCommand.java new file mode 100644 index 00000000..ab37a4e1 --- /dev/null +++ b/juick-server-web/src/main/java/com/juick/server/protocol/annotation/UserCommand.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2008-2017, Juick + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.juick.server.protocol.annotation; + +import org.apache.commons.lang3.StringUtils; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Created by oxpa on 22.03.16. + */ +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface UserCommand { + /** + * + * @return a command pattern + */ + String pattern() default StringUtils.EMPTY; + + /** + * + * @return pattern flags + */ + int patternFlags() default 0; + + /** + * + * @return a string used in HELP command output. Basically, only 1 string + */ + String help() default StringUtils.EMPTY; +} diff --git a/juick-server-web/src/main/java/rocks/xmpp/core/session/debug/LogbackDebugger.java b/juick-server-web/src/main/java/rocks/xmpp/core/session/debug/LogbackDebugger.java new file mode 100644 index 00000000..bbf35996 --- /dev/null +++ b/juick-server-web/src/main/java/rocks/xmpp/core/session/debug/LogbackDebugger.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2008-2017, Juick + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package rocks.xmpp.core.session.debug; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import rocks.xmpp.core.session.XmppSession; + +import java.io.InputStream; +import java.io.OutputStream; + +/** + * Created by vitalyster on 17.11.2016. + */ +public class LogbackDebugger implements XmppDebugger { + private Logger logger; + + @Override + public void initialize(XmppSession xmppSession) { + logger = LoggerFactory.getLogger(xmppSession.getClass()); + } + + @Override + public void writeStanza(String s, Object o) { + logger.debug("OUT: {}", s); + } + + @Override + public void readStanza(String s, Object o) { + logger.debug("IN: {}", s); + } + + @Override + public OutputStream createOutputStream(OutputStream outputStream) { + return outputStream; + } + + @Override + public InputStream createInputStream(InputStream inputStream) { + return inputStream; + } +} -- cgit v1.2.3