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

com.github.houbbbbb.sso.nt.handler.HeartbeatServerHandler Maven / Gradle / Ivy

The newest version!
package com.github.houbbbbb.sso.nt.handler;

import com.github.houbbbbb.sso.config.SSOPFilterConfig;
import com.github.houbbbbb.sso.nt.constants.CacheConstants;
import com.github.houbbbbb.sso.nt.constants.CommonConstants;
import com.github.houbbbbb.sso.nt.entity.AppDTO;
import com.github.houbbbbb.sso.nt.opt.CacheOpt;
import com.github.houbbbbb.sso.nt.util.DebugUtil;
import com.github.houbbbbb.sso.nt.util.HandlerUtils;
import com.github.houbbbbb.sso.util.GsonUtil;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import lombok.Getter;
import lombok.ToString;


import java.net.InetSocketAddress;
import java.util.*;

/**
 * @todo:
 * @author: hbw
 * @date: 2020/7/8
 **/
@ChannelHandler.Sharable
public class HeartbeatServerHandler extends ServerChannelHandler {

    private static Integer timesLimit;
    private static Long timeout;
    public HeartbeatServerHandler (SSOPFilterConfig ssopFilterConfig) {
        timesLimit = ssopFilterConfig.getTickTimedOutTimes();
        timeout = ssopFilterConfig.getTickTimedOut();
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        Handler tickHandler = HandlerFactory.getHandler(HandlerType.TICK_HANDLER);
        ReadInfo readInfo = tickHandler.getReadInfo(ctx, msg);
        tickHandler.handle(readInfo);
        tickHandler.resp(ctx, readInfo);

    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        InetSocketAddress address = (InetSocketAddress) ctx.channel().remoteAddress();
        DebugUtil.debug("exception: " + cause.getMessage(), address.getAddress().getHostAddress() + " : " + address.getPort());
        DebugUtil.warn("exception: " + cause.getMessage(), address.getAddress().getHostAddress() + " : " + address.getPort());
        ctx.close();
    }

    @Getter
    @ToString
    static class HostInfo {
        private String hostName;
        private String ip;
        private Integer port;
        private Long time;

        public HostInfo setHostName(String hostName) {
            this.hostName = hostName;
            return this;
        }

        public HostInfo setIp (String ip) {
            this.ip = ip;
            return this;
        }

        public HostInfo setPort (Integer port) {
            this.port = port;
            return this;
        }

        public HostInfo setTime(Long time) {
            this.time = time;
            return this;
        }

        public static HostInfo create () {
            return new HostInfo();
        }

        private HostInfo () {}
    }

    @ToString
    @Getter
    static class ReadInfo {
        private HostInfo hostInfo;
        private String rd;

        public ReadInfo setHostInfo(HostInfo hostInfo) {
            this.hostInfo = hostInfo;
            return this;
        }

        public ReadInfo setRd(String rd) {
            this.rd = rd;
            return this;
        }

        public static ReadInfo create () {
            return new ReadInfo();
        }

        private ReadInfo () {}
    }

    public static class TickHandler implements Handler {

        public static final String UNDERLINE = "_";


        @Override
        public void handle (ReadInfo readInfo) {
            record(readInfo);
            calculate(readInfo);
        }

        @Override
        public ReadInfo getReadInfo(ChannelHandlerContext ctx, Object msg) {
            String rd = HandlerUtils.rd(msg);
            InetSocketAddress address = (InetSocketAddress) ctx.channel().remoteAddress();
            // hostName不在这里获取
            //String hostName = address.getHostName();
            AppDTO appDTO = GsonUtil.toObj(rd, AppDTO.class);
            String ip = address.getAddress().getHostAddress();
            HostInfo hostInfo = HostInfo.create().setHostName(appDTO.getHostName()).setIp(ip).setTime(System.currentTimeMillis());
            return ReadInfo.create().setHostInfo(hostInfo).setRd(rd);
        }

        @Override
        public void resp(ChannelHandlerContext ctx, ReadInfo readInfo) {
            int size = CacheConstants.LINK_CACHE.size();
            String key = getKey(readInfo.getHostInfo());
            String wt = CommonConstants.APP_INFO;
            if (!CacheConstants.LINK_COUNT.containsKey(key)) {
                CacheConstants.LINK_COUNT.put(key, 0);
            }
            if (CacheConstants.LINK_COUNT.get(key) != size) {
                CacheConstants.LINK_COUNT.put(key, size);
                List appDTOS = new ArrayList<>(16);
                CacheConstants.LINK_CACHE.forEach((a, b) -> {
                    AppDTO appDTO = CacheConstants.INFO_CACHE.get(a);
                    if (null != appDTO) {
                        appDTOS.add(appDTO);
                    }
                });
                wt = GsonUtil.toJson(appDTOS);
            }
            setUpdate(readInfo);
            String re = getClearCache(readInfo, wt);
            if(null != re){
                wt = re;
            }
            HandlerUtils.wt(ctx, wt);
        }

