import Vapor import Foundation import WebKit @MainActor final class WebServer: NSObject, ObservableObject, WKNavigationDelegate { private var app: Application? @Published var isRunning = false @Published var isStarting = false @Published var port: Int @Published var webView = WKWebView() @Published var currentUrl: String = "" var isNotReady: Bool { isStarting || !isRunning } init(port: Int) { self.port = port super.init() webView.navigationDelegate = self } func loadHomeUrl() { let url = URL(string: "http://localhost:\(port)/feed")! webView.load(URLRequest(url: url)) } func reloadPage() { webView.reload() } func startServer(in directory: String) { if let app, !app.didShutdown { print("WebServer: Already running") return } guard !isStarting else { return } self.isStarting = true Task { var vaporArgs = CommandLine.arguments let allowedCommands = ["serve", "routes"] vaporArgs = vaporArgs.filter { allowedCommands.contains($0) || $0 == CommandLine.arguments.first } let app = try await Application.make(.detect(arguments: vaporArgs)) app.logger.logLevel = .warning self.app = app app.middleware.use(TryFilesMiddleware(publicDirectory: directory)) app.http.server.configuration.port = 8000 DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(3)) { self.loadHomeUrl() self.isStarting = false self.isRunning = true } print("WebServer: Starting") try await app.execute() try await app.asyncShutdown() } } func stopServer() { guard let app else { print("WebServer: Already stopped") return } print("WebServer: Stopping") Task { do { try await app.asyncShutdown() } catch { print("Failed to stop web server: \(error)") } DispatchQueue.main.async { self.isRunning = false } } } } extension WebServer { func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { DispatchQueue.main.async { self.currentUrl = webView.url?.absoluteString ?? "Unknown URL" } } }