Example #1
0
    def run(self):
        """Run the main program's logic."""

        # Change into the server's directory.
        os.chdir(self.args.server)

        # If we're only culling backups, do that and exit.
        if self.args.clean:
            return self.cull_backups()

        # Backups directory.
        backups = os.path.join(self.args.server, "backups")
        if not os.path.isdir(backups):
            log.info("Creating backups directory: {}".format(backups))
            os.mkdir(backups)

        # Connect to the Minecraft-Control server.
        log.info("Connecting to Minecraft control server...")
        self.client = MinecraftClient(
            host=self.config["host"],
            port=self.config["port"],
            password=self.config["password"],
            methods=[self.config["method"]],
        )
        self.client.add_handler("auth_ok", self.on_auth_ok)
        self.client.add_handler("auth_error", self.on_auth_error)
        self.client.add_handler("server_message", self.on_message)

        self.client.connect()
        self.client.start()
Example #2
0
    def run(self):
        """Run the main program's logic."""

        # Change into the server's directory.
        os.chdir(self.args.server)

        # If we're only culling backups, do that and exit.
        if self.args.clean:
            return self.cull_backups()

        # Backups directory.
        backups = os.path.join(self.args.server, "backups")
        if not os.path.isdir(backups):
            log.info("Creating backups directory: {}".format(backups))
            os.mkdir(backups)

        # Connect to the Minecraft-Control server.
        log.info("Connecting to Minecraft control server...")
        self.client = MinecraftClient(
            host=self.config["host"],
            port=self.config["port"],
            password=self.config["password"],
            methods=[self.config["method"]],
        )
        self.client.add_handler("auth_ok", self.on_auth_ok)
        self.client.add_handler("auth_error", self.on_auth_error)
        self.client.add_handler("server_message", self.on_message)

        self.client.connect()
        self.client.start()
Example #3
0
debug = False
host, port, password = None, None, None
whitelist = []

if sys.argv[1] == "--debug":
    debug = True
    host, port, password = sys.argv[2:5]
    whitelist = [x.lower() for x in sys.argv[5:]]
else:
    host, port, password = sys.argv[1:4]
    whitelist = [x.lower() for x in sys.argv[4:]]

# Connect to the server.
client = MinecraftClient(
    debug=debug,
    host=host,
    port=port,
    password=password,
)


def on_authed(client):
    print("Authentication successful!")
    client.sendline("say 01-gamemode.py demo started. Whitelist: {}".format(
        str(whitelist)))


def on_error(client, error):
    print("Failed to authenticate: {}".format(error))


def on_message(client, message):
Example #4
0
class Application:
    def __init__(self, args):
        """Initialize the application."""
        self.args = args

        # Verify settings.
        self.verify_args()

        self.config = dict()  # minecraft-control configuration
        self.client = None  # MinecraftClient instance
        self.today = datetime.datetime.utcnow().strftime("%Y-%m-%d_%H-%M-%S")
        self.world = self.get_world_name()
        log.info("Today's date/time: {}".format(self.today))

        # Load the minecraft-control configuration.
        self.load_mc_config()

    def verify_args(self):
        """Do some sanity checking on input arguments."""

        # The minecraft-control config file.
        if not os.path.isfile(self.args.config):
            log.error("{}: not a file".format(self.args.config))
            sys.exit(1)

        # The server directory.
        if not os.path.isfile("{}/server.properties".format(self.args.server)):
            log.error("{}: not a Minecraft server directory (no "
                      "server.properties file present)".format(
                          self.args.server))
            sys.exit(1)

    def load_mc_config(self):
        """Load the configuration from minecraft-control."""
        log.debug("Loading minecraft-control settings from {}".format(
            args.config))

        parser = RawConfigParser()
        with open(self.args.config, "r") as fh:
            parser.readfp(fh)

        self.config["host"] = parser.get("tcp-server", "address")
        self.config["port"] = parser.get("tcp-server", "port")
        self.config["password"] = parser.get("auth", "password")
        self.config["method"] = parser.get("auth", "method")

    def get_world_name(self):
        """Load the server.properties to find the world name."""

        with open("{}/server.properties".format(self.args.server), "r") as fh:
            for line in fh:
                if not "=" in line: continue
                parts = line.split("=", 1)
                key = parts[0].strip()
                value = parts[1].strip()

                if key == "level-name":
                    return value

        raise ValueError("No level-name found in server.properties!")

    def run(self):
        """Run the main program's logic."""

        # Change into the server's directory.
        os.chdir(self.args.server)

        # If we're only culling backups, do that and exit.
        if self.args.clean:
            return self.cull_backups()

        # Backups directory.
        backups = os.path.join(self.args.server, "backups")
        if not os.path.isdir(backups):
            log.info("Creating backups directory: {}".format(backups))
            os.mkdir(backups)

        # Connect to the Minecraft-Control server.
        log.info("Connecting to Minecraft control server...")
        self.client = MinecraftClient(
            host=self.config["host"],
            port=self.config["port"],
            password=self.config["password"],
            methods=[self.config["method"]],
        )
        self.client.add_handler("auth_ok", self.on_auth_ok)
        self.client.add_handler("auth_error", self.on_auth_error)
        self.client.add_handler("server_message", self.on_message)

        self.client.connect()
        self.client.start()

    def on_auth_ok(self, mc):
        """Handle successful authentication."""
        log.info("Connection to server established and authenticated!")

        # Target file name.
        fname = self.today + ".tar.gz"
        target = os.path.join("backups", fname)

        # Turn off saving and save the world now.
        log.info("Turning off auto-saving and saving the world now!")
        self.client.sendline("save-off")
        self.client.sendline("save-all")
        time.sleep(5)

        # Archive the world.
        log.info("Backing up the world as: {}".format(target))
        subprocess.call(["tar", "czvf", target, self.world])

        # Turn saving back on.
        time.sleep(5)
        log.info("Turning auto-saving back on!")
        self.client.sendline("save-on")

        # Cull old backups.
        self.cull_backups()
        quit()

    def cull_backups(self):
        """Trim the backup copies and remove older backups."""
        log.info("Culling backups...")

        # Date cut-off for daily backups.
        daily_cutoff = (
            datetime.datetime.utcnow() -
            datetime.timedelta(days=DAILY_BACKUPS)).strftime("%Y-%m-%d")
        log.debug("Daily cutoff date: {}".format(daily_cutoff))

        # Number of weekly backups spared.
        weekly_spared = 0

        # Check all the existing backups.
        for tar in sorted(os.listdir("backups"), reverse=True):
            if not tar.endswith(".tar.gz"):
                continue

            try:
                dt = datetime.datetime.strptime(tar,
                                                "%Y-%m-%d_%H-%M-%S.tar.gz")
                weekday = dt.weekday()
                date = dt.strftime("%Y-%m-%d")
            except Exception as e:
                log.error("Error parsing datetime from existing backup {}: {}".
                          format(
                              tar,
                              e,
                          ))
                continue

            # If this is within the daily cutoff, we keep it.
            if date > daily_cutoff:
                log.debug(
                    "DAILY KEEP: {} is within the daily cutoff".format(tar))
                continue

            # Now we're at backups older than our daily threshhold, so we only
            # want to keep one backup per week until we have WEEKLY_BACKUPS
            # copies, and only for backups taken on WEEKLY_WEEKDAY day-of-week.
            if weekday == WEEKLY_WEEKDAY and weekly_spared < WEEKLY_BACKUPS:
                log.debug("WEEKLY KEEP: {} is being kept".format(tar))
                weekly_spared += 1
                continue

            # All other old backups get deleted.
            log.info("Cull old backup: {}".format(tar))
            os.unlink("backups/{}".format(tar))

    def on_auth_error(self, mc, error):
        """Handle unsuccessful authentication."""
        log.error(error)
        sys.exit(1)

    def on_message(self, mc, message):
        """Handle a Minecraft server message."""
        log.info("Minecraft server says: {}".format(message))
Example #5
0
class Application:
    def __init__(self, args):
        """Initialize the application."""
        self.args = args

        # Verify settings.
        self.verify_args()

        self.config = dict()  # minecraft-control configuration
        self.client = None  # MinecraftClient instance
        self.today = datetime.datetime.utcnow().strftime("%Y-%m-%d_%H-%M-%S")
        self.world = self.get_world_name()
        log.info("Today's date/time: {}".format(self.today))

        # Load the minecraft-control configuration.
        self.load_mc_config()

    def verify_args(self):
        """Do some sanity checking on input arguments."""

        # The minecraft-control config file.
        if not os.path.isfile(self.args.config):
            log.error("{}: not a file".format(self.args.config))
            sys.exit(1)

        # The server directory.
        if not os.path.isfile("{}/server.properties".format(self.args.server)):
            log.error(
                "{}: not a Minecraft server directory (no " "server.properties file present)".format(self.args.server)
            )
            sys.exit(1)

    def load_mc_config(self):
        """Load the configuration from minecraft-control."""
        log.debug("Loading minecraft-control settings from {}".format(args.config))

        parser = RawConfigParser()
        with open(self.args.config, "r") as fh:
            parser.readfp(fh)

        self.config["host"] = parser.get("tcp-server", "address")
        self.config["port"] = parser.get("tcp-server", "port")
        self.config["password"] = parser.get("auth", "password")
        self.config["method"] = parser.get("auth", "method")

    def get_world_name(self):
        """Load the server.properties to find the world name."""

        with open("{}/server.properties".format(self.args.server), "r") as fh:
            for line in fh:
                if not "=" in line:
                    continue
                parts = line.split("=", 1)
                key = parts[0].strip()
                value = parts[1].strip()

                if key == "level-name":
                    return value

        raise ValueError("No level-name found in server.properties!")

    def run(self):
        """Run the main program's logic."""

        # Change into the server's directory.
        os.chdir(self.args.server)

        # If we're only culling backups, do that and exit.
        if self.args.clean:
            return self.cull_backups()

        # Backups directory.
        backups = os.path.join(self.args.server, "backups")
        if not os.path.isdir(backups):
            log.info("Creating backups directory: {}".format(backups))
            os.mkdir(backups)

        # Connect to the Minecraft-Control server.
        log.info("Connecting to Minecraft control server...")
        self.client = MinecraftClient(
            host=self.config["host"],
            port=self.config["port"],
            password=self.config["password"],
            methods=[self.config["method"]],
        )
        self.client.add_handler("auth_ok", self.on_auth_ok)
        self.client.add_handler("auth_error", self.on_auth_error)
        self.client.add_handler("server_message", self.on_message)

        self.client.connect()
        self.client.start()

    def on_auth_ok(self, mc):
        """Handle successful authentication."""
        log.info("Connection to server established and authenticated!")

        # Target file name.
        fname = self.today + ".tar.gz"
        target = os.path.join("backups", fname)

        # Turn off saving and save the world now.
        log.info("Turning off auto-saving and saving the world now!")
        self.client.sendline("save-off")
        self.client.sendline("save-all")
        time.sleep(5)

        # Archive the world.
        log.info("Backing up the world as: {}".format(target))
        subprocess.call(["tar", "czvf", target, self.world])

        # Turn saving back on.
        time.sleep(5)
        log.info("Turning auto-saving back on!")
        self.client.sendline("save-on")

        # Cull old backups.
        self.cull_backups()
        quit()

    def cull_backups(self):
        """Trim the backup copies and remove older backups."""
        log.info("Culling backups...")

        # Date cut-off for daily backups.
        daily_cutoff = (datetime.datetime.utcnow() - datetime.timedelta(days=DAILY_BACKUPS)).strftime("%Y-%m-%d")
        log.debug("Daily cutoff date: {}".format(daily_cutoff))

        # Number of weekly backups spared.
        weekly_spared = 0

        # Check all the existing backups.
        for tar in sorted(os.listdir("backups"), reverse=True):
            if not tar.endswith(".tar.gz"):
                continue

            try:
                dt = datetime.datetime.strptime(tar, "%Y-%m-%d_%H-%M-%S.tar.gz")
                weekday = dt.weekday()
                date = dt.strftime("%Y-%m-%d")
            except Exception as e:
                log.error("Error parsing datetime from existing backup {}: {}".format(tar, e))
                continue

            # If this is within the daily cutoff, we keep it.
            if date > daily_cutoff:
                log.debug("DAILY KEEP: {} is within the daily cutoff".format(tar))
                continue

            # Now we're at backups older than our daily threshhold, so we only
            # want to keep one backup per week until we have WEEKLY_BACKUPS
            # copies, and only for backups taken on WEEKLY_WEEKDAY day-of-week.
            if weekday == WEEKLY_WEEKDAY and weekly_spared < WEEKLY_BACKUPS:
                log.debug("WEEKLY KEEP: {} is being kept".format(tar))
                weekly_spared += 1
                continue

            # All other old backups get deleted.
            log.info("Cull old backup: {}".format(tar))
            os.unlink("backups/{}".format(tar))

    def on_auth_error(self, mc, error):
        """Handle unsuccessful authentication."""
        log.error(error)
        sys.exit(1)

    def on_message(self, mc, message):
        """Handle a Minecraft server message."""
        log.info("Minecraft server says: {}".format(message))
Example #6
0
debug = False
host, port, password = None, None, None
whitelist = []

if sys.argv[1] == "--debug":
    debug = True
    host, port, password = sys.argv[2:5]
    whitelist = map(lambda x: x.lower(), sys.argv[5:])
else:
    host, port, password = sys.argv[1:4]
    whitelist = map(lambda x: x.lower(), sys.argv[4:])

# Connect to the server.
client = MinecraftClient(
    debug    = debug,
    host     = host,
    port     = port,
    password = password,
)

def on_authed(client):
    print("Authentication successful!")
    client.sendline("say 01-gamemode.py demo started. Whitelist: {}".format(str(whitelist)))

def on_error(client, error):
    print("Failed to authenticate: {}".format(error))

def on_message(client, message):
    print("Saw server message: {}".format(message))

    # Look for people joining the game.
    if "joined the game" in message: