Skip to content

Instantly share code, notes, and snippets.

@daltonclaybrook
Created August 5, 2021 20:06
Show Gist options
  • Save daltonclaybrook/3eba9081b6e03800fd44b8072333c167 to your computer and use it in GitHub Desktop.
Save daltonclaybrook/3eba9081b6e03800fd44b8072333c167 to your computer and use it in GitHub Desktop.
import Foundation
import libspacekit
public struct AstroPhoto: Equatable {
public let title: String
public let url: URL
}
private struct AstroPhotoContext {
let fetcher: AstroPhotoFetcher
let completion: AstroPhotoFetcher.PhotoCompletion
}
/// Utility for fetching the NASA astronomy photo of the day
public final class AstroPhotoFetcher {
public typealias PhotoCompletion = (Result<AstroPhoto, PhotoError>) -> Void
public enum PhotoError: Error {
case noPhotoFound
case invalidPhotoURLs
}
private let nasaAPIKey: String
public init(nasaAPIKey: String) {
self.nasaAPIKey = nasaAPIKey
}
public func fetchPhoto(with completion: @escaping PhotoCompletion) {
let context = AstroPhotoContext(fetcher: self, completion: completion)
let contextPointer = UnsafeMutablePointer<AstroPhotoContext>.allocate(capacity: 1)
contextPointer.initialize(to: context)
nasaAPIKey.withCString { apiKeyPointer in
fetch_photo_of_the_day(
apiKeyPointer,
photoCallback(info:rawContext:),
UnsafeMutableRawPointer(contextPointer)
)
}
}
// MARK: - Completion handlers
fileprivate func handleDidReceivePhoto(_ info: PhotoInfo?, completion: PhotoCompletion) {
guard let info = info else {
return completion(.failure(.noPhotoFound))
}
let title = String(cString: info.title)
let urlString = String(cString: info.url)
guard let url = URL(string: urlString) else {
return completion(.failure(.invalidPhotoURLs))
}
let photo = AstroPhoto(title: title, url: url)
completion(.success(photo))
}
}
// MARK: - Callback
private func photoCallback(info: UnsafeMutablePointer<PhotoInfo>?, rawContext: UnsafeMutableRawPointer?) {
guard let rawContext = rawContext else { return }
let contextPointer = rawContext.assumingMemoryBound(to: AstroPhotoContext.self)
let context = contextPointer.pointee
defer {
contextPointer.deinitialize(count: 1)
contextPointer.deallocate()
}
context.fetcher.handleDidReceivePhoto(info?.pointee, completion: context.completion)
}
import Foundation
import libspacekit
public struct AstroPhoto: Equatable {
public let title: String
public let url: URL
}
/// Utility for fetching the NASA astronomy photo of the day
public final class AstroPhotoFetcher {
public typealias PhotoCompletion = (Result<AstroPhoto, PhotoError>) -> Void
public enum PhotoError: Error {
case noPhotoFound
case invalidPhotoURLs
}
private let nasaAPIKey: String
public init(nasaAPIKey: String) {
self.nasaAPIKey = nasaAPIKey
}
public func fetchPhoto(with completion: @escaping PhotoCompletion) {
// Todo: implement
}
// MARK: - Completion handlers
fileprivate func handleDidReceivePhoto(_ info: PhotoInfo?, completion: PhotoCompletion) {
guard let info = info else {
return completion(.failure(.noPhotoFound))
}
let title = String(cString: info.title)
let urlString = String(cString: info.url)
guard let url = URL(string: urlString) else {
return completion(.failure(.invalidPhotoURLs))
}
let photo = AstroPhoto(title: title, url: url)
completion(.success(photo))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment