cf.adriantodt.David.modules.cmds.FeedCmd.java Source code

Java tutorial

Introduction

Here is the source code for cf.adriantodt.David.modules.cmds.FeedCmd.java

Source

/*
 * This class was created by <AdrianTodt>. It's distributed as
 * part of the DavidBot. Get the Source Code in github:
 * https://github.com/adriantodt/David
 *
 * DavidBot is Open Source and distributed under the
 * GNU Lesser General Public License v2.1:
 * https://github.com/adriantodt/David/blob/master/LICENSE
 *
 * File Created @ [11/11/16 08:20]
 */

package cf.adriantodt.David.modules.cmds;

import cf.adriantodt.David.commands.base.Commands;
import cf.adriantodt.David.commands.base.Holder;
import cf.adriantodt.David.commands.base.ICommand;
import cf.adriantodt.David.loader.Module;
import cf.adriantodt.David.loader.Module.Command;
import cf.adriantodt.David.loader.Module.LoggerInstance;
import cf.adriantodt.David.loader.Module.PostReady;
import cf.adriantodt.David.loader.Module.Type;
import cf.adriantodt.David.modules.db.DBModule;
import cf.adriantodt.David.oldmodules.cmds.PushCmd;
import cf.adriantodt.utils.AsyncUtils;
import cf.adriantodt.utils.CollectionUtils;
import cf.adriantodt.utils.EncodingUtil;
import cf.adriantodt.utils.TaskManager;
import cf.adriantodt.utils.data.ConfigUtils;
import cf.brforgers.core.lib.IOHelper;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.gson.JsonObject;
import com.rometools.rome.feed.synd.SyndFeed;
import com.rometools.rome.io.SyndFeedInput;
import com.rometools.rome.io.XmlReader;
import net.dv8tion.jda.core.entities.TextChannel;
import org.apache.logging.log4j.Logger;

import java.net.URL;
import java.util.*;
import java.util.function.Function;

import static cf.adriantodt.David.modules.cmds.manager.PermissionsModule.BOT_OWNER;
import static cf.brforgers.core.lib.IOHelper.newURL;

@Module(name = "cmds.feed", type = Type.STATIC)
public class FeedCmd {
    private static final Set<Subscription> ALL = Collections.synchronizedSet(new HashSet<>());
    private static final Set<String> ALL_TYPES = Collections.synchronizedSet(new HashSet<>());
    @LoggerInstance
    private static Logger logger;
    private static int i = 0;

    @PostReady
    private static void lazyLoad() {
        logger.trace("Loading...");
        PushCmd.registerDynamicTypes(() -> ALL_TYPES, "feeds");

        DBModule.onDB(r -> r.table("feeds")).run().cursorExpected().forEach(json -> {
            JsonObject feed = json.getAsJsonObject();
            Subscription s = new Subscription(feed.get("pushName").getAsString(),
                    newURL(EncodingUtil.decodeURIComponent(feed.get("url").getAsString())),
                    feed.get("id").getAsString());

            if (feed.has("lastHashCode") && ConfigUtils.isJsonNumber(feed.get("lastHashCode")))
                s.setLastHashCode(feed.get("lastHashCode").getAsInt());
        });

        i = 1;
        logger.trace("k");

        TaskManager.startAsyncTask("Feed Loop", FeedCmd::loop, 5);
    }

    //TODO COMANDO BOM
    @Command("feed")
    private static ICommand createCommand() {
        return Commands.buildSimple("feed.usage", BOT_OWNER).setAction(event -> {
            PushCmd.subscribe(event.getChannel(), Sets.newHashSet("feed_"
                    + new FeedCmd.Subscription(event.getArg(2, 0), IOHelper.newURL(event.getArg(2, 1))).pushName));
            event.awaitTyping().getAnswers().bool(true).queue();
        }).build();
    }

