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

net.isger.brick.bus.NettyEndpoint Maven / Gradle / Ivy

The newest version!
package net.isger.brick.bus;

import java.util.List;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufInputStream;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandler;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOutboundHandler;
import io.netty.handler.codec.DatagramPacketDecoder;
import io.netty.handler.codec.MessageToByteEncoder;
import io.netty.handler.codec.MessageToMessageDecoder;
import io.netty.util.AttributeKey;
import net.isger.brick.Constants;
import net.isger.brick.auth.AuthCommand;
import net.isger.brick.auth.AuthHelper;
import net.isger.brick.auth.AuthIdentity;
import net.isger.brick.auth.BaseToken;
import net.isger.brick.core.Console;
import net.isger.util.Helpers;
import net.isger.util.anno.Alias;
import net.isger.util.anno.Ignore;
import net.isger.util.anno.Ignore.Mode;

/**
 * Netty端点
 * 
 * @author issing
 */
@Ignore
public abstract class NettyEndpoint extends SocketEndpoint {

    private static final AttributeKey ATTR_IDENTITY = AttributeKey.valueOf("brick.bus.netty.channel.identity");

    private static final AttributeKey ATTR_IDENTITY_LOCAL = AttributeKey.valueOf("brick.bus.netty.channel.identity.local");

    /** 控制台 */
    @Ignore(mode = Mode.INCLUDE)
    @Alias(Constants.SYSTEM)
    protected Console console;

    /** 总线 */
    @Ignore(mode = Mode.INCLUDE)
    @Alias(Constants.SYSTEM)
    private Bus bus;

    @Ignore(mode = Mode.INCLUDE)
    private boolean createable;

    @Ignore(mode = Mode.INCLUDE)
    private Integer timeout;

    public NettyEndpoint() {
    }

    public NettyEndpoint(String host, int port) {
        super(host, port);
    }

    /**
     * 打开
     */
    protected void open() {
        super.open();
        /* 初始协议 */
        final ChannelOutboundHandler encoder = new NettyEncoder();
        NettyDecoder pendingDecoder = new NettyDecoder();
        final ChannelInboundHandler decoder = CHANNEL_TCP.equalsIgnoreCase(getChannel()) ? pendingDecoder : new DatagramPacketDecoder(pendingDecoder);
        /* 初始处理 */
        final ChannelInboundHandler handler = new NettyHandler();
        /* 引导处理 */
        bootstrap(new ChannelInitializer() {
            protected void initChannel(Channel channel) throws Exception {
                channel.pipeline().addLast(decoder, encoder, handler);
            }
        });
    }

    /**
     * 引导
     *
     * @param initializer
     */
    protected abstract void bootstrap(ChannelInitializer initializer);

    /**
     * 接收消息
     *
     * @param identity
     * @param message
     * @return
     */
    protected Object receive(AuthIdentity identity, Object message) {
        return getHandler().handle(this, identity, message);
    }

    /**
     * 发送消息
     *
     * @param context
     * @param message
     */
    protected void send(ChannelHandlerContext context, Object message) {
        context.channel().writeAndFlush(message);
    }

    /**
     * 获取身份
     * 
     * @param context
     * @return
     */
    protected AuthIdentity getIdentity(ChannelHandlerContext context) {
        return context.channel().attr(ATTR_IDENTITY).get();
    }

    /**
     * 设置身份
     * 
     * @param context
     * @param identity
     */
    protected void setIdentity(ChannelHandlerContext context, AuthIdentity identity) {
        context.channel().attr(ATTR_IDENTITY).setIfAbsent(identity);
    }

    /**
     * 关闭
     */
    protected void close() {
        super.close();
    }

    @Sharable
    private class NettyEncoder extends MessageToByteEncoder {
        protected void encode(ChannelHandlerContext context, Object message, ByteBuf out) throws Exception {
            byte[] value = getProtocol().getEncoder().encode(message);
            if (value != null) {
                out.writeBytes(value);
            }
        }
    }

    @Sharable
    private class NettyDecoder extends MessageToMessageDecoder {
        protected void decode(ChannelHandlerContext context, ByteBuf in, List out) throws Exception {
            Object message = getProtocol().getDecoder().decode(new ByteBufInputStream(in));
            if (message != null) {
                out.add(message);
            }
        }
    }

    @Sharable
    private class NettyHandler extends ChannelInboundHandlerAdapter {
        public void channelActive(ChannelHandlerContext context) throws Exception {
            super.channelActive(context);
            /* 初始连接会话 */
            if (getIdentity(context) == null) {
                AuthCommand cmd = AuthHelper.makeCommand(Constants.SYSTEM, new BaseToken(context, context));
                cmd.setOperate(AuthCommand.OPERATE_LOGIN);
                console.execute(cmd);
                setIdentity(context, cmd.getIdentity());
                context.channel().attr(ATTR_IDENTITY_LOCAL).set(true);
            }
        }

        public void channelRead(ChannelHandlerContext context, Object message) throws Exception {
            AuthIdentity identity = getIdentity(context);
            identity.active(createable); // 激活会话
            if ((message = receive(identity, message)) != null) {
                send(context, message);
            }
        }

        public void channelInactive(ChannelHandlerContext context) throws Exception {
            /* 注销连接会话 */
            if (Helpers.toBoolean(context.channel().attr(ATTR_IDENTITY_LOCAL).get())) {
                AuthIdentity identity = getIdentity(context);
                if (identity != null) {
                    AuthCommand cmd = AuthHelper.makeCommand(Constants.SYSTEM, identity.getToken());
                    cmd.setIdentity(identity);
                    cmd.setOperate(AuthCommand.OPERATE_LOGOUT);
                    console.execute(cmd);
                }
            }
            super.channelInactive(context);
        }
    }

}