org.redkale.net.http.WebSocket Maven / Gradle / Ivy
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.net.http;
import org.redkale.net.http.WebSocketPacket.FrameType;
import java.io.*;
import java.net.*;
import java.nio.ByteBuffer;
import java.util.*;
import java.util.concurrent.*;
import java.util.function.Supplier;
import java.util.logging.*;
import java.util.stream.Stream;
import org.redkale.convert.Convert;
import org.redkale.util.Comment;
/**
*
* 一个WebSocket连接对应一个WebSocket实体,即一个WebSocket会绑定一个TCP连接。
* 协议上符合HTML5规范, 其流程顺序如下:
* 1.1 onOpen 若返回null,视为WebSocket的连接不合法,强制关闭WebSocket连接;通常用于判断登录态。
* 1.2 createUserid 若返回null,视为WebSocket的连接不合法,强制关闭WebSocket连接;通常用于判断用户权限是否符合。
* 1.3 onConnected WebSocket成功连接后在准备接收数据前回调此方法。
* 1.4 onMessage/onFragment+ WebSocket接收到消息后回调此消息类方法。
* 1.5 onClose WebSocket被关闭后回调此方法。
* 普通模式下 以上方法都应该被重载。
*
*
* 详情见: https://redkale.org
*
* @author zhangjx
* @param Groupid的泛型
* @param Message的泛型
*/
public abstract class WebSocket {
//--------------------------- CLOSECODE -------------------------------
@Comment("服务器主动关闭")
public static final int CLOSECODE_SERVERCLOSE = 3001;
@Comment("客户端主动关闭")
public static final int CLOSECODE_CLIENTCLOSE = 3002;
@Comment("异常关闭")
public static final int CLOSECODE_WSEXCEPTION = 3003;
@Comment("异常数据强制关闭")
public static final int CLOSECODE_ILLPACKET = 3004;
//---------------------------- RETCODE --------------------------------
@Comment("消息不合法")
public static final int RETCODE_SEND_ILLPACKET = 1 << 1; //2
@Comment("WebSocket已经关闭")
public static final int RETCODE_WSOCKET_CLOSED = 1 << 2; //4
@Comment("Socket的buffer不合法")
public static final int RETCODE_ILLEGALBUFFER = 1 << 3; //8
@Comment("WebSocket发送消息异常")
public static final int RETCODE_SENDEXCEPTION = 1 << 4; //16
@Comment("WebSocketEngine实例不存在")
public static final int RETCODE_ENGINE_NULL = 1 << 5; //32
@Comment("WebSocketNode实例不存在")
public static final int RETCODE_NODESERVICE_NULL = 1 << 6; //64
@Comment("WebSocket组为空, 表示无WebSocket连接")
public static final int RETCODE_GROUP_EMPTY = 1 << 7; //128
@Comment("WebSocket已离线")
public static final int RETCODE_WSOFFLINE = 1 << 8; //256
@Comment("WebSocket将延迟发送")
public static final int RETCODE_DEAYSEND = 1 << 9; //512
WebSocketRunner _runner; //不可能为空
WebSocketEngine _engine; //不可能为空
String _sessionid; //不可能为空
G _userid; //不可能为空
SocketAddress _remoteAddress;//不可能为空
String _remoteAddr;//不可能为空
Convert _textConvert; //不可能为空
Convert _binaryConvert; //可能为空
Convert _sendConvert; //不可能为空
java.lang.reflect.Type _messageTextType; //不可能为空
private long createtime = System.currentTimeMillis();
private long pingtime;
private Map attributes = new HashMap<>(); //非线程安全
List delayPackets;
protected WebSocket() {
}
//----------------------------------------------------------------
public final CompletableFuture sendPing() {
this.pingtime = System.currentTimeMillis();
//if (_engine.finest) _engine.logger.finest(this + " on "+_engine.getEngineid()+" ping...");
return sendPacket(WebSocketPacket.DEFAULT_PING_PACKET);
}
public final CompletableFuture sendPing(byte[] data) {
this.pingtime = System.currentTimeMillis();
return sendPacket(new WebSocketPacket(FrameType.PING, data));
}
public final CompletableFuture sendPong(byte[] data) {
return sendPacket(new WebSocketPacket(FrameType.PONG, data));
}
public final long getCreatetime() {
return createtime;
}
/**
* 给自身发送消息, 消息类型是String或byte[]或可JavaBean对象
*
* @param message 不可为空, 只能是String或byte[]或可JavaBean对象
*
* @return 0表示成功, 非0表示错误码
*/
public final CompletableFuture send(Object message) {
return send(false, message, true);
}
/**
* 给自身发送消息, 消息类型是key-value键值对
*
* @param messages key-value键值对
*
* @return 0表示成功, 非0表示错误码
*/
public final CompletableFuture sendMap(Object... messages) {
return send(true, messages, true);
}
/**
* 给自身发送消息, 消息类型是String或byte[]或可JavaBean对象
*
* @param message 不可为空, 只能是String或byte[]或可JavaBean对象
* @param last 是否最后一条
*
* @return 0表示成功, 非0表示错误码
*/
public final CompletableFuture send(Object message, boolean last) {
return send(false, message, last);
}
/**
* 给自身发送消息, 消息类型是key-value键值对
*
* @param last 是否最后一条
* @param messages key-value键值对
*
* @return 0表示成功, 非0表示错误码
*/
public final CompletableFuture sendMap(boolean last, Object... messages) {
return send(true, messages, last);
}
/**
* 给自身发送消息, 消息类型是Object[]
*
* @param mapconvable 是否convertMapTo
* @param message 不可为空, 只能是String或byte[]或可JavaBean对象,或Object[]
* @param last 是否最后一条
*
* @return 0表示成功, 非0表示错误码
*/
private CompletableFuture send(boolean mapconvable, Object message, boolean last) {
if (message instanceof CompletableFuture) {
return ((CompletableFuture) message).thenCompose((json) -> {
if (json == null || json instanceof CharSequence || json instanceof byte[]) {
return sendPacket(new WebSocketPacket((Serializable) json, last));
} else if (message instanceof WebSocketPacket) {
return sendPacket((WebSocketPacket) message);
} else {
return sendPacket(new WebSocketPacket(getSendConvert(), mapconvable, json, last));
}
});
}
if (message == null || message instanceof CharSequence || message instanceof byte[]) {
return sendPacket(new WebSocketPacket((Serializable) message, last));
} else if (message instanceof WebSocketPacket) {
return sendPacket((WebSocketPacket) message);
} else {
return sendPacket(new WebSocketPacket(getSendConvert(), mapconvable, message, last));
}
}
/**
* 给自身发送消息, 消息类型是JavaBean对象
*
* @param convert Convert
* @param message 不可为空, 只能是JSON对象
*
* @return 0表示成功, 非0表示错误码
*/
public final CompletableFuture send(Convert convert, Object message) {
return send(convert, message, true);
}
/**
* 给自身发送消息, 消息类型是JavaBean对象
*
* @param convert Convert
* @param message 不可为空, 只能是JavaBean对象
* @param last 是否最后一条
*
* @return 0表示成功, 非0表示错误码
*/
public final CompletableFuture send(Convert convert, Object message, boolean last) {
if (message instanceof CompletableFuture) {
return ((CompletableFuture) message).thenCompose((json) -> sendPacket(new WebSocketPacket(convert == null ? getSendConvert() : convert, false, json, last)));
}
return sendPacket(new WebSocketPacket(convert == null ? getSendConvert() : convert, false, message, last));
}
/**
* 给自身发送消息体, 包含二进制/文本
*
* @param packet WebSocketPacket
*
* @return 0表示成功, 非0表示错误码
*/
CompletableFuture sendPacket(WebSocketPacket packet) {
if (this._runner == null) {
if (delayPackets == null) delayPackets = new ArrayList<>();
delayPackets.add(packet);
return CompletableFuture.completedFuture(RETCODE_DEAYSEND);
}
CompletableFuture rs = this._runner.sendMessage(packet);
if (_engine.logger.isLoggable(Level.FINEST) && packet != WebSocketPacket.DEFAULT_PING_PACKET) {
_engine.logger.finest("userid:" + getUserid() + " send websocket message(" + packet + ")" + " on " + this);
}
return rs == null ? CompletableFuture.completedFuture(RETCODE_WSOCKET_CLOSED) : rs;
}
//----------------------------------------------------------------
/**
* 给指定userid的WebSocket节点发送 二进制消息/文本消息/JavaBean对象消息
*
* @param message 不可为空
* @param userids Stream
*
* @return 为0表示成功, 其他值表示异常
*/
public final CompletableFuture sendMessage(Object message, Stream userids) {
return sendMessage(message, true, userids);
}
/**
* 给指定userid的WebSocket节点发送 二进制消息/文本消息/JavaBean对象消息
*
* @param message 不可为空
* @param userids Serializable[]
*
* @return 为0表示成功, 其他值表示异常
*/
public final CompletableFuture sendMessage(Object message, G... userids) {
return sendMessage(message, true, userids);
}
/**
* 给指定userid的WebSocket节点发送 二进制消息/文本消息/JavaBean对象消息
*
* @param convert Convert
* @param message 不可为空
* @param userids Stream
*
* @return 为0表示成功, 其他值表示异常
*/
public final CompletableFuture sendMessage(final Convert convert, Object message, Stream userids) {
return sendMessage(convert, message, true, userids);
}
/**
* 给指定userid的WebSocket节点发送 二进制消息/文本消息/JavaBean对象消息
*
* @param convert Convert
* @param message 不可为空
* @param userids Serializable[]
*
* @return 为0表示成功, 其他值表示异常
*/
public final CompletableFuture sendMessage(final Convert convert, Object message, G... userids) {
return sendMessage(convert, message, true, userids);
}
/**
* 给指定userid的WebSocket节点发送 二进制消息/文本消息/JavaBean对象消息
*
* @param message 不可为空
* @param last 是否最后一条
* @param userids Serializable[]
*
* @return 为0表示成功, 其他值表示异常
*/
public final CompletableFuture sendMessage(Object message, boolean last, Stream userids) {
return sendMessage((Convert) null, message, last, userids);
}
/**
* 给指定userid的WebSocket节点发送 二进制消息/文本消息/JavaBean对象消息
*
* @param message 不可为空
* @param last 是否最后一条
* @param userids Serializable[]
*
* @return 为0表示成功, 其他值表示异常
*/
public final CompletableFuture sendMessage(Object message, boolean last, G... userids) {
return sendMessage((Convert) null, message, last, userids);
}
/**
* 给指定userid的WebSocket节点发送 二进制消息/文本消息/JavaBean对象消息
*
* @param convert Convert
* @param message 不可为空
* @param last 是否最后一条
* @param userids Stream
*
* @return 为0表示成功, 其他值表示异常
*/
public final CompletableFuture sendMessage(final Convert convert, Object message, boolean last, final Stream userids) {
Object[] array = userids.toArray();
Serializable[] ss = new Serializable[array.length];
for (int i = 0; i < array.length; i++) {
ss[i] = (Serializable) array[i];
}
return sendMessage(convert, message, last, ss);
}
/**
* 给指定userid的WebSocket节点发送 二进制消息/文本消息/JavaBean对象消息
*
* @param convert Convert
* @param message 不可为空
* @param last 是否最后一条
* @param userids Serializable[]
*
* @return 为0表示成功, 其他值表示异常
*/
public final CompletableFuture sendMessage(final Convert convert, Object message, boolean last, Serializable... userids) {
if (_engine.node == null) return CompletableFuture.completedFuture(RETCODE_NODESERVICE_NULL);
if (message instanceof CompletableFuture) {
return ((CompletableFuture) message).thenCompose((json) -> _engine.node.sendMessage(convert, json, last, userids));
}
CompletableFuture rs = _engine.node.sendMessage(convert, message, last, userids);
if (_engine.logger.isLoggable(Level.FINEST)) _engine.logger.finest("userids:" + Arrays.toString(userids) + " send websocket message(" + message + ")");
return rs;
}
/**
* 广播消息, 给所有人发消息
*
* @param message 消息内容
*
* @return 为0表示成功, 其他值表示部分发送异常
*/
public final CompletableFuture broadcastMessage(final Object message) {
return broadcastMessage((Convert) null, message, true);
}
/**
* 广播消息, 给所有人发消息
*
* @param wsrange 过滤条件
* @param message 消息内容
*
* @return 为0表示成功, 其他值表示部分发送异常
*/
public final CompletableFuture broadcastMessage(final WebSocketRange wsrange, final Object message) {
return broadcastMessage((WebSocketRange) null, (Convert) null, message, true);
}
/**
* 广播消息, 给所有人发消息
*
* @param convert Convert
* @param message 消息内容
*
* @return 为0表示成功, 其他值表示部分发送异常
*/
public final CompletableFuture broadcastMessage(final Convert convert, final Object message) {
return broadcastMessage(convert, message, true);
}
/**
* 广播消息, 给所有人发消息
*
* @param wsrange 过滤条件
* @param convert Convert
* @param message 消息内容
*
* @return 为0表示成功, 其他值表示部分发送异常
*/
public final CompletableFuture broadcastMessage(final WebSocketRange wsrange, final Convert convert, final Object message) {
return broadcastMessage((WebSocketRange) null, convert, message, true);
}
/**
* 广播消息, 给所有人发消息
*
* @param message 消息内容
* @param last 是否最后一条
*
* @return 为0表示成功, 其他值表示部分发送异常
*/
public final CompletableFuture broadcastMessage(final Object message, final boolean last) {
return broadcastMessage((Convert) null, message, last);
}
/**
* 广播消息, 给所有人发消息
*
* @param wsrange 过滤条件
* @param message 消息内容
* @param last 是否最后一条
*
* @return 为0表示成功, 其他值表示部分发送异常
*/
public final CompletableFuture broadcastMessage(final WebSocketRange wsrange, final Object message, final boolean last) {
return broadcastMessage(wsrange, (Convert) null, message, last);
}
/**
* 广播消息, 给所有人发消息
*
* @param convert Convert
* @param message 消息内容
* @param last 是否最后一条
*
* @return 为0表示成功, 其他值表示部分发送异常
*/
public final CompletableFuture broadcastMessage(final Convert convert, final Object message, final boolean last) {
return broadcastMessage((WebSocketRange) null, convert, message, last);
}
/**
* 广播消息, 给所有人发消息
*
* @param wsrange 过滤条件
* @param convert Convert
* @param message 消息内容
* @param last 是否最后一条
*
* @return 为0表示成功, 其他值表示部分发送异常
*/
public final CompletableFuture broadcastMessage(final WebSocketRange wsrange, final Convert convert, final Object message, final boolean last) {
if (_engine.node == null) return CompletableFuture.completedFuture(RETCODE_NODESERVICE_NULL);
if (message instanceof CompletableFuture) {
return ((CompletableFuture) message).thenCompose((json) -> _engine.node.broadcastMessage(wsrange, convert, json, last));
}
CompletableFuture rs = _engine.node.broadcastMessage(wsrange, convert, message, last);
if (_engine.logger.isLoggable(Level.FINEST)) _engine.logger.finest("broadcast send websocket message(" + message + ")");
return rs;
}
/**
* 给指定userid的WebSocket节点发送操作
*
* @param action 操作参数
* @param userids Serializable[]
*
* @return 为0表示成功, 其他值表示异常
*/
public final CompletableFuture sendAction(final WebSocketAction action, Serializable... userids) {
if (_engine.node == null) return CompletableFuture.completedFuture(RETCODE_NODESERVICE_NULL);
CompletableFuture rs = _engine.node.sendAction(action, userids);
if (_engine.logger.isLoggable(Level.FINEST)) _engine.logger.finest("userids:" + Arrays.toString(userids) + " send websocket action(" + action + ")");
return rs;
}
/**
* 广播操作, 给所有人发操作指令
*
* @param action 操作参数
*
* @return 为0表示成功, 其他值表示部分发送异常
*/
public final CompletableFuture broadcastAction(final WebSocketAction action) {
if (_engine.node == null) return CompletableFuture.completedFuture(RETCODE_NODESERVICE_NULL);
CompletableFuture rs = _engine.node.broadcastAction(action);
if (_engine.logger.isLoggable(Level.FINEST)) _engine.logger.finest("broadcast send websocket action(" + action + ")");
return rs;
}
/**
* 获取用户在线的SNCP节点地址列表,不是分布式则返回元素数量为1,且元素值为null的列表
* InetSocketAddress 为 SNCP节点地址
*
* @param userid Serializable
*
* @return 地址列表
*/
public CompletableFuture> getRpcNodeAddresses(final Serializable userid) {
if (_engine.node == null) return CompletableFuture.completedFuture(null);
return _engine.node.getRpcNodeAddresses(userid);
}
/**
* 获取在线用户的详细连接信息
* Map.key 为 SNCP节点地址, 含值为null的key表示没有分布式
* Map.value 为 用户客户端的IP
*
* @param userid Serializable
*
* @return 地址集合
*/
public CompletableFuture