Packages/MoonriseKit/Sources/Feeds/Launches.swift
49 lines · 1818 bytes
5 symbols in this file
1import Foundation
2
3/// An upcoming launch as served by the Moonrise backend (from Launch Library 2).
4public struct Launch: Codable, Sendable, Identifiable, Hashable {
5 public var id: String
6 public var name: String
7 public var net: Date
8 public var windowStart: Date?
9 public var windowEnd: Date?
10 /// Launch Library 2 status abbreviation: Go, TBC, TBD, Hold, Success, Failure, …
11 public var status: String
12 public var statusName: String
13 public var provider: String
14 public var rocket: String
15 public var mission: String?
16 public var missionType: String?
17 public var missionDescription: String?
18 public var orbit: String?
19 public var pad: String
20 public var location: String
21 public var padLatitude: Double?
22 public var padLongitude: Double?
23}
24
25public struct LaunchList: Codable, Sendable {
26 public var fetchedAt: Date?
27 public var launches: [Launch]
28}
29
30public enum LaunchFeed {
31 static let decoder: JSONDecoder = {
32 let d = JSONDecoder()
33 d.dateDecodingStrategy = .custom { decoder in
34 let s = try decoder.singleValueContainer().decode(String.self)
35 if let date = try? Date(s, strategy: .iso8601) { return date }
36 if let date = try? Date(s, strategy: Date.ISO8601FormatStyle(includingFractionalSeconds: true)) { return date }
37 throw DecodingError.dataCorrupted(.init(codingPath: decoder.codingPath, debugDescription: "bad date \(s)"))
38 }
39 return d
40 }()
41
42 public static func decode(_ data: Data) throws -> LaunchList {
43 try decoder.decode(LaunchList.self, from: data)
44 }
45
46 public static func fetch(base: URL, session: URLSession = .shared) async throws -> LaunchList {
47 try decode(await session.data(from: base.appending(path: "v1/launches")).0)
48 }
49}