All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.blankcat.websocket.WebsocketService Maven / Gradle / Ivy

There is a newer version: 2.1.3
Show newest version
package cn.blankcat.websocket;

import cn.blankcat.config.BotConfig;
import cn.blankcat.dto.audio.AudioAction;
import cn.blankcat.dto.channel.Channel;
import cn.blankcat.dto.guild.Guild;
import cn.blankcat.dto.member.Member;
import cn.blankcat.dto.message.Message;
import cn.blankcat.dto.websocket.*;
import cn.blankcat.openapi.GatewayService;
import cn.blankcat.openapi.RetrofitManager;
import cn.blankcat.websocket.handler.HelloHandler;
import cn.blankcat.websocket.handler.PlayLoadHandler;
import cn.blankcat.websocket.handler.ReadyHandler;
import cn.blankcat.websocket.handler.WebsocketHandler;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import okhttp3.WebSocket;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;

public class WebsocketService {

    private static final AtomicBoolean HeartBeatFlag = new AtomicBoolean(true);
    private static final ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
    private static final Logger logger = LoggerFactory.getLogger("websocketService");

    public static Map, List> CLASS_HANDLER_MAP = new HashMap<>(){{
        put(Guild.class, new ArrayList<>());
        put(Message.class, new ArrayList<>());
        put(Channel.class, new ArrayList<>());
        put(Member.class, new ArrayList<>());
        put(AudioAction.class, new ArrayList<>());
        put(WSReadyData.class, new ArrayList<>(){{add(new ReadyHandler());}});
        put(WSHelloData.class, new ArrayList<>(){{add(new HelloHandler());}});
        put(WSPayload.class, new ArrayList<>(){{add(new PlayLoadHandler());}});
    }};
    /**
     * 根据用户设置的intents, 分片信息, 进行鉴权
     * @param intents 要订阅的事件, 可以通过WSEvent.allEventToIntent()获取全部订阅事件
     * @param nowShard 当前分片
     * @param totalShard 总分片
     */
    public void checkIdentity(int intents, long nowShard, long totalShard){
        List shardList = new ArrayList<>() {{
            add(nowShard);
            add(totalShard);
        }};
        WebSocket webSocket = WebsocketManager.getInstance();
        WSIdentityData wsIdentityData = new WSIdentityData();
        wsIdentityData.setIntents(intents);
        wsIdentityData.setToken(BotConfig.DEFAULT.formatBetterToken());
        wsIdentityData.setShard(shardList);
        WSPayload wsPayload = new WSPayload<>();
        wsPayload.setOpCode(WSPayload.OPCode.WSIdentity.getValue());
        wsPayload.setData(wsIdentityData);
        ObjectMapper mapper = new ObjectMapper();
        try {
            String json = mapper.writeValueAsString(wsPayload);
            webSocket.send(json);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        logger.info("正在获取新的session");
    }

    private void resume(){
        // 构建数据
        WSResumeData wsResumeData = new WSResumeData();
        wsResumeData.setToken(BotConfig.DEFAULT.formatBetterToken());
        wsResumeData.setSessionId(BotConfig.DEFAULT.getSessionId());
        wsResumeData.setSeq(BotConfig.DEFAULT.getSeq());
        // 构建playload
        WSPayload wsPayload = new WSPayload<>();
        wsPayload.setOpCode(WSPayload.OPCode.WSResume.getValue());
        wsPayload.setSeq(BotConfig.DEFAULT.getSeq());
        wsPayload.setData(wsResumeData);
        try {
            WebsocketManager.getInstance().send(new ObjectMapper().writeValueAsString(wsPayload));
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        logger.info("正在恢复连接");
    }

    /**
     * 自动订阅所有事件, 同时根据配置文件中的分片信息, 进行websocket连接, 包含自动重连, 心跳和鉴权
     */
    public void connect() {
        connect(WSEvent.allEventToIntent(), BotConfig.DEFAULT.getNowShard(), BotConfig.DEFAULT.getTotalShard());
    }

    /**
     * 根据用户设置的intents, 以及配置文件中的分片信息, 进行websocket连接, 包含自动重连, 心跳和鉴权
     * @param intents 要订阅的事件, 可以通过WSEvent.allEventToIntent()获取全部订阅事件
     */
    public void connect(int intents) {
        connect(intents, BotConfig.DEFAULT.getNowShard(), BotConfig.DEFAULT.getTotalShard());
    }

    /**
     * 根据用户设置的intents, 分片信息, 进行websocket连接, 包含自动重连, 心跳和鉴权
     * @param intents 要订阅的事件, 可以通过WSEvent.allEventToIntent()获取全部订阅事件
     * @param nowShard 当前分片
     * @param totalShard 总分片
     */
    public void connect(int intents, long nowShard, long totalShard){
        try {
            WebsocketAP result = RetrofitManager.getInstance().create(GatewayService.class).getWebsocketGatewayAP().execute().body();
            // 如果重置了那么直接获取新的session, 否则使用旧的session恢复连接
            if (Objects.requireNonNull(result).getSessionStartLimit().getTotal() == result.getSessionStartLimit().getRemaining()
                    || BotConfig.DEFAULT.getSessionId() == null
                    || BotConfig.DEFAULT.getSessionId().isEmpty()) {
                checkIdentity(intents, nowShard, totalShard);
            }else {
                resume();
            }
            newThreadKeepHeart();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    private void keepHeart() {
        logger.info("启动心跳进程成功, 当前是否显示心跳信息为{}(无论是否显示都会发送心跳)", BotConfig.DEFAULT.getDisplayHeart());
        Timer timer = new Timer();
        ObjectMapper mapper = new ObjectMapper();
        WebSocket webSocket = WebsocketManager.getInstance();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                // 持续发送心跳
                if (HeartBeatFlag.get()) {
                    WSPayload wsPayload = new WSPayload();
                    wsPayload.setOpCode(WSPayload.OPCode.WSHeartbeat.getValue());
                    wsPayload.setData(BotConfig.DEFAULT.getSeq());
                    try {
                        webSocket.send(mapper.writeValueAsString(wsPayload));
                        if (BotConfig.DEFAULT.getDisplayHeart()) {
                            logger.info("发送心跳成功");
                        }
                        // 定时保存配置
                        BotConfig.storeTo(BotConfig.DEFAULT, null);
                    } catch (JsonProcessingException e) {
                        e.printStackTrace();
                    }
                }
            }
        }, 1000, BotConfig.DEFAULT.getLastDelay() * 4/ 5);
    }

    private void newThreadKeepHeart(){
        fixedThreadPool.execute(this::keepHeart);
    }

    /**
     * 切换控制是否发送心跳
     */
    public void switchHeartFlag(){
        HeartBeatFlag.set(!HeartBeatFlag.get());
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy