Skip to content

Commit 8dafb52

Browse files
Insert Goog-Api-Client Header
1 parent 8e6b8a2 commit 8dafb52

File tree

6 files changed

+139
-15
lines changed

6 files changed

+139
-15
lines changed

Sources/DataConnect.swift

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ public class DataConnect {
2727
private(set) var grpcClient: GrpcClient
2828
private var operationsManager: OperationsManager
2929

30+
private var callerSDKType: CallerSDKType = .base
31+
3032
private static var instanceStore = InstanceStore()
3133

3234
public enum EmulatorDefaults {
@@ -38,13 +40,20 @@ public class DataConnect {
3840

3941
public class func dataConnect(app: FirebaseApp? = FirebaseApp.app(),
4042
connectorConfig: ConnectorConfig,
41-
settings: DataConnectSettings = DataConnectSettings())
43+
settings: DataConnectSettings = DataConnectSettings(),
44+
callerSDKType: CallerSDKType = .base)
4245
-> DataConnect {
4346
guard let app = app else {
4447
fatalError("No Firebase App present")
4548
}
4649

47-
return instanceStore.instance(for: app, config: connectorConfig, settings: settings)
50+
return instanceStore
51+
.instance(
52+
for: app,
53+
config: connectorConfig,
54+
settings: settings,
55+
callerSDKType: callerSDKType
56+
)
4857
}
4958

5059
// MARK: Emulator
@@ -66,29 +75,33 @@ public class DataConnect {
6675
settings: settings,
6776
connectorConfig: connectorConfig,
6877
auth: Auth.auth(app: app),
69-
appCheck: AppCheck.appCheck(app: app)
78+
appCheck: AppCheck.appCheck(app: app),
79+
callerSDKType: callerSDKType
7080
)
7181

7282
operationsManager = OperationsManager(grpcClient: grpcClient)
7383
}
7484

7585
// MARK: Init
7686

77-
init(app: FirebaseApp, connectorConfig: ConnectorConfig, settings: DataConnectSettings) {
78-
self.app = app
79-
self.settings = settings
80-
self.connectorConfig = connectorConfig
81-
87+
init(app: FirebaseApp, connectorConfig: ConnectorConfig, settings: DataConnectSettings,
88+
callerSDKType: CallerSDKType = .base) {
8289
guard app.options.projectID != nil else {
8390
fatalError("Firebase DataConnect requires the projectID to be set in the app options")
8491
}
8592

93+
self.app = app
94+
self.settings = settings
95+
self.connectorConfig = connectorConfig
96+
self.callerSDKType = callerSDKType
97+
8698
grpcClient = GrpcClient(
8799
app: self.app,
88100
settings: settings,
89101
connectorConfig: connectorConfig,
90102
auth: Auth.auth(app: app),
91-
appCheck: AppCheck.appCheck(app: app)
103+
appCheck: AppCheck.appCheck(app: app),
104+
callerSDKType: self.callerSDKType
92105
)
93106
operationsManager = OperationsManager(grpcClient: grpcClient)
94107
}
@@ -114,6 +127,13 @@ public class DataConnect {
114127
}
115128
}
116129

130+
// This enum is public so the gen sdk can access it
131+
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
132+
public enum CallerSDKType {
133+
case base // base sdk is directly used
134+
case generated // generated sdk is calling the base
135+
}
136+
117137
// MARK: Instance Creation
118138

119139
// Support for creating or reusing DataConnect instances.
@@ -145,13 +165,18 @@ private class InstanceStore {
145165
var instances = [InstanceKey: DataConnect]()
146166

147167
func instance(for app: FirebaseApp, config: ConnectorConfig,
148-
settings: DataConnectSettings) -> DataConnect {
168+
settings: DataConnectSettings, callerSDKType: CallerSDKType) -> DataConnect {
149169
accessQ.sync {
150170
let key = InstanceKey(app: app, config: config)
151171
if let inst = instances[key] {
152172
return inst
153173
} else {
154-
let dc = DataConnect(app: app, connectorConfig: config, settings: settings)
174+
let dc = DataConnect(
175+
app: app,
176+
connectorConfig: config,
177+
settings: settings,
178+
callerSDKType: callerSDKType
179+
)
155180
instances[key] = dc
156181
return dc
157182
}

Sources/Internal/Component.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,6 @@ import Foundation
1818
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
1919
@objc(FIRDataConnectComponent) class DataConnectComponent: NSObject {
2020
@objc class func sdkVersion() -> String {
21-
return Version.version
21+
return Version.sdkVersion
2222
}
2323
}

Sources/Internal/GrpcClient.swift

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,14 @@ actor GrpcClient: CustomStringConvertible {
4444

4545
private let appCheck: AppCheck?
4646

47+
private let callerSDKType: CallerSDKType
48+
4749
enum RequestHeaders {
4850
static let googRequestParamsHeader = "x-goog-request-params"
4951
static let authorizationHeader = "x-firebase-auth-token"
5052
static let appCheckHeader = "X-Firebase-AppCheck"
5153
static let firebaseAppId = "x-firebase-gmpid"
54+
static let googApiClient = "x-goog-api-client"
5255
}
5356

5457
private let googRequestHeaderValue: String
@@ -72,9 +75,23 @@ actor GrpcClient: CustomStringConvertible {
7275
}
7376
}()
7477

78+
private lazy var googApiClientHeaderValue: String = {
79+
let header =
80+
"gl-swift/\(Version.swiftMajorVersion()) fire/\(Version.sdkVersion) \(Version.platformVersionHeader()) grpc-swift/"
81+
82+
switch self.callerSDKType {
83+
case .base:
84+
return header
85+
case .generated:
86+
return "\(header) swift/gen"
87+
}
88+
89+
}()
90+
7591
init(app: FirebaseApp, settings: DataConnectSettings, connectorConfig: ConnectorConfig,
7692
auth: Auth,
77-
appCheck: AppCheck?) {
93+
appCheck: AppCheck?,
94+
callerSDKType: CallerSDKType) {
7895
self.app = app
7996

8097
guard let projectId = app.options.projectID else {
@@ -86,6 +103,7 @@ actor GrpcClient: CustomStringConvertible {
86103
self.connectorConfig = connectorConfig
87104
self.auth = auth
88105
self.appCheck = appCheck
106+
self.callerSDKType = callerSDKType
89107

90108
connectorName =
91109
"projects/\(projectId)/locations/\(connectorConfig.location)/services/\(connectorConfig.serviceId)/connectors/\(connectorConfig.connector)"
@@ -187,6 +205,7 @@ actor GrpcClient: CustomStringConvertible {
187205

188206
headers.add(name: RequestHeaders.googRequestParamsHeader, value: googRequestHeaderValue)
189207
headers.add(name: RequestHeaders.firebaseAppId, value: app.options.googleAppID)
208+
headers.add(name: RequestHeaders.googApiClient, value: googApiClientHeaderValue)
190209

191210
// Add Auth token if available
192211
do {

Sources/Internal/Version.swift

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,41 @@ import Foundation
1616

1717
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
1818
struct Version {
19-
static let version = "11.3.0-beta"
19+
static let sdkVersion = "11.3.0-beta"
20+
21+
// returns value of form gl-PLATFORM_NAME/PLATFORM_VERSION
22+
static func platformVersionHeader() -> String {
23+
let version = ProcessInfo.processInfo.operatingSystemVersion
24+
let versionString = "\(version.majorVersion).\(version.minorVersion).\(version.patchVersion)"
25+
#if os(iOS)
26+
return "gl-ios/\(versionString)"
27+
#elseif os(watchOS)
28+
return "gl-watchos/\(versionString)"
29+
#elseif os(tvOS)
30+
return "gl-tvos/\(versionString)"
31+
#elseif os(macOS)
32+
return "gl-macos/\(versionString)"
33+
#else
34+
return ""
35+
#endif
36+
}
37+
38+
// returns the build time major version of swift
39+
static func swiftMajorVersion() -> String {
40+
#if swift(>=6)
41+
return "6"
42+
#elseif swift(>=5)
43+
return "5"
44+
#elseif swift(>=4)
45+
return "4"
46+
#elseif swift(>=3)
47+
return "3"
48+
#elseif swift(>=2)
49+
return "2"
50+
#elseif swift(>=1)
51+
return "1"
52+
#else
53+
return ""
54+
#endif
55+
}
2056
}

Tests/Unit/HeaderTests.swift

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@ final class HeaderTests: XCTestCase {
3636
connector: "kitchensink"
3737
)
3838

39+
var fakeConnectorConfigTwo = ConnectorConfig(
40+
serviceId: "dataconnect",
41+
location: "us-east1",
42+
connector: "kitchensinkgen"
43+
)
44+
3945
override class func setUp() {
4046
FirebaseApp.configure(options: options)
4147
defaultApp = FirebaseApp.app()
@@ -50,4 +56,42 @@ final class HeaderTests: XCTestCase {
5056
let contains = values.contains { $0 == HeaderTests.defaultApp!.options.googleAppID }
5157
XCTAssertTrue(contains)
5258
}
59+
60+
func testGoogApiClientHeaderBaseSdk() async throws {
61+
let dcOne = DataConnect.dataConnect(connectorConfig: fakeConnectorConfigOne)
62+
let callOptions = await dcOne.grpcClient.createCallOptions()
63+
let values = callOptions.customMetadata.values(
64+
forHeader: GrpcClient.RequestHeaders.googApiClient, canonicalForm: false
65+
)
66+
for value in values {
67+
print("value \(value)")
68+
}
69+
print("values \(values)")
70+
let contains = values
71+
.contains {
72+
$0 ==
73+
"gl-swift/\(Version.swiftMajorVersion()) fire/\(Version.sdkVersion) \(Version.platformVersionHeader()) grpc-swift/"
74+
}
75+
XCTAssertTrue(contains)
76+
}
77+
78+
func testGoogleApiClientHeaderGenSdk() async throws {
79+
let dcOne = DataConnect.dataConnect(
80+
connectorConfig: fakeConnectorConfigTwo,
81+
callerSDKType: .generated
82+
)
83+
let callOptions = await dcOne.grpcClient.createCallOptions()
84+
let values = callOptions.customMetadata.values(
85+
forHeader: GrpcClient.RequestHeaders.googApiClient, canonicalForm: false
86+
)
87+
for value in values {
88+
print("value \(value)")
89+
}
90+
let contains = values
91+
.contains {
92+
$0 ==
93+
"gl-swift/\(Version.swiftMajorVersion()) fire/\(Version.sdkVersion) \(Version.platformVersionHeader()) grpc-swift/ swift/gen"
94+
}
95+
XCTAssertTrue(contains)
96+
}
5397
}

Tests/Unit/UserAgentTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ final class UserAgentTests: XCTestCase {
3434
/// Confirm that Data Connect gets added to the user agent.
3535
func testUserAgent() {
3636
let userAgent = FirebaseApp.firebaseUserAgent()
37-
let version = Version.version
37+
let version = Version.sdkVersion
3838
XCTAssertTrue(userAgent.contains("fire-dc/\(version)"))
3939
}
4040
}

0 commit comments

Comments
 (0)