Compare commits
No commits in common. "main" and "v1.0.0" have entirely different histories.
@ -5,10 +5,9 @@ list of input parameters.
|
|||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
The ``Doxy`` service, in a nutshell, proxies the contents of each and every available `DocC` archive at a specific folder
|
The service, in a nutshell, proxies the contents of each and every available `DocC` archive at a specific folder in the
|
||||||
in the local file system so they can be rendered by any web browser installed in the machine. Furthermore, it is also possible
|
local file system so they can be rendered by any web browser installed in the machine. Furthermore, it is also possible
|
||||||
to query the list of the available `DocC` archives that are found at the *archives* folder in the local file system. Finally,
|
to query the list of the available `DocC` archives that are found at the *archives* folder in the local file system.
|
||||||
the service could be configured by injecting ``Doxy/Options`` parameters as input parameters in the command-line interface.
|
|
||||||
|
|
||||||
The implementation that builds the service in this executable is provided by the `DoxyLibrary` target, that could be
|
The implementation that builds the service in this executable is provided by the `DoxyLibrary` target, that could be
|
||||||
tested in total isolation. This is a standard pattern for [building command-line tools](https://www.swiftbysundell.com/articles/building-a-command-line-tool-using-the-swift-package-manager/)
|
tested in total isolation. This is a standard pattern for [building command-line tools](https://www.swiftbysundell.com/articles/building-a-command-line-tool-using-the-swift-package-manager/)
|
||||||
@ -16,11 +15,7 @@ with the [Swift programming language](https://www.swift.org).
|
|||||||
|
|
||||||
## Topics
|
## Topics
|
||||||
|
|
||||||
### Essentials
|
### Executable
|
||||||
|
|
||||||
- <doc:DoxyInstallation>
|
|
||||||
|
|
||||||
### Service
|
|
||||||
|
|
||||||
- ``Doxy``
|
- ``Doxy``
|
||||||
|
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
@Tutorials(name: "Doxy tutorials") {
|
|
||||||
@Intro(title: "Doxy service tutotials") {
|
|
||||||
These tutorials explains how to install the **Doxy** service, and to use it afterwards; from any command-line
|
|
||||||
interface, such as the *Terminal* app that is shipped with any version of *MacOS*.
|
|
||||||
}
|
|
||||||
|
|
||||||
@Chapter(name: "Installation") {
|
|
||||||
This tutorial explains how to install the **Doxy** service into the system from the command-line interface of
|
|
||||||
choice for the developer.
|
|
||||||
|
|
||||||
@TutorialReference(tutorial: "doc:DoxyInstallation")
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,10 +2,6 @@
|
|||||||
|
|
||||||
## Topics
|
## Topics
|
||||||
|
|
||||||
### Essentials
|
|
||||||
|
|
||||||
- <doc:DoxyInstallation>
|
|
||||||
|
|
||||||
### Input parameters
|
### Input parameters
|
||||||
|
|
||||||
- ``Doxy/Options``
|
- ``Doxy/Options``
|
||||||
|
@ -1,71 +0,0 @@
|
|||||||
@Tutorial(time: 5) {
|
|
||||||
@Intro(title: "Install the Doxy service in the machine") {
|
|
||||||
This tutorial explains step-by-step how to obtain the **Doxy** service from a remote repository and also, how
|
|
||||||
to install this service into a system afterwards, so it would be ready to use by the developer.
|
|
||||||
}
|
|
||||||
|
|
||||||
@Section(title: "Cloning the Doxy service") {
|
|
||||||
@ContentAndMedia {
|
|
||||||
This section focuses on how to clone (or to obtain) the **Doxy** service from its remote repository into the
|
|
||||||
system, so the service is ready to be installed in the machine.
|
|
||||||
|
|
||||||
The `git` command line tool, that is included into the *Command Line tools for Xcode* package, is therefore
|
|
||||||
required to clone the repository. If the command is not already installed in the machine, then download the
|
|
||||||
mentioned package from the [Downloads section in the Apple Developer website](https://developer.apple.com/download/all/).
|
|
||||||
}
|
|
||||||
|
|
||||||
@Steps {
|
|
||||||
@Step {
|
|
||||||
Check whether the `git` command is available to use in the command-line interface of choice.
|
|
||||||
|
|
||||||
In case an absolute path is returned after the command is run, means that the command is installed in
|
|
||||||
the machine. Otherwise, then it is required to install the *Command Line Tools for Xcode* in the machine
|
|
||||||
from [the downloads section of the Apple Developer website]((https://developer.apple.com/download/all/)).
|
|
||||||
|
|
||||||
@Code(name: "Check for the git command in the machine", file: "service_installation-1_1.bash")
|
|
||||||
}
|
|
||||||
|
|
||||||
@Step {
|
|
||||||
Clone the **Doxy** service from a remote repository into the machine using the `git` command.
|
|
||||||
|
|
||||||
@Code(name: "Clone the remote repository into the machine", file: "service_installation-1_2.bash")
|
|
||||||
}
|
|
||||||
|
|
||||||
@Step {
|
|
||||||
Change the current directory to the cloned (or downloaded) folder that contains the source code of the
|
|
||||||
**Doxy** service application.
|
|
||||||
|
|
||||||
@Code(name: "Change the current directory to the cloned folder", file: "service_installation-1_3.bash")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Section(title: "Installing the Doxy service") {
|
|
||||||
@ContentAndMedia {
|
|
||||||
This section focuses on installing the **Doxy** command-line tool from its source code, that has been cloned
|
|
||||||
(or downloaded) from the remote repository in the previous section of this tutorial.
|
|
||||||
}
|
|
||||||
|
|
||||||
@Steps {
|
|
||||||
@Step {
|
|
||||||
Make a release build and then install the generated command-line executable into the machine's user binary
|
|
||||||
location, to allow the developer to use this command easily.
|
|
||||||
|
|
||||||
In case the developer does not have *admin* or *root* privileges, then it is required to copy the generated
|
|
||||||
executable to some folder within the machine manually.
|
|
||||||
|
|
||||||
@Code(name: "Install the service into the machine", file: "service_installation-2_1.bash")
|
|
||||||
}
|
|
||||||
|
|
||||||
@Step {
|
|
||||||
Finally it is recommendable to test whether the executable has been installed in the machine or that the
|
|
||||||
generated executable works as expected.
|
|
||||||
|
|
||||||
For this purpose, the *help* subcommand is called as a parameter
|
|
||||||
with the command-line tool.
|
|
||||||
|
|
||||||
@Code(name: "Test the service has been installed in the machine", file: "service_installation-2_2.bash")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
$ which git
|
|
@ -1 +0,0 @@
|
|||||||
$ git clone https://repo.rock-n-code.com/rock-n-code/doxy.git .
|
|
@ -1 +0,0 @@
|
|||||||
$ cd doxy
|
|
@ -1,3 +0,0 @@
|
|||||||
$ make install
|
|
||||||
# Or manually copy the executable to a custom folder
|
|
||||||
$ cp .build/release/doxy /path/to/some/folder
|
|
@ -1,3 +0,0 @@
|
|||||||
$ doxy --help
|
|
||||||
# In case the executable has been manually copied to some folder.
|
|
||||||
$ ./path/to/some/folder/doxy --help
|
|
@ -18,7 +18,7 @@ extension Doxy {
|
|||||||
/// A hostname to bind the application to.
|
/// A hostname to bind the application to.
|
||||||
@Option(
|
@Option(
|
||||||
name: .long,
|
name: .long,
|
||||||
help: "A hostname to bind the application to."
|
help: "A hostname to bind the application to. Defaults to `127.0.0.1`."
|
||||||
)
|
)
|
||||||
var hostname: String = "127.0.0.1"
|
var hostname: String = "127.0.0.1"
|
||||||
|
|
||||||
@ -32,14 +32,14 @@ extension Doxy {
|
|||||||
/// A name for the Hummingbird application.
|
/// A name for the Hummingbird application.
|
||||||
@Option(
|
@Option(
|
||||||
name: .long,
|
name: .long,
|
||||||
help: "A name for the Hummingbird application."
|
help: "A name for the Hummingbird application. Defaults to `Doxy`."
|
||||||
)
|
)
|
||||||
var name: String = "Doxy"
|
var name: String = "Doxy"
|
||||||
|
|
||||||
/// A port number to bind the application to.
|
/// A port number to bind the application to.
|
||||||
@Option(
|
@Option(
|
||||||
name: .long,
|
name: .long,
|
||||||
help: "A port number to bind the application to."
|
help: "A port number to bind the application to. Defaults to `8080`."
|
||||||
)
|
)
|
||||||
var port: Int = 8080
|
var port: Int = 8080
|
||||||
|
|
||||||
|
@ -4,17 +4,13 @@ A library that provides the **Doxy** service builder to the `DoxyApp` executable
|
|||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
The library, in a nutshell, provides a public ``AppBuilder`` builder that creates a fully functional [Hummingbird](https://hummingbird.codes)
|
The library, in a nutshell, provides a public builder that creates a fully configured [Hummingbird](https://hummingbird.codes)
|
||||||
application that is ready-to-use by the `DoxyApp` executable target. Furthermore, this application can be configured
|
application that is ready-to-use by the `DoxyApp` executable target.
|
||||||
with the ``AppArguments`` parameters the executable receives as inputs.
|
|
||||||
|
|
||||||
In addition, all the business logic required by the ``ArchiveController`` controller that provides the list of available
|
In addition, all the business logic required by the `DocC` archives controller that provides the necessary resources,
|
||||||
`DocC` archives at an specific location in the local file system, and the ``DocCMiddleware`` middleware that proxies the
|
and the `DocC` middleware that proxies the contents of documentation archives in the local machine is being implemented
|
||||||
contents of requested documentation archives in the local machine have been implemented in this target, including all its
|
in this target, including all its relevant protocols and types. Plus, the unit tests for every type implemented in this
|
||||||
relevant protocols and types.
|
target are being written in the `DoxyTests` target.
|
||||||
|
|
||||||
Plus, the test cases for every type found in this target have been written in the `DoxyTests` unit tests target using the
|
|
||||||
new [Swift Testing](https://developer.apple.com/xcode/swift-testing/) testing framework.
|
|
||||||
|
|
||||||
## Topics
|
## Topics
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import Hummingbird
|
import Hummingbird
|
||||||
import Logging
|
|
||||||
|
|
||||||
/// A controller type that provides information about the *DocC* archives containers.
|
/// A controller type that provides information about the *DocC* archives containers.
|
||||||
struct ArchiveController<Context: RequestContext> {
|
struct ArchiveController<Context: RequestContext> {
|
||||||
@ -8,7 +7,6 @@ struct ArchiveController<Context: RequestContext> {
|
|||||||
|
|
||||||
private let archivesPath: String
|
private let archivesPath: String
|
||||||
private let fileService: any FileServicing
|
private let fileService: any FileServicing
|
||||||
private let logger: Logger
|
|
||||||
|
|
||||||
// MARK: Initialisers
|
// MARK: Initialisers
|
||||||
|
|
||||||
@ -16,15 +14,12 @@ struct ArchiveController<Context: RequestContext> {
|
|||||||
/// - Parameters:
|
/// - Parameters:
|
||||||
/// - archivesPath: A path in the local file system where the *DocC* archive contained are located.
|
/// - archivesPath: A path in the local file system where the *DocC* archive contained are located.
|
||||||
/// - fileService: A service that interfaces with the local file system.
|
/// - fileService: A service that interfaces with the local file system.
|
||||||
/// - logger: A service that interfaces with the logging system.
|
|
||||||
init(
|
init(
|
||||||
_ archivesPath: String,
|
_ archivesPath: String,
|
||||||
fileService: any FileServicing = FileService(),
|
fileService: any FileServicing = FileService()
|
||||||
logger: Logger
|
|
||||||
) {
|
) {
|
||||||
self.archivesPath = archivesPath
|
self.archivesPath = archivesPath
|
||||||
self.fileService = fileService
|
self.fileService = fileService
|
||||||
self.logger = logger
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Functions
|
// MARK: Functions
|
||||||
@ -54,62 +49,13 @@ private extension ArchiveController {
|
|||||||
.map { $0.dropLast(String.suffixArchive.count) }
|
.map { $0.dropLast(String.suffixArchive.count) }
|
||||||
.map(String.init)
|
.map(String.init)
|
||||||
.sorted { $0 < $1 }
|
.sorted { $0 < $1 }
|
||||||
let archiveList: ArchiveList = .init(nameArchives)
|
|
||||||
|
return .init(nameArchives)
|
||||||
defer {
|
|
||||||
logger.debug(
|
|
||||||
"A codable response returned: \(String(describing: archiveList))",
|
|
||||||
metadata: .metadata(
|
|
||||||
context: context,
|
|
||||||
request: request,
|
|
||||||
statusCode: .ok
|
|
||||||
),
|
|
||||||
source: .source
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return archiveList
|
|
||||||
} catch .folderNotFound {
|
} catch .folderNotFound {
|
||||||
defer {
|
|
||||||
logger.error(
|
|
||||||
"The resource has not been found.",
|
|
||||||
metadata: .metadata(
|
|
||||||
context: context,
|
|
||||||
request: request,
|
|
||||||
statusCode: .notFound
|
|
||||||
),
|
|
||||||
source: .source
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
throw .init(.notFound)
|
throw .init(.notFound)
|
||||||
} catch .folderPathEmpty, .folderNotDirectory {
|
} catch .folderPathEmpty, .folderNotDirectory {
|
||||||
defer {
|
throw .init(.unprocessableContent)
|
||||||
logger.error(
|
|
||||||
"The folder of the resource has not been located.",
|
|
||||||
metadata: .metadata(
|
|
||||||
context: context,
|
|
||||||
request: request,
|
|
||||||
statusCode: .notAcceptable
|
|
||||||
),
|
|
||||||
source: .source
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
throw .init(.notAcceptable)
|
|
||||||
} catch {
|
} catch {
|
||||||
defer {
|
|
||||||
logger.error(
|
|
||||||
"The request has issues.",
|
|
||||||
metadata: .metadata(
|
|
||||||
context: context,
|
|
||||||
request: request,
|
|
||||||
statusCode: .badRequest
|
|
||||||
),
|
|
||||||
source: .source
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
throw .init(.badRequest)
|
throw .init(.badRequest)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -125,6 +71,5 @@ private extension RouterPath {
|
|||||||
// MARK: - String+Constants
|
// MARK: - String+Constants
|
||||||
|
|
||||||
private extension String {
|
private extension String {
|
||||||
static let source = "ArchiveController"
|
|
||||||
static let suffixArchive: String = ".doccarchive"
|
static let suffixArchive: String = ".doccarchive"
|
||||||
}
|
}
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
import Hummingbird
|
|
||||||
import Logging
|
|
||||||
|
|
||||||
extension Logger.Metadata {
|
|
||||||
|
|
||||||
// MARK: Functions
|
|
||||||
|
|
||||||
static func metadata<Context: RequestContext>(
|
|
||||||
context: Context,
|
|
||||||
request: Request,
|
|
||||||
statusCode: HTTPResponse.Status,
|
|
||||||
redirect: String? = nil
|
|
||||||
) -> Logger.Metadata {
|
|
||||||
var metadata: Logger.Metadata = [
|
|
||||||
"hb.request.id": "\(context.id)",
|
|
||||||
"hb.request.method": "\(request.method.rawValue)",
|
|
||||||
"hb.request.path": "\(request.uri.path)",
|
|
||||||
"hb.request.status": "\(statusCode.code)"
|
|
||||||
]
|
|
||||||
|
|
||||||
if let redirect {
|
|
||||||
metadata["hb.request.redirect"] = "\(redirect)"
|
|
||||||
}
|
|
||||||
|
|
||||||
return metadata
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -19,7 +19,6 @@ struct DocCMiddleware<
|
|||||||
// MARK: Properties
|
// MARK: Properties
|
||||||
|
|
||||||
private let assetProvider: AssetProvider
|
private let assetProvider: AssetProvider
|
||||||
private let logger: Logger
|
|
||||||
|
|
||||||
// MARK: Initialisers
|
// MARK: Initialisers
|
||||||
|
|
||||||
@ -27,30 +26,23 @@ struct DocCMiddleware<
|
|||||||
/// - Parameters:
|
/// - Parameters:
|
||||||
/// - rootFolder: A root folder in the local file system where the *DocC* archive containers are located.
|
/// - rootFolder: A root folder in the local file system where the *DocC* archive containers are located.
|
||||||
/// - threadPool: A thread pool used when loading archives from the file system.
|
/// - threadPool: A thread pool used when loading archives from the file system.
|
||||||
/// - logger: A service that interacts with the logging system,
|
/// - logger: A Logger that outputs information about the root folder requests.
|
||||||
init(
|
init(
|
||||||
_ rootFolder: String,
|
_ rootFolder: String,
|
||||||
threadPool: NIOThreadPool = .singleton,
|
threadPool: NIOThreadPool = .singleton,
|
||||||
logger: Logger
|
logger: Logger = .init(label: "DocCMiddleware")
|
||||||
) where AssetProvider == LocalFileSystem {
|
) where AssetProvider == LocalFileSystem {
|
||||||
self.assetProvider = LocalFileSystem(
|
self.assetProvider = LocalFileSystem(
|
||||||
rootFolder: rootFolder,
|
rootFolder: rootFolder,
|
||||||
threadPool: threadPool,
|
threadPool: threadPool,
|
||||||
logger: logger
|
logger: logger
|
||||||
)
|
)
|
||||||
self.logger = logger
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initialises this middleware with an asset provider, that conforms to the `FileProvider` protocol.
|
/// Initialises this middleware with an asset provider, that conforms to the `FileProvider` protocol.
|
||||||
/// - Parameters:
|
/// - Parameter assetProvider: An asset provider to use with the middleware.
|
||||||
/// - assetProvider: An asset provider to use with the middleware.
|
init(assetProvider: AssetProvider) {
|
||||||
/// - logger: A service that interacts with the logging system,
|
|
||||||
init(
|
|
||||||
assetProvider: AssetProvider,
|
|
||||||
logger: Logger
|
|
||||||
) {
|
|
||||||
self.assetProvider = assetProvider
|
self.assetProvider = assetProvider
|
||||||
self.logger = logger
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Functions
|
// MARK: Functions
|
||||||
@ -65,18 +57,6 @@ struct DocCMiddleware<
|
|||||||
!uriPath.contains(.previousFolder),
|
!uriPath.contains(.previousFolder),
|
||||||
uriPath.hasPrefix(.forwardSlash)
|
uriPath.hasPrefix(.forwardSlash)
|
||||||
else {
|
else {
|
||||||
defer {
|
|
||||||
logger.error(
|
|
||||||
"The request has issues.",
|
|
||||||
metadata: .metadata(
|
|
||||||
context: context,
|
|
||||||
request: input,
|
|
||||||
statusCode: .badRequest
|
|
||||||
),
|
|
||||||
source: .source
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
throw HTTPError(.badRequest)
|
throw HTTPError(.badRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,17 +70,11 @@ struct DocCMiddleware<
|
|||||||
|
|
||||||
// rule #5: Redirects URI resources with `/` to `/documentation`.
|
// rule #5: Redirects URI resources with `/` to `/documentation`.
|
||||||
if uriResource == .forwardSlash {
|
if uriResource == .forwardSlash {
|
||||||
let pathRedirect = if uriPath.hasSuffix(.forwardSlash) {
|
return if uriPath.hasSuffix(.forwardSlash) {
|
||||||
String(format: .Format.Path.documentation, uriPath)
|
.redirect(to: String(format: .Format.Path.documentation, uriPath))
|
||||||
} else {
|
} else {
|
||||||
String(format: .Format.Path.forwardSlash, uriPath)
|
.redirect(to: String(format: .Format.Path.forwardSlash, uriPath))
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect(
|
|
||||||
to: pathRedirect,
|
|
||||||
input: input,
|
|
||||||
context: context
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for staticFile in StaticFile.allCases {
|
for staticFile in StaticFile.allCases {
|
||||||
@ -111,7 +85,6 @@ struct DocCMiddleware<
|
|||||||
return try await serveFile(
|
return try await serveFile(
|
||||||
String(format: .Format.Path.documentationJSON, nameArchive),
|
String(format: .Format.Path.documentationJSON, nameArchive),
|
||||||
at: pathArchive,
|
at: pathArchive,
|
||||||
input: input,
|
|
||||||
context: context
|
context: context
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
@ -120,7 +93,6 @@ struct DocCMiddleware<
|
|||||||
return try await serveFile(
|
return try await serveFile(
|
||||||
uriResource,
|
uriResource,
|
||||||
at: pathArchive,
|
at: pathArchive,
|
||||||
input: input,
|
|
||||||
context: context
|
context: context
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -134,7 +106,6 @@ struct DocCMiddleware<
|
|||||||
return try await serveFile(
|
return try await serveFile(
|
||||||
uriResource,
|
uriResource,
|
||||||
at: pathArchive,
|
at: pathArchive,
|
||||||
input: input,
|
|
||||||
context: context
|
context: context
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -147,32 +118,15 @@ struct DocCMiddleware<
|
|||||||
return try await serveFile(
|
return try await serveFile(
|
||||||
String(format: .Format.Path.index, indexPrefix.path, nameArchive),
|
String(format: .Format.Path.index, indexPrefix.path, nameArchive),
|
||||||
at: pathArchive,
|
at: pathArchive,
|
||||||
input: input,
|
|
||||||
context: context
|
context: context
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
// rule #5: Redirects URI resources with `/documentation` to `/documentation/`.
|
// rule #5: Redirects URI resources with `/documentation` to `/documentation/`.
|
||||||
// rule #6: Redirects URI resources with `/tutorials` to `/tutorials/`.
|
// rule #6: Redirects URI resources with `/tutorials` to `/tutorials/`.
|
||||||
return redirect(
|
return .redirect(to: String(format: .Format.Path.forwardSlash, uriPath))
|
||||||
to: String(format: .Format.Path.forwardSlash, uriPath),
|
|
||||||
input: input,
|
|
||||||
context: context
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
defer {
|
|
||||||
logger.error(
|
|
||||||
"The request has not been implemented yet.",
|
|
||||||
metadata: .metadata(
|
|
||||||
context: context,
|
|
||||||
request: input,
|
|
||||||
statusCode: .notImplemented
|
|
||||||
),
|
|
||||||
source: .source
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
throw HTTPError(.notImplemented)
|
throw HTTPError(.notImplemented)
|
||||||
}
|
}
|
||||||
@ -185,79 +139,23 @@ private extension DocCMiddleware {
|
|||||||
|
|
||||||
// MARK: Functions
|
// MARK: Functions
|
||||||
|
|
||||||
/// Redirects a request to a new relative path.
|
|
||||||
/// - Parameters:
|
|
||||||
/// - path: A relative path to use in the redirection.
|
|
||||||
/// - input: An input request.
|
|
||||||
/// - context: A request context.
|
|
||||||
/// - Returns: A HTTP response containing the redirection to another
|
|
||||||
func redirect(
|
|
||||||
to path: String,
|
|
||||||
input: Request,
|
|
||||||
context: Context
|
|
||||||
) -> Response {
|
|
||||||
defer {
|
|
||||||
logger.debug(
|
|
||||||
"The path URI has been redirected to: \(path)",
|
|
||||||
metadata: .metadata(
|
|
||||||
context: context,
|
|
||||||
request: input,
|
|
||||||
statusCode: .permanentRedirect,
|
|
||||||
redirect: path
|
|
||||||
),
|
|
||||||
source: .source
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return .redirect(to: path)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Serves a resource file from a provider as a HTTP response.
|
/// Serves a resource file from a provider as a HTTP response.
|
||||||
/// - Parameters:
|
/// - Parameters:
|
||||||
/// - path: A relative path to a resource file.
|
/// - path: A relative path to a resource file.
|
||||||
/// - folder: A folder accessible to the provider where to find resource files.
|
/// - folder: A folder accessible to the provider where to find resource files.
|
||||||
/// - input: An input request.
|
|
||||||
/// - context: A request context.
|
/// - context: A request context.
|
||||||
/// - Returns: A HTTP response containing the content of a given resource file inside its body.
|
/// - Returns: A HTTP response containing the content of a given resource file inside its body.
|
||||||
/// - Throws:An error...
|
/// - Throws:An error...
|
||||||
func serveFile(
|
func serveFile(
|
||||||
_ path: String,
|
_ path: String,
|
||||||
at folder: String,
|
at folder: String,
|
||||||
input: Request,
|
|
||||||
context: Context
|
context: Context
|
||||||
) async throws -> Response {
|
) async throws -> Response {
|
||||||
guard let fileIdentifier = assetProvider.getFileIdentifier(folder + path) else {
|
guard let fileIdentifier = assetProvider.getFileIdentifier(folder + path) else {
|
||||||
defer {
|
|
||||||
logger.error(
|
|
||||||
"The resource has not been found.",
|
|
||||||
metadata: .metadata(
|
|
||||||
context: context,
|
|
||||||
request: input,
|
|
||||||
statusCode: .notFound
|
|
||||||
),
|
|
||||||
source: .source
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
throw HTTPError(.notFound)
|
throw HTTPError(.notFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
let body = try await assetProvider.loadFile(
|
let body = try await assetProvider.loadFile(id: fileIdentifier, context: context)
|
||||||
id: fileIdentifier,
|
|
||||||
context: context
|
|
||||||
)
|
|
||||||
|
|
||||||
defer {
|
|
||||||
logger.debug(
|
|
||||||
"The body of the response returned: \(body.contentLength ?? 0) bytes.",
|
|
||||||
metadata: .metadata(
|
|
||||||
context: context,
|
|
||||||
request: input,
|
|
||||||
statusCode: .ok
|
|
||||||
),
|
|
||||||
source: .source
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return .init(
|
return .init(
|
||||||
status: .ok,
|
status: .ok,
|
||||||
@ -267,9 +165,3 @@ private extension DocCMiddleware {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - String+Constants
|
|
||||||
|
|
||||||
private extension String {
|
|
||||||
static let source = "DocCMiddleware"
|
|
||||||
}
|
|
||||||
|
@ -79,14 +79,10 @@ private extension AppBuilder {
|
|||||||
|
|
||||||
router.addMiddleware {
|
router.addMiddleware {
|
||||||
LogRequestsMiddleware(logger.logLevel)
|
LogRequestsMiddleware(logger.logLevel)
|
||||||
DocCMiddleware(archivesPath, logger: logger)
|
DocCMiddleware(archivesPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
ArchiveController(
|
ArchiveController(archivesPath).register(to: router)
|
||||||
archivesPath,
|
|
||||||
logger: logger
|
|
||||||
)
|
|
||||||
.register(to: router)
|
|
||||||
|
|
||||||
return router
|
return router
|
||||||
}
|
}
|
||||||
|
4
Makefile
4
Makefile
@ -36,8 +36,8 @@ update: ## Updates the SPM package dependencies.
|
|||||||
build: ## Builds the project locally.
|
build: ## Builds the project locally.
|
||||||
@swift build -c release
|
@swift build -c release
|
||||||
|
|
||||||
run: build ## Runs the project locally.
|
run: ## Runs the project locally.
|
||||||
@swift run doxy --archives-path "$(DOCC_ARCHIVES_FOLDER)" --log-level debug
|
@swift run -c release
|
||||||
|
|
||||||
tests: ## Runs all the test cases of the project.
|
tests: ## Runs all the test cases of the project.
|
||||||
@swift test --enable-swift-testing
|
@swift test --enable-swift-testing
|
||||||
|
11
README.md
11
README.md
@ -44,17 +44,6 @@ $ make install
|
|||||||
$ doxy --help
|
$ doxy --help
|
||||||
```
|
```
|
||||||
|
|
||||||
If a `permission issue` issue is raised when installing the built executable into the system binaries folder, means the user used have no *admin* and/or *root* priviledges. In that case, the developer should copy/install the built executable manually to a custom location in the file system.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Copy the built executable into a non-protected folder.
|
|
||||||
$ cp ./build/release/doxy /path/to/some/folder
|
|
||||||
# Change the current folder to the non-protected folder.
|
|
||||||
$ cd /path/to/some/folder
|
|
||||||
# Make sure the executable is working
|
|
||||||
$ ./doxy --help
|
|
||||||
```
|
|
||||||
|
|
||||||
### Usage
|
### Usage
|
||||||
|
|
||||||
To use this service, please do execute the following commands in the prompt of the **Terminal** command-line app in the local system:
|
To use this service, please do execute the following commands in the prompt of the **Terminal** command-line app in the local system:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user