1
1
import Foundation
2
2
import os. log
3
3
4
- #if canImport(Combine)
5
- import Combine
6
- #endif
7
-
8
4
internal extension URL {
9
5
enum Mensa {
10
6
static let baseUrl = URL ( string: " https://api.studentenwerk-dresden.de/openmensa/v2/ " ) !
@@ -15,138 +11,56 @@ internal extension URL {
15
11
}
16
12
}
17
13
18
- extension URLSession {
19
- fileprivate func emealDataTask( with url: URL , completion: @escaping ( Result < Data , EmealError > ) -> Void ) {
20
- let task = self . dataTask ( with: url) { data, response, error in
21
- guard
22
- let data = data,
23
- error == nil
24
- else {
25
- if let urlError = error {
26
- completion ( . failure( . other( urlError) ) )
27
- return
28
- }
29
- completion ( . failure( . unknown) )
30
- return
31
- }
32
- completion ( . success( data) )
33
- }
34
- task. resume ( )
35
- }
36
- }
37
-
38
14
// MARK: - Canteens
39
15
40
16
extension Canteen {
41
- public static func all( session: URLSession = . shared,
42
- completion: @escaping ( Result < [ Canteen ] , EmealError > ) -> Void ) {
43
- Logger . emealKit. debug ( " Creating data task for all canteens " )
44
- session. emealDataTask ( with: URL . Mensa. canteens) { result in
45
- switch result {
46
- case . failure( let error) :
47
- Logger . emealKit. error ( " Failed to fetch canteen data: \( String ( describing: error) ) " )
48
- completion ( . failure( error) )
49
- case . success( let data) :
50
- do {
51
- let canteens = try JSONDecoder ( ) . decode ( [ Canteen ] . self, from: data)
52
- Logger . emealKit. debug ( " Successfully fetched \( canteens. count) canteens " )
53
- completion ( . success( canteens) )
54
- } catch let error {
55
- Logger . emealKit. error ( " Failed to decode Canteen data: \( String ( describing: error) ) " )
56
- completion ( . failure( . other( error) ) )
57
- }
58
- }
17
+ public static func all( session: URLSessionProtocol = URLSession . shared) async throws ( EmealError) -> [ Canteen ] {
18
+ Logger . emealKit. debug ( " Fetching all canteens " )
19
+ do {
20
+ let ( data, _) = try await session. data ( from: URL . Mensa. canteens)
21
+ print ( String ( data: data, encoding: . utf8) !)
22
+ let canteens = try JSONDecoder ( ) . decode ( [ Canteen ] . self, from: data)
23
+ Logger . emealKit. debug ( " Successfully fetched \( canteens. count) canteens " )
24
+ return canteens
25
+ } catch ( let error) {
26
+ Logger . emealKit. error ( " Failed to fetch canteen data: \( String ( describing: error) ) " )
27
+ throw . other( error)
59
28
}
60
29
}
61
-
62
- @available ( macOS 12 . 0 , iOS 15 . 0 , * )
63
- public static func all( session: URLSession = . shared) async throws -> [ Canteen ] {
64
- try await withCheckedThrowingContinuation { continuation in
65
- Self . all ( session: session) { result in
66
- continuation. resume ( with: result)
67
- }
68
- }
69
- }
70
- }
71
-
72
- #if canImport(Combine)
73
- extension Canteen {
74
- public static func allPublisher( session: URLSession = . shared) -> AnyPublisher < [ Canteen ] , EmealError > {
75
- session. dataTaskPublisher ( for: URL . Mensa. canteens)
76
- . map { $0. data }
77
- . decode ( type: [ Canteen ] . self, decoder: JSONDecoder ( ) )
78
- . mapError { EmealError . other ( $0) }
79
- . receive ( on: DispatchQueue . main)
80
- . eraseToAnyPublisher ( )
81
- }
82
30
}
83
- #endif
84
31
85
32
// MARK: - Meals
86
33
87
34
extension Meal {
88
- public static func `for`( canteen: CanteenId ,
89
- on date: Date ,
90
- session : URLSession = . shared ,
91
- completion : @escaping ( Result < [ Meal ] , EmealError > ) -> Void ) {
92
- Self . for ( canteen : canteen . rawValue , on : date , session : session , completion : completion )
93
- }
35
+ public static func `for`( canteen: Int , on date : Date , session : URLSessionProtocol = URLSession . shared ) async throws ( EmealError ) -> [ Meal ] {
36
+ Logger . emealKit . debug ( " Fetching meals for canteen \( canteen ) on \( date) " )
37
+ do {
38
+ let ( data , _ ) = try await session . data ( from : URL . Mensa . meals ( canteen : canteen , date : date ) )
39
+ let meals = try JSONDecoder ( ) . decode ( [ Meal ] . self , from : data )
40
+ Logger . emealKit . debug ( " Successfully fetched \( meals . count ) meals " )
94
41
95
- public static func `for`( canteen: Int ,
96
- on date: Date ,
97
- session: URLSession = . shared,
98
- completion: @escaping ( Result < [ Meal ] , EmealError > ) -> Void ) {
99
- Logger . emealKit. debug ( " Creating data task for canteen \( canteen) on \( date) " )
100
- session. emealDataTask ( with: URL . Mensa. meals ( canteen: canteen, date: date) ) { result in
101
- switch result {
102
- case . failure( let error) :
103
- Logger . emealKit. error ( " Failed to fetch meal data: \( String ( describing: error) ) " )
104
- completion ( . failure( error) )
105
- case . success( let data) :
106
- do {
107
- let meals = try JSONDecoder ( ) . decode ( [ Meal ] . self, from: data)
108
- Logger . emealKit. debug ( " Successfully fetched \( meals. count) meals " )
109
- completion ( . success( meals) )
110
- } catch let error {
111
- Logger . emealKit. error ( " Failed to decode meal data: \( String ( describing: error) ) " )
112
- completion ( . failure( . other( error) ) )
42
+ do {
43
+ let feedItems = try await Self . rssData ( )
44
+ return meals. map { meal in
45
+ var meal = meal
46
+ let matchingItem = feedItems. first { $0. matches ( meal: meal) }
47
+ if let matchingItem {
48
+ Logger . emealKit. debug ( " Found matching feeditem for \( meal. id) " )
49
+ meal. isSoldOut = matchingItem. isSoldOut
50
+ }
51
+ return meal
113
52
}
53
+ } catch ( let error) {
54
+ Logger . emealKit. log ( " Failed to fetch rss data, continuing without: \( String ( describing: error) ) " )
55
+ return meals
114
56
}
57
+ } catch ( let error) {
58
+ Logger . emealKit. error ( " Failed to fetch meal data: \( String ( describing: error) ) " )
59
+ throw . other( error)
115
60
}
116
61
}
117
62
118
- @available ( macOS 12 . 0 , iOS 15 . 0 , * )
119
- public static func `for`( canteen: CanteenId , on date: Date , session: URLSession = . shared) async throws -> [ Meal ] {
63
+ public static func `for`( canteen: CanteenId , on date: Date , session: URLSessionProtocol = URLSession . shared) async throws ( EmealError) -> [ Meal ] {
120
64
try await Self . for ( canteen: canteen. rawValue, on: date, session: session)
121
65
}
122
-
123
- @available ( macOS 12 . 0 , iOS 15 . 0 , * )
124
- public static func `for`( canteen: Int , on date: Date , session: URLSession = . shared) async throws -> [ Meal ] {
125
- try await withCheckedThrowingContinuation { continuation in
126
- Self . for ( canteen: canteen, on: date, session: session) { result in
127
- continuation. resume ( with: result)
128
- }
129
- }
130
- }
131
- }
132
-
133
- #if canImport(Combine)
134
- extension Meal {
135
- public static func publisherFor( canteen: Int ,
136
- on date: Date ,
137
- session: URLSession = . shared) -> AnyPublisher < [ Meal ] , EmealError > {
138
- session. dataTaskPublisher ( for: URL . Mensa. meals ( canteen: canteen, date: date) )
139
- . map { $0. data }
140
- . decode ( type: [ Meal ] . self, decoder: JSONDecoder ( ) )
141
- . mapError { EmealError . other ( $0) }
142
- . receive ( on: DispatchQueue . main)
143
- . eraseToAnyPublisher ( )
144
- }
145
-
146
- public static func publisherFor( canteen: CanteenId ,
147
- on date: Date ,
148
- session: URLSession = . shared) -> AnyPublisher < [ Meal ] , EmealError > {
149
- Self . publisherFor ( canteen: canteen. rawValue, on: date, session: session)
150
- }
151
66
}
152
- #endif
0 commit comments