140 lines
4.5 KiB
Swift
140 lines
4.5 KiB
Swift
import Hummingbird
|
|
import Logging
|
|
import NIOPosix
|
|
|
|
struct DocCMiddleware<
|
|
Context: RequestContext,
|
|
AssetProvider: FileProvider
|
|
>: RouterMiddleware {
|
|
|
|
// MARK: Properties
|
|
|
|
private let assetProvider: AssetProvider
|
|
|
|
// MARK: Initialisers
|
|
|
|
init(
|
|
_ rootFolder: String,
|
|
threadPool: NIOThreadPool = .singleton,
|
|
logger: Logger = .init(label: "DocCMiddleware")
|
|
) where AssetProvider == LocalFileSystem {
|
|
self.assetProvider = LocalFileSystem(
|
|
rootFolder: rootFolder,
|
|
threadPool: threadPool,
|
|
logger: logger
|
|
)
|
|
}
|
|
|
|
init(assetProvider: AssetProvider) {
|
|
self.assetProvider = assetProvider
|
|
}
|
|
|
|
// MARK: Functions
|
|
|
|
func handle(
|
|
_ input: Request,
|
|
context: Context,
|
|
next: (Request, Context) async throws -> Response
|
|
) async throws -> Response {
|
|
guard
|
|
let uriPath = input.uri.path.removingPercentEncoding,
|
|
!uriPath.contains(.previousFolder),
|
|
uriPath.hasPrefix(.forwardSlash)
|
|
else {
|
|
throw HTTPError(.badRequest)
|
|
}
|
|
|
|
/*
|
|
Send all requests starting with /documentation/ or /tutorials/ to the index.html file
|
|
Send all requests starting with /css/, /data/, /downloads/, /images/, /img/, /index/, /js/, or /videos/ to their respective folders
|
|
Send all requests to favicon.ico, favicon.svg, and theme-settings.json to their respective files
|
|
Send all requests to /data/documentation.json to the file in the data/documentation/ folder that has the name of the module and ends with .json
|
|
Redirect requests to / and /documentation to /documentation/
|
|
Redirect requests to /tutorials to /tutorials/
|
|
*/
|
|
|
|
guard uriPath.starts(with: /^\/archives\/\w+/) else {
|
|
return try await next(input, context)
|
|
}
|
|
|
|
let pathArchive = Path.archivePath(from: uriPath)
|
|
let nameArchive = Path.archiveName(from: uriPath)
|
|
let uriResource = Path.resourcePath(from: uriPath)
|
|
|
|
if uriResource == .forwardSlash {
|
|
return .redirect(to: uriPath + "/documentation")
|
|
}
|
|
|
|
for staticFile in StaticFile.allCases {
|
|
if uriResource.contains(staticFile.path) {
|
|
if staticFile == .documentation {
|
|
// Send all requests to /data/documentation.json to the file in the data/documentation/ folder that has the name of the module and ends with .json
|
|
return try await serveFile(
|
|
"/data/documentation/\(nameArchive).json",
|
|
at: pathArchive,
|
|
context: context
|
|
)
|
|
} else {
|
|
// Send all requests to favicon.ico, favicon.svg, and theme-settings.json to their respective files
|
|
return try await serveFile(
|
|
uriResource,
|
|
at: pathArchive,
|
|
context: context
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
for assetPrefix in AssetPrefix.allCases {
|
|
if uriResource.contains(assetPrefix.path) {
|
|
return try await serveFile(
|
|
uriResource,
|
|
at: pathArchive,
|
|
context: context
|
|
)
|
|
}
|
|
}
|
|
|
|
for indexPrefix in IndexPrefix.allCases {
|
|
if uriResource.contains(indexPrefix.path) {
|
|
if uriResource.hasSuffix(.forwardSlash) {
|
|
return try await serveFile(
|
|
"\(indexPrefix.path)/\(nameArchive)/index.html",
|
|
at: pathArchive,
|
|
context: context
|
|
)
|
|
} else {
|
|
return .redirect(to: uriPath + "/")
|
|
}
|
|
}
|
|
}
|
|
|
|
throw HTTPError(.notFound)
|
|
}
|
|
|
|
}
|
|
|
|
// MARK: - Helpers
|
|
|
|
private extension DocCMiddleware {
|
|
|
|
// MARK: Functions
|
|
|
|
func serveFile(
|
|
_ path: String,
|
|
at folder: String,
|
|
context: Context
|
|
) async throws -> Response {
|
|
let filePath = folder + path
|
|
|
|
guard let fileIdentifier = assetProvider.getFileIdentifier(filePath) else {
|
|
throw HTTPError(.notFound)
|
|
}
|
|
|
|
let body = try await assetProvider.loadFile(id: fileIdentifier, context: context)
|
|
|
|
return .init(status: .ok, headers: [:], body: body)
|
|
}
|
|
|
|
}
|