Skip to content

Commit

Permalink
Update HTTPServer API (#424)
Browse files Browse the repository at this point in the history
  • Loading branch information
mickael-menu committed May 17, 2024
1 parent a1dd426 commit 473ef6c
Show file tree
Hide file tree
Showing 6 changed files with 44 additions and 62 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ The Readium Swift toolkit now requires a minimum of iOS 13.
#### Shared

* The `Link` property key for archive-based publication assets (e.g. an EPUB/ZIP) is now `https://readium.org/webpub-manifest/properties#archive` instead of `archive`.
* The API of `HTTPServer` slightly changed to be more future-proof.

#### Navigator

Expand Down
29 changes: 8 additions & 21 deletions Sources/Adapters/GCDWebServer/GCDHTTPServer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,14 @@ public enum GCDHTTPServerError: Error {

/// Implementation of `HTTPServer` using ReadiumGCDWebServer under the hood.
public class GCDHTTPServer: HTTPServer, Loggable {
private struct EndpointHandler {
let resourceHandler: (HTTPServerRequest) -> Resource
let failureHandler: HTTPServer.FailureHandler?
}

/// Shared instance of the HTTP server.
public static let shared = GCDHTTPServer()

/// The actual underlying HTTP server instance.
private let server = ReadiumGCDWebServer()

/// Mapping between endpoints and their handlers.
private var handlers: [HTTPURL: EndpointHandler] = [:]
private var handlers: [HTTPURL: HTTPRequestHandler] = [:]

/// Mapping between endpoints and resource transformers.
private var transformers: [HTTPURL: [ResourceTransformer]] = [:]
Expand Down Expand Up @@ -114,7 +109,7 @@ public class GCDHTTPServer: HTTPServer, Loggable {

private func responseResource(
for request: ReadiumGCDWebServerRequest,
completion: @escaping (HTTPServerRequest, Resource, FailureHandler?) -> Void
completion: @escaping (HTTPServerRequest, Resource, HTTPRequestHandler.OnFailure?) -> Void
) {
let completion = { request, resource, failureHandler in
// Escape the queue to avoid deadlocks if something is using the
Expand Down Expand Up @@ -145,11 +140,11 @@ public class GCDHTTPServer: HTTPServer, Loggable {
for (endpoint, handler) in handlers {
if endpoint == pathWithoutAnchor {
let request = HTTPServerRequest(url: url, href: nil)
let resource = handler.resourceHandler(request)
let resource = handler.onRequest(request)
completion(
request,
transform(resource: resource, at: endpoint),
handler.failureHandler
handler.onFailure
)
return

Expand All @@ -158,11 +153,11 @@ public class GCDHTTPServer: HTTPServer, Loggable {
url: url,
href: href
)
let resource = handler.resourceHandler(request)
let resource = handler.onRequest(request)
completion(
request,
transform(resource: resource, at: endpoint),
handler.failureHandler
handler.onFailure
)
return
}
Expand All @@ -182,25 +177,17 @@ public class GCDHTTPServer: HTTPServer, Loggable {

// MARK: HTTPServer

public func serve(at endpoint: HTTPServerEndpoint, handler: @escaping (HTTPServerRequest) -> Resource) throws -> HTTPURL {
try serve(at: endpoint, handler: handler, failureHandler: nil)
}

public func serve(
at endpoint: HTTPServerEndpoint,
handler: @escaping (HTTPServerRequest) -> Resource,
failureHandler: FailureHandler?
handler: HTTPRequestHandler
) throws -> HTTPURL {
try queue.sync(flags: .barrier) {
if case .stopped = state {
try start()
}

let url = try url(for: endpoint)
handlers[url] = EndpointHandler(
resourceHandler: handler,
failureHandler: failureHandler
)
handlers[url] = handler
return url
}
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/Navigator/CBZ/CBZNavigatorViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ open class CBZNavigatorViewController: UIViewController, VisualNavigator, Loggab
publicationBaseURL = try httpServer.serve(
at: uuidEndpoint,
publication: publication,
failureHandler: { [weak self] request, error in
onFailure: { [weak self] request, error in
DispatchQueue.main.async { [weak self] in
guard let self = self, let href = request.href else {
return
Expand Down
7 changes: 3 additions & 4 deletions Sources/Navigator/EPUB/EPUBNavigatorViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,7 @@ final class EPUBNavigatorViewModel: Loggable {
assetsURL: httpServer.serve(
at: "readium",
contentsOf: Bundle.module.resourceURL!.fileURL!
.appendingPath("Assets/Static", isDirectory: true),
failureHandler: nil
.appendingPath("Assets/Static", isDirectory: true)
),
useLegacySettings: false
)
Expand All @@ -73,7 +72,7 @@ final class EPUBNavigatorViewModel: Loggable {
publicationBaseURL = try httpServer.serve(
at: uuidEndpoint, // serving the chapters endpoint
publication: publication,
failureHandler: { [weak self] request, error in
onFailure: { [weak self] request, error in
guard let self = self, let href = request.href else {
return
}
Expand Down Expand Up @@ -187,7 +186,7 @@ final class EPUBNavigatorViewModel: Loggable {
throw Error.noHTTPServer
}
let endpoint = baseEndpoint.addingSuffix("/") + file.lastPathSegment
let url = try httpServer.serve(at: endpoint, contentsOf: file, failureHandler: nil)
let url = try httpServer.serve(at: endpoint, contentsOf: file)
$servedFiles.write { $0[file] = url }
return url
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/Navigator/PDF/PDFNavigatorViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ open class PDFNavigatorViewController: UIViewController, VisualNavigator, Select
publicationBaseURL = try httpServer.serve(
at: uuidEndpoint,
publication: publication,
failureHandler: { request, error in
onFailure: { request, error in
DispatchQueue.main.async { [weak self] in
guard let self = self, let href = request.href else {
return
Expand Down
65 changes: 30 additions & 35 deletions Sources/Shared/Toolkit/HTTP/HTTPServer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,31 +11,15 @@ import Foundation
/// This is required by some Navigators to access a local publication's
/// resources.
public protocol HTTPServer {
typealias FailureHandler = (_ request: HTTPServerRequest, _ error: ResourceError) -> Void

/// Serves resources at the given `endpoint`.
///
/// Subsequent calls with the same `endpoint` overwrite each other.
///
/// - Returns the base URL for this endpoint.
@discardableResult
func serve(
at endpoint: HTTPServerEndpoint,
handler: @escaping (HTTPServerRequest) -> Resource
) throws -> HTTPURL

/// Serves resources at the given `endpoint`.
///
/// Subsequent calls with the same `endpoint` overwrite each other.
///
/// If the resource cannot be served, the `failureHandler` is called.
///
/// - Returns the base URL for this endpoint.
@discardableResult
func serve(
at endpoint: HTTPServerEndpoint,
handler: @escaping (HTTPServerRequest) -> Resource,
failureHandler: FailureHandler?
handler: HTTPRequestHandler
) throws -> HTTPURL

/// Registers a `Resource` transformer that will be run on all responses
Expand All @@ -48,15 +32,6 @@ public protocol HTTPServer {
}

public extension HTTPServer {
@discardableResult
func serve(
at endpoint: HTTPServerEndpoint,
handler: @escaping (HTTPServerRequest) -> Resource,
failureHandler: FailureHandler?
) throws -> HTTPURL {
try serve(at: endpoint, handler: handler)
}

/// Serves the local file `url` at the given `endpoint`.
///
/// If the provided `url` is a directory, then all the files in the
Expand All @@ -70,9 +45,9 @@ public extension HTTPServer {
func serve(
at endpoint: HTTPServerEndpoint,
contentsOf url: FileURL,
failureHandler: FailureHandler? = nil
onFailure: HTTPRequestHandler.OnFailure? = nil
) throws -> HTTPURL {
func handler(request: HTTPServerRequest) -> Resource {
func onRequest(request: HTTPServerRequest) -> Resource {
let file = request.href.flatMap { url.resolve($0) }
?? url

Expand All @@ -87,8 +62,10 @@ public extension HTTPServer {

return try serve(
at: endpoint,
handler: handler(request:),
failureHandler: failureHandler
handler: HTTPRequestHandler(
onRequest: onRequest,
onFailure: onFailure
)
)
}

Expand All @@ -102,11 +79,11 @@ public extension HTTPServer {
func serve(
at endpoint: HTTPServerEndpoint,
publication: Publication,
failureHandler: FailureHandler? = nil
onFailure: HTTPRequestHandler.OnFailure? = nil
) throws -> HTTPURL {
func handler(request: HTTPServerRequest) -> Resource {
func onRequest(request: HTTPServerRequest) -> Resource {
guard let href = request.href else {
failureHandler?(request, .notFound(nil))
onFailure?(request, .notFound(nil))

return FailureResource(
link: Link(href: request.url.string),
Expand All @@ -119,8 +96,10 @@ public extension HTTPServer {

return try serve(
at: endpoint,
handler: handler(request:),
failureHandler: failureHandler
handler: HTTPRequestHandler(
onRequest: onRequest,
onFailure: onFailure
)
)
}
}
Expand All @@ -141,3 +120,19 @@ public struct HTTPServerRequest {
self.href = href
}
}

/// Callbacks handling a request.
///
/// If the resource cannot be served, the `onFailure` callback is called.
public struct HTTPRequestHandler {
public typealias OnRequest = (_ request: HTTPServerRequest) -> Resource
public typealias OnFailure = (_ request: HTTPServerRequest, _ error: ResourceError) -> Void

public let onRequest: OnRequest
public let onFailure: OnFailure?

public init(onRequest: @escaping OnRequest, onFailure: OnFailure? = nil) {
self.onRequest = onRequest
self.onFailure = onFailure
}
}

0 comments on commit 473ef6c

Please sign in to comment.