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

com.tencent.trpc.transport.netty.NettyServerHandler Maven / Gradle / Ivy

/*
 * Tencent is pleased to support the open source community by making tRPC available.
 *
 * Copyright (C) 2023 THL A29 Limited, a Tencent company. 
 * All rights reserved.
 *
 * If you have downloaded a copy of the tRPC source code from Tencent,
 * please note that tRPC source code is licensed under the Apache 2.0 License,
 * A copy of the Apache 2.0 License can be found in the LICENSE file.
 */

package com.tencent.trpc.transport.netty;

import com.tencent.trpc.core.common.config.ProtocolConfig;
import com.tencent.trpc.core.logger.Logger;
import com.tencent.trpc.core.logger.LoggerFactory;
import com.tencent.trpc.core.transport.Channel;
import com.tencent.trpc.core.transport.ChannelHandler;
import com.tencent.trpc.core.utils.NetUtils;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import java.net.InetSocketAddress;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

@io.netty.channel.ChannelHandler.Sharable
public class NettyServerHandler extends ChannelDuplexHandler {

    private static final Logger logger = LoggerFactory.getLogger(NettyServerHandler.class);

    /**
     * Client channel maps, and the key is the address of a client, like ip:port.
     */
    private final ConcurrentMap clientChannels = new ConcurrentHashMap<>();
    private final ChannelHandler handler;
    private final ProtocolConfig config;
    private final boolean isTcp;

    public NettyServerHandler(ChannelHandler handler, ProtocolConfig config, boolean isTcp) {
        this.handler = handler;
        this.config = config;
        this.isTcp = isTcp;
    }

    private Channel removeClientChannel(ChannelHandlerContext ctx) {
        if (isTcp) {
            return clientChannels
                    .remove(NetUtils.toIpPort((InetSocketAddress) ctx.channel().remoteAddress()));
        }
        return null;
    }

    private Channel addClientChannel(ChannelHandlerContext ctx, NettyChannel channel) {
        if (channel != null && isTcp) {
            return clientChannels
                    .put(NetUtils.toIpPort((InetSocketAddress) ctx.channel().remoteAddress()),
                            channel);
        }
        return null;
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        NettyChannel channel = NettyChannelManager.getOrAddChannel(ctx.channel(), config);
        try {
            addClientChannel(ctx, channel);
            handler.connected(channel);
        } finally {
            NettyChannelManager.removeChannelIfDisconnected(ctx.channel());
        }
    }


    @Override
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise)
            throws Exception {
        super.write(ctx, msg, promise);
        NettyChannel channel = NettyChannelManager.getOrAddChannel(ctx.channel(), config);
        try {
            handler.send(channel, msg);
        } finally {
            NettyChannelManager.removeChannelIfDisconnected(ctx.channel());
        }
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        try {
            NettyChannel nettyChannel = NettyChannelManager.getOrAddChannel(ctx.channel(), config);
            handler.received(nettyChannel, msg);
        } finally {
            NettyChannelManager.removeChannelIfDisconnected(ctx.channel());
        }
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        NettyChannel channel = NettyChannelManager.getOrAddChannel(ctx.channel(), config);
        try {
            removeClientChannel(ctx);
            handler.disconnected(channel);
        } finally {
            NettyChannelManager.removeChannelIfDisconnected(ctx.channel());
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        try {
            NettyChannel channel = NettyChannelManager.getOrAddChannel(ctx.channel(), config);
            handler.caught(channel, cause);
            // only close the channel in a TCP scenario.
            if (ctx.channel().isActive() && isTcp) {
                logger.error("close channel:{}, the exception caught:", channel, cause);
                ctx.close();
            }
        } finally {
            NettyChannelManager.removeChannelIfDisconnected(ctx.channel());
        }
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            NettyChannel channel = NettyChannelManager.getOrAddChannel(ctx.channel(), config);
            try {
                IdleState state = ((IdleStateEvent) evt).state();
                logger.warn("idle event[{}] trigger, close channel:{}", state, channel);
                channel.close();
            } finally {
                NettyChannelManager.removeChannelIfDisconnected(ctx.channel());
            }
        }
        super.userEventTriggered(ctx, evt);
    }

    public ConcurrentMap getChannels() {
        return clientChannels;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy