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

com.godmao.mqbroker.Broker Maven / Gradle / Ivy

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

import com.godmao.mqbroker.message.MultipleMessage;
import com.godmao.mqbroker.message.SingleMessage;
import com.godmao.netty.channel.ChannelService;
import com.godmao.netty.server.AbstractServer;
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.concurrent.DefaultThreadFactory;
import io.netty.util.concurrent.Future;
import io.netty.util.internal.ObjectUtil;

import java.util.*;
import java.util.concurrent.TimeUnit;

public class Broker extends AbstractServer {
    private final String name;

    public static void main(String[] args) {
        Map arguments = new HashMap<>();
        for (String arg : args) {
            String[] parts = arg.split("=");
            if (parts.length == 2) {
                String name = parts[0].startsWith("--") ? parts[0].substring(2) : parts[0];
                arguments.put(name, parts[1]);
            }
        }

        String portKey = "broker.port";
        String nameKey = "broker.name";
        final int port = Integer.parseInt(arguments.getOrDefault(portKey, System.getProperty(portKey, "10001")));
        final String name = arguments.getOrDefault(nameKey, System.getProperty(nameKey, "broker"));
        //
        Broker broker = new Broker(port, name);
        broker.start();
    }


    public Broker(int port, String name) {
        super(port);
        ObjectUtil.checkNonEmpty(name, "Broker name is Empty!");
        this.name = name;
//        this.deadLetterQueue = new DeadLetterQueue(1000);
        log.info("[port]: {}", port);
        log.info("[name]: {}", name);
        setChannelInitializer(new BrokerInitializer(this));
        setChannelService(new ChannelService(name + port + "-channels"));
        setParentGroup(Epoll.isAvailable() ?
                               new EpollEventLoopGroup(1, new DefaultThreadFactory(name + port + "-parent")) :
                               new NioEventLoopGroup(1, new DefaultThreadFactory(name + port + "-parent")));
        setChildGroup(Epoll.isAvailable() ?
                              new EpollEventLoopGroup(new DefaultThreadFactory(name + port + "-child")) :
                              new NioEventLoopGroup(new DefaultThreadFactory(name + port + "-child")));
    }


    /**
     * 获取broker的名称
     */
    public String getName() {
        return name;
    }


    /**
     * 获取主题和对应的订阅数量
     */
    public Map getTopicCount() {
        final Map topicCount = new HashMap<>();
        for (final Channel channel : getChannelService()) {
            if (!channel.isActive()) {
                continue;
            }
            final Boolean authorization = channel.attr(Static.AUTHORIZATION).get();

            if (null == authorization || !authorization) {
                continue;
            }
            final Set topics = channel.attr(Static.TOPIC).get();

            for (final String topic : topics) {
                Integer count = topicCount.getOrDefault(topic, 0);
                topicCount.put(topic, ++count);
            }
        }
        return topicCount;
    }


    @Override
    public void onOpen(ChannelHandlerContext ctx) {
        final Channel channel = ctx.channel();
        channel.attr(Static.AUTHORIZATION).set(false);
        channel.attr(Static.TOPIC).set(new LinkedHashSet<>());

        //
        channel.eventLoop().schedule(() -> {
            if (!channel.isActive()) {
                return;
            }
            if (!channel.attr(Static.AUTHORIZATION).get()) {
                channel.close();
                log.info("[连接失败]-[{}-{}]: {} {}", ctx.channel().attr(ChannelService.CHANNELID).get(), ctx.channel().id().asShortText(), ctx.channel().attr(ChannelService.CHANNELADDRESS).get(), "未绑定");
            }
        }, 30, TimeUnit.SECONDS);
    }

    @Override
    public void onClose(ChannelHandlerContext ctx) {
        log.warn("[连接断开]-[{}-{}]: {}", ctx.channel().attr(ChannelService.CHANNELID).get(), ctx.channel().id().asShortText(), ctx.channel().attr(ChannelService.CHANNELADDRESS).get());
    }

    @Override
    public void onError(ChannelHandlerContext ctx, Throwable throwable) {
        log.error("[连接异常]-[{}]:", ctx.channel().attr(ChannelService.CHANNELID).get() + "-" + ctx.channel().id().asShortText(), throwable);
    }

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

    public Future send(final MultipleMessage.Response message, final Channel channel, final int retryCount, final int delay) {
        return send0(message, channel, channel.newPromise(), retryCount, delay);
    }

    public Future send(final SingleMessage.Response message, final Channel channel, final int retryCount, final int delay) {
        return send0(message, channel, channel.newPromise(), retryCount, delay);
    }


    /**
     * 发送消息
     *
     * @param message    消息
     * @param channel    发送消息的会话
     * @param promise    会话的约定
     * @param retryCount 发送失败重试次数
     * @param delay      重试延时发送间隔 /s
     * @return {@link ChannelFuture}
     */
    private Future send0(final Object message, final Channel channel, final ChannelPromise promise, final int retryCount, final int delay) {
        channel.writeAndFlush(message).addListener((ChannelFutureListener) future -> {
            if (future.isSuccess()) {
                promise.trySuccess();
                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;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy