diff options
author | Karel Kočí <cynerd@email.cz> | 2015-08-15 14:50:43 +0200 |
---|---|---|
committer | Karel Kočí <cynerd@email.cz> | 2015-09-03 12:56:29 +0200 |
commit | e4b0c7f50efbe0c42aa933cb58a86a44367c1140 (patch) | |
tree | f6d0a55e04f21ebf0be9a411a31ee8bb6be69628 /modules/utils.py | |
parent | 8eb78a9a915cc2fb08905935bb1d26c1a808d4c2 (diff) | |
download | mcserver-wrapper-e4b0c7f50efbe0c42aa933cb58a86a44367c1140.tar.gz mcserver-wrapper-e4b0c7f50efbe0c42aa933cb58a86a44367c1140.tar.bz2 mcserver-wrapper-e4b0c7f50efbe0c42aa933cb58a86a44367c1140.zip |
Implemented module version of mcwrapper
mcwrapper functionality split to modules. This is basic implementation
of modules handling. Two module types are recognized. For server and
commands for mcwrapper cli interface. This way can be implemented
different command and server features simply without modifying main
script. Interface between main script and modules is defined using
service lists. Service list informs main script what function should
be called in module.
More detailed description should be written to README.md file. Or even
separated file describing module interface.
In this commit are implemented five different modules. Players and status
are server modules. They are used only if mcwrapper is running instance
of Minecraft server. Modules say and list-modules are implementing
mcwrapper actions. And last module argmodules is implementing mcwrapper
argument. For modules usage also added utils.py. This contains shared
usable code that is used even by main mcwrapper script.
Diffstat (limited to 'modules/utils.py')
-rw-r--r-- | modules/utils.py | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/modules/utils.py b/modules/utils.py new file mode 100644 index 0000000..c8406ce --- /dev/null +++ b/modules/utils.py @@ -0,0 +1,196 @@ +# This is python file with usable utilities for modules +# This can't be used as mcwrapper module. Although it's not a problem if loaded. +import os +import datetime +import re +import struct +import traceback +from enum import Enum + +# Dummy variable to be used before it is set by mcwrapper +conf = type('defconf', (object,), {}) + +class Service(Enum): + # Request service of conf function + # This function is called right after argument parsing. + # Configuration is loaded before almost anything is done. + # Prototype: config(conf) + # Where conf is class containing configuration variables. + config = 1 + # Request service of init function + # This function is called right before Minecraft server is started. + # Prototype: init() + init = 2 + # Request service of clean function + # This function is called before mcwrapper exits. + # Prototype: clean() + clean = 3 + # Request service of parse function + # Prototype: parse(line) + # Where line is line from Minecraft server standard and error output. + parse = 4 + # Signalize that exceptions shouldn't be ignored. + # Otherwise exception is printed and module is removed. + exceptionThrow = 101 + # Requests service of action and action_help function. + # This flag can't be denied by serviceServer or by configuration. + # Prototype: action(act, args) + # Where act is string specifying action and args are rest of command line + # arguments. + # Prototype: action_help() + action = 201 + # Requests service of argument function. + # This flag can't be denied by serviceServer or by configuration. + # Prototype: argument(arg, args) + # Where arg is parser argument and args are rest of command line arguments. + argument = 202 + def toStr(service): + if service == Service.config: + return 'S-Config' + elif service == Service.init: + return 'S-Init' + elif service == Service.clean: + return 'S-Clean' + elif service == Service.parse: + return 'S-Parse' + elif service == Service.exceptionThrow: + return 'F-ExceptionThrow' + elif service == Service.action: + return 'P-Action' + elif service == Service.argument: + return 'P-Argument' + +def __module_disable__(module): + """Disable specified module""" + if verbose_level >= 0: + print('Disabling module: ' + str(module)) + if Service.clean in module.services: + try: + module.clean() + except Exception: + traceback.print_exc() + for name, value in vars(conf).items(): + if re.search('^__modules', name): + try: + value.remove(module) + except KeyError: + pass + del module + +def printArgumentsHelp(): + """Prints help for all arguments from loaded modules""" + print(' -h, --help') + print(' Prints this help text.') + print(' -v, --verbose') + print(' Increase verbose level of output.') + print(' -q, --quiet') + print(' Decrease verbose level of output.') + for mod in conf.__modules_argument__: + mod.argument_help() + +def serviceCall(servicename, func, argv=[], mode=0): + """Calls func in all/n-th modules with specified service. + + servicename - String name of service + func - String name of functions to be called + argv - List of arguments passed to functions + mode - Mode of execution + 0 - called for every module without result returning + 1 - called for every module and return result + 2 - called until True is returned from function called + """ + def execmod(servicename, func, argv, mod): + cmd = 'mod.' + func + '( ' + for i in range(0, len(argv)): + cmd += 'argv[' + str(i) + '],' + cmd = cmd[0:len(cmd)-1] + ')' + try: + return eval(cmd) + except Exception as e: + if Service.exceptionThrow in mod.services: + raise e + else: + traceback.print_exc() + __module_disable__(mod) + return None + if mode == 0: + for mod in vars(conf)['__modules_' + servicename + '__'].copy(): + execmod(servicename, func, argv, mod) + return + elif mode == 1: + ret = dict() + for mod in vars(conf)['__modules_' + servicename + '__'].copy(): + ret[mod] = execmod(servicename, func, argv, mod) + return ret + elif mode == 2: + for mod in vars(conf)['__modules_' + servicename + '__'].copy(): + rtn = execmod(servicename, func, argv, mod) + if rtn: + return rtn, mod + return None, None + +def isServerRunning(): + """Check if server is running. It checks if input_pipe exists. + Returns: + True - Running in any state or residue pipe exists. + False - Not running + """ + return os.path.exists(conf.inputPipe) + +__default_config__ = { + "modules": {'say', 'argmodules', 'list-modules', 'printconf'}, + "identifier": None, + } +__default_server_config__ = { + "modules": {'status', 'players'}, + "folder": '/dev/shm/mcwrapper-exampleserver', + "logOutput": False, + "logFile": datetime.datetime.now().strftime('%y-%m-%d-%H-%M-%S') + '.log', + "command": [], + } + +def setServerConf(identifier): + """Sets server configuration.""" + conf.identifier = identifier + try: + conf.server[identifier] + vars(conf).update(conf.server[identifier]) + except AttributeError: + if conf.verbose_level >= 0: + print('W: No configuration associated with identifier: "' + conf.identifier) + configSet(__default_server_config__) + # Set additional runtime configuration variables + conf.inputPipe = conf.folder + '/input_pipe' + +def configSet(confs): + """This is for setting default configurations. If configuration for module is + not set in conf file, then it must be set while module initialization. + + confs - dictionary of configuration options and default values. + """ + for name, val in confs.items(): + try: + dir(conf).index(name) + except ValueError: + exec('conf.' + name + '=val') + +def varint_unpack(data): + "Returns varint value from beginning of data and number of bytes used." + i = 0 + nextbt = True + newdata = 0 + while nextbt: + bt = data[i] + if not bt & (1 << 7): + nextbt = False + bt = bt & ~(1 << 7) + newdata = newdata | (bt << (i * 7)) + print(newdata) + return newdata, i + +def varint_pack(integer): + pass + +################################################################################# +## dummy module +services = () |