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

com.godmao.mqserver.AbstractServer Maven / Gradle / Ivy

There is a newer version: 0.2.7.RELEASE
Show newest version
package com.godmao.mqserver;

import com.godmao.mqserver.handler.TopicSubscribeCancelMessageEncoderHandler;
import com.godmao.mqserver.handler.TopicSubscribeMessageEncoderHandler;
import com.godmao.mqserver.message.*;
import com.godmao.netty.channel.ChannelService;
import com.godmao.netty.client.AbstractClient;
import com.godmao.netty.common.NetUtil;
import io.netty.channel.*;
import io.netty.channel.epoll.Epoll;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.util.AttributeKey;
import io.netty.util.concurrent.*;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

public abstract class AbstractServer extends AbstractClient {
    public static final AttributeKey              AUTHORIZATION = AttributeKey.valueOf("mate-authorization");
    public static final AttributeKey                 TOPIC_VERSION = AttributeKey.valueOf("mate-topic-version");
    public static final AttributeKey> TOPIC         = AttributeKey.valueOf("mate-topic");


    private final String        name;
    private final AtomicLong    counter  = new AtomicLong();
    private final EventExecutor executor = new DefaultEventExecutor();

    public AbstractServer() {
        this(NetUtil.LOCAL_IP);
    }

    public AbstractServer(String name) {
        log.info("name: {}", name);
        this.name = name;
        setChannelInitializer(new ServerInitializer(this));
        setChannelService(new ChannelService(name + "-channel-service"));
        setGroup(Epoll.isAvailable() ?
                         new EpollEventLoopGroup(new DefaultThreadFactory(name + "-server")) :
                         new NioEventLoopGroup(new DefaultThreadFactory(name + "-server")));
    }

    public String getName() {
        return name;
    }

    @Override
    public synchronized void shutdown() {
        if (!this.executor.isShutdown()) {
            this.executor.shutdownGracefully().addListener(future -> {
                if (!future.isSuccess()) {
                    log.error("Error while shutting down executor", future.cause());
                }
            });
        }
        super.shutdown();
    }

    @Override
    public void onOpen(ChannelHandlerContext ctx) {
        final Channel channel = ctx.channel();
        channel.attr(AUTHORIZATION).set(false);
        channel.attr(TOPIC).set(new HashMap<>());
        channel.attr(TOPIC_VERSION).set(-1L);

        ctx.writeAndFlush(new BindMessage(name, NetUtil.LOCAL_IP));
    }


    @Override
    public synchronized void start() {
        //
        super.start();
        //
        scheduledSendHeartbeat();
    }


    // 定时发送心跳包
    private void scheduledSendHeartbeat() {
        executor.scheduleWithFixedDelay(() -> {
            for (final Channel channel : getChannelService()) {
                if (!channel.isActive()) {
                    continue;
                }
                if (!channel.isWritable()) {
                    continue;
                }
                if (!channel.attr(AUTHORIZATION).get()) {
                    continue;
                }
                channel.writeAndFlush(new HeartbeatMessage.Response(channel.attr(TOPIC_VERSION).get()));
            }
        }, 30, 30, TimeUnit.SECONDS);
    }

    @Override
    public void onMessage(ChannelHandlerContext ctx, Object message) {
        log.warn("[未知消息]: {} {} {}", ctx.channel().attr(ChannelService.CHANNELID).get(), ctx.channel().attr(ChannelService.CHANNELADDRESS).get(), message);
    }


    public Future send(final SingleMessage.Response message) {
        return send(message, 0, 0);
    }

    public Future send(final MultipleMessage.Response message) {
        return send(message, 0, 0);
    }

    public Future send(final SingleMessage.Response message, final int retryCount, final int delay) {
        return send(message, new DefaultPromise<>(group.next()), retryCount, delay);
    }

    public Future send(final MultipleMessage.Response message, final int retryCount, final int delay) {
        return send(message, new DefaultPromise<>(group.next()), retryCount, delay);
    }

