#!/usr/bin/python3
"""
Certificate watcher which reloads nginx or reconfigures it, depending on what
happens to externally supplied certificates. Only executed by start.py in case
of TLS_FLAVOR=[mail, cert]
"""

from os.path import exists, split as path_split, join as path_join
from os import system, getenv
import time
from watchdog.observers.polling import PollingObserver
from watchdog.events import FileSystemEventHandler, FileDeletedEvent, \
    FileCreatedEvent, FileModifiedEvent, FileMovedEvent

class ChangeHandler(FileSystemEventHandler):
    "watchdog-handler listening on any event, executing the correct configuration/reload steps"

    def __init__(self, cert_path, keypair_path):
        "Initialize a new changehandler"""
        super().__init__()
        self.cert_path = cert_path
        self.keypair_path = keypair_path

    @staticmethod
    def reload_nginx():
        "merely reload nginx without re-configuring everything"
        if exists("/var/run/nginx.pid"):
            print("Reloading a running nginx")
            system("nginx -s reload")

    @staticmethod
    def reexec_config():
        "execute a reconfiguration of the system, which also reloads"
        print("Reconfiguring system")
        system("/config.py")

    def on_any_event(self, event):
        "event-listener checking if the affected files are the cert-files we're interested in"
        if event.is_directory:
            return

        filename = event.src_path
        if isinstance(event, FileMovedEvent):
            filename = event.dest_path

        if filename in [self.cert_path, self.keypair_path]:
            # all cases except for FileModified need re-configure
            if isinstance(event, (FileCreatedEvent, FileMovedEvent, FileDeletedEvent)):
                ChangeHandler.reexec_config()
            # file modification needs only a nginx reload without config.py
            elif isinstance(event, FileModifiedEvent):
                ChangeHandler.reload_nginx()
        # cert files have been moved away, re-configure
        elif isinstance(event, FileMovedEvent) and event.src_path in [self.cert_path, self.keypair_path]:
            ChangeHandler.reexec_config()


if __name__ == '__main__':
    cert_path = path_join("/certs/", getenv("TLS_CERT_FILENAME", default="cert.pem"))
    cert_dir = path_split(cert_path)[0]
    keypair_path = path_join("/certs/", getenv("TLS_KEYPAIR_FILENAME", default="key.pem"))
    keypair_dir = path_split(keypair_path)[0]

    observer = PollingObserver()
    handler = ChangeHandler(cert_path, keypair_path)
    observer.schedule(handler, cert_dir, recursive=False)
    if keypair_dir != cert_dir:
       observer.schedule(handler, keypair_dir, recursive=False)
    observer.start()

    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        observer.stop()

    observer.join()