All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
xin.alum.aim.groups.Sessions Maven / Gradle / Ivy
package xin.alum.aim.groups;
import xin.alum.aim.AIM;
import xin.alum.aim.constant.ChannelAttr;
import xin.alum.aim.constant.ChannelPlatform;
import xin.alum.aim.model.Reply;
import xin.alum.aim.model.Transportable;
import io.netty.channel.Channel;
import io.netty.channel.group.ChannelGroupFuture;
import io.netty.channel.group.ChannelMatcher;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.AttributeKey;
import io.netty.util.concurrent.GlobalEventExecutor;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.net.InetSocketAddress;
import java.util.Iterator;
import java.util.Optional;
/**
* 所有在线连接管理【不支持群组集群,集群推送请用SessionGroups】
*
* @auther alum(alum @ live.cn)
* @date 2021/8/3 14:52
*/
@Component
public class Sessions extends DefaultChannelGroup {
/**
* 区分
*/
public static final String PREFIX_BIND_USER_GROUP = "AIM_USER_";
/**
* 所有在线用户
*/
public static final String ALL_SESSIONS = "AIM-ALL-SESSIONS";
@Autowired
private SessionGroups groups;
private static final InternalLogger logger = InternalLoggerFactory.getInstance(Sessions.class);
/**
*
*/
public Sessions() {
super(ALL_SESSIONS, GlobalEventExecutor.INSTANCE);
}
/**
* @param name
*/
public Sessions(String name) {
super(name, GlobalEventExecutor.INSTANCE);
}
/**
* 绑定用户通道到Sessions
*
* @param ch
*/
private Boolean bind(Channel ch, String uid) {
int old = super.size();
if (!super.contains(ch)) {
super.add(ch);
}
boolean bResult = groups.bind(ch, PREFIX_BIND_USER_GROUP.concat(uid)).contains(ch);
logger.info("{}新连接接入,原:{},现:{}", ch, old, super.size());
return bResult;
}
/**
* 集群通知 Session上线
*
* @param session
*/
public void kick(Session session) {
Sessions sessions = groups.get(PREFIX_BIND_USER_GROUP.concat(session.getUid()));
if (sessions != null) {
ChannelMatcher m = w -> (!w.id().asShortText().equalsIgnoreCase(session.getCid())) && w.attr(ChannelAttr.PLATFORM).get().equals(session.getPlatform().name());
Iterator users = sessions.iterator();
while (users.hasNext()) {
Channel ch = users.next();
if (m.matches(ch)) {
offline(ch, session);
break;
}
}
}
}
/**
* 让连接通道下线
*/
private void offline(Channel oldChannel, Session session) {
Reply reply = AIM.request.onKick(oldChannel, session);
if (oldChannel.isWritable()) {
//通信旧连接下线
logger.warn("{}通知用户ID【{}】旧连接下线", oldChannel, session.getUid());
oldChannel.writeAndFlush(reply);
}
//关闭旧连接
oldChannel.close();
}
/**
* 获取客户端IP
*
* @param ch
* @return
*/
public String getClientIP(Channel ch) {
InetSocketAddress ip = (InetSocketAddress) ch.remoteAddress();
return ip.getAddress().getHostAddress();
}
/**
* 获取 bindUser设定的UID
*
* @param ch
* @return
*/
public String getUId(Channel ch) {
return ch.attr(ChannelAttr.UID).get();
}
/**
* 获取
*
* @param ch
* @param key
*/
public Object getAttr(Channel ch, String key) {
return ch.attr(AttributeKey.valueOf(key)).get();
}
/**
* 设置属性
*
* @param ch
* @param key
* @param val
* @param
*/
public void setAttr(Channel ch, String key, T val) {
ch.attr(AttributeKey.valueOf(key)).set(val);
}
/**
* 绑定
*/
public void bindUid(Channel ch, String userId) {
bindUser(ch, userId, ChannelPlatform.NON, "");
}
/**
* 绑定
*/
public void bindUser(Channel ch, String userId, String deviceId) {
bindUser(ch, userId, ChannelPlatform.NON, deviceId);
}
/**
* 绑定
*
* @param ch
* @param userId
* @param platform
*/
public Boolean bindUser(Channel ch, String userId, ChannelPlatform platform, String deviceId) {
Optional s = super.stream().filter(w -> w.attr(ChannelAttr.UID).get().equals(userId) && w.attr(ChannelAttr.PLATFORM).get().equals(platform.name())).findFirst();
if (s.isPresent()) {
Channel oldCh = s.get();
offline(oldCh, new Session(userId, ch.id(), platform, getClientIP(ch), deviceId));
} else if (AIM.clusterFactory != null) {
AIM.clusterFactory.kick(new Session(userId, ch.id(), platform, getClientIP(ch), deviceId));
}
ch.attr(ChannelAttr.UID).set(userId);
ch.attr(ChannelAttr.PLATFORM).set(platform.name());
ch.attr(ChannelAttr.DEVICE_ID).set(deviceId);
ch.attr(ChannelAttr.UIP).set(getClientIP(ch));
return bind(ch, userId);
}
static long bytes = 0;
/**
* 向当前群组发送消息[不含集群]
*
* @param msg
* @return
*/
public void sends(Transportable msg) {
sends(w -> w.isWritable(), msg);
}
/**
* 向用户发送消息[含集群]
*
* @param uid
* @param msg
*/
public void send(String uid, Transportable msg) {
if (uid == null || uid.isEmpty()) {
logger.error("Channel未绑定uid={},无法发送!", uid);
} else if (AIM.clusterFactory != null) {
AIM.clusterFactory.push(PREFIX_BIND_USER_GROUP.concat(uid), msg);
} else {
groups.get(PREFIX_BIND_USER_GROUP.concat(uid)).sends(msg);
}
}
/**
* 向不包含ch的其它通道发送消息
*
* @param ch
* @param msg
*/
public ChannelGroupFuture sends(Channel ch, Transportable msg) {
return sends(w -> w.id() != ch.id(), msg);
}
/**
* 向通道Matcher匹配到的连接发送信息
*
* @param matcher 通道匹配表达式
* @param msg 消息体
* @return 结果
*/
public ChannelGroupFuture sends(ChannelMatcher matcher, Transportable msg) {
return super.writeAndFlush(msg, matcher, true);
}
}