net.lyonlancer5.mcmp.karasu.util.VersionIdentifier.java Source code

Java tutorial

Introduction

Here is the source code for net.lyonlancer5.mcmp.karasu.util.VersionIdentifier.java

Source

/***************************************************************************\
* Copyright 2016 [Lyonlancer5]                                              *
*                                                                           *
* Licensed under the Apache License, Version 2.0 (the "License");           *
* you may not use this file except in compliance with the License.          *
* You may obtain a copy of the License at                                   *
*                                                                           *
*     http://www.apache.org/licenses/LICENSE-2.0                            *
*                                                                           *
* Unless required by applicable law or agreed to in writing, software       *
* distributed under the License is distributed on an "AS IS" BASIS,         *
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  *
* See the License for the specific language governing permissions and       *
* limitations under the License.                                            *
\***************************************************************************/
package net.lyonlancer5.mcmp.karasu.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.io.IOUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.google.common.collect.Maps;

import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.Loader;
import cpw.mods.fml.common.gameevent.TickEvent;
import cpw.mods.fml.relauncher.Side;
import net.minecraft.event.ClickEvent;
import net.minecraft.util.ChatComponentText;

public class VersionIdentifier extends Thread {
    private static final VersionIdentifier instance = new VersionIdentifier();
    private static final Logger LOGGER = LogManager.getLogger("Project Karasu ~ Version Check");

    //Update stuff
    private final String remoteUpdateLoc;
    private final File localUpdateLoc;

    private boolean isLatest = false;
    private boolean hasChecked = false;
    private boolean isPre = false;

    private String latestVersion = "";
    private String updateLink = "";
    private long date = 0L;

    //Compatibility stuff
    private final String remoteCompatLoc;
    private final File localCompatLoc;

    private VersionIdentifier() {
        setName("Project Karasu - Version Check");
        remoteUpdateLoc = "https://raw.githubusercontent.com/Lyonlancer5/Project-Karasu/master/update";
        localUpdateLoc = new File(Constants.MAIN_DIR, "update");

        remoteCompatLoc = "https://raw.githubusercontent.com/Lyonlancer5/Project-Karasu/master/compat";
        localCompatLoc = new File(Constants.MAIN_DIR, "compat");
    }

    public static VersionIdentifier instance() {
        return instance;
    }

