@@ -10,7 +10,7 @@ import Combine
10
10
import UIKit
11
11
12
12
protocol ImageWebRepository : WebRepository {
13
- func load( imageURL: URL , width : Int ) -> AnyPublisher < UIImage , Error >
13
+ func load( imageURL: URL ) -> AnyPublisher < Data , Error >
14
14
}
15
15
16
16
struct RealImageWebRepository : ImageWebRepository {
@@ -24,155 +24,17 @@ struct RealImageWebRepository: ImageWebRepository {
24
24
self . baseURL = baseURL
25
25
}
26
26
27
- func load( imageURL: URL , width: Int ) -> AnyPublisher < UIImage , Error > {
28
- guard ( imageURL. absoluteString as NSString ) . pathExtension. lowercased ( ) == " svg " else {
29
- return download ( rawImageURL: imageURL)
30
- . subscribe ( on: bgQueue)
31
- . receive ( on: DispatchQueue . main)
32
- . extractUnderlyingError ( )
33
- . eraseToAnyPublisher ( )
34
- }
35
- return Just < Void > . withErrorType ( Error . self)
36
- . flatMap { self . importImage ( originalURL: imageURL) }
37
- . flatMap { self . exportImage ( imported: $0, width: width) }
38
- . flatMap { self . download ( exported: $0) }
39
- . catch { self . removeCachedResponses ( error: $0) }
27
+ func load( imageURL: URL ) -> AnyPublisher < Data , Error > {
28
+ return download ( rawImageURL: imageURL)
40
29
. subscribe ( on: bgQueue)
41
30
. receive ( on: DispatchQueue . main)
42
31
. extractUnderlyingError ( )
43
32
. eraseToAnyPublisher ( )
44
33
}
45
34
46
- private func importImage( originalURL: URL ) -> AnyPublisher < ImageConversion . Import , Error > {
47
- guard let conversionURL = URL ( string:
48
- baseURL + " /svg-to-png?url= " + originalURL. absoluteString) else {
49
- return Fail < ImageConversion . Import , Error > ( error: APIError . invalidURL) . eraseToAnyPublisher ( )
50
- }
51
- var urlRequest = URLRequest ( url: conversionURL)
52
- urlRequest. httpMethod = " GET "
53
- return session. dataTaskPublisher ( for: urlRequest)
54
- . tryMap { try ImageConversion . Import ( data: $0. data, urlRequest: urlRequest) }
55
- . eraseToAnyPublisher ( )
56
- }
57
-
58
- private func exportImage( imported: ImageConversion . Import ,
59
- width: Int ) -> AnyPublisher < ImageConversion . Export , Error > {
60
- guard let conversionURL = URL ( string: imported. urlString + " ?ajax=true " ) else {
61
- return Fail < ImageConversion . Export , Error > (
62
- error: APIError . imageProcessing ( [ imported. urlRequest] ) )
63
- . eraseToAnyPublisher ( )
64
- }
65
- var urlRequest = URLRequest ( url: conversionURL)
66
- urlRequest. httpMethod = " POST "
67
- let body : [ String : Any ] = [
68
- " file " : ( imported. urlString as NSString ) . lastPathComponent,
69
- " token " : imported. ajaxToken,
70
- " width " : width
71
- ]
72
- let bodyString = body. map { $0. key + " = " + " \( $0. value) " } . joined ( separator: " & " )
73
- urlRequest. httpBody = bodyString. data ( using: . utf8)
74
- let urlRequests = [ imported. urlRequest, urlRequest]
75
- return session. dataTaskPublisher ( for: urlRequest)
76
- . tryMap { try ImageConversion . Export ( data: $0. data, urlRequests: urlRequests) }
77
- . eraseToAnyPublisher ( )
78
- }
79
-
80
- private func download( exported: ImageConversion . Export ) -> AnyPublisher < UIImage , Error > {
81
- download ( rawImageURL: exported. imageURL, requests: exported. urlRequests)
82
- }
83
-
84
- private func download( rawImageURL: URL , requests: [ URLRequest ] = [ ] ) -> AnyPublisher < UIImage , Error > {
35
+ private func download( rawImageURL: URL ) -> AnyPublisher < Data , Error > {
85
36
let urlRequest = URLRequest ( url: rawImageURL)
86
37
return session. dataTaskPublisher ( for: urlRequest)
87
- . tryMap { ( data, response) in
88
- guard let image = UIImage ( data: data)
89
- else { throw APIError . imageProcessing ( requests + [ urlRequest] ) }
90
- return image
91
- }
92
- . eraseToAnyPublisher ( )
93
- }
94
-
95
- private func removeCachedResponses( error: Error ) -> AnyPublisher < UIImage , Error > {
96
- if let apiError = error as? APIError ,
97
- case let . imageProcessing( urlRequests) = apiError,
98
- let cache = session. configuration. urlCache {
99
- urlRequests. forEach ( cache. removeCachedResponse)
100
- }
101
- return Fail ( error: error) . eraseToAnyPublisher ( )
102
- }
103
- }
104
-
105
- private struct ImageConversion { }
106
-
107
- extension ImageConversion {
108
- struct Import {
109
-
110
- let urlString : String
111
- let ajaxToken : String
112
- let urlRequest : URLRequest
113
-
114
- init ( data: Data ? , urlRequest: URLRequest ) throws {
115
- guard let data = data, let string = String ( data: data, encoding: . utf8) ,
116
- let elementWithURL = string. firstMatch ( pattern: #"<form class="form ajax-form".*\.svg">"# ) ,
117
- let conversionURL = elementWithURL. firstMatch ( pattern: #"https.*\.svg"# ) ,
118
- let ajaxTokenElement = string. firstMatch ( pattern: #"name=\"file\"><input .*name=\"token\".*>"# ) ,
119
- let dirtyToken = ajaxTokenElement. firstMatch ( pattern: #"value="([a-z]|[0-9])*"# )
120
- else { throw APIError . imageProcessing ( [ urlRequest] ) }
121
- self . urlString = conversionURL
122
- self . ajaxToken = String ( dirtyToken. suffix ( from: dirtyToken. index ( dirtyToken. startIndex, offsetBy: 7 ) ) )
123
- self . urlRequest = urlRequest
124
- }
125
- }
126
- }
127
-
128
- extension ImageConversion {
129
- struct Export {
130
-
131
- let imageURL : URL
132
- let urlRequests : [ URLRequest ]
133
-
134
- init ( data: Data ? , urlRequests: [ URLRequest ] ) throws {
135
- guard let data = data, let string = String ( data: data, encoding: . utf8) ,
136
- let element = string. firstMatch ( pattern: #"src=.*style="width"# ) ,
137
- let imageURL = element. firstMatch ( pattern: #"\/\/.*\.png"# ) ,
138
- let url = URL ( string: " https: " + imageURL)
139
- else { throw APIError . imageProcessing ( urlRequests) }
140
- self . imageURL = url
141
- self . urlRequests = urlRequests
142
- }
143
- }
144
- }
145
-
146
- private extension String {
147
- func firstMatch( pattern: String ) -> String ? {
148
- guard let regex = try ? NSRegularExpression ( pattern: pattern, options: [ ] ) ,
149
- let matchResult = regex. firstMatch ( in: self , options: [ ] , range: NSRange ( location: 0 , length: count) ) ,
150
- let range = matchResult. ranges. first ( where: { $0. location != NSNotFound } )
151
- else { return nil }
152
- return ( self as NSString ) . substring ( with: range)
153
- }
154
- }
155
-
156
- extension NSTextCheckingResult {
157
- struct Iterator : IteratorProtocol {
158
- typealias Element = NSRange
159
-
160
- private var index : Int = 0
161
- private let collection : NSTextCheckingResult
162
-
163
- init ( collection: NSTextCheckingResult ) {
164
- self . collection = collection
165
- }
166
-
167
- mutating func next( ) -> NSRange ? {
168
- defer { index += 1 }
169
- return index < collection. numberOfRanges ? collection. range ( at: index) : nil
170
- }
171
- }
172
- }
173
-
174
- extension NSTextCheckingResult {
175
- var ranges : IteratorSequence < NSTextCheckingResult . Iterator > {
176
- return . init( . init( collection: self ) )
38
+ . requestData ( )
177
39
}
178
40
}
0 commit comments