From e9cc6077762166ca2f1745cf8cd3c66e6a95b364 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BF=9C=E6=96=B9=E5=A4=95=E9=98=B3?= Date: Fri, 19 Apr 2019 14:59:48 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=E6=9C=8D=E5=8A=A1=E7=AB=AFsd?= =?UTF-8?q?k=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../libs/cim-server-sdk-3.6.jar | Bin 81352 -> 98722 bytes .../java/com/farsunset/cim/CIMConfig.java | 2 +- .../admin/controller/SessionController.java | 7 +- .../farsunset/cim/handler/BindHandler.java | 62 +- .../cim/handler/SessionClosedHandler.java | 25 +- .../cim/push/DefaultMessagePusher.java | 45 +- ...Dispatcher.java => CIMSessionService.java} | 23 +- .../impl/ClusterSessionServiceImpl.java | 59 +- .../impl/MemorySessionServiceImpl.java | 40 +- .../service/impl/MessageDispatcherImpl.java | 83 - cim_for_mina/cim-server-sdk/.classpath | 4 +- .../.settings/org.eclipse.jdt.core.prefs | 6 +- ....eclipse.wst.common.project.facet.core.xml | 2 +- .../cim/sdk/server/constant/CIMConstant.java | 9 +- .../sdk/server/filter/CIMLoggingFilter.java | 4 +- .../server/filter/ServerMessageEncoder.java | 2 +- .../filter/decoder/AppMessageDecoder.java | 2 +- .../filter/decoder/WebMessageDecoder.java | 5 +- .../server/handler/CIMNioSocketAcceptor.java | 32 +- .../sdk/server/handler/CIMRequestHandler.java | 2 +- .../sdk/server/handler/WebsocketHandler.java | 2 +- .../server/{session => model}/CIMSession.java | 217 +- .../cim/sdk/server/model/proto/Session.proto | 19 + .../sdk/server/model/proto/SessionProto.java | 1932 ++++++++++++++++ .../server/session/DefaultSessionManager.java | 84 - .../sdk/server/session/SessionManager.java | 64 - ...oid-sdk-3.6.jar => cim-server-sdk-3.6.jar} | Bin 80779 -> 98313 bytes .../java/com/farsunset/cim/CIMConfig.java | 6 +- .../admin/controller/SessionController.java | 7 +- .../cim/api/controller/MessageController.java | 1 - .../farsunset/cim/handler/BindHandler.java | 66 +- .../cim/handler/SessionClosedHandler.java | 25 +- .../cim/push/DefaultMessagePusher.java | 45 +- ...Dispatcher.java => CIMSessionService.java} | 23 +- .../impl/ClusterSessionServiceImpl.java | 59 +- .../impl/MemorySessionServiceImpl.java | 65 + .../service/impl/MessageDispatcherImpl.java | 83 - .../cim/sdk/server/constant/CIMConstant.java | 24 +- .../server/filter/ServerMessageDecoder.java | 6 +- .../server/filter/ServerMessageEncoder.java | 2 +- .../filter/decoder/AppMessageDecoder.java | 2 +- .../filter/decoder/WebMessageDecoder.java | 8 +- .../server/handler/CIMNioSocketAcceptor.java | 20 +- .../sdk/server/handler/CIMRequestHandler.java | 2 +- .../sdk/server/handler/HeartbeatHandler.java | 14 +- .../sdk/server/handler/WebsocketHandler.java | 4 +- .../server/{session => model}/CIMSession.java | 226 +- .../cim/sdk/server/model/proto/Session.proto | 19 + .../sdk/server/model/proto/SessionProto.java | 2022 +++++++++++++++++ .../server/session/DefaultSessionManager.java | 84 - .../sdk/server/session/SessionManager.java | 64 - 51 files changed, 4658 insertions(+), 951 deletions(-) rename cim_for_mina/cim-boot-server/src/main/java/com/farsunset/cim/service/{MessageDispatcher.java => CIMSessionService.java} (67%) rename cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/session/ClusterSessionManager.java => cim_for_mina/cim-boot-server/src/main/java/com/farsunset/cim/service/impl/ClusterSessionServiceImpl.java (60%) rename cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/service/impl/CIMSessionServiceImpl.java => cim_for_mina/cim-boot-server/src/main/java/com/farsunset/cim/service/impl/MemorySessionServiceImpl.java (56%) delete mode 100644 cim_for_mina/cim-boot-server/src/main/java/com/farsunset/cim/service/impl/MessageDispatcherImpl.java rename cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/{session => model}/CIMSession.java (63%) create mode 100644 cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/model/proto/Session.proto create mode 100644 cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/model/proto/SessionProto.java delete mode 100644 cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/session/DefaultSessionManager.java delete mode 100644 cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/session/SessionManager.java rename cim_for_netty/cim-boot-server/libs/{cim-android-sdk-3.6.jar => cim-server-sdk-3.6.jar} (52%) rename cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/service/{MessageDispatcher.java => CIMSessionService.java} (67%) rename cim_for_mina/cim-boot-server/src/main/java/com/farsunset/cim/session/ClusterSessionManager.java => cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/service/impl/ClusterSessionServiceImpl.java (60%) create mode 100644 cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/service/impl/MemorySessionServiceImpl.java delete mode 100644 cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/service/impl/MessageDispatcherImpl.java rename cim_for_mina/cim-boot-server/src/main/java/com/farsunset/cim/service/impl/CIMSessionServiceImpl.java => cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/handler/HeartbeatHandler.java (75%) rename cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/{session => model}/CIMSession.java (60%) create mode 100644 cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/model/proto/Session.proto create mode 100644 cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/model/proto/SessionProto.java delete mode 100644 cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/session/DefaultSessionManager.java delete mode 100644 cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/session/SessionManager.java diff --git a/cim_for_mina/cim-boot-server/libs/cim-server-sdk-3.6.jar b/cim_for_mina/cim-boot-server/libs/cim-server-sdk-3.6.jar index eaa557e321cb3c1d83e7186d477b2da99fb5a720..8d2c84aaec3b416ae6c490669ea264727cad0871 100644 GIT binary patch delta 73471 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 delta 56500 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 D0*f+X diff --git a/cim_for_mina/cim-boot-server/src/main/java/com/farsunset/cim/CIMConfig.java b/cim_for_mina/cim-boot-server/src/main/java/com/farsunset/cim/CIMConfig.java index e527ee9..28d36b9 100644 --- a/cim_for_mina/cim-boot-server/src/main/java/com/farsunset/cim/CIMConfig.java +++ b/cim_for_mina/cim-boot-server/src/main/java/com/farsunset/cim/CIMConfig.java @@ -16,7 +16,7 @@ import com.farsunset.cim.handler.SessionClosedHandler; import com.farsunset.cim.sdk.server.handler.CIMNioSocketAcceptor; import com.farsunset.cim.sdk.server.handler.CIMRequestHandler; import com.farsunset.cim.sdk.server.model.SentBody; -import com.farsunset.cim.sdk.server.session.CIMSession; +import com.farsunset.cim.sdk.server.model.CIMSession; @Configuration public class CIMConfig implements CIMRequestHandler { diff --git a/cim_for_mina/cim-boot-server/src/main/java/com/farsunset/cim/admin/controller/SessionController.java b/cim_for_mina/cim-boot-server/src/main/java/com/farsunset/cim/admin/controller/SessionController.java index 2e378fd..74b1c00 100644 --- a/cim_for_mina/cim-boot-server/src/main/java/com/farsunset/cim/admin/controller/SessionController.java +++ b/cim_for_mina/cim-boot-server/src/main/java/com/farsunset/cim/admin/controller/SessionController.java @@ -27,17 +27,18 @@ import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; -import com.farsunset.cim.service.impl.CIMSessionServiceImpl; +import com.farsunset.cim.service.CIMSessionService; + @Controller @RequestMapping("/console/session") public class SessionController { @Resource - private CIMSessionServiceImpl sessionManager; + private CIMSessionService memorySessionService; @RequestMapping(value = "/list.action") public String list(Model model) { - model.addAttribute("sessionList", sessionManager.queryAll()); + model.addAttribute("sessionList", memorySessionService.list()); return "console/session/manage"; } } diff --git a/cim_for_mina/cim-boot-server/src/main/java/com/farsunset/cim/handler/BindHandler.java b/cim_for_mina/cim-boot-server/src/main/java/com/farsunset/cim/handler/BindHandler.java index 73aedb1..da7e908 100644 --- a/cim_for_mina/cim-boot-server/src/main/java/com/farsunset/cim/handler/BindHandler.java +++ b/cim_for_mina/cim-boot-server/src/main/java/com/farsunset/cim/handler/BindHandler.java @@ -30,14 +30,14 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; +import com.farsunset.cim.push.CIMMessagePusher; import com.farsunset.cim.sdk.server.constant.CIMConstant; import com.farsunset.cim.sdk.server.handler.CIMRequestHandler; import com.farsunset.cim.sdk.server.model.Message; import com.farsunset.cim.sdk.server.model.ReplyBody; import com.farsunset.cim.sdk.server.model.SentBody; -import com.farsunset.cim.sdk.server.session.CIMSession; -import com.farsunset.cim.service.impl.CIMSessionServiceImpl; -import com.farsunset.cim.util.StringUtil; +import com.farsunset.cim.sdk.server.model.CIMSession; +import com.farsunset.cim.service.CIMSessionService; /** @@ -51,57 +51,57 @@ public class BindHandler implements CIMRequestHandler { protected final Logger logger = LoggerFactory.getLogger(BindHandler.class); @Resource - private CIMSessionServiceImpl sessionManager; + private CIMSessionService memorySessionService; @Value("${server.host}") private String host; + @Resource + private CIMMessagePusher defaultMessagePusher; - public void process(CIMSession newSession, SentBody message) { + public void process(CIMSession newSession, SentBody body) { ReplyBody reply = new ReplyBody(); - reply.setKey(message.getKey()); + reply.setKey(body.getKey()); reply.setCode(CIMConstant.ReturnCode.CODE_200); + reply.setTimestamp(System.currentTimeMillis()); + try { - String account = message.get("account"); - newSession.setGid(StringUtil.getUUID()); + String account = body.get("account"); newSession.setAccount(account); - newSession.setDeviceId(message.get("deviceId")); + newSession.setDeviceId(body.get("deviceId")); newSession.setHost(host); - newSession.setChannel(message.get("channel")); - newSession.setDeviceModel(message.get("device")); - newSession.setClientVersion(message.get("version")); - newSession.setSystemVersion(message.get("osVersion")); + newSession.setChannel(body.get("channel")); + newSession.setDeviceModel(body.get("device")); + newSession.setClientVersion(body.get("version")); + newSession.setSystemVersion(body.get("osVersion")); newSession.setBindTime(System.currentTimeMillis()); - newSession.setPackageName(message.get("packageName")); - newSession.setHeartbeat(System.currentTimeMillis()); - - /** + /* * 由于客户端断线服务端可能会无法获知的情况,客户端重连时,需要关闭旧的连接 */ - CIMSession oldSession = sessionManager.get(account); + CIMSession oldSession = memorySessionService.get(account); - // 如果是账号已经在另一台终端登录。则让另一个终端下线 + /* + * 如果是账号已经在另一台终端登录。则让另一个终端下线 + */ if (oldSession != null && fromOtherDevice(newSession,oldSession) && oldSession.isConnected()) { sendForceOfflineMessage(oldSession, account, newSession.getDeviceModel()); } - - - /** + + /* * 有可能是同一个设备重复连接,则关闭旧的链接,这种情况一般是客户端断网,联网又重新链接上来,之前的旧链接没有来得及通过心跳机制关闭,在这里手动关闭 * 条件1,连接来自是同一个设备 * 条件2.2个连接都是同一台服务器 */ if (oldSession != null && !fromOtherDevice(newSession,oldSession) && Objects.equals(oldSession.getHost(),host)) { - oldSession.removeAttribute(CIMConstant.SESSION_KEY); - oldSession.closeOnFlush(); + closeQuietly(oldSession); } - - sessionManager.add(newSession); + memorySessionService.save(newSession); + } catch (Exception e) { reply.setCode(CIMConstant.ReturnCode.CODE_500); @@ -124,15 +124,17 @@ public class BindHandler implements CIMRequestHandler { msg.setSender("system"); msg.setContent(deviceModel); msg.setId(System.currentTimeMillis()); - closeQuietly(oldSession,msg); + + defaultMessagePusher.push(msg); + + closeQuietly(oldSession); } // 不同设备同一账号登录时关闭旧的连接 - private void closeQuietly(CIMSession oldSession,Message msg) { + private void closeQuietly(CIMSession oldSession) { if (oldSession.isConnected() && Objects.equals(host, oldSession.getHost())) { - oldSession.write(msg); - oldSession.removeAttribute(CIMConstant.SESSION_KEY); + oldSession.setAttribute(CIMConstant.KEY_QUIETLY_CLOSE,true); oldSession.closeOnFlush(); } } diff --git a/cim_for_mina/cim-boot-server/src/main/java/com/farsunset/cim/handler/SessionClosedHandler.java b/cim_for_mina/cim-boot-server/src/main/java/com/farsunset/cim/handler/SessionClosedHandler.java index 4e00c77..c41b547 100644 --- a/cim_for_mina/cim-boot-server/src/main/java/com/farsunset/cim/handler/SessionClosedHandler.java +++ b/cim_for_mina/cim-boot-server/src/main/java/com/farsunset/cim/handler/SessionClosedHandler.java @@ -22,6 +22,8 @@ package com.farsunset.cim.handler; +import java.util.Objects; + import javax.annotation.Resource; import org.slf4j.Logger; @@ -31,8 +33,8 @@ import org.springframework.stereotype.Component; import com.farsunset.cim.sdk.server.constant.CIMConstant; import com.farsunset.cim.sdk.server.handler.CIMRequestHandler; import com.farsunset.cim.sdk.server.model.SentBody; -import com.farsunset.cim.sdk.server.session.CIMSession; -import com.farsunset.cim.service.impl.CIMSessionServiceImpl; +import com.farsunset.cim.sdk.server.model.CIMSession; +import com.farsunset.cim.service.CIMSessionService; /** @@ -46,17 +48,28 @@ public class SessionClosedHandler implements CIMRequestHandler { protected final Logger logger = LoggerFactory.getLogger(SessionClosedHandler.class); @Resource - private CIMSessionServiceImpl sessionManager; + private CIMSessionService memorySessionService; public void process(CIMSession ios, SentBody message) { + Object quietly = ios.getAttribute(CIMConstant.KEY_QUIETLY_CLOSE); + if (Objects.equals(quietly, true)) { + return; + } - Object account = ios.getAttribute(CIMConstant.SESSION_KEY); + Object account = ios.getAttribute(CIMConstant.KEY_ACCOUNT); if (account == null) { return; } - ios.removeAttribute(CIMConstant.SESSION_KEY); - sessionManager.remove(account.toString()); + CIMSession oldSession = memorySessionService.get(account.toString()); + + if (oldSession == null || oldSession.isApnsOpend()) { + return; + } + + oldSession.setState(CIMSession.STATE_DISABLED); + oldSession.setNid(null); + memorySessionService.save(oldSession); } } diff --git a/cim_for_mina/cim-boot-server/src/main/java/com/farsunset/cim/push/DefaultMessagePusher.java b/cim_for_mina/cim-boot-server/src/main/java/com/farsunset/cim/push/DefaultMessagePusher.java index 67962d0..e0e49bc 100644 --- a/cim_for_mina/cim-boot-server/src/main/java/com/farsunset/cim/push/DefaultMessagePusher.java +++ b/cim_for_mina/cim-boot-server/src/main/java/com/farsunset/cim/push/DefaultMessagePusher.java @@ -29,10 +29,9 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import com.farsunset.cim.sdk.server.model.Message; -import com.farsunset.cim.sdk.server.session.CIMSession; -import com.farsunset.cim.sdk.server.session.DefaultSessionManager; +import com.farsunset.cim.sdk.server.model.CIMSession; import com.farsunset.cim.service.ApnsService; -import com.farsunset.cim.service.impl.MessageDispatcherImpl; +import com.farsunset.cim.service.CIMSessionService; /** * 消息发送实现类 @@ -45,10 +44,8 @@ public class DefaultMessagePusher implements CIMMessagePusher { private String host; @Resource - private DefaultSessionManager sessionManager; + private CIMSessionService memorySessionService; - @Resource - private MessageDispatcherImpl messageDispatcher; @Resource @@ -61,31 +58,39 @@ public class DefaultMessagePusher implements CIMMessagePusher { * @param msg */ public void push(Message message) { - CIMSession session = sessionManager.get(message.getReceiver()); + CIMSession session = memorySessionService.get(message.getReceiver()); - /** - * 服务器集群时,可以在此 判断当前session是否连接于本台服务器,如果是,继续往下走,如果不是,将此消息发往当前session连接的服务器并 - */ - if (session.isConnected() && !Objects.equals(host, session.getHost())) { - messageDispatcher.forward(message, session.getHost()); + if(session == null) { return; } - /** - * 如果是在当前服务器则直接推送 + /* + * IOS设备,如果开启了apns,则使用apns推送 */ - if (session.isConnected() && Objects.equals(host, session.getHost())) { - session.write(message); + if (session.isIOSChannel() && session.isApnsOpend()) { + apnsService.push(message, session.getDeviceId()); return; } - /** - * ios设备流程特别处理,如果长链接断开了,并且ApnsAble为打开状态的话优走apns + /* + * 服务器集群时,判断当前session是否连接于本台服务器 + * 如果连接到了其他服务器则转发请求到目标服务器 */ - if (Objects.equals(session.getChannel(), CIMSession.CHANNEL_IOS) && Objects.equals(session.getApnsAble(), CIMSession.APNS_ON)) { - apnsService.push(message, session.getDeviceId()); + if (session.isConnected() && !Objects.equals(host, session.getHost())) { + /** + * @TODO + * 在此调用目标服务器接口来发送 + */ + return; } + /* + * 如果是Android,浏览器或者windows客户端则直接发送 + */ + if (session.isConnected() && Objects.equals(host, session.getHost())) { + session.write(message); + } + } } diff --git a/cim_for_mina/cim-boot-server/src/main/java/com/farsunset/cim/service/MessageDispatcher.java b/cim_for_mina/cim-boot-server/src/main/java/com/farsunset/cim/service/CIMSessionService.java similarity index 67% rename from cim_for_mina/cim-boot-server/src/main/java/com/farsunset/cim/service/MessageDispatcher.java rename to cim_for_mina/cim-boot-server/src/main/java/com/farsunset/cim/service/CIMSessionService.java index 911bfbc..45fb9c8 100644 --- a/cim_for_mina/cim-boot-server/src/main/java/com/farsunset/cim/service/MessageDispatcher.java +++ b/cim_for_mina/cim-boot-server/src/main/java/com/farsunset/cim/service/CIMSessionService.java @@ -1,4 +1,4 @@ -/** +/* * Copyright 2013-2019 Xia Jun(3979434@qq.com). * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,8 +21,23 @@ */ package com.farsunset.cim.service; -import com.farsunset.cim.sdk.server.model.Message; +import java.util.List; + +import com.farsunset.cim.sdk.server.model.CIMSession; + + +/** + * 集群 session管理实现示例, 各位可以自行实现 AbstractSessionManager接口来实现自己的 session管理 服务器集群时 + * 须要将CIMSession 信息存入数据库或者redis中 等 第三方存储空间中,便于所有服务器都可以访问 + */ +public interface CIMSessionService { + + void save(CIMSession session); + + CIMSession get(String account); + + List list(); + + void remove(String account); -public interface MessageDispatcher { - void forward(final Message msg, final String ip); } diff --git a/cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/session/ClusterSessionManager.java b/cim_for_mina/cim-boot-server/src/main/java/com/farsunset/cim/service/impl/ClusterSessionServiceImpl.java similarity index 60% rename from cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/session/ClusterSessionManager.java rename to cim_for_mina/cim-boot-server/src/main/java/com/farsunset/cim/service/impl/ClusterSessionServiceImpl.java index 988ca24..d6beb00 100644 --- a/cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/session/ClusterSessionManager.java +++ b/cim_for_mina/cim-boot-server/src/main/java/com/farsunset/cim/service/impl/ClusterSessionServiceImpl.java @@ -19,47 +19,54 @@ * * *************************************************************************************** */ -package com.farsunset.cim.session; +package com.farsunset.cim.service.impl; + import java.util.List; -import com.farsunset.cim.sdk.server.session.CIMSession; -import com.farsunset.cim.sdk.server.session.SessionManager; + +import javax.annotation.Resource; + +import org.springframework.stereotype.Service; + +import com.farsunset.cim.sdk.server.handler.CIMNioSocketAcceptor; +import com.farsunset.cim.sdk.server.model.CIMSession; +import com.farsunset.cim.service.CIMSessionService; + /** - * 集群 session管理实现示例, 各位可以自行实现 AbstractSessionManager接口来实现自己的 session管理 服务器集群时 - * 须要将CIMSession 信息存入数据库或者nosql 等 第三方存储空间中,便于所有服务器都可以访问 + * 集群情况下,数据库或者redis存储实现 + * 自行实现存储管理 + * */ -public class ClusterSessionManager implements SessionManager { +@Service("clusterSessionService") +public class ClusterSessionServiceImpl implements CIMSessionService { - public CIMSession get(String account) { - - // 这里查询数据库 - /* - * CIMSession session = database.getSession(account); - * session.setIoSession(ContextHolder.getBean(CIMNioSocketAcceptor.class). - * getManagedSessions().get(session.getNid())); return session; - */ - return null; + @Resource + private CIMNioSocketAcceptor nioSocketAcceptor; + + @Override + public void save(CIMSession session) { } @Override - public List queryAll() { + public CIMSession get(String account) { + + /* + * CIMSession session = database.getSession(account); + * session.setIoSession(nioSocketAcceptor.getManagedSessions().get(session.getNid())); + * return session; + */ + return null; } - + @Override public void remove(String account) { - } @Override - public void update(CIMSession session) { - + public List list() { + return null; } - - @Override - public void add(CIMSession arg0) { - - } - + } diff --git a/cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/service/impl/CIMSessionServiceImpl.java b/cim_for_mina/cim-boot-server/src/main/java/com/farsunset/cim/service/impl/MemorySessionServiceImpl.java similarity index 56% rename from cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/service/impl/CIMSessionServiceImpl.java rename to cim_for_mina/cim-boot-server/src/main/java/com/farsunset/cim/service/impl/MemorySessionServiceImpl.java index 94c3d2b..57ba29c 100644 --- a/cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/service/impl/CIMSessionServiceImpl.java +++ b/cim_for_mina/cim-boot-server/src/main/java/com/farsunset/cim/service/impl/MemorySessionServiceImpl.java @@ -21,11 +21,45 @@ */ package com.farsunset.cim.service.impl; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; + import org.springframework.stereotype.Service; -import com.farsunset.cim.sdk.server.session.DefaultSessionManager; +import com.farsunset.cim.sdk.server.model.CIMSession; +import com.farsunset.cim.service.CIMSessionService; -@Service -public class CIMSessionServiceImpl extends DefaultSessionManager { + +/** + * 单机,内存存储实现 + * + */ +@Service("memorySessionService") +public class MemorySessionServiceImpl implements CIMSessionService { + + private ConcurrentHashMap sessionMap = new ConcurrentHashMap(); + + @Override + public void save(CIMSession session) { + sessionMap.put(session.getAccount(), session); + } + + @Override + public CIMSession get(String account) { + return sessionMap.get(account); + } + + @Override + public void remove(String account) { + sessionMap.remove(account); + } + + @Override + public List list() { + List onlineList = new ArrayList<>(); + onlineList.addAll(sessionMap.values()); + return onlineList; + } } diff --git a/cim_for_mina/cim-boot-server/src/main/java/com/farsunset/cim/service/impl/MessageDispatcherImpl.java b/cim_for_mina/cim-boot-server/src/main/java/com/farsunset/cim/service/impl/MessageDispatcherImpl.java deleted file mode 100644 index 3f7ab3c..0000000 --- a/cim_for_mina/cim-boot-server/src/main/java/com/farsunset/cim/service/impl/MessageDispatcherImpl.java +++ /dev/null @@ -1,83 +0,0 @@ -/** - * Copyright 2013-2019 Xia Jun(3979434@qq.com). - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - *************************************************************************************** - * * - * Website : http://www.farsunset.com * - * * - *************************************************************************************** - */ -package com.farsunset.cim.service.impl; - -import java.util.concurrent.TimeUnit; -import java.util.logging.Logger; - -import org.apache.commons.io.IOUtils; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; - -import com.farsunset.cim.sdk.server.model.Message; -import com.farsunset.cim.service.MessageDispatcher; - -import okhttp3.FormBody; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; - -@Component -public class MessageDispatcherImpl implements MessageDispatcher{ - - private static final Logger logger = Logger.getLogger(MessageDispatcherImpl.class.getName()); - - @Value("${sys.message.dispatch.url}") - private String dispatchUrl; - - @Override - public void forward(final Message msg, final String ip) { - String apiUrl = String.format(dispatchUrl, ip); - try { - String response = httpPost(apiUrl, msg); - logger.info("消息转发目标服务器{" + ip + "},结果:" + response); - } catch (Exception e) { - e.printStackTrace(); - logger.severe("消息转发目标服务器" + apiUrl + "message:" + e.getMessage()); - } - } - - @SuppressWarnings("deprecation") - private String httpPost(String url, Message msg) throws Exception { - - OkHttpClient httpclient = new OkHttpClient.Builder().connectTimeout(10, TimeUnit.SECONDS).build(); - FormBody.Builder build = new FormBody.Builder(); - - build.add("id", String.valueOf(msg.getId())); - build.add("action", msg.getAction()); - build.add("title", msg.getTitle()); - build.add("content", msg.getContent()); - build.add("sender", msg.getSender()); - build.add("receiver", msg.getReceiver()); - build.add("format", msg.getFormat()); - build.add("extra", msg.getExtra()); - build.add("timestamp", String.valueOf(msg.getTimestamp())); - Request request = new Request.Builder().url(url).post(build.build()).build(); - - Response response = httpclient.newCall(request).execute(); - String data = response.body().string(); - IOUtils.closeQuietly(response); - return data; - } - - -} diff --git a/cim_for_mina/cim-server-sdk/.classpath b/cim_for_mina/cim-server-sdk/.classpath index 508ecfa..8e97c67 100644 --- a/cim_for_mina/cim-server-sdk/.classpath +++ b/cim_for_mina/cim-server-sdk/.classpath @@ -3,11 +3,11 @@ - + + - diff --git a/cim_for_mina/cim-server-sdk/.settings/org.eclipse.jdt.core.prefs b/cim_for_mina/cim-server-sdk/.settings/org.eclipse.jdt.core.prefs index c537b63..0c68a61 100644 --- a/cim_for_mina/cim-server-sdk/.settings/org.eclipse.jdt.core.prefs +++ b/cim_for_mina/cim-server-sdk/.settings/org.eclipse.jdt.core.prefs @@ -1,7 +1,7 @@ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 -org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.6 +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/cim_for_mina/cim-server-sdk/.settings/org.eclipse.wst.common.project.facet.core.xml b/cim_for_mina/cim-server-sdk/.settings/org.eclipse.wst.common.project.facet.core.xml index 10c580d..c56e134 100644 --- a/cim_for_mina/cim-server-sdk/.settings/org.eclipse.wst.common.project.facet.core.xml +++ b/cim_for_mina/cim-server-sdk/.settings/org.eclipse.wst.common.project.facet.core.xml @@ -1,5 +1,5 @@ - + diff --git a/cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/constant/CIMConstant.java b/cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/constant/CIMConstant.java index 8f18c16..b4c6299 100644 --- a/cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/constant/CIMConstant.java +++ b/cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/constant/CIMConstant.java @@ -40,9 +40,14 @@ public interface CIMConstant { } - String SESSION_KEY = "account"; - String HEARTBEAT_KEY = "heartbeat"; + String KEY_ACCOUNT = "account"; + String KEY_QUIETLY_CLOSE = "quietlyClose"; + + String CLIENT_WEBSOCKET_HANDSHAKE = "client_websocket_handshake"; + + String CLIENT_CONNECT_CLOSED = "client_closed"; + public static interface ProtobufType { byte S_H_RQ = 1; byte C_H_RS = 0; diff --git a/cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/filter/CIMLoggingFilter.java b/cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/filter/CIMLoggingFilter.java index 1fb01e9..0fe9970 100644 --- a/cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/filter/CIMLoggingFilter.java +++ b/cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/filter/CIMLoggingFilter.java @@ -96,8 +96,8 @@ public class CIMLoggingFilter extends IoFilterAdapter { builder.append(" R:").append(session.getRemoteAddress().toString()); } - if (session.containsAttribute(CIMConstant.SESSION_KEY)) { - builder.append(" account:").append(session.getAttribute(CIMConstant.SESSION_KEY)); + if (session.containsAttribute(CIMConstant.KEY_ACCOUNT)) { + builder.append(" account:").append(session.getAttribute(CIMConstant.KEY_ACCOUNT)); } builder.append("]"); return builder.toString(); diff --git a/cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/filter/ServerMessageEncoder.java b/cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/filter/ServerMessageEncoder.java index 3b7a74a..5bca279 100644 --- a/cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/filter/ServerMessageEncoder.java +++ b/cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/filter/ServerMessageEncoder.java @@ -31,7 +31,7 @@ import org.apache.mina.filter.codec.ProtocolEncoderOutput; import com.farsunset.cim.sdk.server.constant.CIMConstant; import com.farsunset.cim.sdk.server.model.HandshakerResponse; import com.farsunset.cim.sdk.server.model.feature.EncodeFormatable; -import com.farsunset.cim.sdk.server.session.CIMSession; +import com.farsunset.cim.sdk.server.model.CIMSession; /** * 服务端发送消息前编码 diff --git a/cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/filter/decoder/AppMessageDecoder.java b/cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/filter/decoder/AppMessageDecoder.java index 07df1f6..540d71d 100644 --- a/cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/filter/decoder/AppMessageDecoder.java +++ b/cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/filter/decoder/AppMessageDecoder.java @@ -33,7 +33,7 @@ import com.farsunset.cim.sdk.server.constant.CIMConstant; import com.farsunset.cim.sdk.server.model.HeartbeatResponse; import com.farsunset.cim.sdk.server.model.SentBody; import com.farsunset.cim.sdk.server.model.proto.SentBodyProto; -import com.farsunset.cim.sdk.server.session.CIMSession; +import com.farsunset.cim.sdk.server.model.CIMSession; /** * 原生app发送的消息解码器 diff --git a/cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/filter/decoder/WebMessageDecoder.java b/cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/filter/decoder/WebMessageDecoder.java index 3ba0813..1dc7d5e 100644 --- a/cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/filter/decoder/WebMessageDecoder.java +++ b/cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/filter/decoder/WebMessageDecoder.java @@ -30,11 +30,10 @@ import org.apache.mina.filter.codec.ProtocolDecoderOutput; import org.apache.mina.filter.codec.demux.MessageDecoderAdapter; import org.apache.mina.filter.codec.demux.MessageDecoderResult; import com.farsunset.cim.sdk.server.constant.CIMConstant; -import com.farsunset.cim.sdk.server.handler.CIMNioSocketAcceptor; import com.farsunset.cim.sdk.server.model.HeartbeatResponse; import com.farsunset.cim.sdk.server.model.SentBody; import com.farsunset.cim.sdk.server.model.proto.SentBodyProto; -import com.farsunset.cim.sdk.server.session.CIMSession; +import com.farsunset.cim.sdk.server.model.CIMSession; import com.google.protobuf.InvalidProtocolBufferException; /** @@ -203,7 +202,7 @@ public class WebMessageDecoder extends MessageDecoderAdapter { iosession.setAttribute(CIMSession.PROTOCOL,CIMSession.WEBSOCKET); SentBody body = new SentBody(); - body.setKey(CIMNioSocketAcceptor.WEBSOCKET_HANDLER_KEY); + body.setKey(CIMConstant.CLIENT_WEBSOCKET_HANDSHAKE); body.setTimestamp(System.currentTimeMillis()); body.put("key", getSecWebSocketKey(message)); out.write(body); diff --git a/cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/handler/CIMNioSocketAcceptor.java b/cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/handler/CIMNioSocketAcceptor.java index eb3468e..d49383d 100644 --- a/cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/handler/CIMNioSocketAcceptor.java +++ b/cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/handler/CIMNioSocketAcceptor.java @@ -1,5 +1,5 @@ /** - * Copyright 2013-2019 Xia Jun(3979434@qq.com). + * Copyright 2013-2023 Xia Jun(3979434@qq.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,6 +25,7 @@ import java.io.IOException; import java.net.InetSocketAddress; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import org.apache.mina.core.service.IoAcceptor; @@ -38,24 +39,16 @@ import org.apache.mina.filter.keepalive.KeepAliveMessageFactory; import org.apache.mina.transport.socket.DefaultSocketSessionConfig; import org.apache.mina.transport.socket.nio.NioSocketAcceptor; +import com.farsunset.cim.sdk.server.constant.CIMConstant; import com.farsunset.cim.sdk.server.filter.CIMLoggingFilter; import com.farsunset.cim.sdk.server.filter.ServerMessageCodecFactory; import com.farsunset.cim.sdk.server.model.HeartbeatRequest; import com.farsunset.cim.sdk.server.model.HeartbeatResponse; import com.farsunset.cim.sdk.server.model.SentBody; -import com.farsunset.cim.sdk.server.session.CIMSession; +import com.farsunset.cim.sdk.server.model.CIMSession; public class CIMNioSocketAcceptor extends IoHandlerAdapter implements KeepAliveMessageFactory { - /** - * websocket特有的握手处理handler - */ - public final static String WEBSOCKET_HANDLER_KEY = "client_websocket_handshake"; - /** - * 连接关闭处理handler - */ - public final static String CIMSESSION_CLOSED_HANDLER_KEY = "client_closed"; - private HashMap innerHandlerMap = new HashMap(); private CIMRequestHandler outerRequestHandler; private IoAcceptor acceptor; @@ -69,7 +62,7 @@ public class CIMNioSocketAcceptor extends IoHandlerAdapter implements KeepAliveM /** * 预制websocket握手请求的处理 */ - innerHandlerMap.put(WEBSOCKET_HANDLER_KEY, new WebsocketHandler()); + innerHandlerMap.put(CIMConstant.CLIENT_WEBSOCKET_HANDSHAKE, new WebsocketHandler()); acceptor = new NioSocketAcceptor(); acceptor.getSessionConfig().setReadBufferSize(READ_BUFFER_SIZE); @@ -81,11 +74,16 @@ public class CIMNioSocketAcceptor extends IoHandlerAdapter implements KeepAliveM keepAliveFilter.setRequestTimeout(TIME_OUT); keepAliveFilter.setForwardEvent(true); - acceptor.getFilterChain().addLast("executor", new ExecutorFilter(Executors.newCachedThreadPool())); + ExecutorService executor = Executors.newCachedThreadPool(runnable -> { + Thread thread = Executors.defaultThreadFactory().newThread(runnable); + thread.setName("mina-thread-" + thread.getId()); + return thread; + }); + acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new ServerMessageCodecFactory())); acceptor.getFilterChain().addLast("logger", new CIMLoggingFilter()); acceptor.getFilterChain().addLast("heartbeat", keepAliveFilter); - + acceptor.getFilterChain().addLast("executor", new ExecutorFilter(executor)); acceptor.setHandler(this); acceptor.bind(new InetSocketAddress(port)); @@ -93,6 +91,7 @@ public class CIMNioSocketAcceptor extends IoHandlerAdapter implements KeepAliveM public void unbind() { acceptor.unbind(); + acceptor.dispose(); } /** @@ -126,13 +125,12 @@ public class CIMNioSocketAcceptor extends IoHandlerAdapter implements KeepAliveM @Override public void sessionClosed(IoSession ios) { - + CIMSession session = new CIMSession(ios); SentBody body = new SentBody(); - body.setKey(CIMSESSION_CLOSED_HANDLER_KEY); + body.setKey(CIMConstant.CLIENT_CONNECT_CLOSED); outerRequestHandler.process(session, body); } - @Override public Object getRequest(IoSession session) { diff --git a/cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/handler/CIMRequestHandler.java b/cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/handler/CIMRequestHandler.java index 16aa5b8..0f49b39 100644 --- a/cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/handler/CIMRequestHandler.java +++ b/cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/handler/CIMRequestHandler.java @@ -26,7 +26,7 @@ package com.farsunset.cim.sdk.server.handler; * @author 3979434@qq.com */ import com.farsunset.cim.sdk.server.model.SentBody; -import com.farsunset.cim.sdk.server.session.CIMSession; +import com.farsunset.cim.sdk.server.model.CIMSession; public interface CIMRequestHandler { diff --git a/cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/handler/WebsocketHandler.java b/cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/handler/WebsocketHandler.java index cd84899..6731762 100644 --- a/cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/handler/WebsocketHandler.java +++ b/cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/handler/WebsocketHandler.java @@ -25,7 +25,7 @@ import java.security.MessageDigest; import com.farsunset.cim.sdk.server.model.SentBody; import com.farsunset.cim.sdk.server.model.HandshakerResponse; -import com.farsunset.cim.sdk.server.session.CIMSession; +import com.farsunset.cim.sdk.server.model.CIMSession; /** * 处理websocket握手请求,返回响应的报文给浏览器 diff --git a/cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/session/CIMSession.java b/cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/model/CIMSession.java similarity index 63% rename from cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/session/CIMSession.java rename to cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/model/CIMSession.java index 1a2a834..d3dcfb8 100644 --- a/cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/session/CIMSession.java +++ b/cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/model/CIMSession.java @@ -1,5 +1,5 @@ /** - * Copyright 2013-2019 Xia Jun(3979434@qq.com). + * Copyright 2013-2023 Xia Jun(3979434@qq.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,35 +19,33 @@ * * *************************************************************************************** */ -package com.farsunset.cim.sdk.server.session; +package com.farsunset.cim.sdk.server.model; import java.io.Serializable; -import java.net.InetAddress; import java.net.SocketAddress; -import java.net.UnknownHostException; +import java.util.Objects; import org.apache.mina.core.future.WriteFuture; import org.apache.mina.core.session.IoSession; import com.farsunset.cim.sdk.server.constant.CIMConstant; +import com.farsunset.cim.sdk.server.model.proto.SessionProto; +import com.google.protobuf.InvalidProtocolBufferException; /** * IoSession包装类,集群时 将此对象存入表中 */ - public class CIMSession implements Serializable { - /** - * - */ private transient static final long serialVersionUID = 1L; - + public transient static String PROTOCOL = "protocol"; public transient static String WEBSOCKET = "websocket"; public transient static String NATIVEAPP = "nativeapp"; - public transient static final int STATUS_ENABLED = 0; - public transient static final int STATUS_DISABLED = 1; + public transient static String HOST = "HOST"; + public transient static final int STATE_ENABLED = 0; + public transient static final int STATE_DISABLED = 1; public transient static final int APNS_ON = 1; public transient static final int APNS_OFF = 0; @@ -59,22 +57,19 @@ public class CIMSession implements Serializable { private transient IoSession session; - private String gid;// session全局ID + private String account;// session绑定的账号,主键,一个账号同一时间之内在一个设备在线 private Long nid;// session在本台服务器上的ID private String deviceId;// 客户端ID (设备号码+应用包名),ios为devicetoken private String host;// session绑定的服务器IP - private String account;// session绑定的账号 private String channel;// 终端设备类型 private String deviceModel;// 终端设备型号 private String clientVersion;// 终端应用版本 private String systemVersion;// 终端系统版本 - private String packageName;// 终端应用包名 private Long bindTime;// 登录时间 - private Long heartbeat;// 心跳时间 private Double longitude;// 经度 private Double latitude;// 维度 private String location;// 位置 - private int apnsAble;// apns推送状态 + private int apns;// apns推送状态 private int state;// 状态 public CIMSession(IoSession session) { @@ -93,7 +88,7 @@ public class CIMSession implements Serializable { public void setAccount(String account) { this.account = account; - setAttribute(CIMConstant.SESSION_KEY, account); + setAttribute(CIMConstant.KEY_ACCOUNT, account); } public Double getLongitude() { @@ -120,17 +115,6 @@ public class CIMSession implements Serializable { this.location = location; } - public String getGid() { - return gid; - } - - public void setGid(String gid) { - - this.gid = gid; - - setAttribute("gid", gid); - } - public Long getNid() { return nid; } @@ -161,7 +145,6 @@ public class CIMSession implements Serializable { public void setDeviceId(String deviceId) { this.deviceId = deviceId; - } public String getHost() { @@ -192,25 +175,16 @@ public class CIMSession implements Serializable { this.systemVersion = systemVersion; } - public Long getHeartbeat() { - return heartbeat; - } - - public void setHeartbeat(Long heartbeat) { - this.heartbeat = heartbeat; - setAttribute(CIMConstant.HEARTBEAT_KEY, heartbeat); - } - public void setHost(String host) { this.host = host; } - public int getApnsAble() { - return apnsAble; + public int getApns() { + return apns; } - public void setApnsAble(int apnsAble) { - this.apnsAble = apnsAble; + public void setApns(int apns) { + this.apns = apns; } public int getState() { @@ -260,27 +234,7 @@ public class CIMSession implements Serializable { } public boolean isConnected() { - if (session != null) { - return session.isConnected(); - } - - if (!isLocalhost()) { - return state == STATUS_ENABLED; - } - - return false; - } - - public boolean isLocalhost() { - - try { - String ip = InetAddress.getLocalHost().getHostAddress(); - return ip.equals(host); - } catch (UnknownHostException e) { - e.printStackTrace(); - } - return false; - + return (session != null && session.isConnected()) || state == STATE_ENABLED; } public void closeNow() { @@ -293,70 +247,111 @@ public class CIMSession implements Serializable { session.closeOnFlush(); } - public void setPackageName(String packageName) { - this.packageName = packageName; + public boolean isIOSChannel() { + return Objects.equals(channel, CHANNEL_IOS); } - public String getPackageName() { - return packageName; + public boolean isAndroidChannel() { + return Objects.equals(channel, CHANNEL_ANDROID); } + public boolean isWindowsChannel() { + return Objects.equals(channel, CHANNEL_WINDOWS); + } + + public boolean isApnsOpend() { + return Objects.equals(apns, APNS_ON); + } + + @Override public int hashCode() { - - return (deviceId + nid + host).hashCode(); + return getClass().hashCode(); } + @Override public boolean equals(Object o) { - if (o instanceof CIMSession) { - return hashCode() == o.hashCode(); + CIMSession target = (CIMSession) o; + return Objects.equals(target.deviceId, deviceId) && Objects.equals(target.nid, nid) + && Objects.equals(target.host, host); } return false; } - public boolean fromOtherDevice(Object o) { - - if (o instanceof CIMSession) { - - CIMSession t = (CIMSession) o; - if (t.deviceId != null && deviceId != null) { - return !t.deviceId.equals(deviceId); - } - } - return false; - } - - public boolean fromCurrentDevice(Object o) { - - return !fromOtherDevice(o); - } - - public void setIoSession(IoSession session) { - this.session = session; - } - - public IoSession getIoSession() { + public IoSession getSession() { return session; } - public String toString() { - StringBuffer buffer = new StringBuffer(); - buffer.append("{"); - - buffer.append("\"").append("gid").append("\":").append("\"").append(gid).append("\"").append(","); - buffer.append("\"").append("nid").append("\":").append(nid).append(","); - buffer.append("\"").append("deviceId").append("\":").append("\"").append(deviceId).append("\"").append(","); - buffer.append("\"").append("host").append("\":").append("\"").append(host).append("\"").append(","); - buffer.append("\"").append("account").append("\":").append("\"").append(account).append("\"").append(","); - buffer.append("\"").append("channel").append("\":").append("\"").append(channel).append("\"").append(","); - buffer.append("\"").append("deviceModel").append("\":").append("\"").append(deviceModel).append("\"").append(","); - buffer.append("\"").append("status").append("\":").append(state).append(","); - buffer.append("\"").append("apnsAble").append("\":").append(apnsAble).append(","); - buffer.append("\"").append("bindTime").append("\":").append(bindTime).append(","); - buffer.append("\"").append("heartbeat").append("\":").append(heartbeat); - buffer.append("}"); - return buffer.toString(); - + public void setSession(IoSession session) { + this.session = session; } + public byte[] getProtobufBody() { + SessionProto.Model.Builder builder = SessionProto.Model.newBuilder(); + if (account != null) { + builder.setAccount(account); + } + if (nid != null) { + builder.setNid(nid); + } + if (deviceId != null) { + builder.setDeviceId(deviceId); + } + if (host != null) { + builder.setHost(host); + } + if (channel != null) { + builder.setChannel(channel); + } + if (deviceModel != null) { + builder.setDeviceModel(deviceModel); + } + if (clientVersion != null) { + builder.setClientVersion(clientVersion); + } + if (systemVersion != null) { + builder.setSystemVersion(systemVersion); + } + if (bindTime != null) { + builder.setBindTime(bindTime); + } + if (longitude != null) { + builder.setLongitude(longitude); + } + if (latitude != null) { + builder.setLatitude(latitude); + } + if (location != null) { + builder.setLocation(location); + } + builder.setState(state); + builder.setApns(apns); + return builder.build().toByteArray(); + } + + + public static CIMSession decode(byte[] protobufBody) throws InvalidProtocolBufferException { + if(protobufBody == null) { + return null; + } + SessionProto.Model proto = SessionProto.Model.parseFrom(protobufBody); + CIMSession session = new CIMSession(); + session.setApns(proto.getApns()); + session.setBindTime(proto.getBindTime()); + session.setChannel(proto.getChannel()); + session.setClientVersion(proto.getClientVersion()); + session.setDeviceId(proto.getDeviceId()); + session.setDeviceModel(proto.getDeviceModel()); + session.setHost(proto.getHost()); + session.setLatitude(proto.getLatitude()); + session.setLongitude(proto.getLongitude()); + session.setLocation(proto.getLocation()); + session.setNid(proto.getNid()); + session.setSystemVersion(proto.getSystemVersion()); + session.setState(proto.getState()); + session.setAccount(proto.getAccount()); + return session; + } + + } diff --git a/cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/model/proto/Session.proto b/cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/model/proto/Session.proto new file mode 100644 index 0000000..edce10d --- /dev/null +++ b/cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/model/proto/Session.proto @@ -0,0 +1,19 @@ +syntax = "proto3"; +package com.farsunset.cim.sdk.server.model.proto; +option java_outer_classname="SessionProto"; +message Model { + string account = 1; + int64 nid = 2; + string deviceId = 3; + string host = 4; + string channel = 5; + string deviceModel = 6; + string clientVersion = 7; + string systemVersion = 8; + int64 bindTime = 9; + double longitude = 10; + double latitude = 11; + string location = 12; + int32 apns = 13; + int32 state = 14; +} diff --git a/cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/model/proto/SessionProto.java b/cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/model/proto/SessionProto.java new file mode 100644 index 0000000..8b2b859 --- /dev/null +++ b/cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/model/proto/SessionProto.java @@ -0,0 +1,1932 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: Session.proto + +package com.farsunset.cim.sdk.server.model.proto; + +public final class SessionProto { + private SessionProto() {} + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistryLite registry) { + } + + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistry registry) { + registerAllExtensions( + (com.google.protobuf.ExtensionRegistryLite) registry); + } + public interface ModelOrBuilder extends + // @@protoc_insertion_point(interface_extends:com.farsunset.cim.sdk.server.model.proto.Model) + com.google.protobuf.MessageOrBuilder { + + /** + * string account = 1; + */ + java.lang.String getAccount(); + /** + * string account = 1; + */ + com.google.protobuf.ByteString + getAccountBytes(); + + /** + * int64 nid = 2; + */ + long getNid(); + + /** + * string deviceId = 3; + */ + java.lang.String getDeviceId(); + /** + * string deviceId = 3; + */ + com.google.protobuf.ByteString + getDeviceIdBytes(); + + /** + * string host = 4; + */ + java.lang.String getHost(); + /** + * string host = 4; + */ + com.google.protobuf.ByteString + getHostBytes(); + + /** + * string channel = 5; + */ + java.lang.String getChannel(); + /** + * string channel = 5; + */ + com.google.protobuf.ByteString + getChannelBytes(); + + /** + * string deviceModel = 6; + */ + java.lang.String getDeviceModel(); + /** + * string deviceModel = 6; + */ + com.google.protobuf.ByteString + getDeviceModelBytes(); + + /** + * string clientVersion = 7; + */ + java.lang.String getClientVersion(); + /** + * string clientVersion = 7; + */ + com.google.protobuf.ByteString + getClientVersionBytes(); + + /** + * string systemVersion = 8; + */ + java.lang.String getSystemVersion(); + /** + * string systemVersion = 8; + */ + com.google.protobuf.ByteString + getSystemVersionBytes(); + + /** + * int64 bindTime = 9; + */ + long getBindTime(); + + /** + * double longitude = 10; + */ + double getLongitude(); + + /** + * double latitude = 11; + */ + double getLatitude(); + + /** + * string location = 12; + */ + java.lang.String getLocation(); + /** + * string location = 12; + */ + com.google.protobuf.ByteString + getLocationBytes(); + + /** + * int32 apns = 13; + */ + int getApns(); + + /** + * int32 state = 14; + */ + int getState(); + } + /** + * Protobuf type {@code com.farsunset.cim.sdk.server.model.proto.Model} + */ + public static final class Model extends + com.google.protobuf.GeneratedMessageV3 implements + // @@protoc_insertion_point(message_implements:com.farsunset.cim.sdk.server.model.proto.Model) + ModelOrBuilder { + private static final long serialVersionUID = 0L; + // Use Model.newBuilder() to construct. + private Model(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + private Model() { + account_ = ""; + nid_ = 0L; + deviceId_ = ""; + host_ = ""; + channel_ = ""; + deviceModel_ = ""; + clientVersion_ = ""; + systemVersion_ = ""; + bindTime_ = 0L; + longitude_ = 0D; + latitude_ = 0D; + location_ = ""; + apns_ = 0; + state_ = 0; + } + + @java.lang.Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return this.unknownFields; + } + private Model( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + this(); + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + int mutable_bitField0_ = 0; + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder(); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownFieldProto3( + input, unknownFields, extensionRegistry, tag)) { + done = true; + } + break; + } + case 10: { + java.lang.String s = input.readStringRequireUtf8(); + + account_ = s; + break; + } + case 16: { + + nid_ = input.readInt64(); + break; + } + case 26: { + java.lang.String s = input.readStringRequireUtf8(); + + deviceId_ = s; + break; + } + case 34: { + java.lang.String s = input.readStringRequireUtf8(); + + host_ = s; + break; + } + case 42: { + java.lang.String s = input.readStringRequireUtf8(); + + channel_ = s; + break; + } + case 50: { + java.lang.String s = input.readStringRequireUtf8(); + + deviceModel_ = s; + break; + } + case 58: { + java.lang.String s = input.readStringRequireUtf8(); + + clientVersion_ = s; + break; + } + case 66: { + java.lang.String s = input.readStringRequireUtf8(); + + systemVersion_ = s; + break; + } + case 72: { + + bindTime_ = input.readInt64(); + break; + } + case 81: { + + longitude_ = input.readDouble(); + break; + } + case 89: { + + latitude_ = input.readDouble(); + break; + } + case 98: { + java.lang.String s = input.readStringRequireUtf8(); + + location_ = s; + break; + } + case 104: { + + apns_ = input.readInt32(); + break; + } + case 112: { + + state_ = input.readInt32(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e).setUnfinishedMessage(this); + } finally { + this.unknownFields = unknownFields.build(); + makeExtensionsImmutable(); + } + } + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return com.farsunset.cim.sdk.server.model.proto.SessionProto.internal_static_com_farsunset_cim_sdk_server_model_proto_Model_descriptor; + } + + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return com.farsunset.cim.sdk.server.model.proto.SessionProto.internal_static_com_farsunset_cim_sdk_server_model_proto_Model_fieldAccessorTable + .ensureFieldAccessorsInitialized( + com.farsunset.cim.sdk.server.model.proto.SessionProto.Model.class, com.farsunset.cim.sdk.server.model.proto.SessionProto.Model.Builder.class); + } + + public static final int ACCOUNT_FIELD_NUMBER = 1; + private volatile java.lang.Object account_; + /** + * string account = 1; + */ + public java.lang.String getAccount() { + java.lang.Object ref = account_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + account_ = s; + return s; + } + } + /** + * string account = 1; + */ + public com.google.protobuf.ByteString + getAccountBytes() { + java.lang.Object ref = account_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + account_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int NID_FIELD_NUMBER = 2; + private long nid_; + /** + * int64 nid = 2; + */ + public long getNid() { + return nid_; + } + + public static final int DEVICEID_FIELD_NUMBER = 3; + private volatile java.lang.Object deviceId_; + /** + * string deviceId = 3; + */ + public java.lang.String getDeviceId() { + java.lang.Object ref = deviceId_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + deviceId_ = s; + return s; + } + } + /** + * string deviceId = 3; + */ + public com.google.protobuf.ByteString + getDeviceIdBytes() { + java.lang.Object ref = deviceId_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + deviceId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int HOST_FIELD_NUMBER = 4; + private volatile java.lang.Object host_; + /** + * string host = 4; + */ + public java.lang.String getHost() { + java.lang.Object ref = host_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + host_ = s; + return s; + } + } + /** + * string host = 4; + */ + public com.google.protobuf.ByteString + getHostBytes() { + java.lang.Object ref = host_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + host_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int CHANNEL_FIELD_NUMBER = 5; + private volatile java.lang.Object channel_; + /** + * string channel = 5; + */ + public java.lang.String getChannel() { + java.lang.Object ref = channel_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + channel_ = s; + return s; + } + } + /** + * string channel = 5; + */ + public com.google.protobuf.ByteString + getChannelBytes() { + java.lang.Object ref = channel_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + channel_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int DEVICEMODEL_FIELD_NUMBER = 6; + private volatile java.lang.Object deviceModel_; + /** + * string deviceModel = 6; + */ + public java.lang.String getDeviceModel() { + java.lang.Object ref = deviceModel_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + deviceModel_ = s; + return s; + } + } + /** + * string deviceModel = 6; + */ + public com.google.protobuf.ByteString + getDeviceModelBytes() { + java.lang.Object ref = deviceModel_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + deviceModel_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int CLIENTVERSION_FIELD_NUMBER = 7; + private volatile java.lang.Object clientVersion_; + /** + * string clientVersion = 7; + */ + public java.lang.String getClientVersion() { + java.lang.Object ref = clientVersion_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + clientVersion_ = s; + return s; + } + } + /** + * string clientVersion = 7; + */ + public com.google.protobuf.ByteString + getClientVersionBytes() { + java.lang.Object ref = clientVersion_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + clientVersion_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int SYSTEMVERSION_FIELD_NUMBER = 8; + private volatile java.lang.Object systemVersion_; + /** + * string systemVersion = 8; + */ + public java.lang.String getSystemVersion() { + java.lang.Object ref = systemVersion_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + systemVersion_ = s; + return s; + } + } + /** + * string systemVersion = 8; + */ + public com.google.protobuf.ByteString + getSystemVersionBytes() { + java.lang.Object ref = systemVersion_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + systemVersion_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int BINDTIME_FIELD_NUMBER = 9; + private long bindTime_; + /** + * int64 bindTime = 9; + */ + public long getBindTime() { + return bindTime_; + } + + public static final int LONGITUDE_FIELD_NUMBER = 10; + private double longitude_; + /** + * double longitude = 10; + */ + public double getLongitude() { + return longitude_; + } + + public static final int LATITUDE_FIELD_NUMBER = 11; + private double latitude_; + /** + * double latitude = 11; + */ + public double getLatitude() { + return latitude_; + } + + public static final int LOCATION_FIELD_NUMBER = 12; + private volatile java.lang.Object location_; + /** + * string location = 12; + */ + public java.lang.String getLocation() { + java.lang.Object ref = location_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + location_ = s; + return s; + } + } + /** + * string location = 12; + */ + public com.google.protobuf.ByteString + getLocationBytes() { + java.lang.Object ref = location_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + location_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int APNS_FIELD_NUMBER = 13; + private int apns_; + /** + * int32 apns = 13; + */ + public int getApns() { + return apns_; + } + + public static final int STATE_FIELD_NUMBER = 14; + private int state_; + /** + * int32 state = 14; + */ + public int getState() { + return state_; + } + + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!getAccountBytes().isEmpty()) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 1, account_); + } + if (nid_ != 0L) { + output.writeInt64(2, nid_); + } + if (!getDeviceIdBytes().isEmpty()) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 3, deviceId_); + } + if (!getHostBytes().isEmpty()) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 4, host_); + } + if (!getChannelBytes().isEmpty()) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 5, channel_); + } + if (!getDeviceModelBytes().isEmpty()) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 6, deviceModel_); + } + if (!getClientVersionBytes().isEmpty()) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 7, clientVersion_); + } + if (!getSystemVersionBytes().isEmpty()) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 8, systemVersion_); + } + if (bindTime_ != 0L) { + output.writeInt64(9, bindTime_); + } + if (longitude_ != 0D) { + output.writeDouble(10, longitude_); + } + if (latitude_ != 0D) { + output.writeDouble(11, latitude_); + } + if (!getLocationBytes().isEmpty()) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 12, location_); + } + if (apns_ != 0) { + output.writeInt32(13, apns_); + } + if (state_ != 0) { + output.writeInt32(14, state_); + } + unknownFields.writeTo(output); + } + + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!getAccountBytes().isEmpty()) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, account_); + } + if (nid_ != 0L) { + size += com.google.protobuf.CodedOutputStream + .computeInt64Size(2, nid_); + } + if (!getDeviceIdBytes().isEmpty()) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(3, deviceId_); + } + if (!getHostBytes().isEmpty()) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(4, host_); + } + if (!getChannelBytes().isEmpty()) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(5, channel_); + } + if (!getDeviceModelBytes().isEmpty()) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(6, deviceModel_); + } + if (!getClientVersionBytes().isEmpty()) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(7, clientVersion_); + } + if (!getSystemVersionBytes().isEmpty()) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(8, systemVersion_); + } + if (bindTime_ != 0L) { + size += com.google.protobuf.CodedOutputStream + .computeInt64Size(9, bindTime_); + } + if (longitude_ != 0D) { + size += com.google.protobuf.CodedOutputStream + .computeDoubleSize(10, longitude_); + } + if (latitude_ != 0D) { + size += com.google.protobuf.CodedOutputStream + .computeDoubleSize(11, latitude_); + } + if (!getLocationBytes().isEmpty()) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(12, location_); + } + if (apns_ != 0) { + size += com.google.protobuf.CodedOutputStream + .computeInt32Size(13, apns_); + } + if (state_ != 0) { + size += com.google.protobuf.CodedOutputStream + .computeInt32Size(14, state_); + } + size += unknownFields.getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof com.farsunset.cim.sdk.server.model.proto.SessionProto.Model)) { + return super.equals(obj); + } + com.farsunset.cim.sdk.server.model.proto.SessionProto.Model other = (com.farsunset.cim.sdk.server.model.proto.SessionProto.Model) obj; + + boolean result = true; + result = result && getAccount() + .equals(other.getAccount()); + result = result && (getNid() + == other.getNid()); + result = result && getDeviceId() + .equals(other.getDeviceId()); + result = result && getHost() + .equals(other.getHost()); + result = result && getChannel() + .equals(other.getChannel()); + result = result && getDeviceModel() + .equals(other.getDeviceModel()); + result = result && getClientVersion() + .equals(other.getClientVersion()); + result = result && getSystemVersion() + .equals(other.getSystemVersion()); + result = result && (getBindTime() + == other.getBindTime()); + result = result && ( + java.lang.Double.doubleToLongBits(getLongitude()) + == java.lang.Double.doubleToLongBits( + other.getLongitude())); + result = result && ( + java.lang.Double.doubleToLongBits(getLatitude()) + == java.lang.Double.doubleToLongBits( + other.getLatitude())); + result = result && getLocation() + .equals(other.getLocation()); + result = result && (getApns() + == other.getApns()); + result = result && (getState() + == other.getState()); + result = result && unknownFields.equals(other.unknownFields); + return result; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + ACCOUNT_FIELD_NUMBER; + hash = (53 * hash) + getAccount().hashCode(); + hash = (37 * hash) + NID_FIELD_NUMBER; + hash = (53 * hash) + com.google.protobuf.Internal.hashLong( + getNid()); + hash = (37 * hash) + DEVICEID_FIELD_NUMBER; + hash = (53 * hash) + getDeviceId().hashCode(); + hash = (37 * hash) + HOST_FIELD_NUMBER; + hash = (53 * hash) + getHost().hashCode(); + hash = (37 * hash) + CHANNEL_FIELD_NUMBER; + hash = (53 * hash) + getChannel().hashCode(); + hash = (37 * hash) + DEVICEMODEL_FIELD_NUMBER; + hash = (53 * hash) + getDeviceModel().hashCode(); + hash = (37 * hash) + CLIENTVERSION_FIELD_NUMBER; + hash = (53 * hash) + getClientVersion().hashCode(); + hash = (37 * hash) + SYSTEMVERSION_FIELD_NUMBER; + hash = (53 * hash) + getSystemVersion().hashCode(); + hash = (37 * hash) + BINDTIME_FIELD_NUMBER; + hash = (53 * hash) + com.google.protobuf.Internal.hashLong( + getBindTime()); + hash = (37 * hash) + LONGITUDE_FIELD_NUMBER; + hash = (53 * hash) + com.google.protobuf.Internal.hashLong( + java.lang.Double.doubleToLongBits(getLongitude())); + hash = (37 * hash) + LATITUDE_FIELD_NUMBER; + hash = (53 * hash) + com.google.protobuf.Internal.hashLong( + java.lang.Double.doubleToLongBits(getLatitude())); + hash = (37 * hash) + LOCATION_FIELD_NUMBER; + hash = (53 * hash) + getLocation().hashCode(); + hash = (37 * hash) + APNS_FIELD_NUMBER; + hash = (53 * hash) + getApns(); + hash = (37 * hash) + STATE_FIELD_NUMBER; + hash = (53 * hash) + getState(); + hash = (29 * hash) + unknownFields.hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static com.farsunset.cim.sdk.server.model.proto.SessionProto.Model parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.farsunset.cim.sdk.server.model.proto.SessionProto.Model parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.farsunset.cim.sdk.server.model.proto.SessionProto.Model parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.farsunset.cim.sdk.server.model.proto.SessionProto.Model parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.farsunset.cim.sdk.server.model.proto.SessionProto.Model parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.farsunset.cim.sdk.server.model.proto.SessionProto.Model parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.farsunset.cim.sdk.server.model.proto.SessionProto.Model parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static com.farsunset.cim.sdk.server.model.proto.SessionProto.Model parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + public static com.farsunset.cim.sdk.server.model.proto.SessionProto.Model parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input); + } + public static com.farsunset.cim.sdk.server.model.proto.SessionProto.Model parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static com.farsunset.cim.sdk.server.model.proto.SessionProto.Model parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static com.farsunset.cim.sdk.server.model.proto.SessionProto.Model parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(com.farsunset.cim.sdk.server.model.proto.SessionProto.Model prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code com.farsunset.cim.sdk.server.model.proto.Model} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageV3.Builder implements + // @@protoc_insertion_point(builder_implements:com.farsunset.cim.sdk.server.model.proto.Model) + com.farsunset.cim.sdk.server.model.proto.SessionProto.ModelOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return com.farsunset.cim.sdk.server.model.proto.SessionProto.internal_static_com_farsunset_cim_sdk_server_model_proto_Model_descriptor; + } + + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return com.farsunset.cim.sdk.server.model.proto.SessionProto.internal_static_com_farsunset_cim_sdk_server_model_proto_Model_fieldAccessorTable + .ensureFieldAccessorsInitialized( + com.farsunset.cim.sdk.server.model.proto.SessionProto.Model.class, com.farsunset.cim.sdk.server.model.proto.SessionProto.Model.Builder.class); + } + + // Construct using com.farsunset.cim.sdk.server.model.proto.SessionProto.Model.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessageV3 + .alwaysUseFieldBuilders) { + } + } + public Builder clear() { + super.clear(); + account_ = ""; + + nid_ = 0L; + + deviceId_ = ""; + + host_ = ""; + + channel_ = ""; + + deviceModel_ = ""; + + clientVersion_ = ""; + + systemVersion_ = ""; + + bindTime_ = 0L; + + longitude_ = 0D; + + latitude_ = 0D; + + location_ = ""; + + apns_ = 0; + + state_ = 0; + + return this; + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return com.farsunset.cim.sdk.server.model.proto.SessionProto.internal_static_com_farsunset_cim_sdk_server_model_proto_Model_descriptor; + } + + public com.farsunset.cim.sdk.server.model.proto.SessionProto.Model getDefaultInstanceForType() { + return com.farsunset.cim.sdk.server.model.proto.SessionProto.Model.getDefaultInstance(); + } + + public com.farsunset.cim.sdk.server.model.proto.SessionProto.Model build() { + com.farsunset.cim.sdk.server.model.proto.SessionProto.Model result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.farsunset.cim.sdk.server.model.proto.SessionProto.Model buildPartial() { + com.farsunset.cim.sdk.server.model.proto.SessionProto.Model result = new com.farsunset.cim.sdk.server.model.proto.SessionProto.Model(this); + result.account_ = account_; + result.nid_ = nid_; + result.deviceId_ = deviceId_; + result.host_ = host_; + result.channel_ = channel_; + result.deviceModel_ = deviceModel_; + result.clientVersion_ = clientVersion_; + result.systemVersion_ = systemVersion_; + result.bindTime_ = bindTime_; + result.longitude_ = longitude_; + result.latitude_ = latitude_; + result.location_ = location_; + result.apns_ = apns_; + result.state_ = state_; + onBuilt(); + return result; + } + + public Builder clone() { + return (Builder) super.clone(); + } + public Builder setField( + com.google.protobuf.Descriptors.FieldDescriptor field, + java.lang.Object value) { + return (Builder) super.setField(field, value); + } + public Builder clearField( + com.google.protobuf.Descriptors.FieldDescriptor field) { + return (Builder) super.clearField(field); + } + public Builder clearOneof( + com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return (Builder) super.clearOneof(oneof); + } + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + int index, java.lang.Object value) { + return (Builder) super.setRepeatedField(field, index, value); + } + public Builder addRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + java.lang.Object value) { + return (Builder) super.addRepeatedField(field, value); + } + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof com.farsunset.cim.sdk.server.model.proto.SessionProto.Model) { + return mergeFrom((com.farsunset.cim.sdk.server.model.proto.SessionProto.Model)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(com.farsunset.cim.sdk.server.model.proto.SessionProto.Model other) { + if (other == com.farsunset.cim.sdk.server.model.proto.SessionProto.Model.getDefaultInstance()) return this; + if (!other.getAccount().isEmpty()) { + account_ = other.account_; + onChanged(); + } + if (other.getNid() != 0L) { + setNid(other.getNid()); + } + if (!other.getDeviceId().isEmpty()) { + deviceId_ = other.deviceId_; + onChanged(); + } + if (!other.getHost().isEmpty()) { + host_ = other.host_; + onChanged(); + } + if (!other.getChannel().isEmpty()) { + channel_ = other.channel_; + onChanged(); + } + if (!other.getDeviceModel().isEmpty()) { + deviceModel_ = other.deviceModel_; + onChanged(); + } + if (!other.getClientVersion().isEmpty()) { + clientVersion_ = other.clientVersion_; + onChanged(); + } + if (!other.getSystemVersion().isEmpty()) { + systemVersion_ = other.systemVersion_; + onChanged(); + } + if (other.getBindTime() != 0L) { + setBindTime(other.getBindTime()); + } + if (other.getLongitude() != 0D) { + setLongitude(other.getLongitude()); + } + if (other.getLatitude() != 0D) { + setLatitude(other.getLatitude()); + } + if (!other.getLocation().isEmpty()) { + location_ = other.location_; + onChanged(); + } + if (other.getApns() != 0) { + setApns(other.getApns()); + } + if (other.getState() != 0) { + setState(other.getState()); + } + this.mergeUnknownFields(other.unknownFields); + onChanged(); + return this; + } + + public final boolean isInitialized() { + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.farsunset.cim.sdk.server.model.proto.SessionProto.Model parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.farsunset.cim.sdk.server.model.proto.SessionProto.Model) e.getUnfinishedMessage(); + throw e.unwrapIOException(); + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + + private java.lang.Object account_ = ""; + /** + * string account = 1; + */ + public java.lang.String getAccount() { + java.lang.Object ref = account_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + account_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string account = 1; + */ + public com.google.protobuf.ByteString + getAccountBytes() { + java.lang.Object ref = account_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + account_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string account = 1; + */ + public Builder setAccount( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + + account_ = value; + onChanged(); + return this; + } + /** + * string account = 1; + */ + public Builder clearAccount() { + + account_ = getDefaultInstance().getAccount(); + onChanged(); + return this; + } + /** + * string account = 1; + */ + public Builder setAccountBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + + account_ = value; + onChanged(); + return this; + } + + private long nid_ ; + /** + * int64 nid = 2; + */ + public long getNid() { + return nid_; + } + /** + * int64 nid = 2; + */ + public Builder setNid(long value) { + + nid_ = value; + onChanged(); + return this; + } + /** + * int64 nid = 2; + */ + public Builder clearNid() { + + nid_ = 0L; + onChanged(); + return this; + } + + private java.lang.Object deviceId_ = ""; + /** + * string deviceId = 3; + */ + public java.lang.String getDeviceId() { + java.lang.Object ref = deviceId_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + deviceId_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string deviceId = 3; + */ + public com.google.protobuf.ByteString + getDeviceIdBytes() { + java.lang.Object ref = deviceId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + deviceId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string deviceId = 3; + */ + public Builder setDeviceId( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + + deviceId_ = value; + onChanged(); + return this; + } + /** + * string deviceId = 3; + */ + public Builder clearDeviceId() { + + deviceId_ = getDefaultInstance().getDeviceId(); + onChanged(); + return this; + } + /** + * string deviceId = 3; + */ + public Builder setDeviceIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + + deviceId_ = value; + onChanged(); + return this; + } + + private java.lang.Object host_ = ""; + /** + * string host = 4; + */ + public java.lang.String getHost() { + java.lang.Object ref = host_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + host_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string host = 4; + */ + public com.google.protobuf.ByteString + getHostBytes() { + java.lang.Object ref = host_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + host_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string host = 4; + */ + public Builder setHost( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + + host_ = value; + onChanged(); + return this; + } + /** + * string host = 4; + */ + public Builder clearHost() { + + host_ = getDefaultInstance().getHost(); + onChanged(); + return this; + } + /** + * string host = 4; + */ + public Builder setHostBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + + host_ = value; + onChanged(); + return this; + } + + private java.lang.Object channel_ = ""; + /** + * string channel = 5; + */ + public java.lang.String getChannel() { + java.lang.Object ref = channel_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + channel_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string channel = 5; + */ + public com.google.protobuf.ByteString + getChannelBytes() { + java.lang.Object ref = channel_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + channel_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string channel = 5; + */ + public Builder setChannel( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + + channel_ = value; + onChanged(); + return this; + } + /** + * string channel = 5; + */ + public Builder clearChannel() { + + channel_ = getDefaultInstance().getChannel(); + onChanged(); + return this; + } + /** + * string channel = 5; + */ + public Builder setChannelBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + + channel_ = value; + onChanged(); + return this; + } + + private java.lang.Object deviceModel_ = ""; + /** + * string deviceModel = 6; + */ + public java.lang.String getDeviceModel() { + java.lang.Object ref = deviceModel_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + deviceModel_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string deviceModel = 6; + */ + public com.google.protobuf.ByteString + getDeviceModelBytes() { + java.lang.Object ref = deviceModel_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + deviceModel_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string deviceModel = 6; + */ + public Builder setDeviceModel( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + + deviceModel_ = value; + onChanged(); + return this; + } + /** + * string deviceModel = 6; + */ + public Builder clearDeviceModel() { + + deviceModel_ = getDefaultInstance().getDeviceModel(); + onChanged(); + return this; + } + /** + * string deviceModel = 6; + */ + public Builder setDeviceModelBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + + deviceModel_ = value; + onChanged(); + return this; + } + + private java.lang.Object clientVersion_ = ""; + /** + * string clientVersion = 7; + */ + public java.lang.String getClientVersion() { + java.lang.Object ref = clientVersion_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + clientVersion_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string clientVersion = 7; + */ + public com.google.protobuf.ByteString + getClientVersionBytes() { + java.lang.Object ref = clientVersion_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + clientVersion_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string clientVersion = 7; + */ + public Builder setClientVersion( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + + clientVersion_ = value; + onChanged(); + return this; + } + /** + * string clientVersion = 7; + */ + public Builder clearClientVersion() { + + clientVersion_ = getDefaultInstance().getClientVersion(); + onChanged(); + return this; + } + /** + * string clientVersion = 7; + */ + public Builder setClientVersionBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + + clientVersion_ = value; + onChanged(); + return this; + } + + private java.lang.Object systemVersion_ = ""; + /** + * string systemVersion = 8; + */ + public java.lang.String getSystemVersion() { + java.lang.Object ref = systemVersion_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + systemVersion_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string systemVersion = 8; + */ + public com.google.protobuf.ByteString + getSystemVersionBytes() { + java.lang.Object ref = systemVersion_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + systemVersion_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string systemVersion = 8; + */ + public Builder setSystemVersion( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + + systemVersion_ = value; + onChanged(); + return this; + } + /** + * string systemVersion = 8; + */ + public Builder clearSystemVersion() { + + systemVersion_ = getDefaultInstance().getSystemVersion(); + onChanged(); + return this; + } + /** + * string systemVersion = 8; + */ + public Builder setSystemVersionBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + + systemVersion_ = value; + onChanged(); + return this; + } + + private long bindTime_ ; + /** + * int64 bindTime = 9; + */ + public long getBindTime() { + return bindTime_; + } + /** + * int64 bindTime = 9; + */ + public Builder setBindTime(long value) { + + bindTime_ = value; + onChanged(); + return this; + } + /** + * int64 bindTime = 9; + */ + public Builder clearBindTime() { + + bindTime_ = 0L; + onChanged(); + return this; + } + + private double longitude_ ; + /** + * double longitude = 10; + */ + public double getLongitude() { + return longitude_; + } + /** + * double longitude = 10; + */ + public Builder setLongitude(double value) { + + longitude_ = value; + onChanged(); + return this; + } + /** + * double longitude = 10; + */ + public Builder clearLongitude() { + + longitude_ = 0D; + onChanged(); + return this; + } + + private double latitude_ ; + /** + * double latitude = 11; + */ + public double getLatitude() { + return latitude_; + } + /** + * double latitude = 11; + */ + public Builder setLatitude(double value) { + + latitude_ = value; + onChanged(); + return this; + } + /** + * double latitude = 11; + */ + public Builder clearLatitude() { + + latitude_ = 0D; + onChanged(); + return this; + } + + private java.lang.Object location_ = ""; + /** + * string location = 12; + */ + public java.lang.String getLocation() { + java.lang.Object ref = location_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + location_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string location = 12; + */ + public com.google.protobuf.ByteString + getLocationBytes() { + java.lang.Object ref = location_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + location_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string location = 12; + */ + public Builder setLocation( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + + location_ = value; + onChanged(); + return this; + } + /** + * string location = 12; + */ + public Builder clearLocation() { + + location_ = getDefaultInstance().getLocation(); + onChanged(); + return this; + } + /** + * string location = 12; + */ + public Builder setLocationBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + + location_ = value; + onChanged(); + return this; + } + + private int apns_ ; + /** + * int32 apns = 13; + */ + public int getApns() { + return apns_; + } + /** + * int32 apns = 13; + */ + public Builder setApns(int value) { + + apns_ = value; + onChanged(); + return this; + } + /** + * int32 apns = 13; + */ + public Builder clearApns() { + + apns_ = 0; + onChanged(); + return this; + } + + private int state_ ; + /** + * int32 state = 14; + */ + public int getState() { + return state_; + } + /** + * int32 state = 14; + */ + public Builder setState(int value) { + + state_ = value; + onChanged(); + return this; + } + /** + * int32 state = 14; + */ + public Builder clearState() { + + state_ = 0; + onChanged(); + return this; + } + public final Builder setUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.setUnknownFieldsProto3(unknownFields); + } + + public final Builder mergeUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.mergeUnknownFields(unknownFields); + } + + + // @@protoc_insertion_point(builder_scope:com.farsunset.cim.sdk.server.model.proto.Model) + } + + // @@protoc_insertion_point(class_scope:com.farsunset.cim.sdk.server.model.proto.Model) + private static final com.farsunset.cim.sdk.server.model.proto.SessionProto.Model DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new com.farsunset.cim.sdk.server.model.proto.SessionProto.Model(); + } + + public static com.farsunset.cim.sdk.server.model.proto.SessionProto.Model getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + public Model parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new Model(input, extensionRegistry); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + public com.farsunset.cim.sdk.server.model.proto.SessionProto.Model getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + + } + + private static final com.google.protobuf.Descriptors.Descriptor + internal_static_com_farsunset_cim_sdk_server_model_proto_Model_descriptor; + private static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_com_farsunset_cim_sdk_server_model_proto_Model_fieldAccessorTable; + + public static com.google.protobuf.Descriptors.FileDescriptor + getDescriptor() { + return descriptor; + } + private static com.google.protobuf.Descriptors.FileDescriptor + descriptor; + static { + java.lang.String[] descriptorData = { + "\n\rSession.proto\022(com.farsunset.cim.sdk.s" + + "erver.model.proto\"\377\001\n\005Model\022\017\n\007account\030\001" + + " \001(\t\022\013\n\003nid\030\002 \001(\003\022\020\n\010deviceId\030\003 \001(\t\022\014\n\004h" + + "ost\030\004 \001(\t\022\017\n\007channel\030\005 \001(\t\022\023\n\013deviceMode" + + "l\030\006 \001(\t\022\025\n\rclientVersion\030\007 \001(\t\022\025\n\rsystem" + + "Version\030\010 \001(\t\022\020\n\010bindTime\030\t \001(\003\022\021\n\tlongi" + + "tude\030\n \001(\001\022\020\n\010latitude\030\013 \001(\001\022\020\n\010location" + + "\030\014 \001(\t\022\014\n\004apns\030\r \001(\005\022\r\n\005state\030\016 \001(\005B\016B\014S" + + "essionProtob\006proto3" + }; + com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = + new com.google.protobuf.Descriptors.FileDescriptor. InternalDescriptorAssigner() { + public com.google.protobuf.ExtensionRegistry assignDescriptors( + com.google.protobuf.Descriptors.FileDescriptor root) { + descriptor = root; + return null; + } + }; + com.google.protobuf.Descriptors.FileDescriptor + .internalBuildGeneratedFileFrom(descriptorData, + new com.google.protobuf.Descriptors.FileDescriptor[] { + }, assigner); + internal_static_com_farsunset_cim_sdk_server_model_proto_Model_descriptor = + getDescriptor().getMessageTypes().get(0); + internal_static_com_farsunset_cim_sdk_server_model_proto_Model_fieldAccessorTable = new + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_com_farsunset_cim_sdk_server_model_proto_Model_descriptor, + new java.lang.String[] { "Account", "Nid", "DeviceId", "Host", "Channel", "DeviceModel", "ClientVersion", "SystemVersion", "BindTime", "Longitude", "Latitude", "Location", "Apns", "State", }); + } + + // @@protoc_insertion_point(outer_class_scope) +} diff --git a/cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/session/DefaultSessionManager.java b/cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/session/DefaultSessionManager.java deleted file mode 100644 index ba537c4..0000000 --- a/cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/session/DefaultSessionManager.java +++ /dev/null @@ -1,84 +0,0 @@ -/** - * Copyright 2013-2019 Xia Jun(3979434@qq.com). - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - *************************************************************************************** - * * - * Website : http://www.farsunset.com * - * * - *************************************************************************************** - */ -package com.farsunset.cim.sdk.server.session; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; - -import com.farsunset.cim.sdk.server.constant.CIMConstant; - -/** - * 自带默认 session管理实现, 各位可以自行实现 AbstractSessionManager接口来实现自己的 session管理 服务器集群时 - * 须要将CIMSession 信息存入数据库或者nosql 等 第三方存储空间中,便于所有服务器都可以访问 - */ -public class DefaultSessionManager implements SessionManager { - - private static HashMap sessions = new HashMap(); - - private static final AtomicInteger connectionsCounter = new AtomicInteger(0); - - /** - * - */ - public void add(CIMSession session) { - if (session != null) { - session.setAttribute(CIMConstant.SESSION_KEY, session.getAccount()); - sessions.put(session.getAccount(), session); - connectionsCounter.incrementAndGet(); - } - - } - - public CIMSession get(String account) { - - return sessions.get(account); - } - - public List queryAll() { - List list = new ArrayList(); - list.addAll(sessions.values()); - return list; - } - - public void remove(CIMSession session) { - - sessions.remove(session.getAttribute(CIMConstant.SESSION_KEY)); - } - - public void remove(String account) { - - sessions.remove(account); - - } - - public boolean containsCIMSession(String account) { - return sessions.containsKey(account); - } - - @Override - public void update(CIMSession session) { - sessions.put(session.getAccount(), session); - } - -} diff --git a/cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/session/SessionManager.java b/cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/session/SessionManager.java deleted file mode 100644 index d067129..0000000 --- a/cim_for_mina/cim-server-sdk/src/com/farsunset/cim/sdk/server/session/SessionManager.java +++ /dev/null @@ -1,64 +0,0 @@ -/** - * Copyright 2013-2019 Xia Jun(3979434@qq.com). - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - *************************************************************************************** - * * - * Website : http://www.farsunset.com * - * * - *************************************************************************************** - */ -package com.farsunset.cim.sdk.server.session; - -import java.util.List; - -/** - * 客户端的 session管理接口 可自行实现此接口管理session - */ - -public interface SessionManager { - - /** - * 添加新的session - */ - public void add(CIMSession session); - - /** - * 更新session - */ - public void update(CIMSession session); - - /** - * - * @param account - * 客户端session的 key 一般可用 用户账号来对应session - * @return - */ - CIMSession get(String account); - - /** - * 获取所有session - * - * @return - */ - public List queryAll(); - - /** - * 删除session - * - * @param session - */ - public void remove(String account); - -} diff --git a/cim_for_netty/cim-boot-server/libs/cim-android-sdk-3.6.jar b/cim_for_netty/cim-boot-server/libs/cim-server-sdk-3.6.jar similarity index 52% rename from cim_for_netty/cim-boot-server/libs/cim-android-sdk-3.6.jar rename to cim_for_netty/cim-boot-server/libs/cim-server-sdk-3.6.jar index 525cec3a68f3a0461d226d351e2b4ac143539b24..104142826aba476950dd4aac335bcf2d236cce87 100644 GIT binary patch delta 37877 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 delta 21044 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 DVLKec diff --git a/cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/CIMConfig.java b/cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/CIMConfig.java index a78b1b1..28d36b9 100644 --- a/cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/CIMConfig.java +++ b/cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/CIMConfig.java @@ -16,7 +16,7 @@ import com.farsunset.cim.handler.SessionClosedHandler; import com.farsunset.cim.sdk.server.handler.CIMNioSocketAcceptor; import com.farsunset.cim.sdk.server.handler.CIMRequestHandler; import com.farsunset.cim.sdk.server.model.SentBody; -import com.farsunset.cim.sdk.server.session.CIMSession; +import com.farsunset.cim.sdk.server.model.CIMSession; @Configuration public class CIMConfig implements CIMRequestHandler { @@ -28,7 +28,7 @@ public class CIMConfig implements CIMRequestHandler { @Resource private SessionClosedHandler closedHandler; - + @Resource private ApplicationContext applicationContext; @@ -55,7 +55,6 @@ public class CIMConfig implements CIMRequestHandler { return nioSocketAcceptor; } - @Override public void process(CIMSession session, SentBody body) { @@ -75,6 +74,5 @@ public class CIMConfig implements CIMRequestHandler { return applicationContext.getBean(handlerClass); } - } \ No newline at end of file diff --git a/cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/admin/controller/SessionController.java b/cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/admin/controller/SessionController.java index 2e378fd..74b1c00 100644 --- a/cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/admin/controller/SessionController.java +++ b/cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/admin/controller/SessionController.java @@ -27,17 +27,18 @@ import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; -import com.farsunset.cim.service.impl.CIMSessionServiceImpl; +import com.farsunset.cim.service.CIMSessionService; + @Controller @RequestMapping("/console/session") public class SessionController { @Resource - private CIMSessionServiceImpl sessionManager; + private CIMSessionService memorySessionService; @RequestMapping(value = "/list.action") public String list(Model model) { - model.addAttribute("sessionList", sessionManager.queryAll()); + model.addAttribute("sessionList", memorySessionService.list()); return "console/session/manage"; } } diff --git a/cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/api/controller/MessageController.java b/cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/api/controller/MessageController.java index 4dc1f15..c42ed85 100644 --- a/cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/api/controller/MessageController.java +++ b/cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/api/controller/MessageController.java @@ -32,7 +32,6 @@ import com.farsunset.cim.push.DefaultMessagePusher; import com.farsunset.cim.push.SystemMessagePusher; import com.farsunset.cim.sdk.server.model.Message; import com.farsunset.cim.util.Constants; -import com.farsunset.cim.util.StringUtil; @RestController diff --git a/cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/handler/BindHandler.java b/cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/handler/BindHandler.java index a789322..da7e908 100644 --- a/cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/handler/BindHandler.java +++ b/cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/handler/BindHandler.java @@ -30,14 +30,14 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; +import com.farsunset.cim.push.CIMMessagePusher; import com.farsunset.cim.sdk.server.constant.CIMConstant; import com.farsunset.cim.sdk.server.handler.CIMRequestHandler; import com.farsunset.cim.sdk.server.model.Message; import com.farsunset.cim.sdk.server.model.ReplyBody; import com.farsunset.cim.sdk.server.model.SentBody; -import com.farsunset.cim.sdk.server.session.CIMSession; -import com.farsunset.cim.service.impl.CIMSessionServiceImpl; -import com.farsunset.cim.util.StringUtil; +import com.farsunset.cim.sdk.server.model.CIMSession; +import com.farsunset.cim.service.CIMSessionService; /** @@ -51,59 +51,57 @@ public class BindHandler implements CIMRequestHandler { protected final Logger logger = LoggerFactory.getLogger(BindHandler.class); @Resource - private CIMSessionServiceImpl sessionManager; + private CIMSessionService memorySessionService; @Value("${server.host}") private String host; + @Resource + private CIMMessagePusher defaultMessagePusher; - public void process(CIMSession newSession, SentBody message) { + public void process(CIMSession newSession, SentBody body) { ReplyBody reply = new ReplyBody(); - reply.setKey(message.getKey()); + reply.setKey(body.getKey()); reply.setCode(CIMConstant.ReturnCode.CODE_200); + reply.setTimestamp(System.currentTimeMillis()); + try { - String account = message.get("account"); - newSession.setGid(StringUtil.getUUID()); + String account = body.get("account"); newSession.setAccount(account); - newSession.setDeviceId(message.get("deviceId")); + newSession.setDeviceId(body.get("deviceId")); newSession.setHost(host); - newSession.setChannel(message.get("channel")); - newSession.setDeviceModel(message.get("device")); - newSession.setClientVersion(message.get("version")); - newSession.setSystemVersion(message.get("osVersion")); + newSession.setChannel(body.get("channel")); + newSession.setDeviceModel(body.get("device")); + newSession.setClientVersion(body.get("version")); + newSession.setSystemVersion(body.get("osVersion")); newSession.setBindTime(System.currentTimeMillis()); - newSession.setPackageName(message.get("packageName")); - - /** + /* * 由于客户端断线服务端可能会无法获知的情况,客户端重连时,需要关闭旧的连接 */ - CIMSession oldSession = sessionManager.get(account); + CIMSession oldSession = memorySessionService.get(account); - // 如果是账号已经在另一台终端登录。则让另一个终端下线 + /* + * 如果是账号已经在另一台终端登录。则让另一个终端下线 + */ if (oldSession != null && fromOtherDevice(newSession,oldSession) && oldSession.isConnected()) { sendForceOfflineMessage(oldSession, account, newSession.getDeviceModel()); } - - - /** + + /* * 有可能是同一个设备重复连接,则关闭旧的链接,这种情况一般是客户端断网,联网又重新链接上来,之前的旧链接没有来得及通过心跳机制关闭,在这里手动关闭 * 条件1,连接来自是同一个设备 * 条件2.2个连接都是同一台服务器 */ if (oldSession != null && !fromOtherDevice(newSession,oldSession) && Objects.equals(oldSession.getHost(),host)) { - oldSession.removeAttribute(CIMConstant.SESSION_KEY); - oldSession.closeNow(); + closeQuietly(oldSession); } - // 第一次设置心跳时间为登录时间 - newSession.setBindTime(System.currentTimeMillis()); - newSession.setHeartbeat(System.currentTimeMillis()); - - sessionManager.add(newSession); + memorySessionService.save(newSession); + } catch (Exception e) { reply.setCode(CIMConstant.ReturnCode.CODE_500); @@ -126,16 +124,18 @@ public class BindHandler implements CIMRequestHandler { msg.setSender("system"); msg.setContent(deviceModel); msg.setId(System.currentTimeMillis()); - closeQuietly(oldSession,msg); + + defaultMessagePusher.push(msg); + + closeQuietly(oldSession); } // 不同设备同一账号登录时关闭旧的连接 - private void closeQuietly(CIMSession oldSession,Message msg) { + private void closeQuietly(CIMSession oldSession) { if (oldSession.isConnected() && Objects.equals(host, oldSession.getHost())) { - oldSession.write(msg); - oldSession.removeAttribute(CIMConstant.SESSION_KEY); - oldSession.closeNow(); + oldSession.setAttribute(CIMConstant.KEY_QUIETLY_CLOSE,true); + oldSession.closeOnFlush(); } } diff --git a/cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/handler/SessionClosedHandler.java b/cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/handler/SessionClosedHandler.java index 4e00c77..c41b547 100644 --- a/cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/handler/SessionClosedHandler.java +++ b/cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/handler/SessionClosedHandler.java @@ -22,6 +22,8 @@ package com.farsunset.cim.handler; +import java.util.Objects; + import javax.annotation.Resource; import org.slf4j.Logger; @@ -31,8 +33,8 @@ import org.springframework.stereotype.Component; import com.farsunset.cim.sdk.server.constant.CIMConstant; import com.farsunset.cim.sdk.server.handler.CIMRequestHandler; import com.farsunset.cim.sdk.server.model.SentBody; -import com.farsunset.cim.sdk.server.session.CIMSession; -import com.farsunset.cim.service.impl.CIMSessionServiceImpl; +import com.farsunset.cim.sdk.server.model.CIMSession; +import com.farsunset.cim.service.CIMSessionService; /** @@ -46,17 +48,28 @@ public class SessionClosedHandler implements CIMRequestHandler { protected final Logger logger = LoggerFactory.getLogger(SessionClosedHandler.class); @Resource - private CIMSessionServiceImpl sessionManager; + private CIMSessionService memorySessionService; public void process(CIMSession ios, SentBody message) { + Object quietly = ios.getAttribute(CIMConstant.KEY_QUIETLY_CLOSE); + if (Objects.equals(quietly, true)) { + return; + } - Object account = ios.getAttribute(CIMConstant.SESSION_KEY); + Object account = ios.getAttribute(CIMConstant.KEY_ACCOUNT); if (account == null) { return; } - ios.removeAttribute(CIMConstant.SESSION_KEY); - sessionManager.remove(account.toString()); + CIMSession oldSession = memorySessionService.get(account.toString()); + + if (oldSession == null || oldSession.isApnsOpend()) { + return; + } + + oldSession.setState(CIMSession.STATE_DISABLED); + oldSession.setNid(null); + memorySessionService.save(oldSession); } } diff --git a/cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/push/DefaultMessagePusher.java b/cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/push/DefaultMessagePusher.java index 67962d0..e0e49bc 100644 --- a/cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/push/DefaultMessagePusher.java +++ b/cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/push/DefaultMessagePusher.java @@ -29,10 +29,9 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import com.farsunset.cim.sdk.server.model.Message; -import com.farsunset.cim.sdk.server.session.CIMSession; -import com.farsunset.cim.sdk.server.session.DefaultSessionManager; +import com.farsunset.cim.sdk.server.model.CIMSession; import com.farsunset.cim.service.ApnsService; -import com.farsunset.cim.service.impl.MessageDispatcherImpl; +import com.farsunset.cim.service.CIMSessionService; /** * 消息发送实现类 @@ -45,10 +44,8 @@ public class DefaultMessagePusher implements CIMMessagePusher { private String host; @Resource - private DefaultSessionManager sessionManager; + private CIMSessionService memorySessionService; - @Resource - private MessageDispatcherImpl messageDispatcher; @Resource @@ -61,31 +58,39 @@ public class DefaultMessagePusher implements CIMMessagePusher { * @param msg */ public void push(Message message) { - CIMSession session = sessionManager.get(message.getReceiver()); + CIMSession session = memorySessionService.get(message.getReceiver()); - /** - * 服务器集群时,可以在此 判断当前session是否连接于本台服务器,如果是,继续往下走,如果不是,将此消息发往当前session连接的服务器并 - */ - if (session.isConnected() && !Objects.equals(host, session.getHost())) { - messageDispatcher.forward(message, session.getHost()); + if(session == null) { return; } - /** - * 如果是在当前服务器则直接推送 + /* + * IOS设备,如果开启了apns,则使用apns推送 */ - if (session.isConnected() && Objects.equals(host, session.getHost())) { - session.write(message); + if (session.isIOSChannel() && session.isApnsOpend()) { + apnsService.push(message, session.getDeviceId()); return; } - /** - * ios设备流程特别处理,如果长链接断开了,并且ApnsAble为打开状态的话优走apns + /* + * 服务器集群时,判断当前session是否连接于本台服务器 + * 如果连接到了其他服务器则转发请求到目标服务器 */ - if (Objects.equals(session.getChannel(), CIMSession.CHANNEL_IOS) && Objects.equals(session.getApnsAble(), CIMSession.APNS_ON)) { - apnsService.push(message, session.getDeviceId()); + if (session.isConnected() && !Objects.equals(host, session.getHost())) { + /** + * @TODO + * 在此调用目标服务器接口来发送 + */ + return; } + /* + * 如果是Android,浏览器或者windows客户端则直接发送 + */ + if (session.isConnected() && Objects.equals(host, session.getHost())) { + session.write(message); + } + } } diff --git a/cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/service/MessageDispatcher.java b/cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/service/CIMSessionService.java similarity index 67% rename from cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/service/MessageDispatcher.java rename to cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/service/CIMSessionService.java index 911bfbc..45fb9c8 100644 --- a/cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/service/MessageDispatcher.java +++ b/cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/service/CIMSessionService.java @@ -1,4 +1,4 @@ -/** +/* * Copyright 2013-2019 Xia Jun(3979434@qq.com). * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,8 +21,23 @@ */ package com.farsunset.cim.service; -import com.farsunset.cim.sdk.server.model.Message; +import java.util.List; + +import com.farsunset.cim.sdk.server.model.CIMSession; + + +/** + * 集群 session管理实现示例, 各位可以自行实现 AbstractSessionManager接口来实现自己的 session管理 服务器集群时 + * 须要将CIMSession 信息存入数据库或者redis中 等 第三方存储空间中,便于所有服务器都可以访问 + */ +public interface CIMSessionService { + + void save(CIMSession session); + + CIMSession get(String account); + + List list(); + + void remove(String account); -public interface MessageDispatcher { - void forward(final Message msg, final String ip); } diff --git a/cim_for_mina/cim-boot-server/src/main/java/com/farsunset/cim/session/ClusterSessionManager.java b/cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/service/impl/ClusterSessionServiceImpl.java similarity index 60% rename from cim_for_mina/cim-boot-server/src/main/java/com/farsunset/cim/session/ClusterSessionManager.java rename to cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/service/impl/ClusterSessionServiceImpl.java index 988ca24..6dacf53 100644 --- a/cim_for_mina/cim-boot-server/src/main/java/com/farsunset/cim/session/ClusterSessionManager.java +++ b/cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/service/impl/ClusterSessionServiceImpl.java @@ -19,47 +19,54 @@ * * *************************************************************************************** */ -package com.farsunset.cim.session; +package com.farsunset.cim.service.impl; + import java.util.List; -import com.farsunset.cim.sdk.server.session.CIMSession; -import com.farsunset.cim.sdk.server.session.SessionManager; + +import javax.annotation.Resource; + +import org.springframework.stereotype.Service; + +import com.farsunset.cim.sdk.server.handler.CIMNioSocketAcceptor; +import com.farsunset.cim.sdk.server.model.CIMSession; +import com.farsunset.cim.service.CIMSessionService; + /** - * 集群 session管理实现示例, 各位可以自行实现 AbstractSessionManager接口来实现自己的 session管理 服务器集群时 - * 须要将CIMSession 信息存入数据库或者nosql 等 第三方存储空间中,便于所有服务器都可以访问 + * 集群情况下,数据库或者redis存储实现 + * 自行实现存储管理 + * */ -public class ClusterSessionManager implements SessionManager { +@Service("clusterSessionService") +public class ClusterSessionServiceImpl implements CIMSessionService { - public CIMSession get(String account) { - - // 这里查询数据库 - /* - * CIMSession session = database.getSession(account); - * session.setIoSession(ContextHolder.getBean(CIMNioSocketAcceptor.class). - * getManagedSessions().get(session.getNid())); return session; - */ - return null; + @Resource + private CIMNioSocketAcceptor nioSocketAcceptor; + + @Override + public void save(CIMSession session) { } @Override - public List queryAll() { + public CIMSession get(String account) { + + /* + * CIMSession session = database.getSession(account); + * session.setIoSession(nioSocketAcceptor.getManagedChannel().get(session.getNid())); + * return session; + */ + return null; } - + @Override public void remove(String account) { - } @Override - public void update(CIMSession session) { - + public List list() { + return null; } - - @Override - public void add(CIMSession arg0) { - - } - + } diff --git a/cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/service/impl/MemorySessionServiceImpl.java b/cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/service/impl/MemorySessionServiceImpl.java new file mode 100644 index 0000000..57ba29c --- /dev/null +++ b/cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/service/impl/MemorySessionServiceImpl.java @@ -0,0 +1,65 @@ +/** + * Copyright 2013-2019 Xia Jun(3979434@qq.com). + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *************************************************************************************** + * * + * Website : http://www.farsunset.com * + * * + *************************************************************************************** + */ +package com.farsunset.cim.service.impl; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; + +import org.springframework.stereotype.Service; + +import com.farsunset.cim.sdk.server.model.CIMSession; +import com.farsunset.cim.service.CIMSessionService; + + +/** + * 单机,内存存储实现 + * + */ +@Service("memorySessionService") +public class MemorySessionServiceImpl implements CIMSessionService { + + private ConcurrentHashMap sessionMap = new ConcurrentHashMap(); + + @Override + public void save(CIMSession session) { + sessionMap.put(session.getAccount(), session); + } + + @Override + public CIMSession get(String account) { + return sessionMap.get(account); + } + + @Override + public void remove(String account) { + sessionMap.remove(account); + } + + @Override + public List list() { + List onlineList = new ArrayList<>(); + onlineList.addAll(sessionMap.values()); + return onlineList; + } + +} diff --git a/cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/service/impl/MessageDispatcherImpl.java b/cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/service/impl/MessageDispatcherImpl.java deleted file mode 100644 index 3f7ab3c..0000000 --- a/cim_for_netty/cim-boot-server/src/main/java/com/farsunset/cim/service/impl/MessageDispatcherImpl.java +++ /dev/null @@ -1,83 +0,0 @@ -/** - * Copyright 2013-2019 Xia Jun(3979434@qq.com). - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - *************************************************************************************** - * * - * Website : http://www.farsunset.com * - * * - *************************************************************************************** - */ -package com.farsunset.cim.service.impl; - -import java.util.concurrent.TimeUnit; -import java.util.logging.Logger; - -import org.apache.commons.io.IOUtils; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; - -import com.farsunset.cim.sdk.server.model.Message; -import com.farsunset.cim.service.MessageDispatcher; - -import okhttp3.FormBody; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; - -@Component -public class MessageDispatcherImpl implements MessageDispatcher{ - - private static final Logger logger = Logger.getLogger(MessageDispatcherImpl.class.getName()); - - @Value("${sys.message.dispatch.url}") - private String dispatchUrl; - - @Override - public void forward(final Message msg, final String ip) { - String apiUrl = String.format(dispatchUrl, ip); - try { - String response = httpPost(apiUrl, msg); - logger.info("消息转发目标服务器{" + ip + "},结果:" + response); - } catch (Exception e) { - e.printStackTrace(); - logger.severe("消息转发目标服务器" + apiUrl + "message:" + e.getMessage()); - } - } - - @SuppressWarnings("deprecation") - private String httpPost(String url, Message msg) throws Exception { - - OkHttpClient httpclient = new OkHttpClient.Builder().connectTimeout(10, TimeUnit.SECONDS).build(); - FormBody.Builder build = new FormBody.Builder(); - - build.add("id", String.valueOf(msg.getId())); - build.add("action", msg.getAction()); - build.add("title", msg.getTitle()); - build.add("content", msg.getContent()); - build.add("sender", msg.getSender()); - build.add("receiver", msg.getReceiver()); - build.add("format", msg.getFormat()); - build.add("extra", msg.getExtra()); - build.add("timestamp", String.valueOf(msg.getTimestamp())); - Request request = new Request.Builder().url(url).post(build.build()).build(); - - Response response = httpclient.newCall(request).execute(); - String data = response.body().string(); - IOUtils.closeQuietly(response); - return data; - } - - -} diff --git a/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/constant/CIMConstant.java b/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/constant/CIMConstant.java index 119eb83..b670335 100644 --- a/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/constant/CIMConstant.java +++ b/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/constant/CIMConstant.java @@ -25,6 +25,8 @@ package com.farsunset.cim.sdk.server.constant; * 常量 */ public interface CIMConstant { + // 消息头长度为3个字节,第一个字节为消息类型,第二,第三字节 转换int后为消息长度 + int DATA_HEADER_LENGTH = 3; public static interface ReturnCode { @@ -38,30 +40,30 @@ public interface CIMConstant { } - String SESSION_KEY = "account"; + String KEY_ACCOUNT = "account"; + + String KEY_QUIETLY_CLOSE = "quietlyClose"; + String HEARTBEAT_KEY = "heartbeat"; + + String CLIENT_WEBSOCKET_HANDSHAKE = "client_websocket_handshake"; + String CLIENT_HEARTBEAT = "client_heartbeat"; - - // 消息头长度为3个字节,第一个字节为消息类型,第二,第三字节 转换int后为消息长度 - int DATA_HEADER_LENGTH = 3; - // WEBSOCKET消息头长度为2个字节 - int WS_DATA_HEADER_LENGTH = 2; - + + String CLIENT_CONNECT_CLOSED = "client_closed"; + public static interface ProtobufType { - byte C_H_RS = 0; byte S_H_RQ = 1; + byte C_H_RS = 0; byte MESSAGE = 2; byte SENTBODY = 3; byte REPLYBODY = 4; } public static interface MessageAction { - // 被其他设备登录挤下线消息 String ACTION_999 = "999"; - // 被系统禁用消息 - String ACTION_444 = "444"; } } diff --git a/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/filter/ServerMessageDecoder.java b/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/filter/ServerMessageDecoder.java index ba61075..1a283c4 100644 --- a/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/filter/ServerMessageDecoder.java +++ b/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/filter/ServerMessageDecoder.java @@ -26,11 +26,11 @@ import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; +import com.farsunset.cim.sdk.server.constant.CIMConstant; import com.farsunset.cim.sdk.server.filter.decoder.AppMessageDecoder; import com.farsunset.cim.sdk.server.filter.decoder.WebMessageDecoder; -import com.farsunset.cim.sdk.server.handler.CIMNioSocketAcceptor; import com.farsunset.cim.sdk.server.model.SentBody; -import com.farsunset.cim.sdk.server.session.CIMSession; +import com.farsunset.cim.sdk.server.model.CIMSession; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; @@ -95,7 +95,7 @@ public class ServerMessageDecoder extends ByteToMessageDecoder { arg0.channel().attr(AttributeKey.valueOf(CIMSession.PROTOCOL)).set(CIMSession.WEBSOCKET); SentBody body = new SentBody(); - body.setKey(CIMNioSocketAcceptor.WEBSOCKET_HANDLER_KEY); + body.setKey(CIMConstant.CLIENT_WEBSOCKET_HANDSHAKE); body.setTimestamp(System.currentTimeMillis()); body.put("key", secKey); queue.add(body); diff --git a/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/filter/ServerMessageEncoder.java b/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/filter/ServerMessageEncoder.java index 004e819..593cac6 100644 --- a/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/filter/ServerMessageEncoder.java +++ b/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/filter/ServerMessageEncoder.java @@ -26,7 +26,7 @@ import java.util.Objects; import com.farsunset.cim.sdk.server.constant.CIMConstant; import com.farsunset.cim.sdk.server.model.HandshakerResponse; import com.farsunset.cim.sdk.server.model.feature.EncodeFormatable; -import com.farsunset.cim.sdk.server.session.CIMSession; +import com.farsunset.cim.sdk.server.model.CIMSession; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; diff --git a/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/filter/decoder/AppMessageDecoder.java b/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/filter/decoder/AppMessageDecoder.java index c83c422..102bbfe 100644 --- a/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/filter/decoder/AppMessageDecoder.java +++ b/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/filter/decoder/AppMessageDecoder.java @@ -26,7 +26,7 @@ import java.util.List; import com.farsunset.cim.sdk.server.constant.CIMConstant; import com.farsunset.cim.sdk.server.model.SentBody; import com.farsunset.cim.sdk.server.model.proto.SentBodyProto; -import com.farsunset.cim.sdk.server.session.CIMSession; +import com.farsunset.cim.sdk.server.model.CIMSession; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; diff --git a/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/filter/decoder/WebMessageDecoder.java b/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/filter/decoder/WebMessageDecoder.java index aedd48a..651fde9 100644 --- a/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/filter/decoder/WebMessageDecoder.java +++ b/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/filter/decoder/WebMessageDecoder.java @@ -21,11 +21,9 @@ */ package com.farsunset.cim.sdk.server.filter.decoder; -import java.nio.charset.Charset; import java.util.List; import com.farsunset.cim.sdk.server.constant.CIMConstant; -import com.farsunset.cim.sdk.server.model.HeartbeatResponse; import com.farsunset.cim.sdk.server.model.SentBody; import com.farsunset.cim.sdk.server.model.proto.SentBodyProto; import com.google.protobuf.InvalidProtocolBufferException; @@ -124,8 +122,10 @@ public class WebMessageDecoder extends ByteToMessageDecoder { * 只处理心跳响应以及,sentbody消息 */ if (type == CIMConstant.ProtobufType.C_H_RS) { - HeartbeatResponse response = HeartbeatResponse.getInstance(); - queue.add(response); + SentBody body = new SentBody(); + body.setKey(CIMConstant.CLIENT_HEARTBEAT); + body.setTimestamp(System.currentTimeMillis()); + queue.add(body); } if (type == CIMConstant.ProtobufType.SENTBODY) { diff --git a/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/handler/CIMNioSocketAcceptor.java b/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/handler/CIMNioSocketAcceptor.java index 759a972..25518cf 100644 --- a/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/handler/CIMNioSocketAcceptor.java +++ b/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/handler/CIMNioSocketAcceptor.java @@ -30,7 +30,7 @@ import com.farsunset.cim.sdk.server.filter.ServerMessageDecoder; import com.farsunset.cim.sdk.server.filter.ServerMessageEncoder; import com.farsunset.cim.sdk.server.model.HeartbeatRequest; import com.farsunset.cim.sdk.server.model.SentBody; -import com.farsunset.cim.sdk.server.session.CIMSession; +import com.farsunset.cim.sdk.server.model.CIMSession; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.Channel; @@ -54,14 +54,6 @@ import io.netty.util.AttributeKey; @Sharable public class CIMNioSocketAcceptor extends SimpleChannelInboundHandler { - /** - * websocket特有的握手处理handler - */ - public final static String WEBSOCKET_HANDLER_KEY = "client_websocket_handshake"; - /** - * 连接关闭处理handler - */ - public final static String CIMSESSION_CLOSED_HANDLER_KEY = "client_closed"; private HashMap innerHandlerMap = new HashMap(); private CIMRequestHandler outerRequestHandler; @@ -81,8 +73,9 @@ public class CIMNioSocketAcceptor extends SimpleChannelInboundHandler /** * 预制websocket握手请求的处理 */ - innerHandlerMap.put(WEBSOCKET_HANDLER_KEY, new WebsocketHandler()); - + innerHandlerMap.put(CIMConstant.CLIENT_WEBSOCKET_HANDSHAKE, new WebsocketHandler()); + innerHandlerMap.put(CIMConstant.CLIENT_HEARTBEAT, new HeartbeatHandler()); + ServerBootstrap bootstrap = new ServerBootstrap(); EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); @@ -123,7 +116,7 @@ public class CIMNioSocketAcceptor extends SimpleChannelInboundHandler } @Override - protected void channelRead0(ChannelHandlerContext ctx, SentBody body) throws Exception { + protected void channelRead0(ChannelHandlerContext ctx, SentBody body) { CIMSession session = new CIMSession(ctx.channel()); @@ -148,7 +141,7 @@ public class CIMNioSocketAcceptor extends SimpleChannelInboundHandler CIMSession session = new CIMSession(ctx.channel()); SentBody body = new SentBody(); - body.setKey(CIMSESSION_CLOSED_HANDLER_KEY); + body.setKey(CIMConstant.CLIENT_CONNECT_CLOSED); outerRequestHandler.process(session, body); } @@ -188,4 +181,5 @@ public class CIMNioSocketAcceptor extends SimpleChannelInboundHandler } return channelGroup.get(id); } + } diff --git a/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/handler/CIMRequestHandler.java b/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/handler/CIMRequestHandler.java index 16aa5b8..0f49b39 100644 --- a/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/handler/CIMRequestHandler.java +++ b/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/handler/CIMRequestHandler.java @@ -26,7 +26,7 @@ package com.farsunset.cim.sdk.server.handler; * @author 3979434@qq.com */ import com.farsunset.cim.sdk.server.model.SentBody; -import com.farsunset.cim.sdk.server.session.CIMSession; +import com.farsunset.cim.sdk.server.model.CIMSession; public interface CIMRequestHandler { diff --git a/cim_for_mina/cim-boot-server/src/main/java/com/farsunset/cim/service/impl/CIMSessionServiceImpl.java b/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/handler/HeartbeatHandler.java similarity index 75% rename from cim_for_mina/cim-boot-server/src/main/java/com/farsunset/cim/service/impl/CIMSessionServiceImpl.java rename to cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/handler/HeartbeatHandler.java index 94c3d2b..86c4f92 100644 --- a/cim_for_mina/cim-boot-server/src/main/java/com/farsunset/cim/service/impl/CIMSessionServiceImpl.java +++ b/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/handler/HeartbeatHandler.java @@ -19,13 +19,15 @@ * * *************************************************************************************** */ -package com.farsunset.cim.service.impl; +package com.farsunset.cim.sdk.server.handler; -import org.springframework.stereotype.Service; -import com.farsunset.cim.sdk.server.session.DefaultSessionManager; +import com.farsunset.cim.sdk.server.model.SentBody; +import com.farsunset.cim.sdk.server.model.CIMSession; -@Service -public class CIMSessionServiceImpl extends DefaultSessionManager { - +/** + * 心跳handler,主要是让netty重置cheannel的空闲时间 + */ +public class HeartbeatHandler implements CIMRequestHandler { + public void process(CIMSession session, SentBody body) {} } diff --git a/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/handler/WebsocketHandler.java b/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/handler/WebsocketHandler.java index 1f7aab2..a9e73ea 100644 --- a/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/handler/WebsocketHandler.java +++ b/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/handler/WebsocketHandler.java @@ -26,12 +26,10 @@ import java.util.Base64; import com.farsunset.cim.sdk.server.model.HandshakerResponse; import com.farsunset.cim.sdk.server.model.SentBody; -import com.farsunset.cim.sdk.server.session.CIMSession; +import com.farsunset.cim.sdk.server.model.CIMSession; /** * 处理websocket握手请求,返回响应的报文给浏览器 - * - * @author Iraid * */ public class WebsocketHandler implements CIMRequestHandler { diff --git a/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/session/CIMSession.java b/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/model/CIMSession.java similarity index 60% rename from cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/session/CIMSession.java rename to cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/model/CIMSession.java index b8f13d4..2b980f1 100644 --- a/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/session/CIMSession.java +++ b/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/model/CIMSession.java @@ -1,5 +1,5 @@ /** - * Copyright 2013-2019 Xia Jun(3979434@qq.com). + * Copyright 2013-2023 Xia Jun(3979434@qq.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,35 +19,34 @@ * * *************************************************************************************** */ -package com.farsunset.cim.sdk.server.session; +package com.farsunset.cim.sdk.server.model; import java.io.Serializable; -import java.net.InetAddress; import java.net.SocketAddress; -import java.net.UnknownHostException; +import java.util.Objects; + import com.farsunset.cim.sdk.server.constant.CIMConstant; +import com.farsunset.cim.sdk.server.model.proto.SessionProto; +import com.google.protobuf.InvalidProtocolBufferException; import io.netty.channel.Channel; import io.netty.util.AttributeKey; /** - * Channel包装类,集群时 将此对象存入表中 + * IoSession包装类,集群时 将此对象存入表中 */ - public class CIMSession implements Serializable { - /** - * - */ private transient static final long serialVersionUID = 1L; public transient static String PROTOCOL = "protocol"; public transient static String WEBSOCKET = "websocket"; public transient static String NATIVEAPP = "nativeapp"; - public transient static final int STATUS_ENABLED = 0; - public transient static final int STATUS_DISABLED = 1; + public transient static String HOST = "HOST"; + public transient static final int STATE_ENABLED = 0; + public transient static final int STATE_DISABLED = 1; public transient static final int APNS_ON = 1; public transient static final int APNS_OFF = 0; @@ -56,31 +55,31 @@ public class CIMSession implements Serializable { public transient static String CHANNEL_WINDOWS = "windows"; public transient static String CHANNEL_WP = "wp"; public transient static String CHANNEL_BROWSER = "browser"; + private transient Channel session; - private String gid;// session全局ID + private String account;// session绑定的账号,主键,一个账号同一时间之内在一个设备在线 private String nid;// session在本台服务器上的ID private String deviceId;// 客户端ID (设备号码+应用包名),ios为devicetoken private String host;// session绑定的服务器IP - private String account;// session绑定的账号 private String channel;// 终端设备类型 private String deviceModel;// 终端设备型号 private String clientVersion;// 终端应用版本 private String systemVersion;// 终端系统版本 - private String packageName;// 终端应用包名 private Long bindTime;// 登录时间 - private Long heartbeat;// 心跳时间 private Double longitude;// 经度 private Double latitude;// 维度 private String location;// 位置 - private int apnsAble;// apns推送状态 - private int status;// 状态 + private int apns;// apns推送状态 + private int state;// 状态 + public CIMSession(Channel session) { this.session = session; this.nid = session.id().asShortText(); } + public CIMSession() { } @@ -91,7 +90,8 @@ public class CIMSession implements Serializable { public void setAccount(String account) { this.account = account; - setAttribute(CIMConstant.SESSION_KEY, account); + + setAttribute(CIMConstant.KEY_ACCOUNT, account); } public Double getLongitude() { @@ -118,14 +118,6 @@ public class CIMSession implements Serializable { this.location = location; } - public String getGid() { - return gid; - } - - public void setGid(String gid) { - this.gid = gid; - } - public String getNid() { return nid; } @@ -186,37 +178,24 @@ public class CIMSession implements Serializable { this.systemVersion = systemVersion; } - public Long getHeartbeat() { - return heartbeat; - } - - public void setHeartbeat(Long heartbeat) { - this.heartbeat = heartbeat; - setAttribute(CIMConstant.HEARTBEAT_KEY, heartbeat); - } - public void setHost(String host) { this.host = host; } - public void setChannel(Channel session) { - this.session = session; + public int getApns() { + return apns; } - public int getApnsAble() { - return apnsAble; + public void setApns(int apns) { + this.apns = apns; } - public void setApnsAble(int apnsAble) { - this.apnsAble = apnsAble; + public int getState() { + return state; } - public int getStatus() { - return status; - } - - public void setStatus(int status) { - this.status = status; + public void setState(int state) { + this.state = state; } public void setAttribute(String key, Object value) { @@ -248,36 +227,16 @@ public class CIMSession implements Serializable { return null; } + public boolean write(Object msg) { if (session != null && session.isActive()) { return session.writeAndFlush(msg).awaitUninterruptibly(5000); } - return false; } public boolean isConnected() { - if (session != null) { - return session.isActive(); - } - - if (!isLocalhost()) { - return status == STATUS_ENABLED; - } - - return false; - } - - public boolean isLocalhost() { - - try { - String ip = InetAddress.getLocalHost().getHostAddress(); - return ip.equals(host); - } catch (UnknownHostException e) { - e.printStackTrace(); - } - return false; - + return (session != null && session.isActive()) || state == STATE_ENABLED; } public void closeNow() { @@ -285,63 +244,108 @@ public class CIMSession implements Serializable { session.close(); } - public void setPackageName(String packageName) { - this.packageName = packageName; + public void closeOnFlush() { + if (session != null) + session.close(); } - public String getPackageName() { - return packageName; + public boolean isIOSChannel() { + return Objects.equals(channel, CHANNEL_IOS); } + public boolean isAndroidChannel() { + return Objects.equals(channel, CHANNEL_ANDROID); + } + + public boolean isWindowsChannel() { + return Objects.equals(channel, CHANNEL_WINDOWS); + } + + public boolean isApnsOpend() { + return Objects.equals(apns, APNS_ON); + } + + @Override public int hashCode() { - - return (deviceId + nid + host).hashCode(); + return getClass().hashCode(); } + @Override public boolean equals(Object o) { - if (o instanceof CIMSession) { - return hashCode() == o.hashCode(); + CIMSession target = (CIMSession) o; + return Objects.equals(target.deviceId, deviceId) && Objects.equals(target.nid, nid) + && Objects.equals(target.host, host); } return false; } - public boolean fromOtherDevice(Object o) { - - if (o instanceof CIMSession) { - - CIMSession t = (CIMSession) o; - if (t.deviceId != null && deviceId != null) { - return !t.deviceId.equals(deviceId); - } + public byte[] getProtobufBody() { + SessionProto.Model.Builder builder = SessionProto.Model.newBuilder(); + if (account != null) { + builder.setAccount(account); } - return false; + if (nid != null) { + builder.setNid(nid); + } + if (deviceId != null) { + builder.setDeviceId(deviceId); + } + if (host != null) { + builder.setHost(host); + } + if (channel != null) { + builder.setChannel(channel); + } + if (deviceModel != null) { + builder.setDeviceModel(deviceModel); + } + if (clientVersion != null) { + builder.setClientVersion(clientVersion); + } + if (systemVersion != null) { + builder.setSystemVersion(systemVersion); + } + if (bindTime != null) { + builder.setBindTime(bindTime); + } + if (longitude != null) { + builder.setLongitude(longitude); + } + if (latitude != null) { + builder.setLatitude(latitude); + } + if (location != null) { + builder.setLocation(location); + } + builder.setState(state); + builder.setApns(apns); + return builder.build().toByteArray(); } - - public boolean fromCurrentDevice(Object o) { - - return !fromOtherDevice(o); - } - - public String toString() { - StringBuffer buffer = new StringBuffer(); - buffer.append("{"); - - buffer.append("\"").append("gid").append("\":").append("\"").append(gid).append("\"").append(","); - buffer.append("\"").append("nid").append("\":").append(nid).append(","); - buffer.append("\"").append("deviceId").append("\":").append("\"").append(deviceId).append("\"").append(","); - buffer.append("\"").append("host").append("\":").append("\"").append(host).append("\"").append(","); - buffer.append("\"").append("account").append("\":").append("\"").append(account).append("\"").append(","); - buffer.append("\"").append("channel").append("\":").append("\"").append(channel).append("\"").append(","); - buffer.append("\"").append("deviceModel").append("\":").append("\"").append(deviceModel).append("\"") - .append(","); - buffer.append("\"").append("status").append("\":").append(status).append(","); - buffer.append("\"").append("apnsAble").append("\":").append(apnsAble).append(","); - buffer.append("\"").append("bindTime").append("\":").append(bindTime).append(","); - buffer.append("\"").append("heartbeat").append("\":").append(heartbeat); - buffer.append("}"); - return buffer.toString(); - + + + public static CIMSession decode(byte[] protobufBody) throws InvalidProtocolBufferException { + if(protobufBody == null) { + return null; + } + SessionProto.Model proto = SessionProto.Model.parseFrom(protobufBody); + CIMSession session = new CIMSession(); + session.setApns(proto.getApns()); + session.setBindTime(proto.getBindTime()); + session.setChannel(proto.getChannel()); + session.setClientVersion(proto.getClientVersion()); + session.setDeviceId(proto.getDeviceId()); + session.setDeviceModel(proto.getDeviceModel()); + session.setHost(proto.getHost()); + session.setLatitude(proto.getLatitude()); + session.setLongitude(proto.getLongitude()); + session.setLocation(proto.getLocation()); + session.setNid(proto.getNid()); + session.setSystemVersion(proto.getSystemVersion()); + session.setState(proto.getState()); + session.setAccount(proto.getAccount()); + return session; } + } diff --git a/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/model/proto/Session.proto b/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/model/proto/Session.proto new file mode 100644 index 0000000..da000b8 --- /dev/null +++ b/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/model/proto/Session.proto @@ -0,0 +1,19 @@ +syntax = "proto3"; +package com.farsunset.cim.sdk.server.model.proto; +option java_outer_classname="SessionProto"; +message Model { + string account = 1; + string nid = 2; + string deviceId = 3; + string host = 4; + string channel = 5; + string deviceModel = 6; + string clientVersion = 7; + string systemVersion = 8; + int64 bindTime = 9; + double longitude = 10; + double latitude = 11; + string location = 12; + int32 apns = 13; + int32 state = 14; +} diff --git a/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/model/proto/SessionProto.java b/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/model/proto/SessionProto.java new file mode 100644 index 0000000..966c489 --- /dev/null +++ b/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/model/proto/SessionProto.java @@ -0,0 +1,2022 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: Session.proto + +package com.farsunset.cim.sdk.server.model.proto; + +public final class SessionProto { + private SessionProto() {} + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistryLite registry) { + } + + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistry registry) { + registerAllExtensions( + (com.google.protobuf.ExtensionRegistryLite) registry); + } + public interface ModelOrBuilder extends + // @@protoc_insertion_point(interface_extends:com.farsunset.cim.sdk.server.model.proto.Model) + com.google.protobuf.MessageOrBuilder { + + /** + * string account = 1; + */ + java.lang.String getAccount(); + /** + * string account = 1; + */ + com.google.protobuf.ByteString + getAccountBytes(); + + /** + * string nid = 2; + */ + java.lang.String getNid(); + /** + * string nid = 2; + */ + com.google.protobuf.ByteString + getNidBytes(); + + /** + * string deviceId = 3; + */ + java.lang.String getDeviceId(); + /** + * string deviceId = 3; + */ + com.google.protobuf.ByteString + getDeviceIdBytes(); + + /** + * string host = 4; + */ + java.lang.String getHost(); + /** + * string host = 4; + */ + com.google.protobuf.ByteString + getHostBytes(); + + /** + * string channel = 5; + */ + java.lang.String getChannel(); + /** + * string channel = 5; + */ + com.google.protobuf.ByteString + getChannelBytes(); + + /** + * string deviceModel = 6; + */ + java.lang.String getDeviceModel(); + /** + * string deviceModel = 6; + */ + com.google.protobuf.ByteString + getDeviceModelBytes(); + + /** + * string clientVersion = 7; + */ + java.lang.String getClientVersion(); + /** + * string clientVersion = 7; + */ + com.google.protobuf.ByteString + getClientVersionBytes(); + + /** + * string systemVersion = 8; + */ + java.lang.String getSystemVersion(); + /** + * string systemVersion = 8; + */ + com.google.protobuf.ByteString + getSystemVersionBytes(); + + /** + * int64 bindTime = 9; + */ + long getBindTime(); + + /** + * double longitude = 10; + */ + double getLongitude(); + + /** + * double latitude = 11; + */ + double getLatitude(); + + /** + * string location = 12; + */ + java.lang.String getLocation(); + /** + * string location = 12; + */ + com.google.protobuf.ByteString + getLocationBytes(); + + /** + * int32 apns = 13; + */ + int getApns(); + + /** + * int32 state = 14; + */ + int getState(); + } + /** + * Protobuf type {@code com.farsunset.cim.sdk.server.model.proto.Model} + */ + public static final class Model extends + com.google.protobuf.GeneratedMessageV3 implements + // @@protoc_insertion_point(message_implements:com.farsunset.cim.sdk.server.model.proto.Model) + ModelOrBuilder { + private static final long serialVersionUID = 0L; + // Use Model.newBuilder() to construct. + private Model(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + private Model() { + account_ = ""; + nid_ = ""; + deviceId_ = ""; + host_ = ""; + channel_ = ""; + deviceModel_ = ""; + clientVersion_ = ""; + systemVersion_ = ""; + location_ = ""; + } + + @java.lang.Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return this.unknownFields; + } + private Model( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + this(); + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + int mutable_bitField0_ = 0; + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder(); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + java.lang.String s = input.readStringRequireUtf8(); + + account_ = s; + break; + } + case 18: { + java.lang.String s = input.readStringRequireUtf8(); + + nid_ = s; + break; + } + case 26: { + java.lang.String s = input.readStringRequireUtf8(); + + deviceId_ = s; + break; + } + case 34: { + java.lang.String s = input.readStringRequireUtf8(); + + host_ = s; + break; + } + case 42: { + java.lang.String s = input.readStringRequireUtf8(); + + channel_ = s; + break; + } + case 50: { + java.lang.String s = input.readStringRequireUtf8(); + + deviceModel_ = s; + break; + } + case 58: { + java.lang.String s = input.readStringRequireUtf8(); + + clientVersion_ = s; + break; + } + case 66: { + java.lang.String s = input.readStringRequireUtf8(); + + systemVersion_ = s; + break; + } + case 72: { + + bindTime_ = input.readInt64(); + break; + } + case 81: { + + longitude_ = input.readDouble(); + break; + } + case 89: { + + latitude_ = input.readDouble(); + break; + } + case 98: { + java.lang.String s = input.readStringRequireUtf8(); + + location_ = s; + break; + } + case 104: { + + apns_ = input.readInt32(); + break; + } + case 112: { + + state_ = input.readInt32(); + break; + } + default: { + if (!parseUnknownField( + input, unknownFields, extensionRegistry, tag)) { + done = true; + } + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e).setUnfinishedMessage(this); + } finally { + this.unknownFields = unknownFields.build(); + makeExtensionsImmutable(); + } + } + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return com.farsunset.cim.sdk.server.model.proto.SessionProto.internal_static_com_farsunset_cim_sdk_server_model_proto_Model_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return com.farsunset.cim.sdk.server.model.proto.SessionProto.internal_static_com_farsunset_cim_sdk_server_model_proto_Model_fieldAccessorTable + .ensureFieldAccessorsInitialized( + com.farsunset.cim.sdk.server.model.proto.SessionProto.Model.class, com.farsunset.cim.sdk.server.model.proto.SessionProto.Model.Builder.class); + } + + public static final int ACCOUNT_FIELD_NUMBER = 1; + private volatile java.lang.Object account_; + /** + * string account = 1; + */ + public java.lang.String getAccount() { + java.lang.Object ref = account_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + account_ = s; + return s; + } + } + /** + * string account = 1; + */ + public com.google.protobuf.ByteString + getAccountBytes() { + java.lang.Object ref = account_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + account_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int NID_FIELD_NUMBER = 2; + private volatile java.lang.Object nid_; + /** + * string nid = 2; + */ + public java.lang.String getNid() { + java.lang.Object ref = nid_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + nid_ = s; + return s; + } + } + /** + * string nid = 2; + */ + public com.google.protobuf.ByteString + getNidBytes() { + java.lang.Object ref = nid_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + nid_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int DEVICEID_FIELD_NUMBER = 3; + private volatile java.lang.Object deviceId_; + /** + * string deviceId = 3; + */ + public java.lang.String getDeviceId() { + java.lang.Object ref = deviceId_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + deviceId_ = s; + return s; + } + } + /** + * string deviceId = 3; + */ + public com.google.protobuf.ByteString + getDeviceIdBytes() { + java.lang.Object ref = deviceId_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + deviceId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int HOST_FIELD_NUMBER = 4; + private volatile java.lang.Object host_; + /** + * string host = 4; + */ + public java.lang.String getHost() { + java.lang.Object ref = host_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + host_ = s; + return s; + } + } + /** + * string host = 4; + */ + public com.google.protobuf.ByteString + getHostBytes() { + java.lang.Object ref = host_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + host_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int CHANNEL_FIELD_NUMBER = 5; + private volatile java.lang.Object channel_; + /** + * string channel = 5; + */ + public java.lang.String getChannel() { + java.lang.Object ref = channel_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + channel_ = s; + return s; + } + } + /** + * string channel = 5; + */ + public com.google.protobuf.ByteString + getChannelBytes() { + java.lang.Object ref = channel_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + channel_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int DEVICEMODEL_FIELD_NUMBER = 6; + private volatile java.lang.Object deviceModel_; + /** + * string deviceModel = 6; + */ + public java.lang.String getDeviceModel() { + java.lang.Object ref = deviceModel_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + deviceModel_ = s; + return s; + } + } + /** + * string deviceModel = 6; + */ + public com.google.protobuf.ByteString + getDeviceModelBytes() { + java.lang.Object ref = deviceModel_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + deviceModel_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int CLIENTVERSION_FIELD_NUMBER = 7; + private volatile java.lang.Object clientVersion_; + /** + * string clientVersion = 7; + */ + public java.lang.String getClientVersion() { + java.lang.Object ref = clientVersion_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + clientVersion_ = s; + return s; + } + } + /** + * string clientVersion = 7; + */ + public com.google.protobuf.ByteString + getClientVersionBytes() { + java.lang.Object ref = clientVersion_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + clientVersion_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int SYSTEMVERSION_FIELD_NUMBER = 8; + private volatile java.lang.Object systemVersion_; + /** + * string systemVersion = 8; + */ + public java.lang.String getSystemVersion() { + java.lang.Object ref = systemVersion_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + systemVersion_ = s; + return s; + } + } + /** + * string systemVersion = 8; + */ + public com.google.protobuf.ByteString + getSystemVersionBytes() { + java.lang.Object ref = systemVersion_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + systemVersion_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int BINDTIME_FIELD_NUMBER = 9; + private long bindTime_; + /** + * int64 bindTime = 9; + */ + public long getBindTime() { + return bindTime_; + } + + public static final int LONGITUDE_FIELD_NUMBER = 10; + private double longitude_; + /** + * double longitude = 10; + */ + public double getLongitude() { + return longitude_; + } + + public static final int LATITUDE_FIELD_NUMBER = 11; + private double latitude_; + /** + * double latitude = 11; + */ + public double getLatitude() { + return latitude_; + } + + public static final int LOCATION_FIELD_NUMBER = 12; + private volatile java.lang.Object location_; + /** + * string location = 12; + */ + public java.lang.String getLocation() { + java.lang.Object ref = location_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + location_ = s; + return s; + } + } + /** + * string location = 12; + */ + public com.google.protobuf.ByteString + getLocationBytes() { + java.lang.Object ref = location_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + location_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int APNS_FIELD_NUMBER = 13; + private int apns_; + /** + * int32 apns = 13; + */ + public int getApns() { + return apns_; + } + + public static final int STATE_FIELD_NUMBER = 14; + private int state_; + /** + * int32 state = 14; + */ + public int getState() { + return state_; + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!getAccountBytes().isEmpty()) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 1, account_); + } + if (!getNidBytes().isEmpty()) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 2, nid_); + } + if (!getDeviceIdBytes().isEmpty()) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 3, deviceId_); + } + if (!getHostBytes().isEmpty()) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 4, host_); + } + if (!getChannelBytes().isEmpty()) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 5, channel_); + } + if (!getDeviceModelBytes().isEmpty()) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 6, deviceModel_); + } + if (!getClientVersionBytes().isEmpty()) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 7, clientVersion_); + } + if (!getSystemVersionBytes().isEmpty()) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 8, systemVersion_); + } + if (bindTime_ != 0L) { + output.writeInt64(9, bindTime_); + } + if (longitude_ != 0D) { + output.writeDouble(10, longitude_); + } + if (latitude_ != 0D) { + output.writeDouble(11, latitude_); + } + if (!getLocationBytes().isEmpty()) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 12, location_); + } + if (apns_ != 0) { + output.writeInt32(13, apns_); + } + if (state_ != 0) { + output.writeInt32(14, state_); + } + unknownFields.writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!getAccountBytes().isEmpty()) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, account_); + } + if (!getNidBytes().isEmpty()) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, nid_); + } + if (!getDeviceIdBytes().isEmpty()) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(3, deviceId_); + } + if (!getHostBytes().isEmpty()) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(4, host_); + } + if (!getChannelBytes().isEmpty()) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(5, channel_); + } + if (!getDeviceModelBytes().isEmpty()) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(6, deviceModel_); + } + if (!getClientVersionBytes().isEmpty()) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(7, clientVersion_); + } + if (!getSystemVersionBytes().isEmpty()) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(8, systemVersion_); + } + if (bindTime_ != 0L) { + size += com.google.protobuf.CodedOutputStream + .computeInt64Size(9, bindTime_); + } + if (longitude_ != 0D) { + size += com.google.protobuf.CodedOutputStream + .computeDoubleSize(10, longitude_); + } + if (latitude_ != 0D) { + size += com.google.protobuf.CodedOutputStream + .computeDoubleSize(11, latitude_); + } + if (!getLocationBytes().isEmpty()) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(12, location_); + } + if (apns_ != 0) { + size += com.google.protobuf.CodedOutputStream + .computeInt32Size(13, apns_); + } + if (state_ != 0) { + size += com.google.protobuf.CodedOutputStream + .computeInt32Size(14, state_); + } + size += unknownFields.getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof com.farsunset.cim.sdk.server.model.proto.SessionProto.Model)) { + return super.equals(obj); + } + com.farsunset.cim.sdk.server.model.proto.SessionProto.Model other = (com.farsunset.cim.sdk.server.model.proto.SessionProto.Model) obj; + + if (!getAccount() + .equals(other.getAccount())) return false; + if (!getNid() + .equals(other.getNid())) return false; + if (!getDeviceId() + .equals(other.getDeviceId())) return false; + if (!getHost() + .equals(other.getHost())) return false; + if (!getChannel() + .equals(other.getChannel())) return false; + if (!getDeviceModel() + .equals(other.getDeviceModel())) return false; + if (!getClientVersion() + .equals(other.getClientVersion())) return false; + if (!getSystemVersion() + .equals(other.getSystemVersion())) return false; + if (getBindTime() + != other.getBindTime()) return false; + if (java.lang.Double.doubleToLongBits(getLongitude()) + != java.lang.Double.doubleToLongBits( + other.getLongitude())) return false; + if (java.lang.Double.doubleToLongBits(getLatitude()) + != java.lang.Double.doubleToLongBits( + other.getLatitude())) return false; + if (!getLocation() + .equals(other.getLocation())) return false; + if (getApns() + != other.getApns()) return false; + if (getState() + != other.getState()) return false; + if (!unknownFields.equals(other.unknownFields)) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + ACCOUNT_FIELD_NUMBER; + hash = (53 * hash) + getAccount().hashCode(); + hash = (37 * hash) + NID_FIELD_NUMBER; + hash = (53 * hash) + getNid().hashCode(); + hash = (37 * hash) + DEVICEID_FIELD_NUMBER; + hash = (53 * hash) + getDeviceId().hashCode(); + hash = (37 * hash) + HOST_FIELD_NUMBER; + hash = (53 * hash) + getHost().hashCode(); + hash = (37 * hash) + CHANNEL_FIELD_NUMBER; + hash = (53 * hash) + getChannel().hashCode(); + hash = (37 * hash) + DEVICEMODEL_FIELD_NUMBER; + hash = (53 * hash) + getDeviceModel().hashCode(); + hash = (37 * hash) + CLIENTVERSION_FIELD_NUMBER; + hash = (53 * hash) + getClientVersion().hashCode(); + hash = (37 * hash) + SYSTEMVERSION_FIELD_NUMBER; + hash = (53 * hash) + getSystemVersion().hashCode(); + hash = (37 * hash) + BINDTIME_FIELD_NUMBER; + hash = (53 * hash) + com.google.protobuf.Internal.hashLong( + getBindTime()); + hash = (37 * hash) + LONGITUDE_FIELD_NUMBER; + hash = (53 * hash) + com.google.protobuf.Internal.hashLong( + java.lang.Double.doubleToLongBits(getLongitude())); + hash = (37 * hash) + LATITUDE_FIELD_NUMBER; + hash = (53 * hash) + com.google.protobuf.Internal.hashLong( + java.lang.Double.doubleToLongBits(getLatitude())); + hash = (37 * hash) + LOCATION_FIELD_NUMBER; + hash = (53 * hash) + getLocation().hashCode(); + hash = (37 * hash) + APNS_FIELD_NUMBER; + hash = (53 * hash) + getApns(); + hash = (37 * hash) + STATE_FIELD_NUMBER; + hash = (53 * hash) + getState(); + hash = (29 * hash) + unknownFields.hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static com.farsunset.cim.sdk.server.model.proto.SessionProto.Model parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.farsunset.cim.sdk.server.model.proto.SessionProto.Model parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.farsunset.cim.sdk.server.model.proto.SessionProto.Model parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.farsunset.cim.sdk.server.model.proto.SessionProto.Model parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.farsunset.cim.sdk.server.model.proto.SessionProto.Model parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.farsunset.cim.sdk.server.model.proto.SessionProto.Model parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.farsunset.cim.sdk.server.model.proto.SessionProto.Model parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static com.farsunset.cim.sdk.server.model.proto.SessionProto.Model parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + public static com.farsunset.cim.sdk.server.model.proto.SessionProto.Model parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input); + } + public static com.farsunset.cim.sdk.server.model.proto.SessionProto.Model parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static com.farsunset.cim.sdk.server.model.proto.SessionProto.Model parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static com.farsunset.cim.sdk.server.model.proto.SessionProto.Model parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(com.farsunset.cim.sdk.server.model.proto.SessionProto.Model prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code com.farsunset.cim.sdk.server.model.proto.Model} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageV3.Builder implements + // @@protoc_insertion_point(builder_implements:com.farsunset.cim.sdk.server.model.proto.Model) + com.farsunset.cim.sdk.server.model.proto.SessionProto.ModelOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return com.farsunset.cim.sdk.server.model.proto.SessionProto.internal_static_com_farsunset_cim_sdk_server_model_proto_Model_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return com.farsunset.cim.sdk.server.model.proto.SessionProto.internal_static_com_farsunset_cim_sdk_server_model_proto_Model_fieldAccessorTable + .ensureFieldAccessorsInitialized( + com.farsunset.cim.sdk.server.model.proto.SessionProto.Model.class, com.farsunset.cim.sdk.server.model.proto.SessionProto.Model.Builder.class); + } + + // Construct using com.farsunset.cim.sdk.server.model.proto.SessionProto.Model.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessageV3 + .alwaysUseFieldBuilders) { + } + } + @java.lang.Override + public Builder clear() { + super.clear(); + account_ = ""; + + nid_ = ""; + + deviceId_ = ""; + + host_ = ""; + + channel_ = ""; + + deviceModel_ = ""; + + clientVersion_ = ""; + + systemVersion_ = ""; + + bindTime_ = 0L; + + longitude_ = 0D; + + latitude_ = 0D; + + location_ = ""; + + apns_ = 0; + + state_ = 0; + + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return com.farsunset.cim.sdk.server.model.proto.SessionProto.internal_static_com_farsunset_cim_sdk_server_model_proto_Model_descriptor; + } + + @java.lang.Override + public com.farsunset.cim.sdk.server.model.proto.SessionProto.Model getDefaultInstanceForType() { + return com.farsunset.cim.sdk.server.model.proto.SessionProto.Model.getDefaultInstance(); + } + + @java.lang.Override + public com.farsunset.cim.sdk.server.model.proto.SessionProto.Model build() { + com.farsunset.cim.sdk.server.model.proto.SessionProto.Model result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public com.farsunset.cim.sdk.server.model.proto.SessionProto.Model buildPartial() { + com.farsunset.cim.sdk.server.model.proto.SessionProto.Model result = new com.farsunset.cim.sdk.server.model.proto.SessionProto.Model(this); + result.account_ = account_; + result.nid_ = nid_; + result.deviceId_ = deviceId_; + result.host_ = host_; + result.channel_ = channel_; + result.deviceModel_ = deviceModel_; + result.clientVersion_ = clientVersion_; + result.systemVersion_ = systemVersion_; + result.bindTime_ = bindTime_; + result.longitude_ = longitude_; + result.latitude_ = latitude_; + result.location_ = location_; + result.apns_ = apns_; + result.state_ = state_; + onBuilt(); + return result; + } + + @java.lang.Override + public Builder clone() { + return super.clone(); + } + @java.lang.Override + public Builder setField( + com.google.protobuf.Descriptors.FieldDescriptor field, + java.lang.Object value) { + return super.setField(field, value); + } + @java.lang.Override + public Builder clearField( + com.google.protobuf.Descriptors.FieldDescriptor field) { + return super.clearField(field); + } + @java.lang.Override + public Builder clearOneof( + com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return super.clearOneof(oneof); + } + @java.lang.Override + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + int index, java.lang.Object value) { + return super.setRepeatedField(field, index, value); + } + @java.lang.Override + public Builder addRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + java.lang.Object value) { + return super.addRepeatedField(field, value); + } + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof com.farsunset.cim.sdk.server.model.proto.SessionProto.Model) { + return mergeFrom((com.farsunset.cim.sdk.server.model.proto.SessionProto.Model)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(com.farsunset.cim.sdk.server.model.proto.SessionProto.Model other) { + if (other == com.farsunset.cim.sdk.server.model.proto.SessionProto.Model.getDefaultInstance()) return this; + if (!other.getAccount().isEmpty()) { + account_ = other.account_; + onChanged(); + } + if (!other.getNid().isEmpty()) { + nid_ = other.nid_; + onChanged(); + } + if (!other.getDeviceId().isEmpty()) { + deviceId_ = other.deviceId_; + onChanged(); + } + if (!other.getHost().isEmpty()) { + host_ = other.host_; + onChanged(); + } + if (!other.getChannel().isEmpty()) { + channel_ = other.channel_; + onChanged(); + } + if (!other.getDeviceModel().isEmpty()) { + deviceModel_ = other.deviceModel_; + onChanged(); + } + if (!other.getClientVersion().isEmpty()) { + clientVersion_ = other.clientVersion_; + onChanged(); + } + if (!other.getSystemVersion().isEmpty()) { + systemVersion_ = other.systemVersion_; + onChanged(); + } + if (other.getBindTime() != 0L) { + setBindTime(other.getBindTime()); + } + if (other.getLongitude() != 0D) { + setLongitude(other.getLongitude()); + } + if (other.getLatitude() != 0D) { + setLatitude(other.getLatitude()); + } + if (!other.getLocation().isEmpty()) { + location_ = other.location_; + onChanged(); + } + if (other.getApns() != 0) { + setApns(other.getApns()); + } + if (other.getState() != 0) { + setState(other.getState()); + } + this.mergeUnknownFields(other.unknownFields); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.farsunset.cim.sdk.server.model.proto.SessionProto.Model parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.farsunset.cim.sdk.server.model.proto.SessionProto.Model) e.getUnfinishedMessage(); + throw e.unwrapIOException(); + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + + private java.lang.Object account_ = ""; + /** + * string account = 1; + */ + public java.lang.String getAccount() { + java.lang.Object ref = account_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + account_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string account = 1; + */ + public com.google.protobuf.ByteString + getAccountBytes() { + java.lang.Object ref = account_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + account_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string account = 1; + */ + public Builder setAccount( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + + account_ = value; + onChanged(); + return this; + } + /** + * string account = 1; + */ + public Builder clearAccount() { + + account_ = getDefaultInstance().getAccount(); + onChanged(); + return this; + } + /** + * string account = 1; + */ + public Builder setAccountBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + + account_ = value; + onChanged(); + return this; + } + + private java.lang.Object nid_ = ""; + /** + * string nid = 2; + */ + public java.lang.String getNid() { + java.lang.Object ref = nid_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + nid_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string nid = 2; + */ + public com.google.protobuf.ByteString + getNidBytes() { + java.lang.Object ref = nid_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + nid_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string nid = 2; + */ + public Builder setNid( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + + nid_ = value; + onChanged(); + return this; + } + /** + * string nid = 2; + */ + public Builder clearNid() { + + nid_ = getDefaultInstance().getNid(); + onChanged(); + return this; + } + /** + * string nid = 2; + */ + public Builder setNidBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + + nid_ = value; + onChanged(); + return this; + } + + private java.lang.Object deviceId_ = ""; + /** + * string deviceId = 3; + */ + public java.lang.String getDeviceId() { + java.lang.Object ref = deviceId_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + deviceId_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string deviceId = 3; + */ + public com.google.protobuf.ByteString + getDeviceIdBytes() { + java.lang.Object ref = deviceId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + deviceId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string deviceId = 3; + */ + public Builder setDeviceId( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + + deviceId_ = value; + onChanged(); + return this; + } + /** + * string deviceId = 3; + */ + public Builder clearDeviceId() { + + deviceId_ = getDefaultInstance().getDeviceId(); + onChanged(); + return this; + } + /** + * string deviceId = 3; + */ + public Builder setDeviceIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + + deviceId_ = value; + onChanged(); + return this; + } + + private java.lang.Object host_ = ""; + /** + * string host = 4; + */ + public java.lang.String getHost() { + java.lang.Object ref = host_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + host_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string host = 4; + */ + public com.google.protobuf.ByteString + getHostBytes() { + java.lang.Object ref = host_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + host_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string host = 4; + */ + public Builder setHost( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + + host_ = value; + onChanged(); + return this; + } + /** + * string host = 4; + */ + public Builder clearHost() { + + host_ = getDefaultInstance().getHost(); + onChanged(); + return this; + } + /** + * string host = 4; + */ + public Builder setHostBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + + host_ = value; + onChanged(); + return this; + } + + private java.lang.Object channel_ = ""; + /** + * string channel = 5; + */ + public java.lang.String getChannel() { + java.lang.Object ref = channel_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + channel_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string channel = 5; + */ + public com.google.protobuf.ByteString + getChannelBytes() { + java.lang.Object ref = channel_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + channel_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string channel = 5; + */ + public Builder setChannel( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + + channel_ = value; + onChanged(); + return this; + } + /** + * string channel = 5; + */ + public Builder clearChannel() { + + channel_ = getDefaultInstance().getChannel(); + onChanged(); + return this; + } + /** + * string channel = 5; + */ + public Builder setChannelBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + + channel_ = value; + onChanged(); + return this; + } + + private java.lang.Object deviceModel_ = ""; + /** + * string deviceModel = 6; + */ + public java.lang.String getDeviceModel() { + java.lang.Object ref = deviceModel_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + deviceModel_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string deviceModel = 6; + */ + public com.google.protobuf.ByteString + getDeviceModelBytes() { + java.lang.Object ref = deviceModel_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + deviceModel_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string deviceModel = 6; + */ + public Builder setDeviceModel( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + + deviceModel_ = value; + onChanged(); + return this; + } + /** + * string deviceModel = 6; + */ + public Builder clearDeviceModel() { + + deviceModel_ = getDefaultInstance().getDeviceModel(); + onChanged(); + return this; + } + /** + * string deviceModel = 6; + */ + public Builder setDeviceModelBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + + deviceModel_ = value; + onChanged(); + return this; + } + + private java.lang.Object clientVersion_ = ""; + /** + * string clientVersion = 7; + */ + public java.lang.String getClientVersion() { + java.lang.Object ref = clientVersion_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + clientVersion_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string clientVersion = 7; + */ + public com.google.protobuf.ByteString + getClientVersionBytes() { + java.lang.Object ref = clientVersion_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + clientVersion_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string clientVersion = 7; + */ + public Builder setClientVersion( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + + clientVersion_ = value; + onChanged(); + return this; + } + /** + * string clientVersion = 7; + */ + public Builder clearClientVersion() { + + clientVersion_ = getDefaultInstance().getClientVersion(); + onChanged(); + return this; + } + /** + * string clientVersion = 7; + */ + public Builder setClientVersionBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + + clientVersion_ = value; + onChanged(); + return this; + } + + private java.lang.Object systemVersion_ = ""; + /** + * string systemVersion = 8; + */ + public java.lang.String getSystemVersion() { + java.lang.Object ref = systemVersion_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + systemVersion_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string systemVersion = 8; + */ + public com.google.protobuf.ByteString + getSystemVersionBytes() { + java.lang.Object ref = systemVersion_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + systemVersion_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string systemVersion = 8; + */ + public Builder setSystemVersion( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + + systemVersion_ = value; + onChanged(); + return this; + } + /** + * string systemVersion = 8; + */ + public Builder clearSystemVersion() { + + systemVersion_ = getDefaultInstance().getSystemVersion(); + onChanged(); + return this; + } + /** + * string systemVersion = 8; + */ + public Builder setSystemVersionBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + + systemVersion_ = value; + onChanged(); + return this; + } + + private long bindTime_ ; + /** + * int64 bindTime = 9; + */ + public long getBindTime() { + return bindTime_; + } + /** + * int64 bindTime = 9; + */ + public Builder setBindTime(long value) { + + bindTime_ = value; + onChanged(); + return this; + } + /** + * int64 bindTime = 9; + */ + public Builder clearBindTime() { + + bindTime_ = 0L; + onChanged(); + return this; + } + + private double longitude_ ; + /** + * double longitude = 10; + */ + public double getLongitude() { + return longitude_; + } + /** + * double longitude = 10; + */ + public Builder setLongitude(double value) { + + longitude_ = value; + onChanged(); + return this; + } + /** + * double longitude = 10; + */ + public Builder clearLongitude() { + + longitude_ = 0D; + onChanged(); + return this; + } + + private double latitude_ ; + /** + * double latitude = 11; + */ + public double getLatitude() { + return latitude_; + } + /** + * double latitude = 11; + */ + public Builder setLatitude(double value) { + + latitude_ = value; + onChanged(); + return this; + } + /** + * double latitude = 11; + */ + public Builder clearLatitude() { + + latitude_ = 0D; + onChanged(); + return this; + } + + private java.lang.Object location_ = ""; + /** + * string location = 12; + */ + public java.lang.String getLocation() { + java.lang.Object ref = location_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + location_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string location = 12; + */ + public com.google.protobuf.ByteString + getLocationBytes() { + java.lang.Object ref = location_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + location_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string location = 12; + */ + public Builder setLocation( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + + location_ = value; + onChanged(); + return this; + } + /** + * string location = 12; + */ + public Builder clearLocation() { + + location_ = getDefaultInstance().getLocation(); + onChanged(); + return this; + } + /** + * string location = 12; + */ + public Builder setLocationBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + + location_ = value; + onChanged(); + return this; + } + + private int apns_ ; + /** + * int32 apns = 13; + */ + public int getApns() { + return apns_; + } + /** + * int32 apns = 13; + */ + public Builder setApns(int value) { + + apns_ = value; + onChanged(); + return this; + } + /** + * int32 apns = 13; + */ + public Builder clearApns() { + + apns_ = 0; + onChanged(); + return this; + } + + private int state_ ; + /** + * int32 state = 14; + */ + public int getState() { + return state_; + } + /** + * int32 state = 14; + */ + public Builder setState(int value) { + + state_ = value; + onChanged(); + return this; + } + /** + * int32 state = 14; + */ + public Builder clearState() { + + state_ = 0; + onChanged(); + return this; + } + @java.lang.Override + public final Builder setUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.setUnknownFields(unknownFields); + } + + @java.lang.Override + public final Builder mergeUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.mergeUnknownFields(unknownFields); + } + + + // @@protoc_insertion_point(builder_scope:com.farsunset.cim.sdk.server.model.proto.Model) + } + + // @@protoc_insertion_point(class_scope:com.farsunset.cim.sdk.server.model.proto.Model) + private static final com.farsunset.cim.sdk.server.model.proto.SessionProto.Model DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new com.farsunset.cim.sdk.server.model.proto.SessionProto.Model(); + } + + public static com.farsunset.cim.sdk.server.model.proto.SessionProto.Model getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public Model parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new Model(input, extensionRegistry); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public com.farsunset.cim.sdk.server.model.proto.SessionProto.Model getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + + } + + private static final com.google.protobuf.Descriptors.Descriptor + internal_static_com_farsunset_cim_sdk_server_model_proto_Model_descriptor; + private static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_com_farsunset_cim_sdk_server_model_proto_Model_fieldAccessorTable; + + public static com.google.protobuf.Descriptors.FileDescriptor + getDescriptor() { + return descriptor; + } + private static com.google.protobuf.Descriptors.FileDescriptor + descriptor; + static { + java.lang.String[] descriptorData = { + "\n\rSession.proto\022(com.farsunset.cim.sdk.s" + + "erver.model.proto\"\377\001\n\005Model\022\017\n\007account\030\001" + + " \001(\t\022\013\n\003nid\030\002 \001(\t\022\020\n\010deviceId\030\003 \001(\t\022\014\n\004h" + + "ost\030\004 \001(\t\022\017\n\007channel\030\005 \001(\t\022\023\n\013deviceMode" + + "l\030\006 \001(\t\022\025\n\rclientVersion\030\007 \001(\t\022\025\n\rsystem" + + "Version\030\010 \001(\t\022\020\n\010bindTime\030\t \001(\003\022\021\n\tlongi" + + "tude\030\n \001(\001\022\020\n\010latitude\030\013 \001(\001\022\020\n\010location" + + "\030\014 \001(\t\022\014\n\004apns\030\r \001(\005\022\r\n\005state\030\016 \001(\005B\016B\014S" + + "essionProtob\006proto3" + }; + com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = + new com.google.protobuf.Descriptors.FileDescriptor. InternalDescriptorAssigner() { + public com.google.protobuf.ExtensionRegistry assignDescriptors( + com.google.protobuf.Descriptors.FileDescriptor root) { + descriptor = root; + return null; + } + }; + com.google.protobuf.Descriptors.FileDescriptor + .internalBuildGeneratedFileFrom(descriptorData, + new com.google.protobuf.Descriptors.FileDescriptor[] { + }, assigner); + internal_static_com_farsunset_cim_sdk_server_model_proto_Model_descriptor = + getDescriptor().getMessageTypes().get(0); + internal_static_com_farsunset_cim_sdk_server_model_proto_Model_fieldAccessorTable = new + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_com_farsunset_cim_sdk_server_model_proto_Model_descriptor, + new java.lang.String[] { "Account", "Nid", "DeviceId", "Host", "Channel", "DeviceModel", "ClientVersion", "SystemVersion", "BindTime", "Longitude", "Latitude", "Location", "Apns", "State", }); + } + + // @@protoc_insertion_point(outer_class_scope) +} diff --git a/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/session/DefaultSessionManager.java b/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/session/DefaultSessionManager.java deleted file mode 100644 index ba537c4..0000000 --- a/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/session/DefaultSessionManager.java +++ /dev/null @@ -1,84 +0,0 @@ -/** - * Copyright 2013-2019 Xia Jun(3979434@qq.com). - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - *************************************************************************************** - * * - * Website : http://www.farsunset.com * - * * - *************************************************************************************** - */ -package com.farsunset.cim.sdk.server.session; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; - -import com.farsunset.cim.sdk.server.constant.CIMConstant; - -/** - * 自带默认 session管理实现, 各位可以自行实现 AbstractSessionManager接口来实现自己的 session管理 服务器集群时 - * 须要将CIMSession 信息存入数据库或者nosql 等 第三方存储空间中,便于所有服务器都可以访问 - */ -public class DefaultSessionManager implements SessionManager { - - private static HashMap sessions = new HashMap(); - - private static final AtomicInteger connectionsCounter = new AtomicInteger(0); - - /** - * - */ - public void add(CIMSession session) { - if (session != null) { - session.setAttribute(CIMConstant.SESSION_KEY, session.getAccount()); - sessions.put(session.getAccount(), session); - connectionsCounter.incrementAndGet(); - } - - } - - public CIMSession get(String account) { - - return sessions.get(account); - } - - public List queryAll() { - List list = new ArrayList(); - list.addAll(sessions.values()); - return list; - } - - public void remove(CIMSession session) { - - sessions.remove(session.getAttribute(CIMConstant.SESSION_KEY)); - } - - public void remove(String account) { - - sessions.remove(account); - - } - - public boolean containsCIMSession(String account) { - return sessions.containsKey(account); - } - - @Override - public void update(CIMSession session) { - sessions.put(session.getAccount(), session); - } - -} diff --git a/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/session/SessionManager.java b/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/session/SessionManager.java deleted file mode 100644 index d067129..0000000 --- a/cim_for_netty/cim-server-sdk/src/com/farsunset/cim/sdk/server/session/SessionManager.java +++ /dev/null @@ -1,64 +0,0 @@ -/** - * Copyright 2013-2019 Xia Jun(3979434@qq.com). - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - *************************************************************************************** - * * - * Website : http://www.farsunset.com * - * * - *************************************************************************************** - */ -package com.farsunset.cim.sdk.server.session; - -import java.util.List; - -/** - * 客户端的 session管理接口 可自行实现此接口管理session - */ - -public interface SessionManager { - - /** - * 添加新的session - */ - public void add(CIMSession session); - - /** - * 更新session - */ - public void update(CIMSession session); - - /** - * - * @param account - * 客户端session的 key 一般可用 用户账号来对应session - * @return - */ - CIMSession get(String account); - - /** - * 获取所有session - * - * @return - */ - public List queryAll(); - - /** - * 删除session - * - * @param session - */ - public void remove(String account); - -}