com.kyne.webby.bukkit.RTKModuleSocket.java Source code

Java tutorial

Introduction

Here is the source code for com.kyne.webby.bukkit.RTKModuleSocket.java

Source

/*
 * Copyright KyneSilverhide 2010-2011
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.kyne.webby.bukkit;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.io.IOUtils;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;

import com.kyne.webby.commons.BackupUtils;
import com.kyne.webby.commons.BackupUtils.BackupMode;
import com.kyne.webby.commons.LogHelper;
import com.kyne.webby.commons.protocol.ServerInfos;
import com.kyne.webby.commons.protocol.WebbyLocalData;
import com.kyne.webby.commons.protocol.WebbyPlayer;

/**
 * This class will listen to all requests from the RTK module (and WebbyWebServer) and answer with informations
 */
public class RTKModuleSocket extends Thread {

    private final BukkitWebbyPlugin plugin;
    private final ServerSocket serverSocket;
    //   private int requestCount = 0;

    public RTKModuleSocket(final int port, final BukkitWebbyPlugin plugin) throws IOException {
        this.serverSocket = new ServerSocket(port);
        this.plugin = plugin;
        LogHelper.initLogger("BukkitWebby", "Minecraft");
    }

    @Override
    public void run() {
        LogHelper.info("Webby Socket (BukkitPlugin) is listening on port : " + this.serverSocket.getLocalPort());
        while (!this.serverSocket.isClosed()) {
            //         this.requestCount++;
            Socket clientSocket = null;
            ObjectInputStream ois = null;
            ObjectOutputStream oos = null;
            try {
                clientSocket = this.serverSocket.accept();
                ois = new ObjectInputStream(clientSocket.getInputStream());
                oos = new ObjectOutputStream(clientSocket.getOutputStream());

                final WebbyLocalData request = (WebbyLocalData) ois.readObject();
                final WebbyLocalData response = this.handleRequest(request);
                oos.writeObject(response);
            } catch (final SocketException e) {
                LogHelper.warn("Socket has been closed. If bukkit is stopping or restarting, this is normal");
            } catch (final IOException e) {
                LogHelper.error("An error occured while waiting for connections", e);
            } catch (final ClassNotFoundException e) {
                LogHelper.error("Unsupported object was sent to Webby ", e);
            } finally {
                IOUtils.closeQuietly(ois);
                IOUtils.closeQuietly(oos);
                IOUtils.closeQuietly(clientSocket);
            }
        }
    }

    /**
     * As Bukkit doens't like multithread, we will only handle one request at a time to avoid concurrent modifications
     * @return
     */
    private synchronized WebbyLocalData handleRequest(final WebbyLocalData request) {
        final Map<String, Object> responseParams = new HashMap<String, Object>();
        final CommandSender sender = Bukkit.getConsoleSender();
        switch (request.getRequestType()) {
        case PING:
            responseParams.put("DATA", true);
            break;
        case GET_INFOS:
            getInfos(responseParams);
            break;
        case BACKUP:
            backupServer(sender, (String) request.getRequestParams().get("DEFAULT_WORLD_NAME"));
            if (request.getRequestParams().containsKey("NOTIFY_RESTORE")) {
                boolean notify = (Boolean) request.getRequestParams().get("NOTIFY_RESTORE");
                if (notify && Bukkit.getOnlinePlayers().size() > 0) {
                    Bukkit.broadcastMessage(
                            "A full server restore has been planned. The server will now be restarted.");
                }
            }
            break;
        case SEND_COMMAND:
            final String command = (String) request.getRequestParams().get("COMMAND");
            LogHelper.info("Sending command " + command);
            // Special commands
            if (command != null && command.startsWith("heal")) {
                final String playerName = command.replaceFirst("heal ", "");
                if (playerName == null || "".equals(playerName.trim())) {
                    LogHelper.warn("Empty or null player name given");
                }
                Player matchingPlayer = null;
                for (final Player player : Bukkit.getOnlinePlayers()) {
                    if (player.getName().trim().equalsIgnoreCase(playerName.trim())) {
                        matchingPlayer = player;
                        break;
                    }
                }
                if (matchingPlayer != null) {
                    matchingPlayer.setHealth(matchingPlayer.getMaxHealth());
                } else {
                    LogHelper.warn("Can't heal player " + playerName + " because it can't be found");
                }
            }
            // Real commands
            else {
                Bukkit.dispatchCommand(sender, command);
            }
            break;
        case RELOAD_BUKKIT:
            Bukkit.reload();
            break;
        case STOP:
            Bukkit.shutdown();
            break;
        case SAVE_WORLDS:
            LogHelper.info("Saving all worlds...");
            List<World> worlds = new ArrayList<World>(Bukkit.getWorlds());
            for (final World world : worlds) {
                world.save();
            }
            LogHelper.info("Saving all online players...");
            Collection<? extends Player> players = Bukkit.getOnlinePlayers();
            for (final Player player : players) {
                player.saveData();
            }
            LogHelper.info("All words and players saved.");
        default:
            responseParams.put("ERROR", "Unsupported request type");
            break;
        }
        return new WebbyLocalData(request.getRequestType(), responseParams);
    }

    private void getInfos(final Map<String, Object> responseParams) {
        final List<WebbyPlayer> playerList = new ArrayList<WebbyPlayer>();
        for (final Player player : Bukkit.getOnlinePlayers()) {
            playerList.add(new WebbyPlayer(player.getName(), player.isOp()));
        }
        final Runtime runtime = Runtime.getRuntime();
        final long freeMemory = runtime.freeMemory();
        final long totalMemory = runtime.totalMemory();
        final long maxMemory = runtime.maxMemory();
        final int mb = 1024 * 1024;

        final ServerInfos serverInfos = new ServerInfos(Bukkit.getVersion(), Bukkit.getMaxPlayers(),
                playerList.size(), playerList, freeMemory / mb, totalMemory / mb, maxMemory / mb);
        responseParams.put("DATA", serverInfos);
    }

    private void backupServer(final CommandSender sender, final String defaultWorldName) {
        LogHelper.info("Starting backup!");
        // Warn users and save their stuff
        if (Bukkit.getOnlinePlayers().size() > 0) {
            Bukkit.broadcastMessage("Server backup is starting. You may experiment some lag.");
            for (final Player player : Bukkit.getOnlinePlayers()) {
                player.saveData();
            }
        }
        // Save, then disable auto-save
        List<World> worlds = new ArrayList<World>(Bukkit.getWorlds());
        for (final World world : worlds) {
            world.save();
        }
        Bukkit.dispatchCommand(sender, "save-off");
        //Start the backup
        final BackupMode backupMode = BackupMode.valueOf(plugin.getConfig().getString("webby.backup_mode", "SMP"));
        if (backupMode == BackupMode.BUKKIT) {
            BackupUtils.startBukkitBackup(this.plugin.getServer());
        } else {
            BackupUtils.startSMPBackup(this.plugin.getServer(), defaultWorldName);
        }
        //Enable auto save
        Bukkit.dispatchCommand(sender, "save-on");
        LogHelper.info("All backup tasks completed !");
    }

    public void closeSocket() {
        try {
            this.serverSocket.close();
        } catch (final IOException e) {
            LogHelper.error("Unable to close the Webby socket", e);
        }
    }
}