-
Notifications
You must be signed in to change notification settings - Fork 33
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Unify Configuration Management #241
Conversation
Hi @jaceklyp! I'm getting around to checking your code. Have just compiled and run it for the first time and I figured it would be great to have more debug logging for network requests. Perhaps controlled by a boolean flag. WDYT? |
Sources/API/APIHeaders.swift
Outdated
|
||
public var defaultHeaders: HTTPHeaders { | ||
guard let userAgent = APIHeaders.userAgent else { | ||
fatalError("Please set the userAgent before accessing defaultHeaders.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is time-sensitive, based on when setUserAgent
is called, right? Shouldn't it rather be an assertion, to not crash the app on production?
import Foundation | ||
import Common | ||
|
||
public enum URLRequestAttribution { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is that used? Was that used? :)
Sources/API/HTTPConstants.swift
Outdated
case trace = "TRACE" | ||
case patch = "PATCH" | ||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't these be put in a tighter scope instead of on Module level? E.g. under APIRequest
|
||
import Foundation | ||
|
||
public protocol ConfigurationURLProvider { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ConfigurationURLProviding
?
enum Constants { | ||
|
||
static let weakEtagPrefix = "W/" | ||
static let successfulStatusCodes = Array(200..<300) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe use Range
instead?
} | ||
} | ||
|
||
func etag(shouldDropWeakPrefix: Bool) -> String? { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
droppingWeakPrefix
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I noticed I’ve had 2 pending comments. Both rather minor, but perhaps worth considering. Dropping them now before I jump into reviewing the rest.
|
||
public static let nonEmptyData = APIResponseRequirements(rawValue: 1 << 0) | ||
public static let etag = APIResponseRequirements(rawValue: 1 << 1) | ||
public static let allow304 = APIResponseRequirements(rawValue: 1 << 2) // setting this overrides nonEmptyData since urlSession will actually return empty data |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer to either have docs for all the options, or user more descriptive naming. Ideally both :) I'd like the options to tell what the Requirement actually enforces, i.e:
requireNonEmptyData
requireETagHeader
allowHTTPNotModified
Sources/API/APIRequest.swift
Outdated
return (data, httpResponse) | ||
} | ||
|
||
private func getHTTPResponse(from response: URLResponse?) throws -> HTTPURLResponse { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you could remove this method and just define URLResponse.asHTTPURLResponse
as throwable function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! 👍 Leaving a bunch of final comments, I’ve also tested macOS and it works great. Will check the code now.
/** | ||
Downloads and stores the configurations provided in parallel. | ||
|
||
- Parameters: | ||
- configurations: An array of `Configuration` enums that need to be downloaded and stored. | ||
|
||
- Throws: | ||
If any configuration fails to fetch or validate, an `Error` of type `.aggregated` is thrown. | ||
The `.aggregated` case of the `Error` enum contains a dictionary of type `[Configuration: Error]` | ||
that associates each failed configuration with its corresponding error. | ||
|
||
- Important: | ||
If any task fails, the error is recorded but the group continues processing the remaining tasks. | ||
The task group is not cancelled automatically when a task throws an error. | ||
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right now this documentation applies to aggregatedError
(when you option+click it). Please move aggregatedError elsewhere so that it applies to fetch(any:)
.
|
||
protocol ConfigurationFetching { | ||
|
||
func fetch(any configurations: [Configuration]) async throws |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I’d suggest fetch(anyOf:)
and fetch(allOf:)
but I’m not strong on that.
self.urlSession = urlSession | ||
self.log = log | ||
|
||
assertUserAgentIsPresent() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👏
} | ||
} | ||
|
||
/// This method is deprecated. Please use the 'fetch()' async method instead. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it’s only used on iOS, perhaps worth guarding this function with #if os(iOS)
?
Or maybe add the deprecation notice to the os_log too?
/// Allows HTTP Not Modified responses. | ||
/// Setting this overrides requireNonEmptyData since urlSession will actually return empty data. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about the following docs:
Allows HTTP 304 (Not Modified) response status code.
When this is set, requireNonEmptyData is not honored, since URLSession returns empty data on HTTP 304.
|
||
let privacyConfigurationData = Data("Privacy Config".utf8) | ||
|
||
// Tests for fetch(any: [Configuration]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cosmetic: I'd use // MARK: -
here
private static let mainThreadCallback = URLSession(configuration: .default, delegate: nil, delegateQueue: OperationQueue.main) | ||
private static let mainThreadCallbackEphemeral = URLSession(configuration: .ephemeral, delegate: nil, delegateQueue: OperationQueue.main) | ||
|
||
public static func makeSession(useMainThreadCallbackQueue: Bool = false, ephemeral: Bool = true) -> URLSession { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One more thing, sorry – I’d avoid calling this function makeSession
, because it’s not making anything. It only picks one of the existing sessions.
I’ve noticed it while reading through macOS app code where it looks like we were creating sessions with every call. How about just session(useMainThreadCallbackQueue: Bool = false, ephemeral: Bool = true)
?
# By Alexey Martemyanov (8) and others # Via GitHub * main: Make FeatureName a struct so it can be extended from client code (#276) add count of all bookmarks in domain to view model (#272) Configuration updates optimizations (#269) Roll-back InteractiveUserScript (#268) Update C-S-S to 4.4.4 (#260) Add invalid payload pixel handler (#264) Fix Error pixel misfiring on valid scenario (#261) add didCancelNavigationAction (#262) Opt-outable private API usage (#254) HTTPS upgrade threading (#256) DDGSync module (#253) fix delayed new window with empty url creation handling (#255) remove major tracker network (#251) Enable username&password passed in URL (#245) fix assertion for popup about:blank navigations without WKNavigation (#247) fix about: scheme fragments dropping (#246) Unify Configuration Management (#241) # Conflicts: # Package.resolved # Package.swift
Task/Issue URL: https://app.asana.com/0/72649045549333/1203797041821336/f
iOS PR: duckduckgo/iOS#1512
macOS PR: duckduckgo/macos-browser#990
What kind of version bump will this require?: Major
Description:
Use common API and Configuration modules located in BSK for fetching privacy related assets.
Add payload validation.
Steps to test this PR:
Internal references:
Software Engineering Expectations
Technical Design Template
When ready for review, remember to post the PR in MM