        /**
         * 返回要清除的本地缓存的session的列表
         * @return
         */
        private String getClearCache(ReadInfo readInfo, String wt){
            if(!CommonConstants.APP_INFO.equals(wt)){
                return null;
            }
            String currentKey = getKey(readInfo.getHostInfo());
            Map> map = new HashMap<>(CacheConstants.UPDATE_CACHE);
            Set sessionList = new HashSet<>(16);
            if(map.size() > 0){
                List removeList = new ArrayList<>(10);
                map.forEach((key, value) -> {
                    if(value.contains(currentKey)){
                        value.remove(currentKey);
                        sessionList.add(key);
                        if(value.size() == 0){
                            removeList.add(key);
                        }
                    }
                });
                removeList.forEach(CacheConstants.UPDATE_CACHE::remove);
            }
            if(sessionList.size() > 0) {
                return CacheOpt.setPrefix(GsonUtil.toJson(sessionList));
            }
            return null;
        }

        /**
         * 将登出信息加入到UPDATE_CACHE中
         * @param readInfo
         */
        private void setUpdate(ReadInfo readInfo){
            String rd = readInfo.getRd();
            AppDTO appDTO = GsonUtil.toObj(rd, AppDTO.class);
            String update = appDTO.getUdpate();
            if(null == update){
                return;
            }
            String session = CacheOpt.getSession(update);
            CacheConstants.UPDATE_CACHE.put(session, CacheConstants.INFO_CACHE.keySet());
            CacheConstants.UPDATE_CACHE.get(session).remove(getKey(readInfo.getHostInfo()));
            if(CacheConstants.UPDATE_CACHE.get(session).size() == 0){
                CacheConstants.UPDATE_CACHE.remove(session);
            }
        }

        private void record (ReadInfo readInfo) {
            String rd = readInfo.getRd();
            HostInfo hostInfo = readInfo.getHostInfo();
            AppDTO appDTO = GsonUtil.toObj(rd, AppDTO.class);
            appDTO = appDTO.setHostName(hostInfo.getHostName()).setIp(hostInfo.getIp());
            hostInfo.setPort(appDTO.getPort());
            CacheConstants.INFO_CACHE.put(getKey(hostInfo), appDTO);
        }

        private String getKey (HostInfo hostInfo) {
            StringBuilder sb = new StringBuilder();
            sb.append(hostInfo.getIp()).append(UNDERLINE).append(hostInfo.getPort());
            String key = sb.toString();
            return key;
        }

        private String getValue (Integer times, HostInfo hostInfo) {
            StringBuilder sb = new StringBuilder();
            sb.append(hostInfo.getTime()).append(UNDERLINE).append(times);
            String value = sb.toString();
            return value;
        }

        private void calculate (ReadInfo readInfo) {
            HostInfo hostInfo = readInfo.getHostInfo();
            String key = getKey(hostInfo);
            if (CacheConstants.LINK_CACHE.containsKey(key)) {
                String value = CacheConstants.LINK_CACHE.get(key);
                CacheConstants.LINK_CACHE.put(key, getValue(getTimes(value), hostInfo));
            } else {
                CacheConstants.LINK_CACHE.put(key, getValue(0, hostInfo));
            }
        }

        private Long getTime (String value) {
            return Long.valueOf(value.split(UNDERLINE)[0]);
        }

        private Integer getTimes (String value) {
            return Integer.valueOf(value.split(UNDERLINE)[1]);
        }

        private Boolean hasTimeouted (String value, HostInfo hostInfo) {
            long now = hostInfo.getTime();
            long last = getTime(value);
            DebugUtil.debug("compare", (now - last));
            if (now - last > timeout) {
                return true;
            }
            return false;
        }

        public void checkTimeout () {
            DebugUtil.debug("time", "tick");
            Map map = new HashMap<>(CacheConstants.LINK_CACHE);
            List removeKeys = new ArrayList<>();
            List timeoutKeys = new ArrayList<>();
            map.forEach((key, value) -> {
                if (hasTimeouted(value, HostInfo.create().setTime(System.currentTimeMillis()))) {
                    int times = getTimes(value);
                    if (times > timesLimit) {
                        removeKeys.add(key);
                    } else {
                        timeoutKeys.add(key);
                    }
                }
            });
            removeKeys.forEach(key -> {
                CacheConstants.LINK_CACHE.remove(key);
                CacheConstants.INFO_CACHE.remove(key);
                CacheConstants.LINK_COUNT.remove(key);
            });
            timeoutKeys.forEach(key -> {
                String value = CacheConstants.LINK_CACHE.get(key);
                CacheConstants.LINK_CACHE.put(key, addTimes(value));
            });
        }

        private String addTimes(String value) {
            long time = getTime(value);
            int times = getTimes(value);
            value = getValue(++times, HostInfo.create().setTime(time));
            return value;
        }
    }

    static class HandlerFactory {
        private static final Map HANDLER_POOL = new HashMap<>(16);
        public static Handler getHandler (HandlerType handlerType) {
            if (!HANDLER_POOL.containsKey(handlerType)) {
                Handler handler = null;
                switch (handlerType) {
                    case TICK_HANDLER: handler = new TickHandler(); break;
                    default: break;
                }
                HANDLER_POOL.put(handlerType, handler);
            }
            return HANDLER_POOL.get(handlerType);
        }
    }

    interface Handler {
        /**
         * 处理
         * @param readInfo
         */
        void handle(ReadInfo readInfo);

        /**
         * 响应
         * @param ctx
         */
        void resp(ChannelHandlerContext ctx, ReadInfo readInfo);

        /**
         * 获取请求信息
         * @param ctx
         * @param msg
         * @return
         */
        ReadInfo getReadInfo(ChannelHandlerContext ctx, Object msg);
    }

    enum HandlerType {
        /**
         * TickHandler
         */
        TICK_HANDLER;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy