Sfoglia il codice sorgente

сохранение состояния юзера, тест клавиатуры

kpmy 8 anni fa
parent
commit
7b6139971c

+ 32 - 0
pom.xml

@@ -57,6 +57,38 @@
             <groupId>org.springframework.statemachine</groupId>
             <artifactId>spring-statemachine-core</artifactId>
             <version>1.2.2.RELEASE</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.springframework.statemachine</groupId>
+                    <artifactId>spring-statemachine-data-common</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.springframework.statemachine</groupId>
+                    <artifactId>spring-statemachine-data-jpa</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.springframework.statemachine</groupId>
+                    <artifactId>spring-statemachine-data-redis</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.springframework.statemachine</groupId>
+                    <artifactId>spring-statemachine-data-mongodb</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-collections4 -->
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-collections4</artifactId>
+            <version>4.1</version>
+        </dependency>
+
+        <!-- https://mvnrepository.com/artifact/commons-beanutils/commons-beanutils -->
+        <dependency>
+            <groupId>commons-beanutils</groupId>
+            <artifactId>commons-beanutils</artifactId>
+            <version>1.9.3</version>
         </dependency>
 
     </dependencies>

+ 0 - 49
src/main/java/in/ocsf/these/days/app/SM.java

@@ -1,49 +0,0 @@
-package in.ocsf.these.days.app;/* kpmy 20.02.2017 */
-
-import in.ocsf.these.days.app.object.ChatEvent;
-import in.ocsf.these.days.app.object.ChatState;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.statemachine.StateMachineContext;
-import org.springframework.statemachine.StateMachinePersist;
-import org.springframework.statemachine.config.EnableStateMachineFactory;
-import org.springframework.statemachine.config.EnumStateMachineConfigurerAdapter;
-import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
-import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
-
-import java.util.EnumSet;
-import java.util.HashMap;
-
-@Configuration
-@EnableStateMachineFactory
-public class SM extends EnumStateMachineConfigurerAdapter<ChatState, ChatEvent> {
-
-    @Override
-    public void configure(StateMachineStateConfigurer<ChatState, ChatEvent> states) throws Exception {
-        states.withStates()
-                .initial(ChatState.unknown)
-                .states(EnumSet.allOf(ChatState.class));
-    }
-
-    @Override
-    public void configure(StateMachineTransitionConfigurer<ChatState, ChatEvent> transitions) throws Exception {
-        transitions.withExternal().source(ChatState.unknown).target(ChatState.newbie).event(ChatEvent.start)
-                .and()
-                .withExternal().source(ChatState.newbie).target(ChatState.client).event(ChatEvent.init);
-    }
-
-    public static class InMemoryStateMachinePersist implements StateMachinePersist<ChatState, ChatEvent, Long> {
-
-        private final HashMap<Long, StateMachineContext<ChatState, ChatEvent>> contexts = new HashMap<>();
-
-        @Override
-        public void write(StateMachineContext<ChatState, ChatEvent> context, Long contextObj) throws Exception {
-            contexts.put(contextObj, context);
-        }
-
-        @Override
-        public StateMachineContext<ChatState, ChatEvent> read(Long contextObj) throws Exception {
-            return contexts.get(contextObj);
-        }
-    }
-
-}

+ 11 - 1
src/main/java/in/ocsf/these/days/app/messaging/ChatHlelper.java → src/main/java/in/ocsf/these/days/app/messaging/ChatHelper.java

@@ -3,10 +3,14 @@ package in.ocsf.these.days.app.messaging;/* kpmy 20.02.2017 */
 import com.pengrad.telegrambot.Callback;
 import com.pengrad.telegrambot.TelegramBot;
 import com.pengrad.telegrambot.TelegramBotAdapter;
+import com.pengrad.telegrambot.model.request.Keyboard;
+import com.pengrad.telegrambot.model.request.ParseMode;
+import com.pengrad.telegrambot.model.request.ReplyKeyboardMarkup;
 import com.pengrad.telegrambot.request.SendMessage;
 import com.pengrad.telegrambot.response.SendResponse;
 import org.apache.log4j.Logger;
 import org.springframework.beans.factory.annotation.Value;
+import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 
 import java.io.IOException;
@@ -15,13 +19,19 @@ import java.util.List;
 import java.util.Optional;
 
 @Service
