| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 |
- // Copyright 2024 Google LLC
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- import Foundation
- import FirebaseAppCheck
- import FirebaseAuth
- import FirebaseCore
- @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
- public class DataConnect {
- private var connectorConfig: ConnectorConfig
- private var app: FirebaseApp
- private var settings: DataConnectSettings
- private var grpcClient: GrpcClient
- private var operationsManager: OperationsManager
- private static var instanceStore = InstanceStore()
- public enum EmulatorDefaults {
- public static let host = "127.0.0.1"
- public static let port = 9399
- }
- // MARK: Static Creation
- public class func dataConnect(app: FirebaseApp? = FirebaseApp.app(),
- connectorConfig: ConnectorConfig,
- settings: DataConnectSettings = DataConnectSettings())
- -> DataConnect {
- guard let app = app else {
- fatalError("No Firebase App present")
- }
- return instanceStore.instance(for: app, config: connectorConfig, settings: settings)
- }
- // MARK: Emulator
- public func useEmulator(host: String = EmulatorDefaults.host,
- port: Int = EmulatorDefaults.port) {
- settings = DataConnectSettings(host: host, port: port, sslEnabled: false)
- // TODO: - shutdown grpc client
- // self.grpcClient.close
- // self.operations.close
- guard let projectID = app.options.projectID else {
- fatalError("Firebase DataConnect requires the projectID to be set in the app options")
- }
- grpcClient = GrpcClient(
- projectId: projectID,
- settings: settings,
- connectorConfig: connectorConfig,
- auth: Auth.auth(app: app),
- appCheck: AppCheck.appCheck(app: app)
- )
- operationsManager = OperationsManager(grpcClient: grpcClient)
- }
- // MARK: Init
- init(app: FirebaseApp, connectorConfig: ConnectorConfig, settings: DataConnectSettings) {
- self.app = app
- self.settings = settings
- self.connectorConfig = connectorConfig
- guard let projectID = app.options.projectID else {
- fatalError("Firebase DataConnect requires the projectID to be set in the app options")
- }
- grpcClient = GrpcClient(
- projectId: projectID,
- settings: settings,
- connectorConfig: connectorConfig,
- auth: Auth.auth(app: app),
- appCheck: AppCheck.appCheck(app: app)
- )
- operationsManager = OperationsManager(grpcClient: grpcClient)
- }
- // MARK: Operations
- public func query<ResultData: Decodable,
- Variable: OperationVariable>(request: QueryRequest<Variable>,
- resultsDataType: ResultData
- .Type,
- publisher: ResultsPublisherType = .observableObject)
- -> any ObservableQueryRef {
- return operationsManager.queryRef(for: request, with: resultsDataType, publisher: publisher)
- }
- public func mutation<ResultData: Decodable,
- Variable: OperationVariable>(request: MutationRequest<Variable>,
- resultsDataType: ResultData
- .Type)
- -> MutationRef<ResultData,
- Variable> {
- return operationsManager.mutationRef(for: request, with: resultsDataType)
- }
- }
- // MARK: Instance Creation
- // Support for creating or reusing DataConnect instances.
- // Instances are keyed by ConnectorConfig and FirebaseApp (projectID)
- @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
- private struct InstanceKey: Hashable, Equatable {
- let config: ConnectorConfig
- let app: FirebaseApp
- init(app: FirebaseApp, config: ConnectorConfig) {
- self.app = app
- self.config = config
- }
- func hash(into hasher: inout Hasher) {
- hasher.combine(app.name)
- hasher.combine(app.options.projectID)
- hasher.combine(config)
- }
- }
- @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
- private class InstanceStore {
- let accessQ = DispatchQueue(
- label: "firebase.dataconnect.instanceQ",
- autoreleaseFrequency: .workItem
- )
- var instances = [InstanceKey: DataConnect]()
- func instance(for app: FirebaseApp, config: ConnectorConfig,
- settings: DataConnectSettings) -> DataConnect {
- accessQ.sync {
- let key = InstanceKey(app: app, config: config)
- if let inst = instances[key] {
- return inst
- } else {
- let dc = DataConnect(app: app, connectorConfig: config, settings: settings)
- instances[key] = dc
- return dc
- }
- }
- }
- }
|