import Hummingbird /// A controller type that provides information about the *DocC* archives containers. struct ArchiveController { // MARK: Properties private let fileService: any FileServicing private let folderArchives: String // MARK: Initialisers /// Initialises this controller. /// - Parameters: /// - folderArchives: A folder in the file system where the *DocC* archive contained are located. /// - fileService: A service that interfaces with the local file system. init( _ folderArchives: String, fileService: any FileServicing = FileService() ) { self.folderArchives = folderArchives self.fileService = fileService } // MARK: Functions /// Registers the controller to a given router. /// - Parameter router: A router to register this controller to. func register(to router: Router) { router.get(.archives, use: listArchives) } } // MARK: - Helpers private extension ArchiveController { // MARK: Functions @Sendable func listArchives( _ request: Request, context: Context ) async throws (HTTPError) -> ArchiveList { do { let nameArchives = try await fileService .listItems(in: folderArchives) .filter { $0.hasSuffix(.suffixArchive) } .map { $0.dropLast(String.suffixArchive.count) } .map(String.init) .sorted { $0 < $1 } return .init(nameArchives) } catch .folderNotFound { throw .init(.notFound) } catch .folderPathEmpty, .folderNotDirectory { throw .init(.unprocessableContent) } catch { throw .init(.badRequest) } } } // MARK: - RouterPath+Constants private extension RouterPath { static let archives: RouterPath = .init("archives") } // MARK: - String+Constants private extension String { static let suffixArchive: String = ".doccarchive" }