Commit 65064349 by zhiwei

斗鱼弹幕级b站消息队列添加

parent c472b5c4
......@@ -65,8 +65,8 @@ public class BilibiliMessageHandler extends ChannelInboundHandlerAdapter{
Matcher matcher = pattern.matcher(source);
while(matcher.find()) {
JSONObject dataJson = JSONObject.parseObject(matcher.group());
BilibiliEntity bilibiliEntity = new BilibiliEntity(dataJson);
System.out.println(bilibiliEntity.toString());
BilibiliMessage bilibiliMessage = new BilibiliMessage(dataJson);
System.out.println(bilibiliMessage);
}
}
ReferenceCountUtil.release(msg);
......
package com.zhiwei.live.danmu.bilibili;
import java.util.List;
import java.util.Vector;
public class BilibiliMessageListener {
public static List<BilibiliMessage> messages = new Vector<>();
public static void addMessages(BilibiliMessage bilibiliMessage) {
messages.add(bilibiliMessage);
}
}
package com.zhiwei.live.danmu.douyu;
import java.io.IOException;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.zhiwei.live.danmu.douyu.constants.DouYuConstants;
import com.zhiwei.live.danmu.douyu.constants.MsgType;
import com.zhiwei.live.danmu.douyu.entity.BaseMsg;
import com.zhiwei.live.danmu.douyu.entity.ChatMsg;
import com.zhiwei.live.danmu.douyu.entity.DgbMsg;
import com.zhiwei.live.danmu.douyu.entity.ErrorMsg;
import com.zhiwei.live.danmu.douyu.entity.GgbbMsg;
import com.zhiwei.live.danmu.douyu.entity.MsgEntity;
import com.zhiwei.live.danmu.douyu.entity.SpbcMsg;
import com.zhiwei.live.danmu.douyu.entity.SsdMsg;
import com.zhiwei.live.danmu.douyu.entity.UenterMsg;
import com.zhiwei.live.danmu.douyu.exceptions.DouYuSDKException;
import com.zhiwei.live.danmu.douyu.util.DataUtil;
import com.zhiwei.live.danmu.douyu.util.STTUtil;
import com.zhiwei.live.danmu.douyu.util.UUIDUtil;
/**
* 功能描述:斗鱼SDK
*
* @auther: coffee
* @date: 2018-07-04 15:19:51
* 修改日志:
*/
public class DouYuClient {
private final static Logger logger = LoggerFactory.getLogger(DouYuClient.class);
private String host; //API Host
private int port; //API 端口
private String roomId; //房间ID(房间号)
private String groupId = DouYuConstants.MASSIVE_GID; //分组ID
private Socket socket; //通讯socket对象
private Thread dataSyncThread; //异步读取消息线程
private Boolean isExitMark = false; //退出标记
private MessageHandler messageHandler;
private List<MessageListener> messageListenerList = new ArrayList<>();
public DouYuClient(String host, int port, String roomId) {
this.host = host;
this.port = port;
this.roomId = roomId;
//初始化
this.init();
}
/**
* 初始化Client
*/
private void init() {
logger.info("初始化斗鱼SDK_Client...");
this.connect();
}
/**
* 打开socket连接
*/
private void connect() {
try {
logger.info("从服务器({}:{})获取弹幕服务器数据", host, port);
socket = new Socket(host, port);
messageHandler = new MessageHandler(socket);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* 登入斗鱼弹幕服务器
*/
public DouYuClient login() {
logger.info("登录房间 {}", roomId);
String content = String.format(DouYuApi.LOGIN_REQ, roomId);
messageHandler.send(content);
return this;
}
/**
* 加入房间分组并接收房间消息
*
* @return
*/
private DouYuClient joinGroup(String groupId) {
if (DouYuConstants.MASSIVE_GID.equals(groupId)) {
logger.info("开启海量弹幕接收模式");
} else {
logger.info("关闭海量弹幕接收模式");
}
logger.info("加入分组({})并开始接收消息", groupId);
String content = String.format(DouYuApi.JOIN_GROUP, roomId, groupId);
messageHandler.send(content);
return this;
}
/**
* 注册消息监听器
*
* @param messageListener
* @return
*/
public DouYuClient registerMessageListener(MessageListener messageListener) {
logger.info("注册消息监听器:{}", messageListener.getClass());
this.messageListenerList.add(messageListener);
return this;
}
/**
* 开始同步并接收房间消息
*/
public DouYuClient sync() {
//加入海量弹幕分组,接收所有消息
this.joinGroup(groupId);
//开启异步线程接收房间消息
dataSyncThread = new Thread(new Runnable() {
@Override
public void run() {
long start = System.currentTimeMillis();
while (true) {
//判断是否退出线程
if (isExitMark == true) {
break;
}
//读取弹幕消息
byte[] bytes = messageHandler.read();
String msg = new String(Arrays.copyOfRange(bytes, 8, bytes.length));
//获取消息类型
String msgType = DataUtil.getMsgType(msg);
if (msgType == null) {
logger.error("获取消息类型失败,消息:{}", msg);
continue;
}
//封装基础消息对象
BaseMsg msgBase = new BaseMsg();
msgBase.setUuid(UUIDUtil.simpleUUID());
msgBase.setType(msgType);
msgBase.setMessage(msg);
//根据不同的消息类型 序列化不同的 实体对象
MsgEntity entity = null;
if (MsgType.CHAT_MSG.equals(msgType)) {
entity = STTUtil.toBean(msg, ChatMsg.class);
} else if (MsgType.DGB.equals(msgType)) {
entity = STTUtil.toBean(msg, DgbMsg.class);
} else if (MsgType.GGBB.equals(msgType)) {
entity = STTUtil.toBean(msg, GgbbMsg.class);
} else if (MsgType.SPBC.equals(msgType)) {
entity = STTUtil.toBean(msg, SpbcMsg.class);
} else if (MsgType.SSD.equals(msgType)) {
entity = STTUtil.toBean(msg, SsdMsg.class);
} else if (MsgType.UENTER.equals(msgType)) {
entity = STTUtil.toBean(msg, UenterMsg.class);
} else if (MsgType.ERROR.equals(msgType)) {
entity = STTUtil.toBean(msg, ErrorMsg.class);
}
if (entity != null) {
entity.setMessage(msg);
entity.setUuid(msgBase.getUuid());
}
//消息监听器处理
for (MessageListener messageListener : messageListenerList) {
try {
//基础消息监听器处理
if (messageListener.getMsgClazz() == BaseMsg.class) {
messageListener.read(msgBase);
}
//指定类型消息监听器处理
else if (entity != null && messageListener.getMsgClazz() == entity.getClass()) {
messageListener.read(entity);
}
//String消息监听器处理
else if (messageListener.getMsgClazz() == String.class) {
messageListener.read(msg);
}
} catch (Exception e) {
logger.error("消息处理出现异常:", e);
}
}
//发送心跳消息保持通道
long end = System.currentTimeMillis();
if (end - start > 30000) {
doKeepLive();
start = System.currentTimeMillis();
}
//休眠1毫秒
try {
Thread.sleep(1);
} catch (InterruptedException e) {
throw new DouYuSDKException(e);
}
}
//客户端关闭,断开socket通道
messageHandler.close();
logger.info("斗鱼弹幕SDK客户端已成功退出");
}
});
dataSyncThread.start();
return this;
}
/**
* 发送心跳消息,保持通道
*/
public void doKeepLive() {
String content = String.format(DouYuApi.KEEP_LIVE);
logger.info("发送心跳信息,保持通道中...");
messageHandler.send(content);
}
/**
* 发送登出消息,用于退出
*/
public void logout(){
String content = String.format(DouYuApi.LOGOUT);
logger.info("发送登出消息中...");
messageHandler.send(content);
}
public void exit() {
logout();
isExitMark = true;
logger.info("斗鱼弹幕SDK客户端正在退出中...");
}
}
package com.zhiwei.live.danmu.douyu;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.zhiwei.crawler.proxy.ProxyHolder;
import com.zhiwei.live.danmu.douyu.constants.DouYuConstants;
import com.zhiwei.live.danmu.douyu.constants.MsgType;
import com.zhiwei.live.danmu.douyu.entity.BaseMsg;
import com.zhiwei.live.danmu.douyu.entity.ChatMsg;
import com.zhiwei.live.danmu.douyu.entity.DgbMsg;
import com.zhiwei.live.danmu.douyu.entity.ErrorMsg;
import com.zhiwei.live.danmu.douyu.entity.GgbbMsg;
import com.zhiwei.live.danmu.douyu.entity.MsgEntity;
import com.zhiwei.live.danmu.douyu.entity.SpbcMsg;
import com.zhiwei.live.danmu.douyu.entity.SsdMsg;
import com.zhiwei.live.danmu.douyu.entity.UenterMsg;
import com.zhiwei.live.danmu.douyu.exceptions.DouYuSDKException;
import com.zhiwei.live.danmu.douyu.util.DataUtil;
import com.zhiwei.live.danmu.douyu.util.STTUtil;
import com.zhiwei.live.danmu.douyu.util.UUIDUtil;
/**
* 功能描述:斗鱼SDK
*
* @auther: coffee
* @date: 2018-07-04 15:19:51
* 修改日志:
*/
public class DouYuClient {
private final static Logger logger = LoggerFactory.getLogger(DouYuClient.class);
private String host; //API Host
private int port; //API 端口
private String roomId; //房间ID(房间号)
private String groupId = DouYuConstants.MASSIVE_GID; //分组ID
private Socket socket; //通讯socket对象
private Thread dataSyncThread; //异步读取消息线程
private Boolean isExitMark = false; //退出标记
private MessageHandler messageHandler;
private List<MessageListener> messageListenerList = new ArrayList<>();
public DouYuClient(String host, int port, String roomId) {
this.host = host;
this.port = port;
this.roomId = roomId;
//初始化
this.init();
}
public DouYuClient(String roomId) {
this.host = "openbarrage.douyutv.com";
this.port = 8601;
this.roomId = roomId;
//初始化
this.init();
}
/**
* 初始化Client
*/
private void init() {
logger.info("初始化斗鱼SDK_Client...");
this.connect();
}
/**
* 打开socket连接
*/
private void connect() {
try {
logger.info("从服务器({}:{})获取弹幕服务器数据", host, port);
socket = new Socket(ProxyHolder.NAT_PROXY.getProxy());
socket.connect(new InetSocketAddress(host, port));
messageHandler = new MessageHandler(socket);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* 登入斗鱼弹幕服务器
*/
public DouYuClient login() {
logger.info("登录房间 {}", roomId);
String content = String.format(DouYuApi.LOGIN_REQ, roomId);
messageHandler.send(content);
return this;
}
/**
* 加入房间分组并接收房间消息
*
* @return
*/
private DouYuClient joinGroup(String groupId) {
if (DouYuConstants.MASSIVE_GID.equals(groupId)) {
logger.info("开启海量弹幕接收模式");
} else {
logger.info("关闭海量弹幕接收模式");
}
logger.info("加入分组({})并开始接收消息", groupId);
String content = String.format(DouYuApi.JOIN_GROUP, roomId, groupId);
messageHandler.send(content);
return this;
}
/**
* 注册消息监听器
*
* @param messageListener
* @return
*/
public DouYuClient registerMessageListener(MessageListener messageListener) {
logger.info("注册消息监听器:{}", messageListener.getClass());
this.messageListenerList.add(messageListener);
return this;
}
/**
* 开始同步并接收房间消息
*/
public DouYuClient sync() {
//加入海量弹幕分组,接收所有消息
this.joinGroup(groupId);
//开启异步线程接收房间消息
dataSyncThread = new Thread(new Runnable() {
@Override
public void run() {
long start = System.currentTimeMillis();
while (true) {
//判断是否退出线程
if (isExitMark == true) {
break;
}
//读取弹幕消息
byte[] bytes = messageHandler.read();
String msg = new String(Arrays.copyOfRange(bytes, 8, bytes.length));
//获取消息类型
String msgType = DataUtil.getMsgType(msg);
if (msgType == null) {
logger.error("获取消息类型失败,消息:{}", msg);
continue;
}
//封装基础消息对象
BaseMsg msgBase = new BaseMsg();
msgBase.setUuid(UUIDUtil.simpleUUID());
msgBase.setType(msgType);
msgBase.setMessage(msg);
//根据不同的消息类型 序列化不同的 实体对象
MsgEntity entity = null;
if (MsgType.CHAT_MSG.equals(msgType)) {
entity = STTUtil.toBean(msg, ChatMsg.class);
} else if (MsgType.DGB.equals(msgType)) {
entity = STTUtil.toBean(msg, DgbMsg.class);
} else if (MsgType.GGBB.equals(msgType)) {
entity = STTUtil.toBean(msg, GgbbMsg.class);
} else if (MsgType.SPBC.equals(msgType)) {
entity = STTUtil.toBean(msg, SpbcMsg.class);
} else if (MsgType.SSD.equals(msgType)) {
entity = STTUtil.toBean(msg, SsdMsg.class);
} else if (MsgType.UENTER.equals(msgType)) {
entity = STTUtil.toBean(msg, UenterMsg.class);
} else if (MsgType.ERROR.equals(msgType)) {
entity = STTUtil.toBean(msg, ErrorMsg.class);
}
if (entity != null) {
entity.setMessage(msg);
entity.setUuid(msgBase.getUuid());
}
//消息监听器处理
for (MessageListener messageListener : messageListenerList) {
try {
//基础消息监听器处理
if (messageListener.getMsgClazz() == BaseMsg.class) {
messageListener.read(msgBase);
}
//指定类型消息监听器处理
else if (entity != null && messageListener.getMsgClazz() == entity.getClass()) {
messageListener.read(entity);
}
//String消息监听器处理
else if (messageListener.getMsgClazz() == String.class) {
messageListener.read(msg);
}
} catch (Exception e) {
logger.error("消息处理出现异常:", e);
}
}
//发送心跳消息保持通道
long end = System.currentTimeMillis();
if (end - start > 30000) {
doKeepLive();
start = System.currentTimeMillis();
}
//休眠1毫秒
try {
Thread.sleep(1);
} catch (InterruptedException e) {
throw new DouYuSDKException(e);
}
}
//客户端关闭,断开socket通道
messageHandler.close();
logger.info("斗鱼弹幕SDK客户端已成功退出");
}
});
dataSyncThread.start();
return this;
}
/**
* 发送心跳消息,保持通道
*/
public void doKeepLive() {
String content = String.format(DouYuApi.KEEP_LIVE);
logger.info("发送心跳信息,保持通道中...");
messageHandler.send(content);
}
/**
* 发送登出消息,用于退出
*/
public void logout(){
String content = String.format(DouYuApi.LOGOUT);
logger.info("发送登出消息中...");
messageHandler.send(content);
}
public void exit() {
logout();
isExitMark = true;
logger.info("斗鱼弹幕SDK客户端正在退出中...");
}
}
package com.zhiwei.live.danmu.douyu;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.zhiwei.common.config.GroupType;
import com.zhiwei.crawler.proxy.ProxyFactory;
import com.zhiwei.live.danmu.douyu.entity.ChatMsg;
/**
* 功能描述:
*
* @auther: coffee
* @date: 2018-07-04 19:37:41
* 修改日志:
*/
public class Main {
private final static Logger logger = LoggerFactory.getLogger(Main.class);
private static final String registry = "zookeeper://192.168.0.36:2181";
private static final String group = "local";
static {
ProxyFactory.init(registry, group, GroupType.PROVIDER);
}
public static void main(String[] args) throws InterruptedException {
DouYuClient client = new DouYuClient("3084150");
client.registerMessageListener(new MessageListener<ChatMsg>() {
@Override
public void read(ChatMsg message) {
//logger.info(message.toChatStr());
// System.out.println(message.toChatStr());
}
});
client.registerMessageListener(new MessageListener<String>() {
@Override
public void read(String message) {
System.out.println(message);
// logger.info(message);
}
});
client.login();
client.sync();
Thread.sleep(30000);
client.exit();
}
}
package com.zhiwei.live.danmu.douyu;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.zhiwei.live.danmu.douyu.exceptions.DouYuSDKException;
/**
* 功能描述:消息处理助手
*
* @auther: coffee
* @date: 2018-07-04 15:11:13
* 修改日志:
*/
public class MessageHandler {
private final static Logger logger = LoggerFactory.getLogger(MessageHandler.class);
private Socket socket;
public MessageHandler(Socket socket) {
this.socket = socket;
}
/**
* 发送消息
*
* @param content
*/
public void send(String content) {
try {
Message message = new Message(content);
OutputStream out = socket.getOutputStream();
out.write(message.getBytes());
out.flush();
} catch (IOException e) {
throw new DouYuSDKException(e);
}
}
/**
* 读取消息
*
* @return
*/
public byte[] read(){
try {
InputStream inputStream = socket.getInputStream();
//下条信息的长度
int contentLen = 0;
//读取前4个字节,得到数据长度
for (int i = 0; i < 4; i++) {
int tmp = inputStream.read();
contentLen += tmp * Math.pow(16, 2 * i);
}
int len = 0;
int readLen = 0;
byte[] bytes = new byte[contentLen];
ByteArrayOutputStream byteArray = new ByteArrayOutputStream();
while ((len = inputStream.read(bytes, 0, contentLen - readLen)) != -1) {
byteArray.write(bytes, 0, len);
readLen += len;
if (readLen == contentLen) {
break;
}
}
return byteArray.toByteArray();
} catch (IOException e) {
throw new DouYuSDKException(e);
}
}
/**
* 关闭socket通道
*
* @throws IOException
*/
public void close(){
try {
socket.close();
} catch (IOException e) {
logger.warn("socket通道关闭异常",e);
}
}
}
package com.zhiwei.live.danmu.douyu;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.zhiwei.live.danmu.douyu.exceptions.DouYuSDKException;
/**
* 功能描述:消息处理助手
*
* @auther: coffee
* @date: 2018-07-04 15:11:13
* 修改日志:
*/
public class MessageHandler {
private final static Logger logger = LoggerFactory.getLogger(MessageHandler.class);
private Socket socket;
public MessageHandler(Socket socket) {
this.socket = socket;
}
/**
* 发送消息
*
* @param content
*/
public void send(String content) {
try {
Message message = new Message(content);
OutputStream out = socket.getOutputStream();
out.write(message.getBytes());
out.flush();
} catch (IOException e) {
throw new DouYuSDKException(e);
}
}
/**
* 读取消息
*
* @return
*/
public byte[] read(){
try {
InputStream inputStream = socket.getInputStream();
//下条信息的长度
int contentLen = 0;
//读取前4个字节,得到数据长度
for (int i = 0; i < 4; i++) {
int tmp = inputStream.read();
contentLen += tmp * Math.pow(16, 2 * i);
}
int len = 0;
int readLen = 0;
byte[] bytes = new byte[contentLen];
ByteArrayOutputStream byteArray = new ByteArrayOutputStream();
while ((len = inputStream.read(bytes, 0, contentLen - readLen)) != -1) {
byteArray.write(bytes, 0, len);
readLen += len;
if (readLen == contentLen) {
break;
}
}
return byteArray.toByteArray();
} catch (IOException e) {
throw new DouYuSDKException(e);
}
}
/**
* 关闭socket通道
*
* @throws IOException
*/
public void close(){
try {
socket.close();
} catch (IOException e) {
logger.warn("socket通道关闭异常",e);
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment