diff options
| -rwxr-xr-x | mcwrapper/__init__.py | 23 | ||||
| -rw-r--r-- | mcwrapper/mod.py | 3 | ||||
| -rw-r--r-- | mcwrapper/players.py | 49 | ||||
| -rw-r--r-- | mcwrapper/status.py | 58 | ||||
| -rw-r--r-- | mcwrapper/wrapper.py | 99 | ||||
| -rwxr-xr-x | setup.py | 2 | 
6 files changed, 158 insertions, 76 deletions
| diff --git a/mcwrapper/__init__.py b/mcwrapper/__init__.py index 18e73aa..f0f1df5 100755 --- a/mcwrapper/__init__.py +++ b/mcwrapper/__init__.py @@ -6,16 +6,27 @@ import argparse  from . import prints  from . import alarm  from .wrapper import MCWrapper +from .status import MCStatus +from .players import MCPlayers  from .mod import MoD  mcserver_wrapper = None +mcserver_status = None +mcserver_players = None  mcserver_mod = None  def __wrapper_atexit__():      "This is called when wrapper is exiting" -    if mcserver_wrapper is not None: -        mcserver_wrapper.clean() +    toclean = ( +            mcserver_wrapper, +            mcserver_status, +            mcserver_players, +            mcserver_mod +            ) +    for c in toclean: +        if c is not None: +            c.clean()  def __wrapper_toexit__(): @@ -75,11 +86,13 @@ def main():      alarm.init() -    global mcserver_wrapper -    mcserver_wrapper = MCWrapper(command, pfile, sfile) +    atexit.register(__wrapper_atexit__) +    global mcserver_wrapper, mcserver_status, mcserver_players +    mcserver_wrapper = MCWrapper(command)      signal.signal(signal.SIGTERM, __signal_term__)      signal.signal(signal.SIGINT, __signal_term__) -    atexit.register(__wrapper_atexit__) +    mcserver_status = MCStatus(mcserver_wrapper, sfile) +    mcserver_players = MCPlayers(mcserver_wrapper, pfile)      mcserver_wrapper.start()      if mod_file is not None: diff --git a/mcwrapper/mod.py b/mcwrapper/mod.py index 73200f1..bb580e8 100644 --- a/mcwrapper/mod.py +++ b/mcwrapper/mod.py @@ -12,6 +12,9 @@ class MoD:          self.file = file          alarm.set("mod-time", period, self.__handler__, repeat=True) +    def clean(self): +        alarm.unset("mod-time") +      def __handler__(self):          lines = []          try: diff --git a/mcwrapper/players.py b/mcwrapper/players.py new file mode 100644 index 0000000..c3dabb4 --- /dev/null +++ b/mcwrapper/players.py @@ -0,0 +1,49 @@ +# vim: expandtab ft=python ts=4 sw=4 sts=4: +import os + +from . import prints + +__PLAYERSFILE__ = 'players' + + +class MCPlayers: +    "Tracks online players" +    def __init__(self, wrapper, file_export=False): +        self.players = set() +        self.wrapper = wrapper +        wrapper.hook_start(self.__reset__) +        wrapper.hook_stop(self.__reset__) +        wrapper.hook_line('logged in with entity id', self.__user_join__) +        wrapper.hook_line('left the game', self.__user_leave__) +        self.file_export = file_export +        self.__reset__() + +    def clean(self): +        try: +            os.remove(__PLAYERSFILE__) +        except FileNotFoundError: +            pass + +    def __reset__(self): +        if self.file_export: +            open(__PLAYERSFILE__, 'w')  # Just create empty file + +    def __user_join__(self, line): +        username = line[len('[00:00:00] [Server thread/INFO]: '):] +        username = username[:username.index('[')] +        prints.info("User '" + username + "' joined server.") +        self.players.add(username) +        if self.file_export: +            with open(__PLAYERSFILE__, 'a') as file: +                file.write(username + '\n') + +    def __user_leave__(self, line): +        username = line[len('[00:00:00] [Server thread/INFO]: '):] +        username = username[:username.index(' ')] +        prints.info("User '" + username + "' left server.") +        self.players.remove(username) +        if self.file_export: +            with open(__PLAYERSFILE__, 'w') as file: +                file.write('\n'.join(self.players)) +                if self.players: +                    file.write('\n') diff --git a/mcwrapper/status.py b/mcwrapper/status.py new file mode 100644 index 0000000..42f8ed8 --- /dev/null +++ b/mcwrapper/status.py @@ -0,0 +1,58 @@ +# vim: expandtab ft=python ts=4 sw=4 sts=4: +import os + +from . import prints + +__STATUSSTRINGS__ = { +    0: "Not running", +    1: "Starting", +    2: "Running", +    3: "Stopping", +    } +__STATUSFILE__ = 'status' + + +class MCStatus: +    "Tracks server status" +    def __init__(self, wrapper, file_export=False): +        self.wrapper = wrapper +        self.status = 0 +        wrapper.hook_start(self.__server_start__) +        wrapper.hook_stop(self.__server_stop__) +        wrapper.hook_line(': Done', self.__server_started__) +        wrapper.hook_line(': Stopping the server', self.__server_stopping__) +        self.file_export = file_export +        if file_export: +            with open(__STATUSFILE__, 'w') as file: +                file.write(__STATUSSTRINGS__[0] + '\n') + +    def clean(self): +        try: +            os.remove(__STATUSFILE__) +        except FileNotFoundError: +            pass + +    def __server_start__(self): +        self.status = 1 +        if self.file_export: +            with open(__STATUSFILE__, 'w') as file: +                file.write(__STATUSSTRINGS__[1] + '\n') + +    def __server_stop__(self): +        if self.file_export: +            with open(__STATUSFILE__, 'w') as file: +                file.write(__STATUSSTRINGS__[0] + '\n') + +    def __server_started__(self, line): +        prints.info("Server start.") +        self.status = 2 +        if self.file_export: +            with open(__STATUSFILE__, 'w') as file: +                file.write(__STATUSSTRINGS__[2] + '\n') + +    def __server_stopping__(self, line): +        prints.info("Server stop.") +        self.status = 3 +        if self.file_export: +            with open(__STATUSFILE__, 'w') as file: +                file.write(__STATUSSTRINGS__[3] + '\n') diff --git a/mcwrapper/wrapper.py b/mcwrapper/wrapper.py index 3e9a0d7..96f74d5 100644 --- a/mcwrapper/wrapper.py +++ b/mcwrapper/wrapper.py @@ -5,30 +5,21 @@ import subprocess  import time  from threading import Thread -from .import prints  - -__STATUSSTRINGS__ = { -    0: "Not running", -    1: "Starting", -    2: "Running", -    3: "Stopping", -    } +from .import prints  __INPUTPIPE__ = 'input_pipe' -__STATUSFILE__ = 'status' -__PLAYERSFILE__ = 'players'  __PIDFILE__ = 'server.pid'  class MCWrapper:      "Minecraft server wrapper class" -    def __init__(self, command, statusfile=False, playersfile=False): -        self.players = set() -        self.status = 0 +    def __init__(self, command):          self.process = None          self.command = command -        self.statusfile = statusfile -        self.plaersfile = playersfile +        self._running = False +        self._hook_start = [] +        self._hook_stop = [] +        self._hook_line = []          prints.info("Server wrapper initializing")          if os.path.isfile(__PIDFILE__):              with open(__PIDFILE__) as file: @@ -45,11 +36,6 @@ class MCWrapper:              os.mkfifo(__INPUTPIPE__, 0o640)          except FileExistsError:              pass -        if statusfile: -            with open(__STATUSFILE__, 'w') as file: -                file.write(__STATUSSTRINGS__[0] + '\n') -        if playersfile: -            open(__PLAYERSFILE__, 'w')          self.inputthread = Thread(target=self.__input_thread__,                                    daemon=True)          self.outputhread = Thread(target=self.__output_thread__, @@ -66,14 +52,6 @@ class MCWrapper:              os.remove(__PIDFILE__)          except FileNotFoundError:              pass -        try: -            os.remove(__STATUSFILE__) -        except FileNotFoundError: -            pass -        try: -            os.remove(__STATUSFILE__) -        except FileNotFoundError: -            pass      def start(self):          "Start Minecraft server" @@ -81,12 +59,11 @@ class MCWrapper:              self.command, stdin=subprocess.PIPE,              stdout=subprocess.PIPE, stderr=subprocess.STDOUT,              start_new_session=False) +        for h in self._hook_start: +            h() +        self._running = True          with open(__PIDFILE__, "w") as file:              file.write(str(self.process.pid)) -        self.status = 1 -        if self.statusfile: -            with open(__STATUSFILE__, 'w') as file: -                file.write(__STATUSSTRINGS__[1] + '\n')          if not self.inputthread.is_alive():              self.inputthread.start()          if not self.outputhread.is_alive(): @@ -98,14 +75,15 @@ class MCWrapper:              self.process.stdin.write(bytes(                  "/stop\n", sys.getdefaultencoding()))              self.process.stdin.flush() +        self._running = False      def running(self):          "Returns True if mc server is running. Othervise False." -        return bool(self.status) +        return True      def write_to_terminal(self, text):          "Write to server terminal. If server not running it does nothing" -        if self.status == 2: +        if self._running:              prints.info("Input: " + text.rstrip(), 1)              self.process.stdin.write(bytes(text, sys.getdefaultencoding()))              self.process.stdin.flush() @@ -113,57 +91,36 @@ class MCWrapper:          else:              return False -    def __user_join__(self, username): -        prints.info("User '" + username + "' joined server.") -        self.players.add(username) -        if self.plaersfile: -            with open(__PLAYERSFILE__, 'a') as file: -                file.write(username + '\n') +    def hook_start(self, handler): +        self._hook_start.append(handler) + +    def hook_stop(self, handler): +        self._hook_stop.append(handler) -    def __user_leave__(self, username): -        prints.info("User '" + username + "' left server.") -        self.players.remove(username) -        if self.plaersfile: -            with open(__PLAYERSFILE__, 'w') as file: -                file.writelines(self.players) -                if self.players: -                    file.write('\n') +    def hook_line(self, contains, handler): +        n = dict() +        n["contains"] = contains +        n["handler"] = handler +        self._hook_line.append(n)      def __parse_line__(self, line): -        if ': Done' in line: -            prints.info("Server start.") -            self.status = 2 -            if self.statusfile: -                with open(__STATUSFILE__, 'w') as file: -                    file.write(__STATUSSTRINGS__[2] + '\n') -        elif ': Stopping the server' in line: -            prints.info("Server stop.") -            self.status = 3 -            if self.statusfile: -                with open(__STATUSFILE__, 'w') as file: -                    file.write(__STATUSSTRINGS__[3] + '\n') -        elif 'logged in with entity id' in line: -            name = line[len('[00:00:00] [Server thread/INFO]: '):] -            name = name[:name.index('[')] -            self.__user_join__(name) -        elif 'left the game' in line: -            name = line[len('[00:00:00] [Server thread/INFO]: '):] -            name = name[:name.index(' ')] -            self.__user_leave__(name) +        i = 0 +        while i < len(self._hook_line): +            if self._hook_line[i]["contains"] in line: +                self._hook_line[i]["handler"](line) +            i += 1      def __output_thread__(self):          for linen in self.process.stdout:              line = linen.decode(sys.getdefaultencoding())              prints.info(line.rstrip(), 2, notime=True)              self.__parse_line__(line.rstrip()) -        if self.statusfile: -            with open(__STATUSFILE__, 'w') as file: -                file.write(__STATUSSTRINGS__[0] + '\n')      def __input_thread__(self):          with open(__INPUTPIPE__, 'r') as pipe:              while True:                  line = pipe.readline().rstrip() +                # TODO use polling                  if line:                      self.write_to_terminal(line + "\n")                  else: @@ -10,6 +10,8 @@ try:      long_description = pypandoc.convert(readme_file, 'rst', format='md')  except (IOError, ImportError):      print("Pandoc not found. Long_description conversion failure.") +except RuntimeError as e: +    print("Pandoc conversion failed: " + str(e))  setup(      name='mcserver-wrapper', | 
