|
@@ -220,3 +220,130 @@ class RadicaleDaemon(Daemon):
|
220
|
220
|
:param callback: callback to execute in daemon
|
221
|
221
|
"""
|
222
|
222
|
self._server.append_thread_callback(callback)
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+# TODO : webdav deamon, make it clean !
|
|
226
|
+
|
|
227
|
+import sys, os
|
|
228
|
+from wsgidav.wsgidav_app import DEFAULT_CONFIG
|
|
229
|
+from wsgidav.xml_tools import useLxml
|
|
230
|
+from wsgidav.wsgidav_app import WsgiDAVApp
|
|
231
|
+from wsgidav._version import __version__
|
|
232
|
+
|
|
233
|
+from inspect import isfunction
|
|
234
|
+import traceback
|
|
235
|
+
|
|
236
|
+DEFAULT_CONFIG_FILE = "wsgidav.conf"
|
|
237
|
+PYTHON_VERSION = "%s.%s.%s" % (sys.version_info[0], sys.version_info[1], sys.version_info[2])
|
|
238
|
+
|
|
239
|
+class WsgiDavDaemon(Daemon):
|
|
240
|
+
|
|
241
|
+ def __init__(self, *args, **kwargs):
|
|
242
|
+ super().__init__(*args, **kwargs)
|
|
243
|
+ self.config = self._initConfig()
|
|
244
|
+ self._server = None
|
|
245
|
+
|
|
246
|
+ def _initConfig(self):
|
|
247
|
+ """Setup configuration dictionary from default, command line and configuration file."""
|
|
248
|
+
|
|
249
|
+ # Set config defaults
|
|
250
|
+ config = DEFAULT_CONFIG.copy()
|
|
251
|
+ temp_verbose = config["verbose"]
|
|
252
|
+
|
|
253
|
+ # Configuration file overrides defaults
|
|
254
|
+ config_file = os.path.abspath(DEFAULT_CONFIG_FILE)
|
|
255
|
+ if config_file:
|
|
256
|
+ fileConf = self._readConfigFile(config_file, temp_verbose)
|
|
257
|
+ config.update(fileConf)
|
|
258
|
+ else:
|
|
259
|
+ if temp_verbose >= 2:
|
|
260
|
+ print("Running without configuration file.")
|
|
261
|
+
|
|
262
|
+ if not useLxml and config["verbose"] >= 1:
|
|
263
|
+ print(
|
|
264
|
+ "WARNING: Could not import lxml: using xml instead (slower). Consider installing lxml from http://codespeak.net/lxml/.")
|
|
265
|
+
|
|
266
|
+ if not config["provider_mapping"]:
|
|
267
|
+ print("ERROR: No DAV provider defined. Try --help option.", file=sys.stderr)
|
|
268
|
+ sys.exit(-1)
|
|
269
|
+
|
|
270
|
+ return config
|
|
271
|
+
|
|
272
|
+ def _readConfigFile(self, config_file, verbose):
|
|
273
|
+ """Read configuration file options into a dictionary."""
|
|
274
|
+
|
|
275
|
+ if not os.path.exists(config_file):
|
|
276
|
+ raise RuntimeError("Couldn't open configuration file '%s'." % config_file)
|
|
277
|
+
|
|
278
|
+ try:
|
|
279
|
+ import imp
|
|
280
|
+ conf = {}
|
|
281
|
+ configmodule = imp.load_source("configuration_module", config_file)
|
|
282
|
+
|
|
283
|
+ for k, v in vars(configmodule).items():
|
|
284
|
+ if k.startswith("__"):
|
|
285
|
+ continue
|
|
286
|
+ elif isfunction(v):
|
|
287
|
+ continue
|
|
288
|
+ conf[k] = v
|
|
289
|
+ except Exception as e:
|
|
290
|
+ exceptioninfo = traceback.format_exception_only(sys.exc_type, sys.exc_value) # @UndefinedVariable
|
|
291
|
+ exceptiontext = ""
|
|
292
|
+ for einfo in exceptioninfo:
|
|
293
|
+ exceptiontext += einfo + "\n"
|
|
294
|
+
|
|
295
|
+ print("Failed to read configuration file: " + config_file + "\nDue to " + exceptiontext, file=sys.stderr)
|
|
296
|
+ raise
|
|
297
|
+
|
|
298
|
+ return conf
|
|
299
|
+
|
|
300
|
+ def run(self):
|
|
301
|
+ app = WsgiDAVApp(self.config)
|
|
302
|
+
|
|
303
|
+ # Try running WsgiDAV inside the following external servers:
|
|
304
|
+ self._runCherryPy(app, self.config, "cherrypy-bundled")
|
|
305
|
+
|
|
306
|
+ def _runCherryPy(self, app, config, mode):
|
|
307
|
+ """Run WsgiDAV using cherrypy.wsgiserver, if CherryPy is installed."""
|
|
308
|
+ assert mode in ("cherrypy", "cherrypy-bundled")
|
|
309
|
+
|
|
310
|
+ try:
|
|
311
|
+ from wsgidav.server.cherrypy import wsgiserver
|
|
312
|
+
|
|
313
|
+ version = "WsgiDAV/%s %s Python/%s" % (
|
|
314
|
+ __version__,
|
|
315
|
+ wsgiserver.CherryPyWSGIServer.version,
|
|
316
|
+ PYTHON_VERSION)
|
|
317
|
+
|
|
318
|
+ wsgiserver.CherryPyWSGIServer.version = version
|
|
319
|
+ protocol = "http"
|
|
320
|
+
|
|
321
|
+ if config["verbose"] >= 1:
|
|
322
|
+ print("Running %s" % version)
|
|
323
|
+ print("Listening on %s://%s:%s ..." % (protocol, config["host"], config["port"]))
|
|
324
|
+ self._server = wsgiserver.CherryPyWSGIServer(
|
|
325
|
+ (config["host"], config["port"]),
|
|
326
|
+ app,
|
|
327
|
+ server_name=version,
|
|
328
|
+ )
|
|
329
|
+
|
|
330
|
+ self._server.start()
|
|
331
|
+ except ImportError as e:
|
|
332
|
+ if config["verbose"] >= 1:
|
|
333
|
+ print("Could not import wsgiserver.CherryPyWSGIServer.")
|
|
334
|
+ return False
|
|
335
|
+ return True
|
|
336
|
+
|
|
337
|
+ def stop(self):
|
|
338
|
+ self._server.stop()
|
|
339
|
+ print("WsgiDav : je m'arrête")
|
|
340
|
+
|
|
341
|
+ def append_thread_callback(self, callback: collections.Callable) -> None:
|
|
342
|
+ """
|
|
343
|
+ Place here the logic who permit to execute a callback in your daemon.
|
|
344
|
+ To get an exemple of that, take a look at
|
|
345
|
+ socketserver.BaseServer#service_actions and how we use it in
|
|
346
|
+ tracim.lib.daemons.TracimSocketServerMixin#service_actions .
|
|
347
|
+ :param callback: callback to execute in your thread.
|
|
348
|
+ """
|
|
349
|
+ raise NotImplementedError()
|