package com.netty.push.handler.context; import io.netty.channel.Channel; import io.netty.channel.ChannelFutureListener; import io.netty.channel.group.ChannelGroup; import io.netty.channel.group.ChannelGroupFuture; import io.netty.channel.group.DefaultChannelGroup; import io.netty.util.concurrent.GlobalEventExecutor; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.UUID; import javax.annotation.PostConstruct; import javax.annotation.Resource; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Service; import com.google.protobuf.ByteString; import com.netty.push.dao.IPushDao; import com.netty.push.pojo.AppInfo; import com.netty.push.pojo.ChannelDeviceInfo; import com.netty.push.pojo.ChannelInfo; import com.netty.push.pojo.DeviceInfo; import com.netty.push.pojo.MessageDevice; import com.netty.push.pojo.MessageInfo; import com.netty.push.pojo.MessageOffline; import com.netty.push.pojo.MessagePushedInfo; import com.netty.push.utils.DateUtils; import com.netty.push.utils.Md5Util; import com.xwtec.protoc.CommandProtoc; /** * 应用上下文环境 * * @author maofw * */ @Service("applicationContext") @Scope("singleton") public class ApplicationContext { // ChannelGroup用于保存所有连接的客户端,注意要用static来保证只有一个ChannelGroup实例,否则每new一个TcpServerHandler都会创建一个ChannelGroup private static ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); // 存储所有设备列表 // private static final Map<String, ChannelDevice> devices = new HashMap<String, ChannelDevice>(); private static final Map<Channel, ChannelInfo> channelInfos = new HashMap<Channel, ChannelInfo>(); // private static final Map<String, String> regDevices = new HashMap<String, String>(); // 离线消息 private static final List<MessageOffline> messageOfflines = new ArrayList<MessageOffline>(); // app应用信息 private static final Map<Long, AppInfo> apps = new HashMap<Long, AppInfo>(); private static ApplicationContext applicationContext; /** * 消息类型 0-系统消息 1-用户消息 */ public static final int MESSAGE_TYPE_SYSTEM = 0; public static final int MESSAGE_TYPE_USER = 1; /** * 消息状态状态 0-有效 1-无效 */ public static final int MESSAGE_STATE_YES = 0; public static final int MESSAGE_STATE_NO = 1; /** * 设备是否在线(1-在线 0-离线) */ public static final int DEVICE_ONLINE_YES = 1; public static final int DEVICE_ONLINE_NO = 0; /** * 消息类型 0-群消息 1-点对点消息 */ public static final int MESSAGE_TYPE_SEND_TO_ALL = 0; public static final int MESSAGE_TYPE_SEND_TO_POINT = 1; /** * 离线是否可见 0-离线设备发送离线消息 1-离线设备不发送 */ public static final int MESSAGE_OFFLINE_SHOW_YES = 0; public static final int MESSAGE_OFFLINE_SHOW_NO = 1; /** * 设备-消息状态 0-初始状态(消息已发送尚未收到回执,下次轮询不能再发) 1-收到回执(不在发送相同消息) 2-push超时仍未收到回执 */ public static final int MESSAGE_PUSHED_STATE_INIT = 0; public static final int MESSAGE_PUSHED_STATE_RECEIPT = 1; public static final int MESSAGE_PUSHED_STATE_FAILED = 2; /** * 注册设备错误码 */ public static final int REGIST_SUCCESS = 1; public static final int REGIST_FAILED = 0; public static final int REGIST_APPINFO_NULL = -100; public static final int REGIST_APPKEY_PACKAGE_NOT_MATCHED = -200; @Resource private IPushDao pushDao; public static ApplicationContext getInstance() { return applicationContext; } /** * 初始化执行方法 */ @PostConstruct public void init() { System.out.println(this.getClass().getName() + " INIT ..."); // List<DeviceInfo> deviceList = pushDao.queryDeviceList(); if (channelInfos != null && !channelInfos.isEmpty()) { Map<String, List<MessagePushedInfo>> messagePushedMap = pushDao.queryMessagePushedInfo(); Iterator<Map.Entry<Channel, ChannelInfo>> iterator = channelInfos.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry<Channel, ChannelInfo> entry = iterator.next(); ChannelInfo channelInfo = entry.getValue(); if (channelInfo != null) { List<ChannelDeviceInfo> list = channelInfo.getChannelDeviceInfos(); if (list != null && list.size() > 0) { for (ChannelDeviceInfo cdi : list) { if (cdi != null && cdi.getDeviceInfo() != null && cdi.getDeviceInfo().getDeviceId() != null) { cdi.setMessagePushedInfos(messagePushedMap.get(cdi.getDeviceInfo().getDeviceId())); } } } } } } // 加载离线设备列表 List<MessageOffline> msgOfflines = pushDao.queryMessageOfflineList(); if (msgOfflines != null && msgOfflines.size() > 0) { messageOfflines.clear(); messageOfflines.addAll(msgOfflines); } // 加载app列表 List<AppInfo> appList = pushDao.queryAppList(); if (appList != null && appList.size() > 0) { apps.clear(); for (AppInfo appInfo : appList) { apps.put(appInfo.getAppId(), appInfo); } } applicationContext = this; System.out.println(this.getClass().getName() + " INIT SUCCESS!!!\n"); } /** * 刷新心跳 */ public void refreshHeart(Channel channel) { if (channel == null) { return; } if (channelInfos != null && !channelInfos.isEmpty() && channelInfos.containsKey(channel)) { ChannelInfo channelInfo = channelInfos.get(channel); if (channelInfo != null) { channelInfo.setHeartTime(System.currentTimeMillis()); } } } /** * 设备 心跳监控 超时的需要下线处理 */ public void deviceMonitors(Long timeout) { if (channelInfos != null && !channelInfos.isEmpty()) { List<DeviceInfo> deviceListNew = new ArrayList<DeviceInfo>(); Iterator<Map.Entry<Channel, ChannelInfo>> iterator = channelInfos.entrySet().iterator(); StringBuffer sb = new StringBuffer(); while (iterator.hasNext()) { Map.Entry<Channel, ChannelInfo> entry = iterator.next(); ChannelInfo channelInfo = entry.getValue(); if (channelInfo != null) { Long heartTime = channelInfo.getHeartTime() == null ? 0 : channelInfo.getHeartTime(); Long cha = System.currentTimeMillis() - heartTime; sb.append("CHANNELINFO DEVICE SIZE:"+(channelInfo.getChannelDeviceInfos()==null?0:channelInfo.getChannelDeviceInfos().size())+" - HEARTTIME:"+heartTime +" - TIMEOUT:"+timeout+" - CHA:"+cha+"\n"); if (cha >= timeout) { // 超时了已经 List<ChannelDeviceInfo> list = channelInfo.getChannelDeviceInfos(); if (list != null && list.size() > 0) { for (ChannelDeviceInfo cdi : list) { if (cdi != null && cdi.getDeviceInfo() != null) { DeviceInfo deviceInfo = cdi.getDeviceInfo(); deviceInfo.setIsOnline(DEVICE_ONLINE_NO); deviceInfo.setOfflineTime(new Date()); deviceListNew.add(deviceInfo); sb.append("DEVICE STATUS:" + (deviceInfo.getDeviceId() + "-" + deviceInfo.getImei()) + "-" + (deviceInfo.getIsOnline() == DEVICE_ONLINE_YES ? "ONLINE" : "OFFLINE")); sb.append("-TIMEOUT OFFLINE!\n"); } } list.clear(); } // 关闭渠道信息 Channel channel = entry.getKey(); if (channel != null) { channel.close().addListener(ChannelFutureListener.CLOSE); } // 移除渠道信息 iterator.remove(); } } } pushDao.updateDeviceInfoList(deviceListNew); if (sb.length() > 0) { System.out.println(sb.toString()); sb.delete(0, sb.length() - 1); } sb = null; deviceListNew.clear(); deviceListNew = null; } } /** * 获取所有离线设备信息 * * @return */ public List<MessageOffline> getMessageOfflines() { return messageOfflines; } /** * 获得离线消息 * * @param msgId * @param deviceId * @return */ private MessageOffline getMessageOffline(Long msgId, String deviceId) { MessageOffline messageOffline = null; if (messageOfflines != null) { for (MessageOffline mf : messageOfflines) { if (mf == null) { continue; } if (mf.getMsgId() != null && mf.getMsgId().equals(msgId) && mf.getDeviceId() != null && mf.getDeviceId().equals(deviceId)) { messageOffline = mf; break; } } } return messageOffline; } /** * 创建PUSH消息 * * @param appKey * @param title * @param content * @param type * @param isOfflinShow * @param expireTimes * @return */ public MessageInfo createMessageInfo(String appKey, String title, String content, int type, int isOfflineShow, long expireTimes, Date startTime, Date endTime) { AppInfo appInfo = this.getAppInfo(appKey); if (appInfo != null) { MessageInfo messageInfo = new MessageInfo(); messageInfo.setAppId(appInfo.getAppId()); messageInfo.setTitle(title); messageInfo.setContent(content); messageInfo.setType(type); messageInfo.setIsOfflineShow(isOfflineShow); messageInfo.setExpireTimes(expireTimes); messageInfo.setPushTime(new Date()); messageInfo.setStartTime(startTime); messageInfo.setEndTime(endTime); messageInfo.setState(MESSAGE_STATE_YES); int x = this.pushDao.saveMessage(messageInfo); if (x > 0) { return messageInfo; } } return null; } /** * 设备登陆后 发送默认消息 * * @param appPackage * @param title * @param content * @param isReceipt * @return */ public CommandProtoc.PushMessage getDefaultPushMessageForLogin(String deviceId, String title, String content, boolean isReceipt) { try { DeviceInfo deviceInfo = this.getDeviceInfo(deviceId); AppInfo appInfo = deviceInfo == null ? null : this.getAppInfo(deviceInfo.getAppKey()); if (appInfo != null) { String appPackage = appInfo.getAppPackage(); CommandProtoc.Message message = this.createCommandMessage(String.valueOf(Integer.MAX_VALUE), appPackage, CommandProtoc.Message.UserStatus.ONLINE, DateUtils.getDateString(new Date()), title, content.getBytes("UTF-8"), isReceipt, MESSAGE_TYPE_SYSTEM); CommandProtoc.PushMessage.Builder builder = this.createCommandPushMessage(CommandProtoc.PushMessage.Type.MESSAGE); builder.setMessage(message); return builder.build(); } } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return null; } /** * 保存消息 * * @param messageInfo * @return */ public int[] saveMessageDevices(List<MessageDevice> messageDevices) { if (messageDevices == null) { return null; } return this.pushDao.saveOrUpdateMessageDeviceList(messageDevices); } /** * 保存消息 * * @param messageInfo * @return */ public int saveMessageInfo(MessageInfo messageInfo) { if (messageInfo == null) { return -1; } return this.pushDao.saveMessage(messageInfo); } /** * 保存离线消息 * * @param messageOffline */ public synchronized MessageOffline saveMessageOffline(Long msgId, String deviceId) { MessageOffline messageOffline = this.getMessageOffline(msgId, deviceId); if (messageOffline == null) { messageOffline = new MessageOffline(); messageOffline.setMsgId(msgId); messageOffline.setDeviceId(deviceId); messageOfflines.add(messageOffline); // 保存到数据库中 pushDao.saveOrUpdateMessageOffline(messageOffline); } return messageOffline; } /** * 删除离线设备消息 * * @param msgId * @param deviceId * @return */ public int deleteMessageOffline(Long msgId, String deviceId) { MessageOffline messageOffline = this.getMessageOffline(msgId, deviceId); if (messageOffline != null) { // 删除数据库中的信息 int x = this.pushDao.deleteMessageOffline(messageOffline); // 刪除緩存中的信息 if (x > 0) { messageOfflines.remove(messageOffline); } return x; } return 0; } /** * 获取设备离线消息列表 * * @param deviceId * @return */ public List<MessageInfo> getMessageOfflineOfDevice(String deviceId) { return this.pushDao.queryMessageOfflineList(deviceId); } /** * 获取 设备信息 * * @param deviceId * @return */ public DeviceInfo getDeviceInfo(String deviceId) { DeviceInfo deviceInfo = getDeviceInfoFromCache(deviceId); if (deviceInfo == null) { deviceInfo = this.pushDao.queryDeviceByDeviceId(deviceId); } return deviceInfo; } /** * 获得DeviceInfo信息 * * @param deviceId * @param list * @return */ private DeviceInfo getDeviceInfoFromCache(String deviceId) { ChannelDeviceInfo channelDeviceInfo = getChannelDeviceInfoFromCache(deviceId); if (channelDeviceInfo != null) { return channelDeviceInfo.getDeviceInfo(); } return null; } /** * 从缓存中获取ChannelDeviceInfo * * @param deviceId * @return */ private ChannelDeviceInfo getChannelDeviceInfoFromCache(String deviceId) { ChannelDeviceInfo channelDeviceInfo = null; if (deviceId != null && channelInfos != null && !channelInfos.isEmpty()) { Iterator<Map.Entry<Channel, ChannelInfo>> iterator = channelInfos.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry<Channel, ChannelInfo> entry = iterator.next(); ChannelInfo channelInfo = entry.getValue(); if (channelInfo != null) { List<ChannelDeviceInfo> list = channelInfo.getChannelDeviceInfos(); if (deviceId != null && list != null && list.size() > 0) { for (ChannelDeviceInfo cdi : list) { if (cdi != null && cdi.getDeviceInfo() != null && deviceId.equals(cdi.getDeviceInfo().getDeviceId())) { channelDeviceInfo = cdi; break; } } } } } } return channelDeviceInfo; } /** * 获取AppInfo信息 * * @param appKey * @return */ public AppInfo getAppInfo(String appKey) { if (appKey == null) { return null; } AppInfo tmpAppInfo = null; Iterator<Map.Entry<Long, AppInfo>> iterator = apps.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry<Long, AppInfo> entry = iterator.next(); AppInfo appInfo = entry.getValue(); if (appInfo != null && appInfo.getAppKey() != null && appInfo.getAppKey().equals(appKey)) { tmpAppInfo = appInfo; break; } } return tmpAppInfo; } /** * 注册设备信息 * * @param deviceInfo */ public int registDevice(Channel channel, CommandProtoc.Registration registration) { if (registration != null) { AppInfo tmpAppInfo = getAppInfo(registration.getAppKey()); if (tmpAppInfo == null) { return REGIST_APPINFO_NULL; } if (tmpAppInfo.getAppPackage() == null || !tmpAppInfo.getAppPackage().equals(registration.getAppPackage())) { // package与app key不对应 return REGIST_APPKEY_PACKAGE_NOT_MATCHED; } DeviceInfo deviceInfo = null; ChannelInfo channelInfo = null; if (channelInfos.containsKey(channel)) { channelInfo = channelInfos.get(channelInfo); } if (channelInfo == null) { channelInfo = new ChannelInfo(); channelInfos.put(channel, channelInfo); } // 获取渠道设备信息列表 List<ChannelDeviceInfo> channelDeviceInfoList = channelInfo.getChannelDeviceInfos(); if (channelDeviceInfoList == null) { channelDeviceInfoList = new ArrayList<ChannelDeviceInfo>(); channelInfo.setChannelDeviceInfos(channelDeviceInfoList); } // 获得渠道设备信息 ChannelDeviceInfo channelDeviceInfo = this.getChannelDeviceInfoFromCache(registration.getDeviceId()); if (channelDeviceInfo == null) { channelDeviceInfo = new ChannelDeviceInfo(); // 设置渠道 channelDeviceInfo.setChannel(channel); // 设置已发送消息列表 Map<String, List<MessagePushedInfo>> messagePushedMap = pushDao.queryMessagePushedInfo(); if (messagePushedMap != null && !messagePushedMap.isEmpty()) { channelDeviceInfo.setMessagePushedInfos(messagePushedMap.get(registration.getDeviceId())); } channelDeviceInfoList.add(channelDeviceInfo); } if (deviceInfo == null) { deviceInfo = this.getDeviceInfo(registration.getDeviceId()); } if (deviceInfo == null) { deviceInfo = new DeviceInfo(); channelDeviceInfo.setDeviceInfo(deviceInfo); } // 设置设备信息内容 channelDeviceInfo.setDeviceInfo(deviceInfo); if (deviceInfo.getRegId() == null) { // 重新创建一个ID String regId = Md5Util.toMD5(UUID.randomUUID().toString()); deviceInfo.setRegId(regId); deviceInfo.setAppId(tmpAppInfo.getAppId()); deviceInfo.setUserId(tmpAppInfo.getUserId()); deviceInfo.setAppKey(tmpAppInfo.getAppKey()); deviceInfo.setChannel(registration.getChannel()); deviceInfo.setImei(registration.getImei()); deviceInfo.setDeviceId(registration.getDeviceId()); // 更新到数据库 int r = pushDao.saveOrUpdateDeviceInfo(deviceInfo); if (r > 0) { return REGIST_SUCCESS; } } else { // 保存设备到缓存中 // channelDevice.setChannel(channel); return REGIST_SUCCESS; } } return REGIST_FAILED; } /** * 添加渠道到渠道组里面 用于群发消息 * * @param channel * @return */ public boolean addChannel(Channel channel) { if (channel != null) { return channels.add(channel); } return false; } /** * 关闭所有channel * * @return */ public ChannelGroupFuture closeAllChannels() { if (channels != null && channels.size() > 0) { return channels.close(); } return null; } /** * 设备上线 * * @param deviceId * @return */ public boolean online(String deviceId) { if (deviceId != null) { ChannelDeviceInfo channelDeviceInfo = this.getChannelDeviceInfoFromCache(deviceId); if (channelDeviceInfo != null) { ChannelInfo channelInfo = channelInfos.get(channelDeviceInfo.getChannel()); // 更新心跳时间 if (channelInfo != null) { channelInfo.setHeartTime(System.currentTimeMillis()); } // 更新设备在线状态 DeviceInfo deviceInfo = channelDeviceInfo.getDeviceInfo(); if (deviceInfo != null) { deviceInfo.setIsOnline(DEVICE_ONLINE_YES); deviceInfo.setOnlineTime(new Date()); int x = this.pushDao.saveOrUpdateDeviceInfo(deviceInfo); if (x > 0) { System.out.println("DEVICE ONLINE:" + deviceId + "-" + deviceInfo.getImei()+"\n"); return true; } } } } return false; } /** * 设备下线 * * @param deviceId * @return */ public boolean offline(String deviceId) { if (deviceId != null) { ChannelDeviceInfo channelDeviceInfo = this.getChannelDeviceInfoFromCache(deviceId); if (channelDeviceInfo != null) { // 更新设备在线状态 DeviceInfo deviceInfo = channelDeviceInfo.getDeviceInfo(); if (deviceInfo != null) { deviceInfo.setIsOnline(DEVICE_ONLINE_NO); deviceInfo.setOfflineTime(new Date()); this.pushDao.saveOrUpdateDeviceInfo(deviceInfo); } Channel channel = channelDeviceInfo.getChannel(); if (channel != null) { channel.close().addListener(ChannelFutureListener.CLOSE); ChannelInfo channelInfo = channelInfos.get(channel); if (channelInfo != null && channelInfo.getChannelDeviceInfos() != null) { channelDeviceInfo.setDeviceInfo(null); channelDeviceInfo.setMessagePushedInfos(null); channelInfo.getChannelDeviceInfos().remove(channelDeviceInfo); } } System.out.println("DEVICE OFFLINE:" + deviceId + (deviceInfo == null ? "" : ("-" + deviceInfo.getImei()))); return true; } System.out.println("DEVICE ALREADY OFFLINE:" + deviceId ); return true; } return false; } /** * 渠道下线 * * @param deviceId * @return */ public boolean offline(Channel channel) { System.out.print("OFFLINE:channel="+channel); if (channel != null) { System.out.print("-channelInfos="+channelInfos); ChannelInfo channelInfo = channelInfos.get(channel); System.out.print("-channelInfo="+channelInfo); System.out.println("-device size="+((channelInfo==null||channelInfo.getChannelDeviceInfos() ==null)?0:channelInfo.getChannelDeviceInfos().size())); if (channelInfo != null && channelInfo.getChannelDeviceInfos() != null && channelInfo.getChannelDeviceInfos().size() > 0) { List<DeviceInfo> deviceInfos = new ArrayList<DeviceInfo>(); List<ChannelDeviceInfo> channelDeviceInfos = channelInfo.getChannelDeviceInfos(); for (ChannelDeviceInfo channelDeviceInfo : channelDeviceInfos) { if (channelDeviceInfo != null) { // 更新设备在线状态 DeviceInfo deviceInfo = channelDeviceInfo.getDeviceInfo(); if (deviceInfo != null) { deviceInfo.setIsOnline(DEVICE_ONLINE_NO); deviceInfo.setOfflineTime(new Date()); deviceInfos.add(deviceInfo); System.out.println("DEVICE OFFLINE:" + deviceInfo.getDeviceId() + (deviceInfo == null ? "" : ("-" + deviceInfo.getImei()))); } } } if (deviceInfos != null && deviceInfos.size() > 0) { this.pushDao.updateDeviceInfoList(deviceInfos); } channelInfo.getChannelDeviceInfos().removeAll(channelDeviceInfos); } channelInfos.remove(channel); channel.close().addListener(ChannelFutureListener.CLOSE); return true; } System.out.println("-end"); return false; } /** * 发送所有消息 */ public void sendAllMessages() { // 数据库获取消息列表内容 List<MessageInfo> messages = pushDao.queryMessageList(); if (messages != null && messages.size() > 0) { for (MessageInfo mi : messages) { if (mi == null) { continue; } // 发送消息 类型在线消息 sendMessage(mi, CommandProtoc.Message.UserStatus.ONLINE); } } } /** * 发送消息给终端设备 * * @param messageInfo */ public void sendMessage(MessageInfo messageInfo, CommandProtoc.Message.UserStatus status) { if (messageInfo != null) { switch (messageInfo.getType()) { case MESSAGE_TYPE_SEND_TO_ALL: // 群消息 sendMessageToAll(messageInfo, status); break; case MESSAGE_TYPE_SEND_TO_POINT: // 点对点消息 sendMessageToPoint(messageInfo, status); break; default: break; } } } /** * 群消息 * * @param messageInfo */ public void sendMessageToAll(MessageInfo messageInfo, CommandProtoc.Message.UserStatus status) { // 设备消息数据 List<DeviceInfo> deviceList = this.pushDao.queryDeviceListByAppId(messageInfo.getAppId()); if (deviceList == null || deviceList.size() <= 0) { return; } sendMessageToDevices(messageInfo, status, deviceList); } /** * 点对点消息 * * @param messageInfo */ private void sendMessageToPoint(MessageInfo messageInfo, CommandProtoc.Message.UserStatus status) { // 获取该消息中是否存在 设备关联列表 List<DeviceInfo> deviceList = this.pushDao.queryMessageDeviceList(messageInfo.getAppId(), messageInfo.getMsgId()); if (deviceList == null || deviceList.size() <= 0) { return; } sendMessageToDevices(messageInfo, status, deviceList); } /** * 发送PUSH消息 * * @param messageInfo * @param status * @param deviceList */ public void sendMessageToDevices(MessageInfo messageInfo, CommandProtoc.Message.UserStatus status, List<DeviceInfo> deviceList) { // System.out.println("sendMessageToDevices come in!"); if (deviceList != null && deviceList.size() > 0) { // 创建消息对象 CommandProtoc.PushMessage.Builder builder = this.createCommandPushMessage(CommandProtoc.PushMessage.Type.MESSAGE); CommandProtoc.PushMessage pushMessage = this.getRealPushMessage(builder, messageInfo, status); // 已经推送过的消息列表 List<MessagePushedInfo> messageDeviceList = new ArrayList<MessagePushedInfo>(); ChannelGroup mchannels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); for (DeviceInfo deviceInfo : deviceList) { if (deviceInfo == null) { continue; } // 获取设备消息发送对象 MessagePushedInfo messagePushedInfo = this.makeMessageInfoToDevice(mchannels, messageInfo, deviceInfo); if (messagePushedInfo != null) { // 更新数据库数据 if (messageDeviceList != null && messageDeviceList.size() >= 100) { // 提交数据库 this.pushDao.saveMessagePushedList(messageDeviceList); messageDeviceList.clear(); } messageDeviceList.add(messagePushedInfo); } } // 更新数据库数据 if (messageDeviceList != null && messageDeviceList.size() > 0) { // 提交数据库 this.pushDao.saveMessagePushedList(messageDeviceList); messageDeviceList.clear(); messageDeviceList = null; } if (!mchannels.isEmpty()) { System.out.println("writeAndFlush pushMessage:=======================\n" + pushMessage); // 发送消息 mchannels.writeAndFlush(pushMessage); mchannels.clear(); } mchannels = null; } } /** * 实际发送消息方法 * * @param pushMessage * @param status * @param messageInfo * @param deviceId * @return */ private MessagePushedInfo makeMessageInfoToDevice(ChannelGroup mchannels, MessageInfo messageInfo, DeviceInfo deviceInfo) { // System.out.println("makeMessageInfoToDevice come in!"); // 获取设备消息发送对象 MessagePushedInfo messagePushedInfo = getMessagePushedInfo(messageInfo, deviceInfo); if (messagePushedInfo != null) { // 发送消息 if (deviceInfo != null && deviceInfo.getIsOnline() == DEVICE_ONLINE_YES) { // 如果设备在线 则添加发送通道 ChannelDeviceInfo channelDeviceInfo = this.getChannelDeviceInfoFromCache(deviceInfo.getDeviceId()); // System.out.println("makeMessageInfoToDevice channelDeviceInfo=" + channelDeviceInfo); Channel channel = channelDeviceInfo == null ? null : channelDeviceInfo.getChannel(); if (channel != null && channel.isWritable()) { mchannels.add(channel); } else { return null; } } } return messagePushedInfo; } /** * 保存回执信息 * * @param appKey * @param msgId * @param regId * @return */ public int saveMessagePushedInfo(Channel channel, String appKey, String msgId, String regId) { AppInfo tmpAppInfo = getAppInfo(appKey); if (tmpAppInfo == null) { return -1; } if (msgId == null || regId == null) { return -1; } // 获取deviceId ChannelInfo channelInfo = channelInfos.get(channel); if (channelInfo == null) { return -1; } String deviceId = null; DeviceInfo deviceInfo = null; List<ChannelDeviceInfo> list = channelInfo.getChannelDeviceInfos(); if (list != null && list.size() > 0) { for (ChannelDeviceInfo cdi : list) { if (cdi != null && cdi.getDeviceInfo() != null && regId.equals(cdi.getDeviceInfo().getRegId())) { deviceInfo = cdi.getDeviceInfo(); break; } } } deviceId = (deviceInfo == null) ? null : deviceInfo.getDeviceId(); if (deviceId == null) { return -1; } Long msgIdLong = Long.parseLong(msgId); // 获取设备信息 MessagePushedInfo tmpMessagePushedInfo = getMessagePushedInfoFromCache(msgIdLong, deviceId); if (tmpMessagePushedInfo == null) { return -1; } // 更新内容后保存数据库 tmpMessagePushedInfo.setReceiptTime(new Date()); tmpMessagePushedInfo.setState(MESSAGE_PUSHED_STATE_RECEIPT); int rx = this.pushDao.saveMessagePushedInfo(tmpMessagePushedInfo); System.out.println("SAVEMESSAGEPUSHEDINFO MSGID:"+msgIdLong+" - DEVICEID:"+deviceId+" - RESULT:" + rx); if (rx > 0) { // 消息确认成功了 删除该设备的离线消息 int m = this.deleteMessageOffline(msgIdLong, deviceId); System.out.println("DELETEMESSAGEOFFLINE MSGID:"+msgIdLong+" - DEVICEID:"+deviceId+" - RESULT:" + m); } return rx; } /** * 获得设备列表 * * @param regIds * @param appKey * @return */ public List<DeviceInfo> queryDeviceInfoListByRegIds(String appKey, List<String> regIds) { return this.pushDao.queryDeviceInfoFromRegIds(appKey, regIds); } /** * 从缓存中查找MessagePushedInfo对象 * * @param msgId * @param deviceId * @return */ private MessagePushedInfo getMessagePushedInfoFromCache(Long msgId, String deviceId) { // 获取设备信息 ChannelDeviceInfo channelDeviceInfo = this.getChannelDeviceInfoFromCache(deviceId); if (channelDeviceInfo == null) { return null; } // 獲取目前的列表 List<MessagePushedInfo> messagePushedList = channelDeviceInfo.getMessagePushedInfos(); if (messagePushedList == null || messagePushedList.size() <= 0) { return null; } MessagePushedInfo tmpMessagePushedInfo = null; for (MessagePushedInfo messagePushedInfo : messagePushedList) { if (messagePushedInfo == null) { continue; } if (deviceId.equals(messagePushedInfo.getDeviceId()) && msgId.equals(messagePushedInfo.getMsgId())) { // 找到了之前发送的消息实体 则更新内容后保存数据库 tmpMessagePushedInfo = messagePushedInfo; break; } } return tmpMessagePushedInfo; } /** * 加入緩存中 * * @param messagePushedInfo * @return */ private int addMessagePushedInfoToCache(String deviceId, MessagePushedInfo messagePushedInfo) { // 获取设备信息 ChannelDeviceInfo channelDeviceInfo = this.getChannelDeviceInfoFromCache(deviceId); if (channelDeviceInfo == null) { return -1; } // 獲取目前的列表 List<MessagePushedInfo> messagePushedList = channelDeviceInfo.getMessagePushedInfos(); if (messagePushedList == null) { messagePushedList = new ArrayList<MessagePushedInfo>(); messagePushedList.add(messagePushedInfo); channelDeviceInfo.setMessagePushedInfos(messagePushedList); } else { messagePushedList.add(messagePushedInfo); } return 1; } /** * 更新发送设备信息到数据库 * * @param deviceId * @return */ private MessagePushedInfo getMessagePushedInfo(MessageInfo messageInfo, DeviceInfo deviceInfo) { if (messageInfo == null || deviceInfo == null) { return null; } // 獲取appinfo信息 AppInfo deviceAppInfo = apps.get(deviceInfo.getAppId()); AppInfo messageAppInfo = apps.get(messageInfo.getAppId()); if (deviceAppInfo != messageAppInfo) { return null; } // 判断设备是否离线 if (isDeviceOffline(deviceInfo)) { // 如果设备已经离线了 则关闭相应的channel ChannelDeviceInfo channelDeviceInfo = this.getChannelDeviceInfoFromCache(deviceInfo.getDeviceId()); if (channelDeviceInfo != null) { Channel channel = channelDeviceInfo.getChannel(); if (channel != null && channel.isOpen()) { channel.close().addListener(ChannelFutureListener.CLOSE); } } // 离线的消息就不需要发送了 直接保存到离线消息中 if (messageInfo.getIsOfflineShow() == MESSAGE_OFFLINE_SHOW_YES) { // 保存离线消息 this.saveMessageOffline(messageInfo.getMsgId(), deviceInfo.getDeviceId()); return null; } } else { MessagePushedInfo messagePushedInfo = getMessagePushedInfoFromCache(messageInfo.getMsgId(), deviceInfo.getDeviceId()); if (messagePushedInfo == null) { messagePushedInfo = new MessagePushedInfo(); messagePushedInfo.setDeviceId(deviceInfo.getDeviceId()); messagePushedInfo.setMsgId(messageInfo.getMsgId()); messagePushedInfo.setPushTime(new Date()); // 超时时间 0-无超时(认为发送即成功,无需客户端确认回执) if (messageInfo.getExpireTimes() == 0) { // 默认设置设备已经确认了 messagePushedInfo.setReceiptTime(new Date()); messagePushedInfo.setState(MESSAGE_PUSHED_STATE_RECEIPT); } else { messagePushedInfo.setState(MESSAGE_PUSHED_STATE_INIT); } this.addMessagePushedInfoToCache(deviceInfo.getDeviceId(), messagePushedInfo); } else if (messagePushedInfo.getState() == MESSAGE_PUSHED_STATE_RECEIPT) { // 已經回執過了 不需要再發送 return null; } return messagePushedInfo; } return null; } /** * 判断设备是否离线 * * @param channelDevice * @return */ private boolean isDeviceOffline(DeviceInfo deviceInfo) { if (deviceInfo != null) { if (deviceInfo == null || deviceInfo.getIsOnline() == DEVICE_ONLINE_NO) { return true; } return false; } return true; } /** * 群消息 * * @param messageInfo */ private CommandProtoc.PushMessage getRealPushMessage(CommandProtoc.PushMessage.Builder builder, MessageInfo messageInfo, CommandProtoc.Message.UserStatus status) { AppInfo appinfo = apps.get(messageInfo.getAppId()); if (appinfo != null) { CommandProtoc.Message message = null; try { message = this.createCommandMessage(String.valueOf(messageInfo.getMsgId()), appinfo.getAppPackage(), status, DateUtils.getDateString(messageInfo.getPushTime()), messageInfo.getTitle(), messageInfo.getContent().getBytes("UTF-8"), (messageInfo.getExpireTimes() == 0 ? false : true), MESSAGE_TYPE_USER); builder.setMessage(message); // 生成PushMessage消息对象 CommandProtoc.PushMessage pushMessage = builder.build(); return pushMessage; } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return null; } /** * 创建发送消息对象 * * @param type * @return */ private CommandProtoc.PushMessage.Builder createCommandPushMessage(CommandProtoc.PushMessage.Type type) { CommandProtoc.PushMessage.Builder builder = CommandProtoc.PushMessage.newBuilder(); builder.setType(type); return builder; } /** * 创建RegistrationResult对象 * * @param type * @return */ public CommandProtoc.PushMessage createCommandRegistrationResult(String appKey, String appPackage, String registrationId) { CommandProtoc.RegistrationResult.Builder builder = CommandProtoc.RegistrationResult.newBuilder(); builder.setAppKey(appKey); builder.setAppPackage(appPackage); if (registrationId != null) { builder.setRegistrationId(registrationId); } CommandProtoc.RegistrationResult commandProtoc = builder.build(); // 创建消息对象 CommandProtoc.PushMessage.Builder messageBuilder = this.createCommandPushMessage(CommandProtoc.PushMessage.Type.REGISTRATION_RESULT); messageBuilder.setRegistrationResult(commandProtoc); return messageBuilder.build(); } /** * 创建DeviceOnoffResult对象 * * @param type * @return */ public CommandProtoc.PushMessage createCommandDeviceOnoffResult(String appPackage, CommandProtoc.DeviceOnoffResult.ResultCode resultCode, CommandProtoc.Message.UserStatus userStatus) { CommandProtoc.DeviceOnoffResult.Builder builder = CommandProtoc.DeviceOnoffResult.newBuilder(); if (appPackage != null) { builder.setAppPackage(appPackage); } builder.setResCode(resultCode); builder.setUserStatus(userStatus); CommandProtoc.DeviceOnoffResult commandProtoc = builder.build(); // 创建消息对象 CommandProtoc.PushMessage.Builder messageBuilder = this.createCommandPushMessage(CommandProtoc.PushMessage.Type.DEVICE_ONOFFLINE_RESULT); messageBuilder.setDeviceOnoffResult(commandProtoc); return messageBuilder.build(); } /** * 创建Message对象 * * @param type * @return */ private CommandProtoc.Message createCommandMessage(String msgId, String appPackage, CommandProtoc.Message.UserStatus userStatus, String pushTime, String title, byte[] content, boolean isReceipt, int type) { CommandProtoc.Message.Builder builder = CommandProtoc.Message.newBuilder(); builder.setAppPackage(appPackage); builder.setStatus(userStatus); builder.setPushTime(pushTime); builder.setTitle(title); builder.setContent(ByteString.copyFrom(content)); builder.setIsReceipt(isReceipt); builder.setMsgId(msgId); builder.setType(type); CommandProtoc.Message commandProtoc = builder.build(); return commandProtoc; } /** * 销毁 */ public void destory() { channelInfos.clear(); messageOfflines.clear(); apps.clear(); channels.clear(); } }