|  | @@ -2,6 +2,7 @@ import threading
 | 
	
		
			
			| 2 | 2 |  from wsgiref.simple_server import make_server
 | 
	
		
			
			| 3 | 3 |  
 | 
	
		
			
			| 4 | 4 |  import signal
 | 
	
		
			
			|  | 5 | +
 | 
	
		
			
			| 5 | 6 |  from radicale import Application as RadicaleApplication
 | 
	
		
			
			| 6 | 7 |  from radicale import HTTPServer as RadicaleHTTPServer
 | 
	
		
			
			| 7 | 8 |  from radicale import HTTPSServer as RadicaleHTTPSServer
 | 
	
	
		
			
			|  | @@ -16,6 +17,8 @@ class DaemonsManager(object):
 | 
	
		
			
			| 16 | 17 |      def __init__(self, app: TGApp):
 | 
	
		
			
			| 17 | 18 |          self._app = app
 | 
	
		
			
			| 18 | 19 |          self._daemons = {}
 | 
	
		
			
			|  | 20 | +        signal.signal(signal.SIGTERM, lambda *_: self.stop_all())
 | 
	
		
			
			|  | 21 | +        signal.signal(signal.SIGINT, lambda *_: self.stop_all())
 | 
	
		
			
			| 19 | 22 |  
 | 
	
		
			
			| 20 | 23 |      def run(self, name: str, daemon_class: object, **kwargs) -> None:
 | 
	
		
			
			| 21 | 24 |          """
 | 
	
	
		
			
			|  | @@ -32,55 +35,57 @@ class DaemonsManager(object):
 | 
	
		
			
			| 32 | 35 |                  'Daemon with name "{0}" already running'.format(name)
 | 
	
		
			
			| 33 | 36 |              )
 | 
	
		
			
			| 34 | 37 |  
 | 
	
		
			
			| 35 |  | -        kwargs['app'] = self._app
 | 
	
		
			
			| 36 |  | -        shutdown_program = threading.Event()
 | 
	
		
			
			| 37 |  | -        # SIGTERM and SIGINT (aka KeyboardInterrupt) should just mark this for
 | 
	
		
			
			| 38 |  | -        # shutdown
 | 
	
		
			
			| 39 |  | -        signal.signal(signal.SIGTERM, lambda *_: shutdown_program.set())
 | 
	
		
			
			| 40 |  | -        signal.signal(signal.SIGINT, lambda *_: shutdown_program.set())
 | 
	
		
			
			| 41 |  | -
 | 
	
		
			
			| 42 |  | -        try:
 | 
	
		
			
			| 43 |  | -            threading.Thread(target=daemon_class.start, kwargs=kwargs).start()
 | 
	
		
			
			| 44 |  | -            self._daemons[name] = daemon_class
 | 
	
		
			
			| 45 |  | -        finally:
 | 
	
		
			
			| 46 |  | -            shutdown_program.set()
 | 
	
		
			
			| 47 |  | -
 | 
	
		
			
			|  | 38 | +        daemon = daemon_class(name=name, kwargs=kwargs, daemon=True)
 | 
	
		
			
			|  | 39 | +        daemon.start()
 | 
	
		
			
			|  | 40 | +        self._daemons[name] = daemon
 | 
	
		
			
			| 48 | 41 |  
 | 
	
		
			
			| 49 |  | -class Daemon(object):
 | 
	
		
			
			| 50 |  | -    _name = NotImplemented
 | 
	
		
			
			| 51 |  | -
 | 
	
		
			
			| 52 |  | -    def __init__(self, app: TGApp):
 | 
	
		
			
			| 53 |  | -        self._app = app
 | 
	
		
			
			| 54 |  | -
 | 
	
		
			
			| 55 |  | -    @classmethod
 | 
	
		
			
			| 56 |  | -    def start(cls, **kwargs):
 | 
	
		
			
			| 57 |  | -        return cls(**kwargs)
 | 
	
		
			
			|  | 42 | +    def stop(self, name: str) -> None:
 | 
	
		
			
			|  | 43 | +        """
 | 
	
		
			
			|  | 44 | +        Stop daemon with his name and wait for him.
 | 
	
		
			
			|  | 45 | +        Where name is given name when daemon started
 | 
	
		
			
			|  | 46 | +        with run method. If daemon name unknow, raise IndexError.
 | 
	
		
			
			|  | 47 | +        :param name:
 | 
	
		
			
			|  | 48 | +        """
 | 
	
		
			
			|  | 49 | +        self._daemons[name].stop()
 | 
	
		
			
			|  | 50 | +        self._daemons[name].join()
 | 
	
		
			
			| 58 | 51 |  
 | 
	
		
			
			| 59 |  | -    @classmethod
 | 
	
		
			
			| 60 |  | -    def kill(cls):
 | 
	
		
			
			|  | 52 | +    def stop_all(self) -> None:
 | 
	
		
			
			|  | 53 | +        """
 | 
	
		
			
			|  | 54 | +        Stop all started daemons and w<ait for them.
 | 
	
		
			
			|  | 55 | +        """
 | 
	
		
			
			|  | 56 | +        for daemon_name in self._daemons:
 | 
	
		
			
			|  | 57 | +            self._daemons[daemon_name].stop()
 | 
	
		
			
			|  | 58 | +        for daemon_name in self._daemons:
 | 
	
		
			
			|  | 59 | +            self._daemons[daemon_name].join()
 | 
	
		
			
			|  | 60 | +
 | 
	
		
			
			|  | 61 | +
 | 
	
		
			
			|  | 62 | +class Daemon(threading.Thread):
 | 
	
		
			
			|  | 63 | +    """
 | 
	
		
			
			|  | 64 | +    Thread who contains daemon. You must implement start and stop methods to
 | 
	
		
			
			|  | 65 | +    manage daemon life correctly.
 | 
	
		
			
			|  | 66 | +    """
 | 
	
		
			
			|  | 67 | +    def run(self):
 | 
	
		
			
			| 61 | 68 |          raise NotImplementedError()
 | 
	
		
			
			| 62 | 69 |  
 | 
	
		
			
			| 63 |  | -    @property
 | 
	
		
			
			| 64 |  | -    def name(self):
 | 
	
		
			
			| 65 |  | -        return self._name
 | 
	
		
			
			|  | 70 | +    def stop(self):
 | 
	
		
			
			|  | 71 | +        raise NotImplementedError()
 | 
	
		
			
			| 66 | 72 |  
 | 
	
		
			
			| 67 | 73 |  
 | 
	
		
			
			| 68 | 74 |  class RadicaleDaemon(Daemon):
 | 
	
		
			
			| 69 |  | -    _name = 'tracim-radicale-server'
 | 
	
		
			
			| 70 |  | -
 | 
	
		
			
			| 71 |  | -    @classmethod
 | 
	
		
			
			| 72 |  | -    def kill(cls):
 | 
	
		
			
			| 73 |  | -        pass  # TODO
 | 
	
		
			
			|  | 75 | +    def __init__(self, *args, **kwargs):
 | 
	
		
			
			|  | 76 | +        super().__init__(*args, **kwargs)
 | 
	
		
			
			|  | 77 | +        self._prepare_config()
 | 
	
		
			
			|  | 78 | +        self._server = self._get_server()
 | 
	
		
			
			| 74 | 79 |  
 | 
	
		
			
			| 75 |  | -    def __init__(self, app: TGApp):
 | 
	
		
			
			|  | 80 | +    def run(self):
 | 
	
		
			
			| 76 | 81 |          """
 | 
	
		
			
			| 77 | 82 |          To see origin radical server start method, refer to
 | 
	
		
			
			| 78 | 83 |          radicale.__main__.run
 | 
	
		
			
			| 79 | 84 |          """
 | 
	
		
			
			| 80 |  | -        super().__init__(app)
 | 
	
		
			
			| 81 |  | -        self._prepare_config()
 | 
	
		
			
			| 82 |  | -        server = self._get_server()
 | 
	
		
			
			| 83 |  | -        server.serve_forever()
 | 
	
		
			
			|  | 85 | +        self._server.serve_forever()
 | 
	
		
			
			|  | 86 | +
 | 
	
		
			
			|  | 87 | +    def stop(self):
 | 
	
		
			
			|  | 88 | +        self._server.shutdown()
 | 
	
		
			
			| 84 | 89 |  
 | 
	
		
			
			| 85 | 90 |      def _prepare_config(self):
 | 
	
		
			
			| 86 | 91 |          from tracim.config.app_cfg import CFG
 |