    /**
     * Checks if the given version is compatible with the current version running
     * @param remoteVersion The version we are connecting to
     * @param remoteSide The side of the target connection
     */
    public boolean isCompatibleVersion(String remoteVersion, Side remoteSide) {
        Constants.LOGGER.info("Remote version: " + remoteVersion + " @ Side." + remoteSide.name());
        Constants.LOGGER.info(
                "Local version: " + Constants.VERSION + " @ Side." + FMLCommonHandler.instance().getSide().name());

        try {
            if (!localCompatLoc.exists()
                    || (System.currentTimeMillis() - localCompatLoc.lastModified()) > 604800000000L) {
                ModFileUtils.download(remoteCompatLoc, localCompatLoc);
            }

            List<String> lines = IOUtils.readLines(new FileInputStream(localCompatLoc));
            for (String s : lines) {
                String[] pars = s.split(":");
                if (pars[0].equalsIgnoreCase(Constants.VERSION)) {
                    for (String oneVer : pars[1].split(",")) {
                        if (oneVer.equals(remoteVersion))
                            return true;
                        else
                            continue;
                    }
                }
            }

        } catch (Exception e) {
            //NOISE
        }

        Map<String, Integer> localv = identify(Constants.VERSION), remotev = identify(remoteVersion);
        if (remotev.get("major") != localv.get("major"))
            return false;
        if (remotev.get("minor") != localv.get("minor"))
            return false;
        if (remotev.get("revision") != localv.get("revision"))
            return false;

        if (remotev.get("is-pre-release") == localv.get("is-pre-release")) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * Identifies the version via the given {@code format}
     * and returns a map instance with the following keys:
     * 
     * "major": the major version
     * "minor": the minor version
     * "revision": the revision no.
     * "build": the build no.
     * "pre-release-id": the pre-release ID, can be negative if it is a stable version
     * "is-pre-release": determines whether the format given is a pre-release or not (0 for false, 1 for true)
     */
    public static Map<String, Integer> identify(String format) {
        HashMap<String, Integer> vars = Maps.newHashMap();
        String[] var0 = format.split("\\.");
        if (var0.length < 4)
            return null;

        int major = Integer.parseInt(var0[0]), minor = Integer.parseInt(var0[1]),
                revision = Integer.parseInt(var0[2]);
        int build, preId = 0;

        if (var0[3].contains("-pre")) {
            String[] var1 = var0[3].split("-");
            build = Integer.parseInt(var1[0]);
            preId = Integer.parseInt(var1[1].substring(3));
            vars.put("pre-release-id", Integer.valueOf(preId));
            vars.put("is-pre-release", Integer.valueOf(1));
        } else {
            build = Integer.parseInt(var0[3]);
            vars.put("pre-release-id", Integer.valueOf(-1));
            vars.put("is-pre-release", Integer.valueOf(0));
        }

        vars.put("major", major);
        vars.put("minor", minor);
        vars.put("revision", revision);
        vars.put("build", build);

        return vars;
    }

    public void run() {
        if (!ModFileUtils.isDevEnv) {

            //MARKER: Do check whether the thread is restarted, just in case...
            if (!hasChecked) {
                //MARKER: First off, download a local copy of the cache
                try {
                    LOGGER.info("Querying master repository");
                    ModFileUtils.download(remoteUpdateLoc, localUpdateLoc);
                } catch (IOException e) {
                    LOGGER.warn("Failed to query remote repository");
                    isLatest = true;
                    hasChecked = true;
                    return;
                }

                //MARKER: Load the cache and get the latest version
                try {
                    LOGGER.info("Loading update cache");
                    //mcversion:<stable>:version:date_in_long:url
                    //mcversion:<pre>:version:date_in_long:url

                    List<String> lines = IOUtils.readLines(new FileInputStream(localUpdateLoc));
                    for (String s : lines) {
                        String[] params = s.split(":");
                        if (params[0].equals(Loader.MC_VERSION)) {
                            if (isPre && params[1].equals("pre")) {
                                latestVersion = params[2];
                                date = Long.parseLong(params[3]);
                                updateLink = params[4];
                            } else if (!isPre && params[1].equals("stable")) {
                                latestVersion = params[2];
                                date = Long.parseLong(params[3]);
                                updateLink = params[4];
                            }
                            break;
                        }
                    }
                } catch (IOException e) {
                    LOGGER.warn("Failed to load local cache", e);
                    isLatest = true;
                    hasChecked = true;
                    return;
                }

                //MARKER: Then compare EACH
                Map<String, Integer> local = identify(Constants.VERSION), remote = identify(latestVersion);
                if (!isPre) {
                    if (remote.get("major") > local.get("major") || remote.get("minor") > local.get("minor")
                            || remote.get("revision") > local.get("revision")
                            || remote.get("build") > local.get("build")) {
                        LOGGER.info("A new update for Project Karasu is available!");
                        LOGGER.info("v" + latestVersion + " - released on "
                                + ((new SimpleDateFormat("MM/dd/yyyy")).format(new Date(date))));
                        hasChecked = true;
                        isLatest = false;
                        return;
                    }
                } else {
                    if (remote.get("pre-release-id") > local.get("pre-release-id")) {
                        LOGGER.info("A pre-release update has been released");
                        LOGGER.info("v" + latestVersion + " - released on "
                                + ((new SimpleDateFormat("MM/dd/yyyy")).format(new Date(date))));
                        hasChecked = true;
                        isLatest = false;
                        return;
                    }
                }

                isLatest = true;
                hasChecked = true;
                LOGGER.info("No updates found");
            }
        }
    }

    public static class UpdateNotifier {

        private boolean hasNotified = false;

        public void notify(TickEvent.PlayerTickEvent event) {
            if (!hasNotified && event.player.worldObj.isRemote && !VersionIdentifier.instance().isLatest) {
                ChatComponentText cct = new ChatComponentText("\u00a76Project Karasu has an update - Get it here!");
                cct.getChatStyle().setChatClickEvent(
                        new ClickEvent(ClickEvent.Action.OPEN_URL, VersionIdentifier.instance().updateLink));
                event.player.addChatMessage(cct);
                hasNotified = true;
            }

            if (!hasNotified && event.player.worldObj.isRemote && VersionIdentifier.instance().isLatest) {
                ChatComponentText chat = new ChatComponentText(
                        "\u00a76Project Karasu - The Backporting Initiative is loaded - v" + Constants.VERSION);
                event.player.addChatMessage(chat);
                hasNotified = true;
            }
        }

        public static void register() {
            if (!ModFileUtils.isDevEnv) {
                Constants.LOGGER.info("Running update thread");
                FMLCommonHandler.instance().bus().register(new UpdateNotifier());
            }
        }
    }
}