-public class ChatHlelper {
+public class ChatHelper {
 
     private final Logger log = Logger.getLogger(getClass());
 
     @Value("${these-days.bot.token}")
     private String token;
 
+    @Async
+    public void sendSimpleTextMessage(Long chatId, String text) {
+        Keyboard keyboard = new ReplyKeyboardMarkup(new String[][]{{"пырвет"}});
+        sendMessage(new SendMessage(chatId, text).parseMode(ParseMode.Markdown).replyMarkup(keyboard));
+    }
+
     public Optional<SendResponse> sendMessage(SendMessage request) {
         TelegramBot bot = TelegramBotAdapter.build(token);
         List<SendResponse> responseList = new ArrayList<>();

+ 4 - 0
src/main/java/in/ocsf/these/days/app/messaging/UpdateHelper.java

@@ -21,6 +21,10 @@ public class UpdateHelper {
         return uh;
     }
 
+    public Long getChatId() {
+        return !isEdit() ? inner.message().chat().id() : inner.editedMessage().chat().id();
+    }
+
     public User getUser() {
         return !isEdit() ? inner.message().from() : inner.editedMessage().from();
     }

+ 0 - 5
src/main/java/in/ocsf/these/days/app/object/ChatEvent.java

@@ -1,5 +0,0 @@
-package in.ocsf.these.days.app.object;/* kpmy 20.02.2017 */
-
-public enum ChatEvent {
-    start, init
-}

+ 0 - 5
src/main/java/in/ocsf/these/days/app/object/ChatState.java

@@ -1,5 +0,0 @@
-package in.ocsf.these.days.app.object;/* kpmy 20.02.2017 */
-
-public enum ChatState {
-    unknown, newbie, client
-}

+ 2 - 2
src/main/java/in/ocsf/these/days/app/object/UpdateState.java

@@ -3,10 +3,10 @@ package in.ocsf.these.days.app.object;/* kpmy 19.02.2017 */
 import org.springframework.data.annotation.Id;
 import org.springframework.data.mongodb.core.mapping.Document;
 
-@Document(collection = "handleUpdate-state")
+@Document(collection = "update-state")
 public class UpdateState {
 
-    public static final String defaultId = "last-handleUpdate";
+    public static final String defaultId = "last-update";
 
     @Id
     private String id = defaultId;

+ 12 - 0
src/main/java/in/ocsf/these/days/app/object/User.java

@@ -3,6 +3,8 @@ package in.ocsf.these.days.app.object;/* kpmy 19.02.2017 */
 import org.springframework.data.annotation.Id;
 import org.springframework.data.mongodb.core.mapping.Document;
 
+import java.util.Map;
+
 @Document(collection = "user")
 public class User {
 
@@ -15,6 +17,8 @@ public class User {
 
     private String userName;
 
+    private Map<String, Object> state;
+
     public static User fromUser(com.pengrad.telegrambot.model.User u) {
         User ret = new User();
         ret.id = Long.valueOf(u.id());
@@ -55,4 +59,12 @@ public class User {
     public void setUserName(String userName) {
         this.userName = userName;
     }
+
+    public Map<String, Object> getState() {
+        return state;
+    }
+
+    public void setState(Map<String, Object> state) {
+        this.state = state;
+    }
 }

+ 39 - 0
src/main/java/in/ocsf/these/days/app/service/StateService.java

@@ -0,0 +1,39 @@
+package in.ocsf.these.days.app.service;/* kpmy 20.02.2017 */
+
+import in.ocsf.these.days.app.object.User;
+import in.ocsf.these.days.app.state.UserEvent;
+import in.ocsf.these.days.app.state.UserState;
+import in.ocsf.these.days.app.state.UserStateMachineFactoryConfig;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.statemachine.StateMachine;
+import org.springframework.statemachine.config.StateMachineFactory;
+import org.springframework.statemachine.persist.DefaultStateMachinePersister;
+import org.springframework.statemachine.persist.StateMachinePersister;
+import org.springframework.stereotype.Service;
+
+@Service
+public class StateService {
+
+    @Autowired
+    @Qualifier("userStateMachineFactory")
+    private StateMachineFactory<UserState, UserEvent> userStateMachineFactory;
+
+    public StateMachine<UserState, UserEvent> getStateFor(User user) throws Exception {
+        StateMachinePersister<UserState, UserEvent, User> persist = new DefaultStateMachinePersister<>(new UserStateMachineFactoryConfig.InUserStateMachinePersist());
+
+        StateMachine<UserState, UserEvent> ret = userStateMachineFactory.getStateMachine(Long.toHexString(user.getId()));
+        ret.start();
+
+        if (user.getState() != null)
+            ret = persist.restore(ret, user);
+
+        return ret;
+    }
+
+    public void setStateFor(User user, StateMachine<UserState, UserEvent> state) throws Exception {
+        StateMachinePersister<UserState, UserEvent, User> persist = new DefaultStateMachinePersister<>(new UserStateMachineFactoryConfig.InUserStateMachinePersist());
+
+        persist.persist(state, user);
+    }
+}

+ 13 - 12
src/main/java/in/ocsf/these/days/app/service/UpdateService.java

@@ -1,20 +1,17 @@
 package in.ocsf.these.days.app.service;/* kpmy 19.02.2017 */
 
 import com.pengrad.telegrambot.model.Update;
-import in.ocsf.these.days.app.SM;
+import in.ocsf.these.days.app.messaging.ChatHelper;
 import in.ocsf.these.days.app.messaging.UpdateHelper;
-import in.ocsf.these.days.app.object.ChatEvent;
-import in.ocsf.these.days.app.object.ChatState;
 import in.ocsf.these.days.app.object.User;
 import in.ocsf.these.days.app.repo.CardRepositrory;
 import in.ocsf.these.days.app.repo.MessageRepository;
 import in.ocsf.these.days.app.repo.UserRepository;
+import in.ocsf.these.days.app.state.UserEvent;
+import in.ocsf.these.days.app.state.UserState;
 import org.apache.log4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.statemachine.StateMachine;
-import org.springframework.statemachine.config.StateMachineFactory;
-import org.springframework.statemachine.persist.DefaultStateMachinePersister;
-import org.springframework.statemachine.persist.StateMachinePersister;
 import org.springframework.stereotype.Service;
 
 import java.util.List;
@@ -34,7 +31,10 @@ public class UpdateService {
     private CardRepositrory cardRepo;
 
     @Autowired
-    private StateMachineFactory<ChatState, ChatEvent> stateMachineFactory;
+    private StateService stateService;
+
+    @Autowired
+    private ChatHelper chat;
 
     private void handleUpdate(UpdateHelper upd) throws Exception {
         if (!upd.isEdit()) {
@@ -44,11 +44,12 @@ public class UpdateService {
                     switch (cmd.get(0)) {
                         case "/start":
                             User user = User.fromUser(upd.getUser());
-                            StateMachine<ChatState, ChatEvent> state = stateMachineFactory.getStateMachine(Long.toHexString(user.getId()));
-                            state.start();
-                            StateMachinePersister<ChatState, ChatEvent, Long> persist = new DefaultStateMachinePersister<>(new SM.InMemoryStateMachinePersist());
-                            persist.persist(state, user.getId());
-                            log.info(Long.toHexString(user.getId()));
+                            StateMachine<UserState, UserEvent> state = stateService.getStateFor(user);
+                            if (state.getState().getId().equals(UserState.unknown)) {
+                                stateService.setStateFor(user, state);
+                                chat.sendSimpleTextMessage(upd.getChatId(), "дратути...");
+                                userRepo.save(user);
+                            }
                             break;
                     }
                 } else {

+ 27 - 0
src/main/java/in/ocsf/these/days/app/state/BeanMapPersist.java

@@ -0,0 +1,27 @@
+package in.ocsf.these.days.app.state;/* kpmy 20.02.2017 */
+
+import org.apache.commons.beanutils.BeanMap;
+import org.springframework.statemachine.StateMachineContext;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public interface BeanMapPersist {
+
+    default Map<String, Object> toMap(StateMachineContext context) throws Exception {
+        Map<String, Object> data = new HashMap<>(new BeanMap(context));
+        data.replace("class", ((Class) data.get("class")).getCanonicalName());
+        return data;
+    }
+
+    default StateMachineContext fromMap(Map<String, Object> data) throws Exception {
+        if (data != null) {
+            data.replace("class", Class.forName((String) data.get("class")));
+            BeanMap beanMap = new BeanMap();
+            beanMap.putAll(data);
+            return (StateMachineContext) beanMap.getBean();
+        } else {
+            return null;
+        }
+    }
+}

+ 5 - 0
src/main/java/in/ocsf/these/days/app/state/UserEvent.java

@@ -0,0 +1,5 @@
+package in.ocsf.these.days.app.state;/* kpmy 20.02.2017 */
+
+public enum UserEvent {
+    start, init
+}

+ 5 - 0
src/main/java/in/ocsf/these/days/app/state/UserState.java

@@ -0,0 +1,5 @@
+package in.ocsf.these.days.app.state;/* kpmy 20.02.2017 */
+
+public enum UserState {
+    unknown, newbie, client
+}

+ 45 - 0
src/main/java/in/ocsf/these/days/app/state/UserStateMachineFactoryConfig.java

@@ -0,0 +1,45 @@
+package in.ocsf.these.days.app.state;/* kpmy 20.02.2017 */
+
+import in.ocsf.these.days.app.object.User;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.statemachine.StateMachineContext;
+import org.springframework.statemachine.StateMachinePersist;
+import org.springframework.statemachine.config.EnableStateMachineFactory;
+import org.springframework.statemachine.config.EnumStateMachineConfigurerAdapter;
+import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
+import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
+
+import java.util.EnumSet;
+
+@Configuration
+@EnableStateMachineFactory(name = "userStateMachineFactory")
+public class UserStateMachineFactoryConfig extends EnumStateMachineConfigurerAdapter<UserState, UserEvent> {
+
+    @Override
+    public void configure(StateMachineStateConfigurer<UserState, UserEvent> states) throws Exception {
+        states.withStates()
+                .initial(UserState.unknown)
+                .states(EnumSet.allOf(UserState.class));
+    }
+
+    @Override
+    public void configure(StateMachineTransitionConfigurer<UserState, UserEvent> transitions) throws Exception {
+        transitions.withExternal().source(UserState.unknown).target(UserState.newbie).event(UserEvent.start)
+                .and()
+                .withExternal().source(UserState.newbie).target(UserState.client).event(UserEvent.init);
+    }
+
+    public static class InUserStateMachinePersist implements StateMachinePersist<UserState, UserEvent, User>, BeanMapPersist {
+
+        @Override
+        public void write(StateMachineContext<UserState, UserEvent> context, User user) throws Exception {
+            user.setState(toMap(context));
+        }
+
+        @Override
+        public StateMachineContext<UserState, UserEvent> read(User user) throws Exception {
+            return fromMap(user.getState());
+        }
+    }
+
+}

+ 5 - 0
src/main/java/in/ocsf/these/days/app/state/WelcomeChatEvent.java

@@ -0,0 +1,5 @@
+package in.ocsf.these.days.app.state;/* kpmy 20.02.2017 */
+
+public enum WelcomeChatEvent {
+    reply
+}

+ 5 - 0
src/main/java/in/ocsf/these/days/app/state/WelcomeChatState.java

@@ -0,0 +1,5 @@
+package in.ocsf.these.days.app.state;/* kpmy 20.02.2017 */
+
+public enum WelcomeChatState {
+    hello, goodbye
+}

+ 24 - 0
src/main/java/in/ocsf/these/days/app/state/WelcomeChatStateMachineFactoryConfig.java

@@ -0,0 +1,24 @@
+package in.ocsf.these.days.app.state;/* kpmy 20.02.2017 */
+
+import org.springframework.statemachine.config.EnumStateMachineConfigurerAdapter;
+import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
+import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
+
+import java.util.EnumSet;
+
+//@Configuration
+//@EnableStateMachineFactory(name = "welcomeChatStateMachineFactory")
+public class WelcomeChatStateMachineFactoryConfig extends EnumStateMachineConfigurerAdapter<WelcomeChatState, WelcomeChatEvent> {
+
+    @Override
+    public void configure(StateMachineStateConfigurer<WelcomeChatState, WelcomeChatEvent> states) throws Exception {
+        states.withStates()
+                .initial(WelcomeChatState.hello)
+                .states(EnumSet.allOf(WelcomeChatState.class));
+    }
+
+    @Override
+    public void configure(StateMachineTransitionConfigurer<WelcomeChatState, WelcomeChatEvent> transitions) throws Exception {
+        transitions.withExternal().source(WelcomeChatState.hello).target(WelcomeChatState.goodbye).event(WelcomeChatEvent.reply);
+    }
+}