    public Future send(final SingleMessage.Response message, final Promise promise, final int retryCount, final int delay) {
        // 找到所有 活跃 绑定过 包含主题 的所有服务
        final Set matches_ = getChannelService().matches(
                channel -> channel.isActive() &&
                        channel.attr(AUTHORIZATION).get() &&
                        channel.attr(TOPIC).get().containsKey(message.getTopic())
        );

        if (matches_.isEmpty()) {
            if (retryCount < 1) {
                promise.setFailure(new Exception("No matching channels found: " + message.getTopic()));
            } else {
                super.group.next().schedule(() -> send(message, promise, retryCount - 1, delay * 2), delay, TimeUnit.SECONDS);
            }
        } else {
            // 选择一个channel(轮询策略)
            final int flag = Math.abs((int) (counter.incrementAndGet() % (long) matches_.size()));
            final Channel channel = (Channel) matches_.toArray()[flag];
            send0(message, channel, promise, retryCount, delay);
        }

        return promise;
    }


    public Future send(final MultipleMessage.Response message, final Promise promise, final int retryCount, final int delay) {
        // 找到所有 活跃 绑定过 包含主题 的所有服务
        final Set matches_ = getChannelService().matches(
                channel -> channel.isActive() &&
                        channel.attr(AUTHORIZATION).get() &&
                        channel.attr(TOPIC).get().keySet().containsAll(message.getTopics())
        );

        if (matches_.isEmpty()) {
            if (retryCount < 1) {
                promise.setFailure(new Exception("No matching channels found: " + message.getTopics()));
            } else {
                super.group.next().schedule(() -> send(message, promise, retryCount - 1, delay * 2), delay, TimeUnit.SECONDS);
            }
        } else {
            // 选择一个channel(轮询策略)
            final int flag = Math.abs((int) (counter.incrementAndGet() % (long) matches_.size()));
            final Channel channel = (Channel) matches_.toArray()[flag];
            send0(message, channel, promise, retryCount, delay);
        }

        return promise;
    }

    /**
     * 发送消息
     *
     * @param message    消息
     * @param channel    发送消息的会话
     * @param promise    会话的约定
     * @param retryCount 发送失败重试次数
     * @param delay      重试延时发送间隔 /s
     * @return {@link ChannelFuture}
     */
    private Future send0(final Object message, final Channel channel, final Promise promise, final int retryCount, final int delay) {
        channel.writeAndFlush(message).addListener((ChannelFutureListener) future -> {
            if (future.isSuccess()) {
                promise.trySuccess(null);
                return;
            }
            if (retryCount < 1 || !future.channel().isActive()) {
                promise.tryFailure(future.cause());
                return;
            }
            channel.eventLoop().schedule(() -> send0(message, channel, promise, retryCount - 1, delay * 2), delay, TimeUnit.SECONDS);
        });
        return promise;
    }


    /**
     * 消息订阅
     */
    public void subscribe(TopicSubscribeMessage subscribeMessage) {
        getChannelService().writeAndFlush(
                TopicSubscribeMessageEncoderHandler.INSTANCE.encode(subscribeMessage),
                channel -> channel.isActive() && channel.attr(AUTHORIZATION).get()
        );
    }

    public void subscribe(Set topics) {
        subscribe(new TopicSubscribeMessage(topics));
    }

    /**
     * 取消订阅
     */
    public void subscribeCancel(TopicSubscribeCancelMessage subscribeCancelMessage) {
        getChannelService().writeAndFlush(
                TopicSubscribeCancelMessageEncoderHandler.INSTANCE.encode(subscribeCancelMessage),
                channel -> channel.isActive() && channel.attr(AUTHORIZATION).get()
        );
    }

    public void subscribeCancel(Set topics) {
        subscribeCancel(new TopicSubscribeCancelMessage(topics));
    }

    public abstract void onMessage(ChannelHandlerContext ctx, final String topic, final byte[] data);

    public abstract void onOpen(ChannelHandlerContext ctx, final BindMessage bindMessage);
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy