@@ -135,74 +135,135 @@ public enum RelaySelector {
135
135
static func applyConstraints< T: AnyRelay > (
136
136
_ relayConstraint: RelayConstraint < UserSelectedRelays > ,
137
137
filterConstraint: RelayConstraint < RelayFilter > ,
138
+ daita: Bool ,
138
139
relays: [ RelayWithLocation < T > ]
139
- ) -> [ RelayWithLocation < T > ] {
140
- // Filter on active status, filter, and location.
141
- let filteredRelays = relays. filter { relayWithLocation -> Bool in
142
- guard relayWithLocation. relay. active else {
143
- return false
144
- }
140
+ ) throws -> [ RelayWithLocation < T > ] {
141
+ // Filter on active status, daita support, filter constraint and relay constraint.
142
+ var filteredRelays = try filterByActive ( relays: relays)
143
+ filteredRelays = try filterByFilterConstraint ( relays: filteredRelays, constraint: filterConstraint)
144
+ filteredRelays = try filterByLocationConstraint ( relays: filteredRelays, constraint: relayConstraint)
145
+ filteredRelays = try filterByDaita ( relays: filteredRelays, daita: daita)
146
+ return filterByCountryInclusion ( relays: filteredRelays, constraint: relayConstraint)
147
+ }
148
+
149
+ /// Produce a port that is either user provided or randomly selected, satisfying the given constraints.
150
+ static func applyPortConstraint(
151
+ _ portConstraint: RelayConstraint < UInt16 > ,
152
+ rawPortRanges: [ [ UInt16 ] ] ,
153
+ numberOfFailedAttempts: UInt
154
+ ) -> UInt16 ? {
155
+ switch portConstraint {
156
+ case let . only( port) :
157
+ return port
158
+
159
+ case . any:
160
+ // 1. First two attempts should pick a random port.
161
+ // 2. The next two should pick port 53.
162
+ // 3. Repeat steps 1 and 2.
163
+ let useDefaultPort = ( numberOfFailedAttempts % 4 == 2 ) || ( numberOfFailedAttempts % 4 == 3 )
164
+
165
+ return useDefaultPort ? defaultPort : pickRandomPort ( rawPortRanges: rawPortRanges)
166
+ }
167
+ }
168
+
169
+ private static func filterByActive< T: AnyRelay > (
170
+ relays: [ RelayWithLocation < T > ]
171
+ ) throws -> [ RelayWithLocation < T > ] {
172
+ let filteredRelays = relays. filter { relayWithLocation in
173
+ relayWithLocation. relay. active
174
+ }
175
+
176
+ return if filteredRelays. isEmpty {
177
+ throw NoRelaysSatisfyingConstraintsError ( reason: . noActiveRelaysFound)
178
+ } else {
179
+ filteredRelays
180
+ }
181
+ }
145
182
146
- switch filterConstraint {
183
+ private static func filterByDaita< T: AnyRelay > (
184
+ relays: [ RelayWithLocation < T > ] ,
185
+ daita: Bool
186
+ ) throws -> [ RelayWithLocation < T > ] {
187
+ guard daita else { return relays }
188
+
189
+ let filteredRelays = relays. filter { relayWithLocation in
190
+ relayWithLocation. relay. daita == true
191
+ }
192
+
193
+ return if filteredRelays. isEmpty {
194
+ throw NoRelaysSatisfyingConstraintsError ( reason: . noDaitaRelaysFound)
195
+ } else {
196
+ filteredRelays
197
+ }
198
+ }
199
+
200
+ private static func filterByFilterConstraint< T: AnyRelay > (
201
+ relays: [ RelayWithLocation < T > ] ,
202
+ constraint: RelayConstraint < RelayFilter >
203
+ ) throws -> [ RelayWithLocation < T > ] {
204
+ let filteredRelays = relays. filter { relayWithLocation in
205
+ switch constraint {
147
206
case . any:
148
- break
207
+ true
149
208
case let . only( filter) :
150
- if !relayMatchesFilter( relayWithLocation. relay, filter: filter) {
151
- return false
152
- }
209
+ relayMatchesFilter ( relayWithLocation. relay, filter: filter)
153
210
}
211
+ }
154
212
155
- return switch relayConstraint {
213
+ return if filteredRelays. isEmpty {
214
+ throw NoRelaysSatisfyingConstraintsError ( reason: . filterConstraintNotMatching)
215
+ } else {
216
+ filteredRelays
217
+ }
218
+ }
219
+
220
+ private static func filterByLocationConstraint< T: AnyRelay > (
221
+ relays: [ RelayWithLocation < T > ] ,
222
+ constraint: RelayConstraint < UserSelectedRelays >
223
+ ) throws -> [ RelayWithLocation < T > ] {
224
+ let filteredRelays = relays. filter { relayWithLocation in
225
+ switch constraint {
156
226
case . any:
157
227
true
158
- case let . only( relayConstraint ) :
228
+ case let . only( constraint ) :
159
229
// At least one location must match the relay under test.
160
- relayConstraint . locations. contains { location in
230
+ constraint . locations. contains { location in
161
231
relayWithLocation. matches ( location: location)
162
232
}
163
233
}
164
234
}
165
235
166
- // Filter on country inclusion.
167
- let includeInCountryFilteredRelays = filteredRelays. filter { relayWithLocation in
168
- return switch relayConstraint {
236
+ return if filteredRelays. isEmpty {
237
+ throw NoRelaysSatisfyingConstraintsError ( reason: . relayConstraintNotMatching)
238
+ } else {
239
+ filteredRelays
240
+ }
241
+ }
242
+
243
+ private static func filterByCountryInclusion< T: AnyRelay > (
244
+ relays: [ RelayWithLocation < T > ] ,
245
+ constraint: RelayConstraint < UserSelectedRelays >
246
+ ) -> [ RelayWithLocation < T > ] {
247
+ let filteredRelays = relays. filter { relayWithLocation in
248
+ return switch constraint {
169
249
case . any:
170
250
true
171
251
case let . only( relayConstraint) :
172
252
relayConstraint. locations. contains { location in
173
253
if case . country = location {
174
- return relayWithLocation. relay. includeInCountry
254
+ relayWithLocation. relay. includeInCountry
255
+ } else {
256
+ false
175
257
}
176
- return false
177
258
}
178
259
}
179
260
}
180
261
181
262
// If no relays should be included in the matched country, instead accept all.
182
- if includeInCountryFilteredRelays . isEmpty {
183
- return filteredRelays
263
+ return if filteredRelays . isEmpty {
264
+ relays
184
265
} else {
185
- return includeInCountryFilteredRelays
186
- }
187
- }
188
-
189
- /// Produce a port that is either user provided or randomly selected, satisfying the given constraints.
190
- static func applyPortConstraint(
191
- _ portConstraint: RelayConstraint < UInt16 > ,
192
- rawPortRanges: [ [ UInt16 ] ] ,
193
- numberOfFailedAttempts: UInt
194
- ) -> UInt16 ? {
195
- switch portConstraint {
196
- case let . only( port) :
197
- return port
198
-
199
- case . any:
200
- // 1. First two attempts should pick a random port.
201
- // 2. The next two should pick port 53.
202
- // 3. Repeat steps 1 and 2.
203
- let useDefaultPort = ( numberOfFailedAttempts % 4 == 2 ) || ( numberOfFailedAttempts % 4 == 3 )
204
-
205
- return useDefaultPort ? defaultPort : pickRandomPort ( rawPortRanges: rawPortRanges)
266
+ filteredRelays
206
267
}
207
268
}
208
269
}
0 commit comments