forked from shadowfacts/Tusker
parent
242c60d74d
commit
82ec120871
|
@ -25,27 +25,30 @@ public struct Client: Sendable {
|
||||||
|
|
||||||
public var timeoutInterval: TimeInterval = 60
|
public var timeoutInterval: TimeInterval = 60
|
||||||
|
|
||||||
static let decoder: JSONDecoder = {
|
private static let dateFormatter: DateFormatter = {
|
||||||
let decoder = JSONDecoder()
|
|
||||||
|
|
||||||
let formatter = DateFormatter()
|
let formatter = DateFormatter()
|
||||||
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SZ"
|
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SZ"
|
||||||
formatter.timeZone = TimeZone(abbreviation: "UTC")
|
formatter.timeZone = TimeZone(abbreviation: "UTC")
|
||||||
formatter.locale = Locale(identifier: "en_US_POSIX")
|
formatter.locale = Locale(identifier: "en_US_POSIX")
|
||||||
let iso8601 = ISO8601DateFormatter()
|
return formatter
|
||||||
|
}()
|
||||||
|
private static let iso8601Formatter = ISO8601DateFormatter()
|
||||||
|
private static func decodeDate(string: String) -> Date? {
|
||||||
|
// for the next time mastodon accidentally changes date formats >.>
|
||||||
|
return dateFormatter.date(from: string) ?? iso8601Formatter.date(from: string)
|
||||||
|
}
|
||||||
|
|
||||||
|
static let decoder: JSONDecoder = {
|
||||||
|
let decoder = JSONDecoder()
|
||||||
decoder.dateDecodingStrategy = .custom({ (decoder) in
|
decoder.dateDecodingStrategy = .custom({ (decoder) in
|
||||||
let container = try decoder.singleValueContainer()
|
let container = try decoder.singleValueContainer()
|
||||||
let str = try container.decode(String.self)
|
let str = try container.decode(String.self)
|
||||||
// for the next time mastodon accidentally changes date formats >.>
|
if let date = Self.decodeDate(string: str) {
|
||||||
if let date = formatter.date(from: str) {
|
|
||||||
return date
|
|
||||||
} else if let date = iso8601.date(from: str) {
|
|
||||||
return date
|
return date
|
||||||
} else {
|
} else {
|
||||||
throw DecodingError.typeMismatch(Date.self, .init(codingPath: container.codingPath, debugDescription: "unexpected date format: \(str)"))
|
throw DecodingError.typeMismatch(Date.self, .init(codingPath: container.codingPath, debugDescription: "unexpected date format: \(str)"))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return decoder
|
return decoder
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -105,6 +108,15 @@ public struct Client: Sendable {
|
||||||
return task
|
return task
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func error(from response: HTTPURLResponse) -> ErrorType {
|
||||||
|
if response.statusCode == 429,
|
||||||
|
let date = response.value(forHTTPHeaderField: "X-RateLimit-Reset").flatMap(Self.decodeDate) {
|
||||||
|
return .rateLimited(date)
|
||||||
|
} else {
|
||||||
|
return .unexpectedStatus(response.statusCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public func run<Result: Sendable>(_ request: Request<Result>) async throws -> (Result, Pagination?) {
|
public func run<Result: Sendable>(_ request: Request<Result>) async throws -> (Result, Pagination?) {
|
||||||
return try await withCheckedThrowingContinuation { continuation in
|
return try await withCheckedThrowingContinuation { continuation in
|
||||||
|
@ -575,6 +587,8 @@ extension Client {
|
||||||
return "Invalid Model"
|
return "Invalid Model"
|
||||||
case .mastodonError(let code, let error):
|
case .mastodonError(let code, let error):
|
||||||
return "Server Error (\(code)): \(error)"
|
return "Server Error (\(code)): \(error)"
|
||||||
|
case .rateLimited(let reset):
|
||||||
|
return "Rate Limited Until \(reset.formatted(date: .omitted, time: .standard))"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -585,6 +599,7 @@ extension Client {
|
||||||
case invalidResponse
|
case invalidResponse
|
||||||
case invalidModel(Swift.Error)
|
case invalidModel(Swift.Error)
|
||||||
case mastodonError(Int, String)
|
case mastodonError(Int, String)
|
||||||
|
case rateLimited(Date)
|
||||||
}
|
}
|
||||||
|
|
||||||
enum NodeInfoError: LocalizedError {
|
enum NodeInfoError: LocalizedError {
|
||||||
|
|
Loading…
Reference in New Issue