mirror of
https://gitee.com/farsunset/cim.git
synced 2025-07-25 17:21:46 +08:00
重构服务端sdk结构
This commit is contained in:
parent
351c6bc0ae
commit
e9cc607776
Binary file not shown.
@ -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.CIMNioSocketAcceptor;
|
||||||
import com.farsunset.cim.sdk.server.handler.CIMRequestHandler;
|
import com.farsunset.cim.sdk.server.handler.CIMRequestHandler;
|
||||||
import com.farsunset.cim.sdk.server.model.SentBody;
|
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
|
@Configuration
|
||||||
public class CIMConfig implements CIMRequestHandler {
|
public class CIMConfig implements CIMRequestHandler {
|
||||||
|
@ -27,17 +27,18 @@ import org.springframework.stereotype.Controller;
|
|||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
|
||||||
import com.farsunset.cim.service.impl.CIMSessionServiceImpl;
|
import com.farsunset.cim.service.CIMSessionService;
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
@RequestMapping("/console/session")
|
@RequestMapping("/console/session")
|
||||||
public class SessionController {
|
public class SessionController {
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private CIMSessionServiceImpl sessionManager;
|
private CIMSessionService memorySessionService;
|
||||||
|
|
||||||
@RequestMapping(value = "/list.action")
|
@RequestMapping(value = "/list.action")
|
||||||
public String list(Model model) {
|
public String list(Model model) {
|
||||||
model.addAttribute("sessionList", sessionManager.queryAll());
|
model.addAttribute("sessionList", memorySessionService.list());
|
||||||
return "console/session/manage";
|
return "console/session/manage";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,14 +30,14 @@ import org.slf4j.LoggerFactory;
|
|||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Component;
|
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.constant.CIMConstant;
|
||||||
import com.farsunset.cim.sdk.server.handler.CIMRequestHandler;
|
import com.farsunset.cim.sdk.server.handler.CIMRequestHandler;
|
||||||
import com.farsunset.cim.sdk.server.model.Message;
|
import com.farsunset.cim.sdk.server.model.Message;
|
||||||
import com.farsunset.cim.sdk.server.model.ReplyBody;
|
import com.farsunset.cim.sdk.server.model.ReplyBody;
|
||||||
import com.farsunset.cim.sdk.server.model.SentBody;
|
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 com.farsunset.cim.service.impl.CIMSessionServiceImpl;
|
import com.farsunset.cim.service.CIMSessionService;
|
||||||
import com.farsunset.cim.util.StringUtil;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -51,57 +51,57 @@ public class BindHandler implements CIMRequestHandler {
|
|||||||
protected final Logger logger = LoggerFactory.getLogger(BindHandler.class);
|
protected final Logger logger = LoggerFactory.getLogger(BindHandler.class);
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private CIMSessionServiceImpl sessionManager;
|
private CIMSessionService memorySessionService;
|
||||||
|
|
||||||
@Value("${server.host}")
|
@Value("${server.host}")
|
||||||
private String 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();
|
ReplyBody reply = new ReplyBody();
|
||||||
reply.setKey(message.getKey());
|
reply.setKey(body.getKey());
|
||||||
reply.setCode(CIMConstant.ReturnCode.CODE_200);
|
reply.setCode(CIMConstant.ReturnCode.CODE_200);
|
||||||
|
reply.setTimestamp(System.currentTimeMillis());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
String account = message.get("account");
|
String account = body.get("account");
|
||||||
newSession.setGid(StringUtil.getUUID());
|
|
||||||
newSession.setAccount(account);
|
newSession.setAccount(account);
|
||||||
newSession.setDeviceId(message.get("deviceId"));
|
newSession.setDeviceId(body.get("deviceId"));
|
||||||
newSession.setHost(host);
|
newSession.setHost(host);
|
||||||
newSession.setChannel(message.get("channel"));
|
newSession.setChannel(body.get("channel"));
|
||||||
newSession.setDeviceModel(message.get("device"));
|
newSession.setDeviceModel(body.get("device"));
|
||||||
newSession.setClientVersion(message.get("version"));
|
newSession.setClientVersion(body.get("version"));
|
||||||
newSession.setSystemVersion(message.get("osVersion"));
|
newSession.setSystemVersion(body.get("osVersion"));
|
||||||
newSession.setBindTime(System.currentTimeMillis());
|
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()) {
|
if (oldSession != null && fromOtherDevice(newSession,oldSession) && oldSession.isConnected()) {
|
||||||
sendForceOfflineMessage(oldSession, account, newSession.getDeviceModel());
|
sendForceOfflineMessage(oldSession, account, newSession.getDeviceModel());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
/**
|
|
||||||
* 有可能是同一个设备重复连接,则关闭旧的链接,这种情况一般是客户端断网,联网又重新链接上来,之前的旧链接没有来得及通过心跳机制关闭,在这里手动关闭
|
* 有可能是同一个设备重复连接,则关闭旧的链接,这种情况一般是客户端断网,联网又重新链接上来,之前的旧链接没有来得及通过心跳机制关闭,在这里手动关闭
|
||||||
* 条件1,连接来自是同一个设备
|
* 条件1,连接来自是同一个设备
|
||||||
* 条件2.2个连接都是同一台服务器
|
* 条件2.2个连接都是同一台服务器
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (oldSession != null && !fromOtherDevice(newSession,oldSession) && Objects.equals(oldSession.getHost(),host)) {
|
if (oldSession != null && !fromOtherDevice(newSession,oldSession) && Objects.equals(oldSession.getHost(),host)) {
|
||||||
oldSession.removeAttribute(CIMConstant.SESSION_KEY);
|
closeQuietly(oldSession);
|
||||||
oldSession.closeOnFlush();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
sessionManager.add(newSession);
|
memorySessionService.save(newSession);
|
||||||
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
reply.setCode(CIMConstant.ReturnCode.CODE_500);
|
reply.setCode(CIMConstant.ReturnCode.CODE_500);
|
||||||
@ -124,15 +124,17 @@ public class BindHandler implements CIMRequestHandler {
|
|||||||
msg.setSender("system");
|
msg.setSender("system");
|
||||||
msg.setContent(deviceModel);
|
msg.setContent(deviceModel);
|
||||||
msg.setId(System.currentTimeMillis());
|
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())) {
|
if (oldSession.isConnected() && Objects.equals(host, oldSession.getHost())) {
|
||||||
oldSession.write(msg);
|
oldSession.setAttribute(CIMConstant.KEY_QUIETLY_CLOSE,true);
|
||||||
oldSession.removeAttribute(CIMConstant.SESSION_KEY);
|
|
||||||
oldSession.closeOnFlush();
|
oldSession.closeOnFlush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,8 @@
|
|||||||
package com.farsunset.cim.handler;
|
package com.farsunset.cim.handler;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
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.constant.CIMConstant;
|
||||||
import com.farsunset.cim.sdk.server.handler.CIMRequestHandler;
|
import com.farsunset.cim.sdk.server.handler.CIMRequestHandler;
|
||||||
import com.farsunset.cim.sdk.server.model.SentBody;
|
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 com.farsunset.cim.service.impl.CIMSessionServiceImpl;
|
import com.farsunset.cim.service.CIMSessionService;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -46,17 +48,28 @@ public class SessionClosedHandler implements CIMRequestHandler {
|
|||||||
protected final Logger logger = LoggerFactory.getLogger(SessionClosedHandler.class);
|
protected final Logger logger = LoggerFactory.getLogger(SessionClosedHandler.class);
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private CIMSessionServiceImpl sessionManager;
|
private CIMSessionService memorySessionService;
|
||||||
|
|
||||||
public void process(CIMSession ios, SentBody message) {
|
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) {
|
if (account == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ios.removeAttribute(CIMConstant.SESSION_KEY);
|
CIMSession oldSession = memorySessionService.get(account.toString());
|
||||||
sessionManager.remove(account.toString());
|
|
||||||
|
if (oldSession == null || oldSession.isApnsOpend()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
oldSession.setState(CIMSession.STATE_DISABLED);
|
||||||
|
oldSession.setNid(null);
|
||||||
|
memorySessionService.save(oldSession);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -29,10 +29,9 @@ import org.springframework.beans.factory.annotation.Value;
|
|||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import com.farsunset.cim.sdk.server.model.Message;
|
import com.farsunset.cim.sdk.server.model.Message;
|
||||||
import com.farsunset.cim.sdk.server.session.CIMSession;
|
import com.farsunset.cim.sdk.server.model.CIMSession;
|
||||||
import com.farsunset.cim.sdk.server.session.DefaultSessionManager;
|
|
||||||
import com.farsunset.cim.service.ApnsService;
|
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;
|
private String host;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private DefaultSessionManager sessionManager;
|
private CIMSessionService memorySessionService;
|
||||||
|
|
||||||
@Resource
|
|
||||||
private MessageDispatcherImpl messageDispatcher;
|
|
||||||
|
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
@ -61,31 +58,39 @@ public class DefaultMessagePusher implements CIMMessagePusher {
|
|||||||
* @param msg
|
* @param msg
|
||||||
*/
|
*/
|
||||||
public void push(Message message) {
|
public void push(Message message) {
|
||||||
CIMSession session = sessionManager.get(message.getReceiver());
|
CIMSession session = memorySessionService.get(message.getReceiver());
|
||||||
|
|
||||||
/**
|
if(session == null) {
|
||||||
* 服务器集群时,可以在此 判断当前session是否连接于本台服务器,如果是,继续往下走,如果不是,将此消息发往当前session连接的服务器并
|
|
||||||
*/
|
|
||||||
if (session.isConnected() && !Objects.equals(host, session.getHost())) {
|
|
||||||
messageDispatcher.forward(message, session.getHost());
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* 如果是在当前服务器则直接推送
|
* IOS设备,如果开启了apns,则使用apns推送
|
||||||
*/
|
*/
|
||||||
if (session.isConnected() && Objects.equals(host, session.getHost())) {
|
if (session.isIOSChannel() && session.isApnsOpend()) {
|
||||||
session.write(message);
|
apnsService.push(message, session.getDeviceId());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* ios设备流程特别处理,如果长链接断开了,并且ApnsAble为打开状态的话优走apns
|
* 服务器集群时,判断当前session是否连接于本台服务器
|
||||||
|
* 如果连接到了其他服务器则转发请求到目标服务器
|
||||||
*/
|
*/
|
||||||
if (Objects.equals(session.getChannel(), CIMSession.CHANNEL_IOS) && Objects.equals(session.getApnsAble(), CIMSession.APNS_ON)) {
|
if (session.isConnected() && !Objects.equals(host, session.getHost())) {
|
||||||
apnsService.push(message, session.getDeviceId());
|
/**
|
||||||
|
* @TODO
|
||||||
|
* 在此调用目标服务器接口来发送
|
||||||
|
*/
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 如果是Android,浏览器或者windows客户端则直接发送
|
||||||
|
*/
|
||||||
|
if (session.isConnected() && Objects.equals(host, session.getHost())) {
|
||||||
|
session.write(message);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/**
|
/*
|
||||||
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
|
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -21,8 +21,23 @@
|
|||||||
*/
|
*/
|
||||||
package com.farsunset.cim.service;
|
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<CIMSession> list();
|
||||||
|
|
||||||
|
void remove(String account);
|
||||||
|
|
||||||
public interface MessageDispatcher {
|
|
||||||
void forward(final Message msg, final String ip);
|
|
||||||
}
|
}
|
@ -19,47 +19,54 @@
|
|||||||
* *
|
* *
|
||||||
***************************************************************************************
|
***************************************************************************************
|
||||||
*/
|
*/
|
||||||
package com.farsunset.cim.session;
|
package com.farsunset.cim.service.impl;
|
||||||
|
|
||||||
|
|
||||||
import java.util.List;
|
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管理 服务器集群时
|
* 集群情况下,数据库或者redis存储实现
|
||||||
* 须要将CIMSession 信息存入数据库或者nosql 等 第三方存储空间中,便于所有服务器都可以访问
|
* 自行实现存储管理
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
public class ClusterSessionManager implements SessionManager {
|
@Service("clusterSessionService")
|
||||||
|
public class ClusterSessionServiceImpl implements CIMSessionService {
|
||||||
|
|
||||||
public CIMSession get(String account) {
|
@Resource
|
||||||
|
private CIMNioSocketAcceptor nioSocketAcceptor;
|
||||||
// 这里查询数据库
|
|
||||||
/*
|
@Override
|
||||||
* CIMSession session = database.getSession(account);
|
public void save(CIMSession session) {
|
||||||
* session.setIoSession(ContextHolder.getBean(CIMNioSocketAcceptor.class).
|
|
||||||
* getManagedSessions().get(session.getNid())); return session;
|
|
||||||
*/
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<CIMSession> queryAll() {
|
public CIMSession get(String account) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CIMSession session = database.getSession(account);
|
||||||
|
* session.setIoSession(nioSocketAcceptor.getManagedSessions().get(session.getNid()));
|
||||||
|
* return session;
|
||||||
|
*/
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void remove(String account) {
|
public void remove(String account) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(CIMSession session) {
|
public List<CIMSession> list() {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void add(CIMSession arg0) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
@ -21,11 +21,45 @@
|
|||||||
*/
|
*/
|
||||||
package com.farsunset.cim.service.impl;
|
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 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<String, CIMSession> sessionMap = new ConcurrentHashMap<String, CIMSession>();
|
||||||
|
|
||||||
|
@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<CIMSession> list() {
|
||||||
|
List<CIMSession> onlineList = new ArrayList<>();
|
||||||
|
onlineList.addAll(sessionMap.values());
|
||||||
|
return onlineList;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
@ -3,11 +3,11 @@
|
|||||||
<classpathentry kind="src" path="src"/>
|
<classpathentry kind="src" path="src"/>
|
||||||
<classpathentry kind="lib" path="libs/mina-core-2.0.16.jar"/>
|
<classpathentry kind="lib" path="libs/mina-core-2.0.16.jar"/>
|
||||||
<classpathentry kind="lib" path="libs/slf4j-api-1.7.25.jar"/>
|
<classpathentry kind="lib" path="libs/slf4j-api-1.7.25.jar"/>
|
||||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6">
|
<classpathentry kind="lib" path="libs/protobuf-java-3.7.0.jar"/>
|
||||||
|
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
|
||||||
<attributes>
|
<attributes>
|
||||||
<attribute name="owner.project.facets" value="java"/>
|
<attribute name="owner.project.facets" value="java"/>
|
||||||
</attributes>
|
</attributes>
|
||||||
</classpathentry>
|
</classpathentry>
|
||||||
<classpathentry kind="lib" path="libs/protobuf-java-3.7.0.jar"/>
|
|
||||||
<classpathentry kind="output" path="bin"/>
|
<classpathentry kind="output" path="bin"/>
|
||||||
</classpath>
|
</classpath>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
eclipse.preferences.version=1
|
eclipse.preferences.version=1
|
||||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
|
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
|
||||||
org.eclipse.jdt.core.compiler.compliance=1.6
|
org.eclipse.jdt.core.compiler.compliance=1.8
|
||||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=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
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<faceted-project>
|
<faceted-project>
|
||||||
<fixed facet="java"/>
|
<fixed facet="java"/>
|
||||||
<installed facet="java" version="1.6"/>
|
<installed facet="java" version="1.8"/>
|
||||||
</faceted-project>
|
</faceted-project>
|
||||||
|
@ -40,9 +40,14 @@ public interface CIMConstant {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String SESSION_KEY = "account";
|
String KEY_ACCOUNT = "account";
|
||||||
String HEARTBEAT_KEY = "heartbeat";
|
|
||||||
|
|
||||||
|
String KEY_QUIETLY_CLOSE = "quietlyClose";
|
||||||
|
|
||||||
|
String CLIENT_WEBSOCKET_HANDSHAKE = "client_websocket_handshake";
|
||||||
|
|
||||||
|
String CLIENT_CONNECT_CLOSED = "client_closed";
|
||||||
|
|
||||||
public static interface ProtobufType {
|
public static interface ProtobufType {
|
||||||
byte S_H_RQ = 1;
|
byte S_H_RQ = 1;
|
||||||
byte C_H_RS = 0;
|
byte C_H_RS = 0;
|
||||||
|
@ -96,8 +96,8 @@ public class CIMLoggingFilter extends IoFilterAdapter {
|
|||||||
builder.append(" R:").append(session.getRemoteAddress().toString());
|
builder.append(" R:").append(session.getRemoteAddress().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (session.containsAttribute(CIMConstant.SESSION_KEY)) {
|
if (session.containsAttribute(CIMConstant.KEY_ACCOUNT)) {
|
||||||
builder.append(" account:").append(session.getAttribute(CIMConstant.SESSION_KEY));
|
builder.append(" account:").append(session.getAttribute(CIMConstant.KEY_ACCOUNT));
|
||||||
}
|
}
|
||||||
builder.append("]");
|
builder.append("]");
|
||||||
return builder.toString();
|
return builder.toString();
|
||||||
|
@ -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.constant.CIMConstant;
|
||||||
import com.farsunset.cim.sdk.server.model.HandshakerResponse;
|
import com.farsunset.cim.sdk.server.model.HandshakerResponse;
|
||||||
import com.farsunset.cim.sdk.server.model.feature.EncodeFormatable;
|
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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 服务端发送消息前编码
|
* 服务端发送消息前编码
|
||||||
|
@ -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.HeartbeatResponse;
|
||||||
import com.farsunset.cim.sdk.server.model.SentBody;
|
import com.farsunset.cim.sdk.server.model.SentBody;
|
||||||
import com.farsunset.cim.sdk.server.model.proto.SentBodyProto;
|
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发送的消息解码器
|
* 原生app发送的消息解码器
|
||||||
|
@ -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.MessageDecoderAdapter;
|
||||||
import org.apache.mina.filter.codec.demux.MessageDecoderResult;
|
import org.apache.mina.filter.codec.demux.MessageDecoderResult;
|
||||||
import com.farsunset.cim.sdk.server.constant.CIMConstant;
|
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.HeartbeatResponse;
|
||||||
import com.farsunset.cim.sdk.server.model.SentBody;
|
import com.farsunset.cim.sdk.server.model.SentBody;
|
||||||
import com.farsunset.cim.sdk.server.model.proto.SentBodyProto;
|
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;
|
import com.google.protobuf.InvalidProtocolBufferException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -203,7 +202,7 @@ public class WebMessageDecoder extends MessageDecoderAdapter {
|
|||||||
iosession.setAttribute(CIMSession.PROTOCOL,CIMSession.WEBSOCKET);
|
iosession.setAttribute(CIMSession.PROTOCOL,CIMSession.WEBSOCKET);
|
||||||
|
|
||||||
SentBody body = new SentBody();
|
SentBody body = new SentBody();
|
||||||
body.setKey(CIMNioSocketAcceptor.WEBSOCKET_HANDLER_KEY);
|
body.setKey(CIMConstant.CLIENT_WEBSOCKET_HANDSHAKE);
|
||||||
body.setTimestamp(System.currentTimeMillis());
|
body.setTimestamp(System.currentTimeMillis());
|
||||||
body.put("key", getSecWebSocketKey(message));
|
body.put("key", getSecWebSocketKey(message));
|
||||||
out.write(body);
|
out.write(body);
|
||||||
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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.net.InetSocketAddress;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
import org.apache.mina.core.service.IoAcceptor;
|
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.DefaultSocketSessionConfig;
|
||||||
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
|
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.CIMLoggingFilter;
|
||||||
import com.farsunset.cim.sdk.server.filter.ServerMessageCodecFactory;
|
import com.farsunset.cim.sdk.server.filter.ServerMessageCodecFactory;
|
||||||
import com.farsunset.cim.sdk.server.model.HeartbeatRequest;
|
import com.farsunset.cim.sdk.server.model.HeartbeatRequest;
|
||||||
import com.farsunset.cim.sdk.server.model.HeartbeatResponse;
|
import com.farsunset.cim.sdk.server.model.HeartbeatResponse;
|
||||||
import com.farsunset.cim.sdk.server.model.SentBody;
|
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 {
|
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<String, CIMRequestHandler> innerHandlerMap = new HashMap<String, CIMRequestHandler>();
|
private HashMap<String, CIMRequestHandler> innerHandlerMap = new HashMap<String, CIMRequestHandler>();
|
||||||
private CIMRequestHandler outerRequestHandler;
|
private CIMRequestHandler outerRequestHandler;
|
||||||
private IoAcceptor acceptor;
|
private IoAcceptor acceptor;
|
||||||
@ -69,7 +62,7 @@ public class CIMNioSocketAcceptor extends IoHandlerAdapter implements KeepAliveM
|
|||||||
/**
|
/**
|
||||||
* 预制websocket握手请求的处理
|
* 预制websocket握手请求的处理
|
||||||
*/
|
*/
|
||||||
innerHandlerMap.put(WEBSOCKET_HANDLER_KEY, new WebsocketHandler());
|
innerHandlerMap.put(CIMConstant.CLIENT_WEBSOCKET_HANDSHAKE, new WebsocketHandler());
|
||||||
|
|
||||||
acceptor = new NioSocketAcceptor();
|
acceptor = new NioSocketAcceptor();
|
||||||
acceptor.getSessionConfig().setReadBufferSize(READ_BUFFER_SIZE);
|
acceptor.getSessionConfig().setReadBufferSize(READ_BUFFER_SIZE);
|
||||||
@ -81,11 +74,16 @@ public class CIMNioSocketAcceptor extends IoHandlerAdapter implements KeepAliveM
|
|||||||
keepAliveFilter.setRequestTimeout(TIME_OUT);
|
keepAliveFilter.setRequestTimeout(TIME_OUT);
|
||||||
keepAliveFilter.setForwardEvent(true);
|
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("codec", new ProtocolCodecFilter(new ServerMessageCodecFactory()));
|
||||||
acceptor.getFilterChain().addLast("logger", new CIMLoggingFilter());
|
acceptor.getFilterChain().addLast("logger", new CIMLoggingFilter());
|
||||||
acceptor.getFilterChain().addLast("heartbeat", keepAliveFilter);
|
acceptor.getFilterChain().addLast("heartbeat", keepAliveFilter);
|
||||||
|
acceptor.getFilterChain().addLast("executor", new ExecutorFilter(executor));
|
||||||
acceptor.setHandler(this);
|
acceptor.setHandler(this);
|
||||||
|
|
||||||
acceptor.bind(new InetSocketAddress(port));
|
acceptor.bind(new InetSocketAddress(port));
|
||||||
@ -93,6 +91,7 @@ public class CIMNioSocketAcceptor extends IoHandlerAdapter implements KeepAliveM
|
|||||||
|
|
||||||
public void unbind() {
|
public void unbind() {
|
||||||
acceptor.unbind();
|
acceptor.unbind();
|
||||||
|
acceptor.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -126,13 +125,12 @@ public class CIMNioSocketAcceptor extends IoHandlerAdapter implements KeepAliveM
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sessionClosed(IoSession ios) {
|
public void sessionClosed(IoSession ios) {
|
||||||
|
|
||||||
CIMSession session = new CIMSession(ios);
|
CIMSession session = new CIMSession(ios);
|
||||||
SentBody body = new SentBody();
|
SentBody body = new SentBody();
|
||||||
body.setKey(CIMSESSION_CLOSED_HANDLER_KEY);
|
body.setKey(CIMConstant.CLIENT_CONNECT_CLOSED);
|
||||||
outerRequestHandler.process(session, body);
|
outerRequestHandler.process(session, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getRequest(IoSession session) {
|
public Object getRequest(IoSession session) {
|
||||||
|
@ -26,7 +26,7 @@ package com.farsunset.cim.sdk.server.handler;
|
|||||||
* @author 3979434@qq.com
|
* @author 3979434@qq.com
|
||||||
*/
|
*/
|
||||||
import com.farsunset.cim.sdk.server.model.SentBody;
|
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 {
|
public interface CIMRequestHandler {
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ import java.security.MessageDigest;
|
|||||||
|
|
||||||
import com.farsunset.cim.sdk.server.model.SentBody;
|
import com.farsunset.cim.sdk.server.model.SentBody;
|
||||||
import com.farsunset.cim.sdk.server.model.HandshakerResponse;
|
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握手请求,返回响应的报文给浏览器
|
* 处理websocket握手请求,返回响应的报文给浏览器
|
||||||
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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.io.Serializable;
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
import java.net.UnknownHostException;
|
import java.util.Objects;
|
||||||
|
|
||||||
import org.apache.mina.core.future.WriteFuture;
|
import org.apache.mina.core.future.WriteFuture;
|
||||||
import org.apache.mina.core.session.IoSession;
|
import org.apache.mina.core.session.IoSession;
|
||||||
|
|
||||||
import com.farsunset.cim.sdk.server.constant.CIMConstant;
|
import com.farsunset.cim.sdk.server.constant.CIMConstant;
|
||||||
|
import com.farsunset.cim.sdk.server.model.proto.SessionProto;
|
||||||
|
import com.google.protobuf.InvalidProtocolBufferException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IoSession包装类,集群时 将此对象存入表中
|
* IoSession包装类,集群时 将此对象存入表中
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class CIMSession implements Serializable {
|
public class CIMSession implements Serializable {
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
private transient static final long serialVersionUID = 1L;
|
private transient static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
public transient static String PROTOCOL = "protocol";
|
public transient static String PROTOCOL = "protocol";
|
||||||
public transient static String WEBSOCKET = "websocket";
|
public transient static String WEBSOCKET = "websocket";
|
||||||
public transient static String NATIVEAPP = "nativeapp";
|
public transient static String NATIVEAPP = "nativeapp";
|
||||||
|
|
||||||
public transient static final int STATUS_ENABLED = 0;
|
public transient static String HOST = "HOST";
|
||||||
public transient static final int STATUS_DISABLED = 1;
|
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_ON = 1;
|
||||||
public transient static final int APNS_OFF = 0;
|
public transient static final int APNS_OFF = 0;
|
||||||
|
|
||||||
@ -59,22 +57,19 @@ public class CIMSession implements Serializable {
|
|||||||
|
|
||||||
private transient IoSession session;
|
private transient IoSession session;
|
||||||
|
|
||||||
private String gid;// session全局ID
|
private String account;// session绑定的账号,主键,一个账号同一时间之内在一个设备在线
|
||||||
private Long nid;// session在本台服务器上的ID
|
private Long nid;// session在本台服务器上的ID
|
||||||
private String deviceId;// 客户端ID (设备号码+应用包名),ios为devicetoken
|
private String deviceId;// 客户端ID (设备号码+应用包名),ios为devicetoken
|
||||||
private String host;// session绑定的服务器IP
|
private String host;// session绑定的服务器IP
|
||||||
private String account;// session绑定的账号
|
|
||||||
private String channel;// 终端设备类型
|
private String channel;// 终端设备类型
|
||||||
private String deviceModel;// 终端设备型号
|
private String deviceModel;// 终端设备型号
|
||||||
private String clientVersion;// 终端应用版本
|
private String clientVersion;// 终端应用版本
|
||||||
private String systemVersion;// 终端系统版本
|
private String systemVersion;// 终端系统版本
|
||||||
private String packageName;// 终端应用包名
|
|
||||||
private Long bindTime;// 登录时间
|
private Long bindTime;// 登录时间
|
||||||
private Long heartbeat;// 心跳时间
|
|
||||||
private Double longitude;// 经度
|
private Double longitude;// 经度
|
||||||
private Double latitude;// 维度
|
private Double latitude;// 维度
|
||||||
private String location;// 位置
|
private String location;// 位置
|
||||||
private int apnsAble;// apns推送状态
|
private int apns;// apns推送状态
|
||||||
private int state;// 状态
|
private int state;// 状态
|
||||||
|
|
||||||
public CIMSession(IoSession session) {
|
public CIMSession(IoSession session) {
|
||||||
@ -93,7 +88,7 @@ public class CIMSession implements Serializable {
|
|||||||
public void setAccount(String account) {
|
public void setAccount(String account) {
|
||||||
this.account = account;
|
this.account = account;
|
||||||
|
|
||||||
setAttribute(CIMConstant.SESSION_KEY, account);
|
setAttribute(CIMConstant.KEY_ACCOUNT, account);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Double getLongitude() {
|
public Double getLongitude() {
|
||||||
@ -120,17 +115,6 @@ public class CIMSession implements Serializable {
|
|||||||
this.location = location;
|
this.location = location;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getGid() {
|
|
||||||
return gid;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setGid(String gid) {
|
|
||||||
|
|
||||||
this.gid = gid;
|
|
||||||
|
|
||||||
setAttribute("gid", gid);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Long getNid() {
|
public Long getNid() {
|
||||||
return nid;
|
return nid;
|
||||||
}
|
}
|
||||||
@ -161,7 +145,6 @@ public class CIMSession implements Serializable {
|
|||||||
|
|
||||||
public void setDeviceId(String deviceId) {
|
public void setDeviceId(String deviceId) {
|
||||||
this.deviceId = deviceId;
|
this.deviceId = deviceId;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getHost() {
|
public String getHost() {
|
||||||
@ -192,25 +175,16 @@ public class CIMSession implements Serializable {
|
|||||||
this.systemVersion = systemVersion;
|
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) {
|
public void setHost(String host) {
|
||||||
this.host = host;
|
this.host = host;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getApnsAble() {
|
public int getApns() {
|
||||||
return apnsAble;
|
return apns;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setApnsAble(int apnsAble) {
|
public void setApns(int apns) {
|
||||||
this.apnsAble = apnsAble;
|
this.apns = apns;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getState() {
|
public int getState() {
|
||||||
@ -260,27 +234,7 @@ public class CIMSession implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isConnected() {
|
public boolean isConnected() {
|
||||||
if (session != null) {
|
return (session != null && session.isConnected()) || state == STATE_ENABLED;
|
||||||
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;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void closeNow() {
|
public void closeNow() {
|
||||||
@ -293,70 +247,111 @@ public class CIMSession implements Serializable {
|
|||||||
session.closeOnFlush();
|
session.closeOnFlush();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPackageName(String packageName) {
|
public boolean isIOSChannel() {
|
||||||
this.packageName = packageName;
|
return Objects.equals(channel, CHANNEL_IOS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getPackageName() {
|
public boolean isAndroidChannel() {
|
||||||
return packageName;
|
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() {
|
public int hashCode() {
|
||||||
|
return getClass().hashCode();
|
||||||
return (deviceId + nid + host).hashCode();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
|
|
||||||
if (o instanceof CIMSession) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean fromOtherDevice(Object o) {
|
public IoSession getSession() {
|
||||||
|
|
||||||
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() {
|
|
||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
public void setSession(IoSession session) {
|
||||||
StringBuffer buffer = new StringBuffer();
|
this.session = session;
|
||||||
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 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
@ -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;
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@ -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<String, CIMSession> sessions = new HashMap<String, CIMSession>();
|
|
||||||
|
|
||||||
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<CIMSession> queryAll() {
|
|
||||||
List<CIMSession> list = new ArrayList<CIMSession>();
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -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<CIMSession> queryAll();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除session
|
|
||||||
*
|
|
||||||
* @param session
|
|
||||||
*/
|
|
||||||
public void remove(String account);
|
|
||||||
|
|
||||||
}
|
|
Binary file not shown.
@ -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.CIMNioSocketAcceptor;
|
||||||
import com.farsunset.cim.sdk.server.handler.CIMRequestHandler;
|
import com.farsunset.cim.sdk.server.handler.CIMRequestHandler;
|
||||||
import com.farsunset.cim.sdk.server.model.SentBody;
|
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
|
@Configuration
|
||||||
public class CIMConfig implements CIMRequestHandler {
|
public class CIMConfig implements CIMRequestHandler {
|
||||||
@ -28,7 +28,7 @@ public class CIMConfig implements CIMRequestHandler {
|
|||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private SessionClosedHandler closedHandler;
|
private SessionClosedHandler closedHandler;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private ApplicationContext applicationContext;
|
private ApplicationContext applicationContext;
|
||||||
|
|
||||||
@ -55,7 +55,6 @@ public class CIMConfig implements CIMRequestHandler {
|
|||||||
return nioSocketAcceptor;
|
return nioSocketAcceptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void process(CIMSession session, SentBody body) {
|
public void process(CIMSession session, SentBody body) {
|
||||||
|
|
||||||
@ -75,6 +74,5 @@ public class CIMConfig implements CIMRequestHandler {
|
|||||||
return applicationContext.getBean(handlerClass);
|
return applicationContext.getBean(handlerClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
@ -27,17 +27,18 @@ import org.springframework.stereotype.Controller;
|
|||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
|
||||||
import com.farsunset.cim.service.impl.CIMSessionServiceImpl;
|
import com.farsunset.cim.service.CIMSessionService;
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
@RequestMapping("/console/session")
|
@RequestMapping("/console/session")
|
||||||
public class SessionController {
|
public class SessionController {
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private CIMSessionServiceImpl sessionManager;
|
private CIMSessionService memorySessionService;
|
||||||
|
|
||||||
@RequestMapping(value = "/list.action")
|
@RequestMapping(value = "/list.action")
|
||||||
public String list(Model model) {
|
public String list(Model model) {
|
||||||
model.addAttribute("sessionList", sessionManager.queryAll());
|
model.addAttribute("sessionList", memorySessionService.list());
|
||||||
return "console/session/manage";
|
return "console/session/manage";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,6 @@ import com.farsunset.cim.push.DefaultMessagePusher;
|
|||||||
import com.farsunset.cim.push.SystemMessagePusher;
|
import com.farsunset.cim.push.SystemMessagePusher;
|
||||||
import com.farsunset.cim.sdk.server.model.Message;
|
import com.farsunset.cim.sdk.server.model.Message;
|
||||||
import com.farsunset.cim.util.Constants;
|
import com.farsunset.cim.util.Constants;
|
||||||
import com.farsunset.cim.util.StringUtil;
|
|
||||||
|
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
|
@ -30,14 +30,14 @@ import org.slf4j.LoggerFactory;
|
|||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Component;
|
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.constant.CIMConstant;
|
||||||
import com.farsunset.cim.sdk.server.handler.CIMRequestHandler;
|
import com.farsunset.cim.sdk.server.handler.CIMRequestHandler;
|
||||||
import com.farsunset.cim.sdk.server.model.Message;
|
import com.farsunset.cim.sdk.server.model.Message;
|
||||||
import com.farsunset.cim.sdk.server.model.ReplyBody;
|
import com.farsunset.cim.sdk.server.model.ReplyBody;
|
||||||
import com.farsunset.cim.sdk.server.model.SentBody;
|
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 com.farsunset.cim.service.impl.CIMSessionServiceImpl;
|
import com.farsunset.cim.service.CIMSessionService;
|
||||||
import com.farsunset.cim.util.StringUtil;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -51,59 +51,57 @@ public class BindHandler implements CIMRequestHandler {
|
|||||||
protected final Logger logger = LoggerFactory.getLogger(BindHandler.class);
|
protected final Logger logger = LoggerFactory.getLogger(BindHandler.class);
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private CIMSessionServiceImpl sessionManager;
|
private CIMSessionService memorySessionService;
|
||||||
|
|
||||||
@Value("${server.host}")
|
@Value("${server.host}")
|
||||||
private String 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();
|
ReplyBody reply = new ReplyBody();
|
||||||
reply.setKey(message.getKey());
|
reply.setKey(body.getKey());
|
||||||
reply.setCode(CIMConstant.ReturnCode.CODE_200);
|
reply.setCode(CIMConstant.ReturnCode.CODE_200);
|
||||||
|
reply.setTimestamp(System.currentTimeMillis());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
String account = message.get("account");
|
String account = body.get("account");
|
||||||
newSession.setGid(StringUtil.getUUID());
|
|
||||||
newSession.setAccount(account);
|
newSession.setAccount(account);
|
||||||
newSession.setDeviceId(message.get("deviceId"));
|
newSession.setDeviceId(body.get("deviceId"));
|
||||||
newSession.setHost(host);
|
newSession.setHost(host);
|
||||||
newSession.setChannel(message.get("channel"));
|
newSession.setChannel(body.get("channel"));
|
||||||
newSession.setDeviceModel(message.get("device"));
|
newSession.setDeviceModel(body.get("device"));
|
||||||
newSession.setClientVersion(message.get("version"));
|
newSession.setClientVersion(body.get("version"));
|
||||||
newSession.setSystemVersion(message.get("osVersion"));
|
newSession.setSystemVersion(body.get("osVersion"));
|
||||||
newSession.setBindTime(System.currentTimeMillis());
|
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()) {
|
if (oldSession != null && fromOtherDevice(newSession,oldSession) && oldSession.isConnected()) {
|
||||||
sendForceOfflineMessage(oldSession, account, newSession.getDeviceModel());
|
sendForceOfflineMessage(oldSession, account, newSession.getDeviceModel());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
/**
|
|
||||||
* 有可能是同一个设备重复连接,则关闭旧的链接,这种情况一般是客户端断网,联网又重新链接上来,之前的旧链接没有来得及通过心跳机制关闭,在这里手动关闭
|
* 有可能是同一个设备重复连接,则关闭旧的链接,这种情况一般是客户端断网,联网又重新链接上来,之前的旧链接没有来得及通过心跳机制关闭,在这里手动关闭
|
||||||
* 条件1,连接来自是同一个设备
|
* 条件1,连接来自是同一个设备
|
||||||
* 条件2.2个连接都是同一台服务器
|
* 条件2.2个连接都是同一台服务器
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (oldSession != null && !fromOtherDevice(newSession,oldSession) && Objects.equals(oldSession.getHost(),host)) {
|
if (oldSession != null && !fromOtherDevice(newSession,oldSession) && Objects.equals(oldSession.getHost(),host)) {
|
||||||
oldSession.removeAttribute(CIMConstant.SESSION_KEY);
|
closeQuietly(oldSession);
|
||||||
oldSession.closeNow();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 第一次设置心跳时间为登录时间
|
memorySessionService.save(newSession);
|
||||||
newSession.setBindTime(System.currentTimeMillis());
|
|
||||||
newSession.setHeartbeat(System.currentTimeMillis());
|
|
||||||
|
|
||||||
sessionManager.add(newSession);
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
reply.setCode(CIMConstant.ReturnCode.CODE_500);
|
reply.setCode(CIMConstant.ReturnCode.CODE_500);
|
||||||
@ -126,16 +124,18 @@ public class BindHandler implements CIMRequestHandler {
|
|||||||
msg.setSender("system");
|
msg.setSender("system");
|
||||||
msg.setContent(deviceModel);
|
msg.setContent(deviceModel);
|
||||||
msg.setId(System.currentTimeMillis());
|
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())) {
|
if (oldSession.isConnected() && Objects.equals(host, oldSession.getHost())) {
|
||||||
oldSession.write(msg);
|
oldSession.setAttribute(CIMConstant.KEY_QUIETLY_CLOSE,true);
|
||||||
oldSession.removeAttribute(CIMConstant.SESSION_KEY);
|
oldSession.closeOnFlush();
|
||||||
oldSession.closeNow();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +22,8 @@
|
|||||||
package com.farsunset.cim.handler;
|
package com.farsunset.cim.handler;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
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.constant.CIMConstant;
|
||||||
import com.farsunset.cim.sdk.server.handler.CIMRequestHandler;
|
import com.farsunset.cim.sdk.server.handler.CIMRequestHandler;
|
||||||
import com.farsunset.cim.sdk.server.model.SentBody;
|
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 com.farsunset.cim.service.impl.CIMSessionServiceImpl;
|
import com.farsunset.cim.service.CIMSessionService;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -46,17 +48,28 @@ public class SessionClosedHandler implements CIMRequestHandler {
|
|||||||
protected final Logger logger = LoggerFactory.getLogger(SessionClosedHandler.class);
|
protected final Logger logger = LoggerFactory.getLogger(SessionClosedHandler.class);
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private CIMSessionServiceImpl sessionManager;
|
private CIMSessionService memorySessionService;
|
||||||
|
|
||||||
public void process(CIMSession ios, SentBody message) {
|
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) {
|
if (account == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ios.removeAttribute(CIMConstant.SESSION_KEY);
|
CIMSession oldSession = memorySessionService.get(account.toString());
|
||||||
sessionManager.remove(account.toString());
|
|
||||||
|
if (oldSession == null || oldSession.isApnsOpend()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
oldSession.setState(CIMSession.STATE_DISABLED);
|
||||||
|
oldSession.setNid(null);
|
||||||
|
memorySessionService.save(oldSession);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -29,10 +29,9 @@ import org.springframework.beans.factory.annotation.Value;
|
|||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import com.farsunset.cim.sdk.server.model.Message;
|
import com.farsunset.cim.sdk.server.model.Message;
|
||||||
import com.farsunset.cim.sdk.server.session.CIMSession;
|
import com.farsunset.cim.sdk.server.model.CIMSession;
|
||||||
import com.farsunset.cim.sdk.server.session.DefaultSessionManager;
|
|
||||||
import com.farsunset.cim.service.ApnsService;
|
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;
|
private String host;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private DefaultSessionManager sessionManager;
|
private CIMSessionService memorySessionService;
|
||||||
|
|
||||||
@Resource
|
|
||||||
private MessageDispatcherImpl messageDispatcher;
|
|
||||||
|
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
@ -61,31 +58,39 @@ public class DefaultMessagePusher implements CIMMessagePusher {
|
|||||||
* @param msg
|
* @param msg
|
||||||
*/
|
*/
|
||||||
public void push(Message message) {
|
public void push(Message message) {
|
||||||
CIMSession session = sessionManager.get(message.getReceiver());
|
CIMSession session = memorySessionService.get(message.getReceiver());
|
||||||
|
|
||||||
/**
|
if(session == null) {
|
||||||
* 服务器集群时,可以在此 判断当前session是否连接于本台服务器,如果是,继续往下走,如果不是,将此消息发往当前session连接的服务器并
|
|
||||||
*/
|
|
||||||
if (session.isConnected() && !Objects.equals(host, session.getHost())) {
|
|
||||||
messageDispatcher.forward(message, session.getHost());
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* 如果是在当前服务器则直接推送
|
* IOS设备,如果开启了apns,则使用apns推送
|
||||||
*/
|
*/
|
||||||
if (session.isConnected() && Objects.equals(host, session.getHost())) {
|
if (session.isIOSChannel() && session.isApnsOpend()) {
|
||||||
session.write(message);
|
apnsService.push(message, session.getDeviceId());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* ios设备流程特别处理,如果长链接断开了,并且ApnsAble为打开状态的话优走apns
|
* 服务器集群时,判断当前session是否连接于本台服务器
|
||||||
|
* 如果连接到了其他服务器则转发请求到目标服务器
|
||||||
*/
|
*/
|
||||||
if (Objects.equals(session.getChannel(), CIMSession.CHANNEL_IOS) && Objects.equals(session.getApnsAble(), CIMSession.APNS_ON)) {
|
if (session.isConnected() && !Objects.equals(host, session.getHost())) {
|
||||||
apnsService.push(message, session.getDeviceId());
|
/**
|
||||||
|
* @TODO
|
||||||
|
* 在此调用目标服务器接口来发送
|
||||||
|
*/
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 如果是Android,浏览器或者windows客户端则直接发送
|
||||||
|
*/
|
||||||
|
if (session.isConnected() && Objects.equals(host, session.getHost())) {
|
||||||
|
session.write(message);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/**
|
/*
|
||||||
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
|
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -21,8 +21,23 @@
|
|||||||
*/
|
*/
|
||||||
package com.farsunset.cim.service;
|
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<CIMSession> list();
|
||||||
|
|
||||||
|
void remove(String account);
|
||||||
|
|
||||||
public interface MessageDispatcher {
|
|
||||||
void forward(final Message msg, final String ip);
|
|
||||||
}
|
}
|
@ -19,47 +19,54 @@
|
|||||||
* *
|
* *
|
||||||
***************************************************************************************
|
***************************************************************************************
|
||||||
*/
|
*/
|
||||||
package com.farsunset.cim.session;
|
package com.farsunset.cim.service.impl;
|
||||||
|
|
||||||
|
|
||||||
import java.util.List;
|
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管理 服务器集群时
|
* 集群情况下,数据库或者redis存储实现
|
||||||
* 须要将CIMSession 信息存入数据库或者nosql 等 第三方存储空间中,便于所有服务器都可以访问
|
* 自行实现存储管理
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
public class ClusterSessionManager implements SessionManager {
|
@Service("clusterSessionService")
|
||||||
|
public class ClusterSessionServiceImpl implements CIMSessionService {
|
||||||
|
|
||||||
public CIMSession get(String account) {
|
@Resource
|
||||||
|
private CIMNioSocketAcceptor nioSocketAcceptor;
|
||||||
// 这里查询数据库
|
|
||||||
/*
|
@Override
|
||||||
* CIMSession session = database.getSession(account);
|
public void save(CIMSession session) {
|
||||||
* session.setIoSession(ContextHolder.getBean(CIMNioSocketAcceptor.class).
|
|
||||||
* getManagedSessions().get(session.getNid())); return session;
|
|
||||||
*/
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<CIMSession> queryAll() {
|
public CIMSession get(String account) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CIMSession session = database.getSession(account);
|
||||||
|
* session.setIoSession(nioSocketAcceptor.getManagedChannel().get(session.getNid()));
|
||||||
|
* return session;
|
||||||
|
*/
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void remove(String account) {
|
public void remove(String account) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(CIMSession session) {
|
public List<CIMSession> list() {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void add(CIMSession arg0) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
@ -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<String, CIMSession> sessionMap = new ConcurrentHashMap<String, CIMSession>();
|
||||||
|
|
||||||
|
@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<CIMSession> list() {
|
||||||
|
List<CIMSession> onlineList = new ArrayList<>();
|
||||||
|
onlineList.addAll(sessionMap.values());
|
||||||
|
return onlineList;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
@ -25,6 +25,8 @@ package com.farsunset.cim.sdk.server.constant;
|
|||||||
* 常量
|
* 常量
|
||||||
*/
|
*/
|
||||||
public interface CIMConstant {
|
public interface CIMConstant {
|
||||||
|
// 消息头长度为3个字节,第一个字节为消息类型,第二,第三字节 转换int后为消息长度
|
||||||
|
int DATA_HEADER_LENGTH = 3;
|
||||||
|
|
||||||
public static interface ReturnCode {
|
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 HEARTBEAT_KEY = "heartbeat";
|
||||||
|
|
||||||
|
|
||||||
|
String CLIENT_WEBSOCKET_HANDSHAKE = "client_websocket_handshake";
|
||||||
|
|
||||||
String CLIENT_HEARTBEAT = "client_heartbeat";
|
String CLIENT_HEARTBEAT = "client_heartbeat";
|
||||||
|
|
||||||
// 消息头长度为3个字节,第一个字节为消息类型,第二,第三字节 转换int后为消息长度
|
String CLIENT_CONNECT_CLOSED = "client_closed";
|
||||||
int DATA_HEADER_LENGTH = 3;
|
|
||||||
// WEBSOCKET消息头长度为2个字节
|
|
||||||
int WS_DATA_HEADER_LENGTH = 2;
|
|
||||||
|
|
||||||
public static interface ProtobufType {
|
public static interface ProtobufType {
|
||||||
byte C_H_RS = 0;
|
|
||||||
byte S_H_RQ = 1;
|
byte S_H_RQ = 1;
|
||||||
|
byte C_H_RS = 0;
|
||||||
byte MESSAGE = 2;
|
byte MESSAGE = 2;
|
||||||
byte SENTBODY = 3;
|
byte SENTBODY = 3;
|
||||||
byte REPLYBODY = 4;
|
byte REPLYBODY = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static interface MessageAction {
|
public static interface MessageAction {
|
||||||
|
|
||||||
// 被其他设备登录挤下线消息
|
// 被其他设备登录挤下线消息
|
||||||
String ACTION_999 = "999";
|
String ACTION_999 = "999";
|
||||||
// 被系统禁用消息
|
|
||||||
String ACTION_444 = "444";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -26,11 +26,11 @@ import java.util.Objects;
|
|||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
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.AppMessageDecoder;
|
||||||
import com.farsunset.cim.sdk.server.filter.decoder.WebMessageDecoder;
|
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.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.buffer.ByteBuf;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
@ -95,7 +95,7 @@ public class ServerMessageDecoder extends ByteToMessageDecoder {
|
|||||||
arg0.channel().attr(AttributeKey.valueOf(CIMSession.PROTOCOL)).set(CIMSession.WEBSOCKET);
|
arg0.channel().attr(AttributeKey.valueOf(CIMSession.PROTOCOL)).set(CIMSession.WEBSOCKET);
|
||||||
|
|
||||||
SentBody body = new SentBody();
|
SentBody body = new SentBody();
|
||||||
body.setKey(CIMNioSocketAcceptor.WEBSOCKET_HANDLER_KEY);
|
body.setKey(CIMConstant.CLIENT_WEBSOCKET_HANDSHAKE);
|
||||||
body.setTimestamp(System.currentTimeMillis());
|
body.setTimestamp(System.currentTimeMillis());
|
||||||
body.put("key", secKey);
|
body.put("key", secKey);
|
||||||
queue.add(body);
|
queue.add(body);
|
||||||
|
@ -26,7 +26,7 @@ import java.util.Objects;
|
|||||||
import com.farsunset.cim.sdk.server.constant.CIMConstant;
|
import com.farsunset.cim.sdk.server.constant.CIMConstant;
|
||||||
import com.farsunset.cim.sdk.server.model.HandshakerResponse;
|
import com.farsunset.cim.sdk.server.model.HandshakerResponse;
|
||||||
import com.farsunset.cim.sdk.server.model.feature.EncodeFormatable;
|
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.buffer.ByteBuf;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
@ -26,7 +26,7 @@ import java.util.List;
|
|||||||
import com.farsunset.cim.sdk.server.constant.CIMConstant;
|
import com.farsunset.cim.sdk.server.constant.CIMConstant;
|
||||||
import com.farsunset.cim.sdk.server.model.SentBody;
|
import com.farsunset.cim.sdk.server.model.SentBody;
|
||||||
import com.farsunset.cim.sdk.server.model.proto.SentBodyProto;
|
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.buffer.ByteBuf;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
@ -21,11 +21,9 @@
|
|||||||
*/
|
*/
|
||||||
package com.farsunset.cim.sdk.server.filter.decoder;
|
package com.farsunset.cim.sdk.server.filter.decoder;
|
||||||
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import com.farsunset.cim.sdk.server.constant.CIMConstant;
|
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.SentBody;
|
||||||
import com.farsunset.cim.sdk.server.model.proto.SentBodyProto;
|
import com.farsunset.cim.sdk.server.model.proto.SentBodyProto;
|
||||||
import com.google.protobuf.InvalidProtocolBufferException;
|
import com.google.protobuf.InvalidProtocolBufferException;
|
||||||
@ -124,8 +122,10 @@ public class WebMessageDecoder extends ByteToMessageDecoder {
|
|||||||
* 只处理心跳响应以及,sentbody消息
|
* 只处理心跳响应以及,sentbody消息
|
||||||
*/
|
*/
|
||||||
if (type == CIMConstant.ProtobufType.C_H_RS) {
|
if (type == CIMConstant.ProtobufType.C_H_RS) {
|
||||||
HeartbeatResponse response = HeartbeatResponse.getInstance();
|
SentBody body = new SentBody();
|
||||||
queue.add(response);
|
body.setKey(CIMConstant.CLIENT_HEARTBEAT);
|
||||||
|
body.setTimestamp(System.currentTimeMillis());
|
||||||
|
queue.add(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == CIMConstant.ProtobufType.SENTBODY) {
|
if (type == CIMConstant.ProtobufType.SENTBODY) {
|
||||||
|
@ -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.filter.ServerMessageEncoder;
|
||||||
import com.farsunset.cim.sdk.server.model.HeartbeatRequest;
|
import com.farsunset.cim.sdk.server.model.HeartbeatRequest;
|
||||||
import com.farsunset.cim.sdk.server.model.SentBody;
|
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.bootstrap.ServerBootstrap;
|
||||||
import io.netty.channel.Channel;
|
import io.netty.channel.Channel;
|
||||||
@ -54,14 +54,6 @@ import io.netty.util.AttributeKey;
|
|||||||
@Sharable
|
@Sharable
|
||||||
public class CIMNioSocketAcceptor extends SimpleChannelInboundHandler<SentBody> {
|
public class CIMNioSocketAcceptor extends SimpleChannelInboundHandler<SentBody> {
|
||||||
|
|
||||||
/**
|
|
||||||
* 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<String, CIMRequestHandler> innerHandlerMap = new HashMap<String, CIMRequestHandler>();
|
private HashMap<String, CIMRequestHandler> innerHandlerMap = new HashMap<String, CIMRequestHandler>();
|
||||||
private CIMRequestHandler outerRequestHandler;
|
private CIMRequestHandler outerRequestHandler;
|
||||||
@ -81,8 +73,9 @@ public class CIMNioSocketAcceptor extends SimpleChannelInboundHandler<SentBody>
|
|||||||
/**
|
/**
|
||||||
* 预制websocket握手请求的处理
|
* 预制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();
|
ServerBootstrap bootstrap = new ServerBootstrap();
|
||||||
EventLoopGroup bossGroup = new NioEventLoopGroup();
|
EventLoopGroup bossGroup = new NioEventLoopGroup();
|
||||||
EventLoopGroup workerGroup = new NioEventLoopGroup();
|
EventLoopGroup workerGroup = new NioEventLoopGroup();
|
||||||
@ -123,7 +116,7 @@ public class CIMNioSocketAcceptor extends SimpleChannelInboundHandler<SentBody>
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void channelRead0(ChannelHandlerContext ctx, SentBody body) throws Exception {
|
protected void channelRead0(ChannelHandlerContext ctx, SentBody body) {
|
||||||
|
|
||||||
CIMSession session = new CIMSession(ctx.channel());
|
CIMSession session = new CIMSession(ctx.channel());
|
||||||
|
|
||||||
@ -148,7 +141,7 @@ public class CIMNioSocketAcceptor extends SimpleChannelInboundHandler<SentBody>
|
|||||||
|
|
||||||
CIMSession session = new CIMSession(ctx.channel());
|
CIMSession session = new CIMSession(ctx.channel());
|
||||||
SentBody body = new SentBody();
|
SentBody body = new SentBody();
|
||||||
body.setKey(CIMSESSION_CLOSED_HANDLER_KEY);
|
body.setKey(CIMConstant.CLIENT_CONNECT_CLOSED);
|
||||||
outerRequestHandler.process(session, body);
|
outerRequestHandler.process(session, body);
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -188,4 +181,5 @@ public class CIMNioSocketAcceptor extends SimpleChannelInboundHandler<SentBody>
|
|||||||
}
|
}
|
||||||
return channelGroup.get(id);
|
return channelGroup.get(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ package com.farsunset.cim.sdk.server.handler;
|
|||||||
* @author 3979434@qq.com
|
* @author 3979434@qq.com
|
||||||
*/
|
*/
|
||||||
import com.farsunset.cim.sdk.server.model.SentBody;
|
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 {
|
public interface CIMRequestHandler {
|
||||||
|
|
||||||
|
@ -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) {}
|
||||||
}
|
}
|
@ -26,12 +26,10 @@ import java.util.Base64;
|
|||||||
|
|
||||||
import com.farsunset.cim.sdk.server.model.HandshakerResponse;
|
import com.farsunset.cim.sdk.server.model.HandshakerResponse;
|
||||||
import com.farsunset.cim.sdk.server.model.SentBody;
|
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握手请求,返回响应的报文给浏览器
|
* 处理websocket握手请求,返回响应的报文给浏览器
|
||||||
*
|
|
||||||
* @author Iraid
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class WebsocketHandler implements CIMRequestHandler {
|
public class WebsocketHandler implements CIMRequestHandler {
|
||||||
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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.io.Serializable;
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.SocketAddress;
|
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.constant.CIMConstant;
|
||||||
|
import com.farsunset.cim.sdk.server.model.proto.SessionProto;
|
||||||
|
import com.google.protobuf.InvalidProtocolBufferException;
|
||||||
|
|
||||||
import io.netty.channel.Channel;
|
import io.netty.channel.Channel;
|
||||||
import io.netty.util.AttributeKey;
|
import io.netty.util.AttributeKey;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Channel包装类,集群时 将此对象存入表中
|
* IoSession包装类,集群时 将此对象存入表中
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class CIMSession implements Serializable {
|
public class CIMSession implements Serializable {
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
private transient static final long serialVersionUID = 1L;
|
private transient static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
public transient static String PROTOCOL = "protocol";
|
public transient static String PROTOCOL = "protocol";
|
||||||
public transient static String WEBSOCKET = "websocket";
|
public transient static String WEBSOCKET = "websocket";
|
||||||
public transient static String NATIVEAPP = "nativeapp";
|
public transient static String NATIVEAPP = "nativeapp";
|
||||||
|
|
||||||
public transient static final int STATUS_ENABLED = 0;
|
public transient static String HOST = "HOST";
|
||||||
public transient static final int STATUS_DISABLED = 1;
|
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_ON = 1;
|
||||||
public transient static final int APNS_OFF = 0;
|
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_WINDOWS = "windows";
|
||||||
public transient static String CHANNEL_WP = "wp";
|
public transient static String CHANNEL_WP = "wp";
|
||||||
public transient static String CHANNEL_BROWSER = "browser";
|
public transient static String CHANNEL_BROWSER = "browser";
|
||||||
|
|
||||||
private transient Channel session;
|
private transient Channel session;
|
||||||
|
|
||||||
private String gid;// session全局ID
|
private String account;// session绑定的账号,主键,一个账号同一时间之内在一个设备在线
|
||||||
private String nid;// session在本台服务器上的ID
|
private String nid;// session在本台服务器上的ID
|
||||||
private String deviceId;// 客户端ID (设备号码+应用包名),ios为devicetoken
|
private String deviceId;// 客户端ID (设备号码+应用包名),ios为devicetoken
|
||||||
private String host;// session绑定的服务器IP
|
private String host;// session绑定的服务器IP
|
||||||
private String account;// session绑定的账号
|
|
||||||
private String channel;// 终端设备类型
|
private String channel;// 终端设备类型
|
||||||
private String deviceModel;// 终端设备型号
|
private String deviceModel;// 终端设备型号
|
||||||
private String clientVersion;// 终端应用版本
|
private String clientVersion;// 终端应用版本
|
||||||
private String systemVersion;// 终端系统版本
|
private String systemVersion;// 终端系统版本
|
||||||
private String packageName;// 终端应用包名
|
|
||||||
private Long bindTime;// 登录时间
|
private Long bindTime;// 登录时间
|
||||||
private Long heartbeat;// 心跳时间
|
|
||||||
private Double longitude;// 经度
|
private Double longitude;// 经度
|
||||||
private Double latitude;// 维度
|
private Double latitude;// 维度
|
||||||
private String location;// 位置
|
private String location;// 位置
|
||||||
private int apnsAble;// apns推送状态
|
private int apns;// apns推送状态
|
||||||
private int status;// 状态
|
private int state;// 状态
|
||||||
|
|
||||||
|
|
||||||
public CIMSession(Channel session) {
|
public CIMSession(Channel session) {
|
||||||
this.session = session;
|
this.session = session;
|
||||||
this.nid = session.id().asShortText();
|
this.nid = session.id().asShortText();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public CIMSession() {
|
public CIMSession() {
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -91,7 +90,8 @@ public class CIMSession implements Serializable {
|
|||||||
|
|
||||||
public void setAccount(String account) {
|
public void setAccount(String account) {
|
||||||
this.account = account;
|
this.account = account;
|
||||||
setAttribute(CIMConstant.SESSION_KEY, account);
|
|
||||||
|
setAttribute(CIMConstant.KEY_ACCOUNT, account);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Double getLongitude() {
|
public Double getLongitude() {
|
||||||
@ -118,14 +118,6 @@ public class CIMSession implements Serializable {
|
|||||||
this.location = location;
|
this.location = location;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getGid() {
|
|
||||||
return gid;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setGid(String gid) {
|
|
||||||
this.gid = gid;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getNid() {
|
public String getNid() {
|
||||||
return nid;
|
return nid;
|
||||||
}
|
}
|
||||||
@ -186,37 +178,24 @@ public class CIMSession implements Serializable {
|
|||||||
this.systemVersion = systemVersion;
|
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) {
|
public void setHost(String host) {
|
||||||
this.host = host;
|
this.host = host;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setChannel(Channel session) {
|
public int getApns() {
|
||||||
this.session = session;
|
return apns;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getApnsAble() {
|
public void setApns(int apns) {
|
||||||
return apnsAble;
|
this.apns = apns;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setApnsAble(int apnsAble) {
|
public int getState() {
|
||||||
this.apnsAble = apnsAble;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getStatus() {
|
public void setState(int state) {
|
||||||
return status;
|
this.state = state;
|
||||||
}
|
|
||||||
|
|
||||||
public void setStatus(int status) {
|
|
||||||
this.status = status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAttribute(String key, Object value) {
|
public void setAttribute(String key, Object value) {
|
||||||
@ -248,36 +227,16 @@ public class CIMSession implements Serializable {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public boolean write(Object msg) {
|
public boolean write(Object msg) {
|
||||||
if (session != null && session.isActive()) {
|
if (session != null && session.isActive()) {
|
||||||
return session.writeAndFlush(msg).awaitUninterruptibly(5000);
|
return session.writeAndFlush(msg).awaitUninterruptibly(5000);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isConnected() {
|
public boolean isConnected() {
|
||||||
if (session != null) {
|
return (session != null && session.isActive()) || state == STATE_ENABLED;
|
||||||
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;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void closeNow() {
|
public void closeNow() {
|
||||||
@ -285,63 +244,108 @@ public class CIMSession implements Serializable {
|
|||||||
session.close();
|
session.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPackageName(String packageName) {
|
public void closeOnFlush() {
|
||||||
this.packageName = packageName;
|
if (session != null)
|
||||||
|
session.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getPackageName() {
|
public boolean isIOSChannel() {
|
||||||
return packageName;
|
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() {
|
public int hashCode() {
|
||||||
|
return getClass().hashCode();
|
||||||
return (deviceId + nid + host).hashCode();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
|
|
||||||
if (o instanceof CIMSession) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean fromOtherDevice(Object o) {
|
public byte[] getProtobufBody() {
|
||||||
|
SessionProto.Model.Builder builder = SessionProto.Model.newBuilder();
|
||||||
if (o instanceof CIMSession) {
|
if (account != null) {
|
||||||
|
builder.setAccount(account);
|
||||||
CIMSession t = (CIMSession) o;
|
|
||||||
if (t.deviceId != null && deviceId != null) {
|
|
||||||
return !t.deviceId.equals(deviceId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
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) {
|
|
||||||
|
public static CIMSession decode(byte[] protobufBody) throws InvalidProtocolBufferException {
|
||||||
return !fromOtherDevice(o);
|
if(protobufBody == null) {
|
||||||
}
|
return null;
|
||||||
|
}
|
||||||
public String toString() {
|
SessionProto.Model proto = SessionProto.Model.parseFrom(protobufBody);
|
||||||
StringBuffer buffer = new StringBuffer();
|
CIMSession session = new CIMSession();
|
||||||
buffer.append("{");
|
session.setApns(proto.getApns());
|
||||||
|
session.setBindTime(proto.getBindTime());
|
||||||
buffer.append("\"").append("gid").append("\":").append("\"").append(gid).append("\"").append(",");
|
session.setChannel(proto.getChannel());
|
||||||
buffer.append("\"").append("nid").append("\":").append(nid).append(",");
|
session.setClientVersion(proto.getClientVersion());
|
||||||
buffer.append("\"").append("deviceId").append("\":").append("\"").append(deviceId).append("\"").append(",");
|
session.setDeviceId(proto.getDeviceId());
|
||||||
buffer.append("\"").append("host").append("\":").append("\"").append(host).append("\"").append(",");
|
session.setDeviceModel(proto.getDeviceModel());
|
||||||
buffer.append("\"").append("account").append("\":").append("\"").append(account).append("\"").append(",");
|
session.setHost(proto.getHost());
|
||||||
buffer.append("\"").append("channel").append("\":").append("\"").append(channel).append("\"").append(",");
|
session.setLatitude(proto.getLatitude());
|
||||||
buffer.append("\"").append("deviceModel").append("\":").append("\"").append(deviceModel).append("\"")
|
session.setLongitude(proto.getLongitude());
|
||||||
.append(",");
|
session.setLocation(proto.getLocation());
|
||||||
buffer.append("\"").append("status").append("\":").append(status).append(",");
|
session.setNid(proto.getNid());
|
||||||
buffer.append("\"").append("apnsAble").append("\":").append(apnsAble).append(",");
|
session.setSystemVersion(proto.getSystemVersion());
|
||||||
buffer.append("\"").append("bindTime").append("\":").append(bindTime).append(",");
|
session.setState(proto.getState());
|
||||||
buffer.append("\"").append("heartbeat").append("\":").append(heartbeat);
|
session.setAccount(proto.getAccount());
|
||||||
buffer.append("}");
|
return session;
|
||||||
return buffer.toString();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
@ -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;
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@ -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<String, CIMSession> sessions = new HashMap<String, CIMSession>();
|
|
||||||
|
|
||||||
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<CIMSession> queryAll() {
|
|
||||||
List<CIMSession> list = new ArrayList<CIMSession>();
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -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<CIMSession> queryAll();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除session
|
|
||||||
*
|
|
||||||
* @param session
|
|
||||||
*/
|
|
||||||
public void remove(String account);
|
|
||||||
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user