    public static void loop() {
        logger.trace("Loop(" + i + ");");
        logger.trace("ALL.size() = " + ALL.size());
        cleanup();
        ALL.forEach(FeedCmd::onSendFeed);
        if (i == 0) {
            ALL.forEach(FeedCmd::onFeed);
            i = 12;
        } else
            i--;
        logger.trace("Loop.End;");
    }

    public static void cleanup() {
        ALL.removeIf(s -> !s.isActive());
        ALL.removeIf(s -> PushCmd.resolveTextChannels("feed_" + s.pushName).size() == 0);
    }

    public static void onFeed(Subscription subs) {
        try {
            SyndFeedInput input = new SyndFeedInput();
            SyndFeed feed = input.build(new XmlReader(subs.url));
            Holder<Integer> i = new Holder<>(0);
            Holder<Optional<Integer>> h = new Holder<>(Optional.empty());
            Lists.reverse(CollectionUtils.subListOn(feed.getEntries(),
                    entryPredicate -> subs.equalsLastHashCode(entryPredicate.getLink().hashCode())))
                    .forEach(entry -> {
                        i.var++;
                        subs.compiledPushes.add(FeedingUtil.handleEntry(subs, entry));
                        h.var = Optional.of(entry.getLink().hashCode());
                    });
            if (i.var != 0)
                logger.trace(subs.pushName + ".size() += " + i.var);
            h.var.ifPresent(subs::setLastHashCode);
        } catch (Exception e) {
            logger.error("Error while creating messages", e);
        }
    }

    public static void onSendFeed(Subscription subs) {
        if (subs.compiledPushes.size() == 0)
            return;
        logger.trace(subs.pushName + ".size() = " + subs.compiledPushes.size());
        AsyncUtils.async(() -> PushCmd.pushSimple("feed_" + subs.pushName, subs.compiledPushes.remove(0))).run();
    }

    public static class Subscription {
        public final URL url;
        public final String pushName, id;
        List<Function<TextChannel, String>> compiledPushes = Collections.synchronizedList(new ArrayList<>());
        private int lastHashCode = 0;
        private boolean active = true, loadedOnce = false;

        public Subscription(String pushName, URL url) {
            this(pushName, url, DBModule
                    .onDB(r -> r.table("feeds")
                            .insert(r.hashMap("pushName", pushName)
                                    .with("url", EncodingUtil.encodeURIComponent(url.toString()))
                                    .with("lastHashCode", null)))
                    .run().mapExpected().get("generated_keys").getAsJsonArray().get(0).getAsString());
        }

        private Subscription(String pushName, URL url, String id) {
            this.url = url;
            this.pushName = pushName;
            this.id = id;
            ALL.add(this);
            ALL_TYPES.add("feed_" + pushName);
        }

        public boolean equalsLastHashCode(int newestHashCode) {
            boolean v;
            //ignoreHashCode = true -> FALSE
            //ignoreHashCode = false -> getLastHashCode() == newestHashCode
            // - IntelliJ
            v = !ignoreHashCode() && (getLastHashCode() == newestHashCode);
            logger.trace(v);
            return v;
        }

        public int getLastHashCode() {
            return lastHashCode;
        }

        public void setLastHashCode(int lastHashCode) {
            this.lastHashCode = lastHashCode;
            this.loadedOnce = true;
            DBModule.onDB(r -> r.table("feeds").get(id).update(r.hashMap("lastHashCode", lastHashCode))).noReply();
        }

        public boolean ignoreHashCode() {
            return !loadedOnce;
        }

        public boolean isActive() {
            return active;
        }

        public void cancel() {
            this.active = false;
        }

        @Override
        protected void finalize() throws Throwable {
            cancel();
            AsyncUtils.async("Finalizer-AsyncJob", () -> {
                ALL_TYPES.remove("feed_" + pushName);
                DBModule.onDB(r -> r.table("feeds").get(id).delete()).noReply();
                PushCmd.unsubscribeAll(Collections.singleton(pushName));
            }).run();
            super.finalize();
        }
    }

}