Browse Source

正在输入... 功能完成 (输入指示器)

779513719 5 years ago
parent
commit
7913db5668

+ 9 - 3
jim-common/src/main/java/org/jim/common/ImStatus.java

@@ -41,13 +41,19 @@ public enum ImStatus implements Status{
 	C10022(10022,"online service account is zero!","当前平台部门下没有在线客服,请稍后!"),
 	C10023(
 			10023,"cancel message failed!"
-			,"撤销消息失败,数据格式不正确,请参考:{ 'id':String消息id,'createTime':Long消息创建时间,'from':String来源ID" +
+			,"撤销消息失败,数据格式不正确,请参考:{ 'id':String消息id,'from':String来源ID" +
 			",'msgState':Integer消息状态{0:正常消息,1:撤销消息},'group_id':String群组id仅在chatType为1时需要" +
 			",'chatType':Integer聊天类型{0:未知,1:群聊,2:私聊} }!"
 	),
 	C10024(10024,"ok","消息撤销成功"),
-	C10025(10025,"cancel message failed!","消息撤销失败,当前撤销消息不是您发的消息,不可以被撤销!")
-
+	C10025(10025,"cancel message failed!","消息撤销失败,当前撤销消息不是您发的消息,不可以被撤销!"),
+	C10026(
+			10026,"input indicator failed!"
+					,"输入指示器请求格式不正确,请参考:{ 'from':String来源ID" +
+					",'group_id':String群组id仅在chatType为1时需要" +
+					",'chatType':Integer聊天类型{0:未知,1:群聊,2:私聊} }!"
+	),
+	C10027(10027,"ok","对方正在输入...")
 	;
 
 

+ 8 - 0
jim-common/src/main/java/org/jim/common/packets/Command.java

@@ -167,6 +167,14 @@ public enum Command{
    * <code>COMMAND_GET_MESSAGE_RESP = 20;</code>
    */
   COMMAND_GET_MESSAGE_RESP(20),
+  /**
+   * 输入指示器 请求;
+   */
+  COMMAND_INPUT_POINTER_REQ(21),
+  /**
+   * 输入指示器 响应;
+   */
+  COMMAND_INPUT_POINTER_RESP(22),
   ;
 
   public final int getNumber() {

+ 104 - 0
jim-common/src/main/java/org/jim/common/packets/InputIndicatorReqBody.java

@@ -0,0 +1,104 @@
+package org.jim.common.packets;
+
+/**
+ * @author Darren
+ * @date 2020/2/13 17:58
+ */
+public class InputIndicatorReqBody extends Message {
+
+    /**
+     * 消息发到哪个群组;
+     */
+    private String group_id;
+    /**
+     * 聊天类型;(如公聊、私聊)
+     */
+    private Integer chatType;
+    /**
+     * 发送用户id;
+     */
+    private String from;
+
+    private InputIndicatorReqBody() {
+    }
+
+    private InputIndicatorReqBody(String group_id, Integer chatType, String from) {
+        this.group_id = group_id;
+        this.chatType = chatType;
+        this.from = from;
+    }
+
+    public static InputIndicatorReqBody.Builder newBuilder(){
+        return new InputIndicatorReqBody.Builder();
+    }
+
+    public String getGroup_id() {
+        return group_id;
+    }
+
+    public InputIndicatorReqBody setGroup_id(String group_id) {
+        this.group_id = group_id;
+        return this;
+    }
+
+    public Integer getChatType() {
+        return chatType;
+    }
+
+    public InputIndicatorReqBody setChatType(Integer chatType) {
+        this.chatType = chatType;
+        return this;
+    }
+
+    public String getFrom() {
+        return from;
+    }
+
+    public InputIndicatorReqBody setFrom(String from) {
+        this.from = from;
+        return this;
+    }
+
+    public static class Builder extends Message.Builder<InputIndicatorReqBody,InputIndicatorReqBody.Builder>{
+
+        /**
+         * 消息发到哪个群组;
+         */
+        private String group_id;
+        /**
+         * 聊天类型;(如公聊、私聊)
+         */
+        private Integer chatType;
+        /**
+         * 发送用户id;
+         */
+        private String from;
+
+        public Builder setGroup_id(String group_id) {
+            this.group_id = group_id;
+            return this;
+        }
+
+        public Builder setChatType(Integer chatType) {
+            this.chatType = chatType;
+            return this;
+        }
+
+        public Builder setFrom(String from) {
+            this.from = from;
+            return this;
+        }
+
+        @Override
+        protected Builder getThis() {
+            return this;
+        }
+
+        @Override
+        public InputIndicatorReqBody build() {
+            return new InputIndicatorReqBody(this.group_id, this.chatType, this.from);
+        }
+    }
+
+
+}

+ 6 - 0
jim-parent/pom.xml

@@ -61,6 +61,7 @@
 		<jedis.version>2.7.3</jedis.version>
 		<redisson.version>3.7.0</redisson.version>
 		<j2cache.version>2.3.21-release</j2cache.version>
+		<quartz.version>2.3.0</quartz.version>
 	</properties>
 	<repositories>
 
@@ -266,6 +267,11 @@
 				<artifactId>j2cache-core</artifactId>
 				<version>${j2cache.version}</version>
 			</dependency>
+			<dependency>
+				<groupId>org.quartz-scheduler</groupId>
+				<artifactId>quartz</artifactId>
+				<version>${quartz.version}</version>
+			</dependency>
 		</dependencies>
 	</dependencyManagement>
 	<!-- 插件配置 -->

+ 3 - 1
jim-server/src/main/java/org/jim/server/command/command.properties

@@ -21,4 +21,6 @@
 #\u83B7\u53D6\u7528\u6237\u6D88\u606F\u5904\u7406\u5668
 19 = org.jim.server.command.handler.MessageReqHandler
 #\u64A4\u56DE\u6D88\u606F\u5904\u7406\u5668
-15 = org.jim.server.command.handler.IMCancelMessageHandler,org.jim.server.command.handler.processor.chat.IMCancelMessageProcessor
+15 = org.jim.server.command.handler.IMCancelMessageReqHandler,org.jim.server.command.handler.processor.chat.IMCancelMessageProcessor
+#\u8F93\u5165\u6307\u793A\u5668(\u6B63\u5728\u8F93\u5165...)
+21 =org.jim.server.command.handler.IMInputIndicatorReqHandler

+ 3 - 1
jim-server/src/main/java/org/jim/server/command/handler/CloseReqHandler.java

@@ -31,6 +31,7 @@ public class CloseReqHandler extends AbstractCmdHandler
 
 	private static final String GROUP_PROPERTY = " group_id,name,avatar,service_account_role_department_middle_id,consumer_id,group_type,company_id,department_id ";
 
+	private static final String CURRENT_SYSTEM_ALL_USER_ID = "CURRENT_SYSTEM_ALL_USER_ID";
 
 	static {
 		try {
@@ -67,7 +68,6 @@ public class CloseReqHandler extends AbstractCmdHandler
 								+ VisitTypeEnum.SERVICEACCOUNT.getKey() ;
 						String[] userIdArray = {user.getId()};
 						jedisTemplate.hashDel(serviceAccountContainerKey,userIdArray);
-
 						//判断 客服是否具有查看当前部门下 全部客服通话的权限 如果有移除
 						if( Boolean.valueOf(user.getExtras().getString("hasViewAllServiceAccount")) ){
 							String adminContainerKey = user.getExtras().getString("companyId")
@@ -87,6 +87,7 @@ public class CloseReqHandler extends AbstractCmdHandler
 						//修改 sw_visitor_department_middle 表中的 online状态; '用户状态 1:已下线 0:在线'
 						VisitorDepartmentMiddle.dao.findById(user.getId()).set("online",1).update();
 					}
+					jedisTemplate.listRemove(CURRENT_SYSTEM_ALL_USER_ID,0,user.getId());
 				}
 			}
 			ImAio.remove(channelContext, "收到关闭请求");
@@ -122,6 +123,7 @@ public class CloseReqHandler extends AbstractCmdHandler
 				//修改 sw_visitor_department_middle 表中的 online状态; '用户状态 1:已下线 0:在线'
 				VisitorDepartmentMiddle.dao.findById(user.getId()).set("online",1).update();
 			}
+			jedisTemplate.listRemove(CURRENT_SYSTEM_ALL_USER_ID,0,userId);
 			ImAio.remove(userId, "收到关闭请求!");
 		}
 		return ImKit.ConvertRespPacket(new RespBody(Command.COMMAND_CLOSE_REQ, ImStatus.C10021), channelContext);

+ 6 - 4
jim-server/src/main/java/org/jim/server/command/handler/IMCancelMessageHandler.java

@@ -4,6 +4,7 @@ import org.apache.commons.collections4.CollectionUtils;
 import org.jim.common.ImAio;
 import org.jim.common.ImConst;
 import org.jim.common.ImPacket;
+import org.jim.common.ImStatus;
 import org.jim.common.packets.*;
 import org.jim.server.command.AbstractCmdHandler;
 import org.jim.server.command.handler.processor.chat.IMCancelMessageProcessor;
@@ -19,7 +20,7 @@ import java.util.List;
  * @author Darren
  * @date 2020/2/12 10:00
  */
-public class IMCancelMessageHandler extends AbstractCmdHandler {
+public class IMCancelMessageReqHandler extends AbstractCmdHandler {
 
     @Override
     public Command command() {
@@ -30,11 +31,10 @@ public class IMCancelMessageHandler extends AbstractCmdHandler {
      * 消息撤销处理方法
      * {
      *   'id':String消息id,
-     *   'createTime':Long消息创建时间,
      *   'from':String来源ID,
      *   'msgState':Integer消息状态{0:正常消息,1:撤销消息},
      *   'group_id':String群组id仅在chatType为1时需要,
-     *   'chatType':Integer聊天类型{0:未知,1:群聊,2:私聊
+     *   'chatType':Integer聊天类型{0:未知,1:群聊,2:私聊}
      * }
      * @param packet
      * @param channelContext
@@ -60,7 +60,9 @@ public class IMCancelMessageHandler extends AbstractCmdHandler {
         }
         if( CancelMessageTypeEnum.CANCEL.getKey() == cancelMessageReqBody.getMsgState() ){
             ImPacket respPacket = cancelMessageProcessor.get(0).handler(cancelMessageReqBody,channelContext);
-
+            if( respPacket.getStatus().getCode() == ImStatus.C10025.getCode() ){
+                return respPacket;
+            }
             ImPacket cancelMessagePacket = new ImPacket(Command.COMMAND_CANCEL_MSG_REQ,new RespBody(Command.COMMAND_CANCEL_MSG_REQ, cancelMessageReqBody).toByte());
             cancelMessagePacket.setSynSeq(packet.getSynSeq());
             if(ChatType.CHAT_TYPE_PUBLIC.getNumber() == cancelMessageReqBody.getChatType()){

+ 61 - 0
jim-server/src/main/java/org/jim/server/command/handler/IMInputIndicatorReqHandler.java

@@ -0,0 +1,61 @@
+package org.jim.server.command.handler;
+
+import org.jim.common.ImAio;
+import org.jim.common.ImPacket;
+import org.jim.common.packets.ChatType;
+import org.jim.common.packets.Command;
+import org.jim.common.packets.InputIndicatorReqBody;
+import org.jim.common.packets.RespBody;
+import org.jim.server.command.AbstractCmdHandler;
+import org.jim.server.util.InputIndicatorKit;
+import org.tio.core.Aio;
+import org.tio.core.ChannelContext;
+
+/**
+ * 输入指示器 (正在输入)
+ * @author Darren
+ * @date 2020/2/13 17:47
+ */
+public class IMInputIndicatorReqHandler extends AbstractCmdHandler {
+
+    @Override
+    public Command command() {
+        return Command.COMMAND_INPUT_POINTER_REQ;
+    }
+
+    /**
+     *{
+     *   'from':String来源ID,
+     *   'group_id':String群组id仅在chatType为1时需要,
+     *   'chatType':Integer聊天类型{0:未知,1:群聊,2:私聊}
+     *}
+     * @param packet
+     * @param channelContext
+     * @return {@link {@link ImPacket}}
+     * @author Darren
+     * @date 2020/2/13 20:22
+     */
+    @Override
+    public ImPacket handler(ImPacket packet, ChannelContext channelContext) throws Exception {
+        if( null == packet.getBody() ){
+            Aio.remove(channelContext, "body is null");
+            return null;
+        }
+        InputIndicatorReqBody reqBody = InputIndicatorKit.toInputIndicatorReqBody(packet.getBody());
+        if( reqBody == null ){
+            ImPacket respChatPacket = InputIndicatorKit.dataInCorrectRespPacket(channelContext);
+            return respChatPacket;
+        }
+        ImPacket inputIndicatorPacket = new ImPacket(Command.COMMAND_INPUT_POINTER_REQ,new RespBody(Command.COMMAND_INPUT_POINTER_REQ, reqBody).toByte());
+        inputIndicatorPacket.setSynSeq(packet.getSynSeq());
+        if(ChatType.CHAT_TYPE_PUBLIC.getNumber() == reqBody.getChatType()){
+            String group_id = reqBody.getGroup_id();
+            //告知 群组 对方正在输入
+            ImAio.sendToGroup(group_id, inputIndicatorPacket);
+            //发送成功响应包
+            return InputIndicatorKit.sendSuccessRespPacket(channelContext);
+        }
+        return null;
+    }
+
+}

+ 3 - 4
jim-server/src/main/java/org/jim/server/command/handler/LoginReqHandler.java

@@ -123,13 +123,12 @@ public class LoginReqHandler extends AbstractCmdHandler {
 	private void sendServiceAccountAutoMsg(User user) {
 		log.info("执行自动发送客服设置的消息...");
 		ImServerGroupContext groupContext = (ImServerGroupContext)imConfig.getGroupContext();
-		IMAutoMsgQueueRunnable IMAutoMsgQueueRunnable = new IMAutoMsgQueueRunnable(groupContext.getTimExecutor());
+		IMAutoMsgQueueRunnable iMAutoMsgQueueRunnable = new IMAutoMsgQueueRunnable(groupContext.getTimExecutor());
 		List<Group> groups = user.getGroups();
 		for (Group group : groups) {
-			IMAutoMsgQueueRunnable.addMsg(group);
-			IMAutoMsgQueueRunnable.getExecutor().execute(IMAutoMsgQueueRunnable);
+			iMAutoMsgQueueRunnable.addMsg(group);
+			iMAutoMsgQueueRunnable.getExecutor().execute(iMAutoMsgQueueRunnable);
 		}
-
 	}
 
 	/**

+ 0 - 1
jim-server/src/main/java/org/jim/server/command/handler/UserReqHandler.java

@@ -40,7 +40,6 @@ public class UserReqHandler extends AbstractCmdHandler {
 		RespBody resPacket = null;
 		
 		String userId = userReqBody.getUserid();
-		//TODO
 		System.out.println("执行获取用户信息消息命令处理器... ");
 		if(StringUtils.isEmpty(userId)) {
 			return ImKit.ConvertRespPacket(new RespBody(Command.COMMAND_GET_USER_RESP, ImStatus.C10004), channelContext);

+ 2 - 1
jim-server/src/main/java/org/jim/server/command/handler/processor/chat/IMAutoMessageProcessor.java

@@ -17,6 +17,7 @@ import org.tio.core.ChannelContext;
 import org.tio.utils.lock.SetWithLock;
 
 import java.util.*;
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 /**
@@ -54,7 +55,7 @@ public class IMAutoMessageProcessor implements CmdProcessor, ImConst {
                     needSleepTime -= alreadySleepTime;
                     alreadySleepTime += needSleepTime;
                     try {
-                        Thread.sleep(needSleepTime * 1000);
+                        TimeUnit.SECONDS.sleep(needSleepTime);
                     } catch (InterruptedException e) {
                         log.error("执行自动消息处理方法时,发生错误...");
                         e.printStackTrace();

+ 4 - 5
jim-server/src/main/java/org/jim/server/util/CancelMessageKit.java

@@ -54,10 +54,9 @@ public class CancelMessageKit {
         boolean b1 = StringUtils.isNotEmpty(cancelMessageReqBody.getId());
         boolean b2 = StringUtils.isNotEmpty(cancelMessageReqBody.getGroup_id());
         boolean b3 = StringUtils.isNotEmpty(cancelMessageReqBody.getFrom());
-        boolean b4 = null == cancelMessageReqBody.getMsgState();
-        boolean b5 = null == cancelMessageReqBody.getChatType();
-        boolean b6 = null == cancelMessageReqBody.getCreateTime();
-        return (b1 && b2 && b3 && b4 && b5 && b6);
+        boolean b4 = null != cancelMessageReqBody.getMsgState();
+        boolean b5 = null != cancelMessageReqBody.getChatType();
+        return (b1 && b2 && b3 && b4 && b5);
     }
 
     /**
@@ -89,7 +88,7 @@ public class CancelMessageKit {
     }
 
     /**
-     * 消息数据格式不正确响应包
+     * 消息撤销失败,当前撤销消息不是您发的消息,不可以被撤销!
      * @param channelContext
      * @return imPacket
      * @throws Exception

+ 101 - 0
jim-server/src/main/java/org/jim/server/util/InputIndicatorKit.java

@@ -0,0 +1,101 @@
+package org.jim.server.util;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.log4j.Logger;
+import org.jim.common.ImPacket;
+import org.jim.common.ImStatus;
+import org.jim.common.http.HttpConst;
+import org.jim.common.packets.CancelMessageReqBody;
+import org.jim.common.packets.Command;
+import org.jim.common.packets.InputIndicatorReqBody;
+import org.jim.common.packets.RespBody;
+import org.jim.common.utils.ImKit;
+import org.jim.common.utils.JsonKit;
+import org.tio.core.ChannelContext;
+
+import java.io.UnsupportedEncodingException;
+
+/**
+ * @author Darren
+ * @date 2020/2/13 19:24
+ */
+public class InputIndicatorKit {
+
+    private static Logger log = Logger.getLogger(InputIndicatorKit.class);
+
+    /**
+     * 转换为消息结构;
+     * @param body
+     * @return
+     */
+    public static InputIndicatorReqBody toInputIndicatorReqBody(byte[] body){
+        InputIndicatorReqBody inputIndicatorReqBody = parseInputIndicatorReqBody(body);
+        if( null != inputIndicatorReqBody ){
+            if( validateInputIndicatorReqBody(inputIndicatorReqBody) ){
+                return inputIndicatorReqBody;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 验证消息体中的值
+     * @param inputIndicatorReqBody
+     * @return
+     */
+    private static boolean validateInputIndicatorReqBody(InputIndicatorReqBody inputIndicatorReqBody) {
+        boolean b1 = StringUtils.isNotEmpty(inputIndicatorReqBody.getGroup_id());
+        boolean b2 = StringUtils.isNotEmpty(inputIndicatorReqBody.getFrom());
+        boolean b3 = null != inputIndicatorReqBody.getChatType();
+        return (b1 && b2 && b3);
+    }
+
+    /**
+     * 转换为消息结构;
+     * @param body
+     * @return
+     */
+    private static InputIndicatorReqBody parseInputIndicatorReqBody(byte[] body) {
+        if(body == null) {
+            return null;
+        }
+        InputIndicatorReqBody inputIndicatorReqBody = null;
+        try {
+            String text = new String(body, HttpConst.CHARSET_NAME);
+            inputIndicatorReqBody = JsonKit.toBean(text, InputIndicatorReqBody.class);
+            if( null != inputIndicatorReqBody){
+                return inputIndicatorReqBody;
+            }
+        } catch (UnsupportedEncodingException e) {
+            log.error(e.toString());
+        }
+        return inputIndicatorReqBody;
+    }
+
+    /**
+     * 数据格式不正确响应包
+     * @param channelContext
+     * @return imPacket
+     * @throws Exception
+     */
+    public static ImPacket dataInCorrectRespPacket(ChannelContext channelContext) {
+        RespBody respBody = new RespBody(Command.COMMAND_INPUT_POINTER_RESP, ImStatus.C10026);
+        ImPacket respPacket = ImKit.ConvertRespPacket(respBody, channelContext);
+        respPacket.setStatus(ImStatus.C10026);
+        return respPacket;
+    }
+
+    /**
+     * 成功响应包
+     * @param channelContext
+     * @return
+     * @throws Exception
+     */
+    public static ImPacket sendSuccessRespPacket(ChannelContext channelContext) {
+        RespBody respBody = new RespBody(Command.COMMAND_INPUT_POINTER_RESP,ImStatus.C10027);
+        ImPacket respPacket = ImKit.ConvertRespPacket(respBody, channelContext);
+        respPacket.setStatus(ImStatus.C10027);
+        return respPacket;
+    }
+
+}

+ 5 - 0
server-chat/pom.xml

@@ -53,6 +53,11 @@
             <artifactId>slf4j-log4j12</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>org.quartz-scheduler</groupId>
+            <artifactId>quartz</artifactId>
+        </dependency>
+
     </dependencies>
     <build>
         <plugins>

+ 103 - 1
server-chat/src/main/java/com/cn/ServerChatStart.java

@@ -1,16 +1,36 @@
 package com.cn;
 
 import com.cn.config.PropertyDataBaseConfigBuilder;
+import com.cn.job.PrintWordsJob;
 import com.cn.listener.IMChatGroupListener;
 import com.cn.processor.IMChatWsHandshakeProcessor;
 import com.cn.service.IMChatLoginServiceProcessor;
+import nl.basjes.shaded.org.springframework.util.CollectionUtils;
+import org.jim.common.ImAio;
 import org.jim.common.ImConfig;
+import org.jim.common.ImPacket;
+import org.jim.common.cache.redis.JedisTemplate;
 import org.jim.common.config.PropertyImConfigBuilder;
+import org.jim.common.packets.CloseReqBody;
 import org.jim.common.packets.Command;
 import org.jim.server.ImServerStarter;
 import org.jim.server.command.CommandManager;
+import org.jim.server.command.handler.CloseReqHandler;
 import org.jim.server.command.handler.HandshakeReqHandler;
+import org.jim.server.command.handler.JoinGroupReqHandler;
 import org.jim.server.command.handler.LoginReqHandler;
+import org.quartz.*;
+import org.quartz.impl.StdSchedulerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.tio.core.Aio;
+import org.tio.core.ChannelContext;
+import org.tio.utils.lock.SetWithLock;
+
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
 
 /**
  * @author Darren
@@ -18,6 +38,21 @@ import org.jim.server.command.handler.LoginReqHandler;
  */
 public class ServerChatStart {
 
+    private static JedisTemplate jedisTemplate = null;
+
+    private static Logger logger = LoggerFactory.getLogger(ServerChatStart.class);
+
+    private static final String CURRENT_SYSTEM_ALL_USER_ID = "CURRENT_SYSTEM_ALL_USER_ID";
+
+    static {
+        try {
+            jedisTemplate = JedisTemplate.me();
+        } catch (Exception e) {
+            logger.info("JedisTemplate初始化失败!");
+            e.printStackTrace();
+        }
+    }
+
     /**
      * 项目入口
      * @param args
@@ -46,10 +81,77 @@ public class ServerChatStart {
 
 
         /*****************end *******************************************************************************************/
-
         imServerStarter.start();
+        //initQuartz();
+        initRedisData();
 
     }
 
+    /**
+     * 修改由于程序重启或关闭 而没有 走正常的 关闭请求处理器 的 user
+     * @param
+     * @return {@link }
+     * @author Darren
+     * @date 2020/2/14 12:02
+     */
+    private static void initRedisData(){
+        //修改由于程序重启或关闭 而没有 走正常的 关闭请求处理器 的 user
+        List<String> userIds = jedisTemplate.listGetAll(CURRENT_SYSTEM_ALL_USER_ID);
+        if(!CollectionUtils.isEmpty(userIds)){
+            for (String userId : userIds) {
+                SetWithLock<ChannelContext> channelContexts = ImAio.getChannelContextsByUserId(userId);
+                if( null != channelContexts && channelContexts.size() > 0 ){
+                    //获取读锁
+                    ReadLock readLock = channelContexts.getLock().readLock();
+                    //加锁
+                    readLock.lock();
+                    try {
+                        Set<ChannelContext> channels = channelContexts.getObj();
+                        for (ChannelContext channelContext : channels) {
+                            ImPacket imPacket = new ImPacket(new CloseReqBody(userId).toByte());
+                            CloseReqHandler closeReqHandler = CommandManager.getCommand(Command.COMMAND_CLOSE_REQ, CloseReqHandler.class);
+                            closeReqHandler.handler(imPacket,channelContext);
+                        }
+                    } catch (Exception e) {
+                        logger.error(e.toString(),e);
+                    }finally {
+                        //解锁
+                        readLock.unlock();
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * 集成 quartz 定时任务启动
+     * @param
+     * @return {@link }
+     * @author Darren
+     * @date 2020/2/13 17:05
+     */
+    private static void initQuartz() throws SchedulerException, InterruptedException {
+        StdSchedulerFactory stdSchedulerFactory = new StdSchedulerFactory();
+        Scheduler scheduler = stdSchedulerFactory.getScheduler();
+        JobDetail jobDetail = JobBuilder.newJob(PrintWordsJob.class)
+                .withIdentity("job1", "group1").build();
+        // 3、构建Trigger实例,每隔1s执行一次
+        Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "triggerGroup1")
+                .startNow()//立即生效
+                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
+                        //每隔1s执行一次
+                        .withIntervalInSeconds(2)
+                        //一直执行
+                        .repeatForever()).build();
+        //4、执行
+        scheduler.scheduleJob(jobDetail, trigger);
+        System.out.println("--------scheduler start ! ------------");
+        scheduler.start();
+        //睡眠
+        TimeUnit.MINUTES.sleep(1);
+        scheduler.shutdown();
+        System.out.println("--------scheduler shutdown ! ------------");
+    }
+
 
 }

+ 22 - 0
server-chat/src/main/java/com/cn/job/PrintWordsJob.java

@@ -0,0 +1,22 @@
+package com.cn.job;
+
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+import org.quartz.JobExecutionException;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Random;
+
+/**
+ * @author Darren
+ * @date 2020/2/13 16:40
+ */
+public class PrintWordsJob implements Job {
+
+    @Override
+    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
+        String printTime = new SimpleDateFormat("yy-MM-dd HH-mm-ss").format(new Date());
+        System.out.println("PrintWordsJob start at:" + printTime + ", prints: Hello Job-" + new Random().nextInt(100));
+    }
+}

+ 11 - 0
server-chat/src/main/java/com/cn/service/IMChatLoginServiceProcessor.java

@@ -30,6 +30,8 @@ public class IMChatLoginServiceProcessor implements LoginCmdProcessor {
 
     private static final String GROUP_PROPERTY = " group_id,name,avatar,service_account_role_department_middle_id,consumer_id,group_type,company_id,department_id ";
 
+    private static final String CURRENT_SYSTEM_ALL_USER_ID = "CURRENT_SYSTEM_ALL_USER_ID";
+
     static {
         try {
             jedisTemplate = JedisTemplate.me();
@@ -64,6 +66,15 @@ public class IMChatLoginServiceProcessor implements LoginCmdProcessor {
                 loginRespBody =  new LoginRespBody(Command.COMMAND_LOGIN_RESP,ImStatus.C10022,user);
             }else{
                 loginRespBody = new LoginRespBody(Command.COMMAND_LOGIN_RESP,ImStatus.C10007,user);
+                List<String> userIds = jedisTemplate.listGetAll(CURRENT_SYSTEM_ALL_USER_ID);
+                if(!CollectionUtils.isEmpty(userIds)){
+                    if( !userIds.contains(user.getId()) ){
+                        //存储所有登录的用户 的 userId
+                        jedisTemplate.listPushTail(CURRENT_SYSTEM_ALL_USER_ID,user.getId());
+                    }
+                }else{
+                    jedisTemplate.listPushTail(CURRENT_SYSTEM_ALL_USER_ID,user.getId());
+                }
             }
         }
         return loginRespBody;