...
This commit is contained in:
197
server_webdav.py
Executable file
197
server_webdav.py
Executable file
@@ -0,0 +1,197 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
WebDAV-based Markdown Editor Server
|
||||
Uses WsgiDAV for standards-compliant file operations
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import yaml
|
||||
import json
|
||||
from pathlib import Path
|
||||
from wsgidav.wsgidav_app import WsgiDAVApp
|
||||
from wsgidav.fs_dav_provider import FilesystemProvider
|
||||
from cheroot import wsgi
|
||||
from cheroot.ssl.builtin import BuiltinSSLAdapter
|
||||
|
||||
|
||||
class MarkdownEditorApp:
|
||||
"""Main application that wraps WsgiDAV and adds custom endpoints"""
|
||||
|
||||
def __init__(self, config_path="config.yaml"):
|
||||
self.config = self.load_config(config_path)
|
||||
self.collections = self.config.get('collections', {})
|
||||
self.setup_collections()
|
||||
self.webdav_app = self.create_webdav_app()
|
||||
|
||||
def load_config(self, config_path):
|
||||
"""Load configuration from YAML file"""
|
||||
with open(config_path, 'r') as f:
|
||||
return yaml.safe_load(f)
|
||||
|
||||
def setup_collections(self):
|
||||
"""Create collection directories if they don't exist"""
|
||||
for name, config in self.collections.items():
|
||||
path = Path(config['path'])
|
||||
path.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Create images subdirectory
|
||||
images_path = path / 'images'
|
||||
images_path.mkdir(exist_ok=True)
|
||||
|
||||
print(f"Collection '{name}' -> {path.absolute()}")
|
||||
|
||||
def create_webdav_app(self):
|
||||
"""Create WsgiDAV application with configured collections"""
|
||||
provider_mapping = {}
|
||||
|
||||
for name, config in self.collections.items():
|
||||
path = os.path.abspath(config['path'])
|
||||
provider_mapping[f'/fs/{name}'] = FilesystemProvider(path)
|
||||
|
||||
config = {
|
||||
'host': self.config['server']['host'],
|
||||
'port': self.config['server']['port'],
|
||||
'provider_mapping': provider_mapping,
|
||||
'verbose': self.config['webdav'].get('verbose', 1),
|
||||
'logging': {
|
||||
'enable_loggers': []
|
||||
},
|
||||
'property_manager': True,
|
||||
'lock_storage': True,
|
||||
'simple_dc': {
|
||||
'user_mapping': {
|
||||
'*': True # Allow anonymous access for development
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return WsgiDAVApp(config)
|
||||
|
||||
def __call__(self, environ, start_response):
|
||||
"""WSGI application entry point"""
|
||||
path = environ.get('PATH_INFO', '')
|
||||
method = environ.get('REQUEST_METHOD', '')
|
||||
|
||||
# Handle collection list endpoint
|
||||
if path == '/fs/' and method == 'GET':
|
||||
return self.handle_collections_list(environ, start_response)
|
||||
|
||||
# Handle static files
|
||||
if path.startswith('/static/'):
|
||||
return self.handle_static(environ, start_response)
|
||||
|
||||
# Handle root - serve index.html
|
||||
if path == '/' or path == '/index.html':
|
||||
return self.handle_index(environ, start_response)
|
||||
|
||||
# All other requests go to WebDAV
|
||||
return self.webdav_app(environ, start_response)
|
||||
|
||||
def handle_collections_list(self, environ, start_response):
|
||||
"""Return list of available collections"""
|
||||
collections = list(self.collections.keys())
|
||||
response_body = json.dumps(collections).encode('utf-8')
|
||||
|
||||
start_response('200 OK', [
|
||||
('Content-Type', 'application/json'),
|
||||
('Content-Length', str(len(response_body))),
|
||||
('Access-Control-Allow-Origin', '*')
|
||||
])
|
||||
|
||||
return [response_body]
|
||||
|
||||
def handle_static(self, environ, start_response):
|
||||
"""Serve static files"""
|
||||
path = environ.get('PATH_INFO', '')[1:] # Remove leading /
|
||||
file_path = Path(path)
|
||||
|
||||
if not file_path.exists() or not file_path.is_file():
|
||||
start_response('404 Not Found', [('Content-Type', 'text/plain')])
|
||||
return [b'File not found']
|
||||
|
||||
# Determine content type
|
||||
content_types = {
|
||||
'.html': 'text/html',
|
||||
'.css': 'text/css',
|
||||
'.js': 'application/javascript',
|
||||
'.json': 'application/json',
|
||||
'.png': 'image/png',
|
||||
'.jpg': 'image/jpeg',
|
||||
'.jpeg': 'image/jpeg',
|
||||
'.gif': 'image/gif',
|
||||
'.svg': 'image/svg+xml',
|
||||
'.ico': 'image/x-icon'
|
||||
}
|
||||
|
||||
ext = file_path.suffix.lower()
|
||||
content_type = content_types.get(ext, 'application/octet-stream')
|
||||
|
||||
with open(file_path, 'rb') as f:
|
||||
content = f.read()
|
||||
|
||||
start_response('200 OK', [
|
||||
('Content-Type', content_type),
|
||||
('Content-Length', str(len(content)))
|
||||
])
|
||||
|
||||
return [content]
|
||||
|
||||
def handle_index(self, environ, start_response):
|
||||
"""Serve index.html"""
|
||||
index_path = Path('templates/index.html')
|
||||
|
||||
if not index_path.exists():
|
||||
start_response('404 Not Found', [('Content-Type', 'text/plain')])
|
||||
return [b'index.html not found']
|
||||
|
||||
with open(index_path, 'r', encoding='utf-8') as f:
|
||||
content = f.read().encode('utf-8')
|
||||
|
||||
start_response('200 OK', [
|
||||
('Content-Type', 'text/html; charset=utf-8'),
|
||||
('Content-Length', str(len(content)))
|
||||
])
|
||||
|
||||
return [content]
|
||||
|
||||
|
||||
def main():
|
||||
"""Start the server"""
|
||||
print("=" * 60)
|
||||
print("Markdown Editor with WebDAV Backend")
|
||||
print("=" * 60)
|
||||
|
||||
# Create application
|
||||
app = MarkdownEditorApp()
|
||||
|
||||
# Get server config
|
||||
host = app.config['server']['host']
|
||||
port = app.config['server']['port']
|
||||
|
||||
print(f"\nServer starting on http://{host}:{port}")
|
||||
print(f"\nAvailable collections:")
|
||||
for name, config in app.collections.items():
|
||||
print(f" - {name}: {config['description']}")
|
||||
print(f" WebDAV: http://{host}:{port}/fs/{name}/")
|
||||
|
||||
print(f"\nWeb UI: http://{host}:{port}/")
|
||||
print("\nPress Ctrl+C to stop the server")
|
||||
print("=" * 60)
|
||||
|
||||
# Create and start server
|
||||
server = wsgi.Server(
|
||||
bind_addr=(host, port),
|
||||
wsgi_app=app
|
||||
)
|
||||
|
||||
try:
|
||||
server.start()
|
||||
except KeyboardInterrupt:
|
||||
print("\n\nShutting down...")
|
||||
server.stop()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user