@@ -470,105 +470,106 @@ enum FunctionsConstants {
470470 }
471471 }
472472 }
473-
473+
474474 @available ( iOS 13 , macCatalyst 13 , macOS 10 . 15 , tvOS 13 , watchOS 7 , * )
475- func stream( at url: URL ,
476- withObject data: Any ? ,
477- options: HTTPSCallableOptions ? ,
478- timeout: TimeInterval ) async throws
475+ func stream( at url: URL ,
476+ withObject data: Any ? ,
477+ options: HTTPSCallableOptions ? ,
478+ timeout: TimeInterval ) async throws
479479 -> AsyncThrowingStream < HTTPSCallableResult , Error > {
480- let context = try await contextProvider. context ( options: options)
481- let fetcher = try makeFetcherForStreamableContent (
482- url: url,
483- data: data,
484- options: options,
485- timeout: timeout,
486- context: context
487- )
488-
489- do {
490- let rawData = try await fetcher. beginFetch ( )
491- return try callableResultFromResponseAsync ( data: rawData, error: nil )
492- } catch {
493- // This method always throws when `error` is not `nil`, but ideally,
494- // it should be refactored so it looks less confusing.
495- return try callableResultFromResponseAsync ( data: nil , error: error)
496- }
480+ let context = try await contextProvider. context ( options: options)
481+ let fetcher = try makeFetcherForStreamableContent (
482+ url: url,
483+ data: data,
484+ options: options,
485+ timeout: timeout,
486+ context: context
487+ )
488+
489+ do {
490+ let rawData = try await fetcher. beginFetch ( )
491+ return try callableResultFromResponseAsync ( data: rawData, error: nil )
492+ } catch {
493+ // This method always throws when `error` is not `nil`, but ideally,
494+ // it should be refactored so it looks less confusing.
495+ return try callableResultFromResponseAsync ( data: nil , error: error)
497496 }
497+ }
498498
499499 @available ( iOS 13 . 0 , * )
500- func callableResultFromResponseAsync( data: Data ? ,
501- error: Error ? ) throws -> AsyncThrowingStream <
502- HTTPSCallableResult , Error
500+ func callableResultFromResponseAsync( data: Data ? ,
501+ error: Error ? ) throws -> AsyncThrowingStream <
502+ HTTPSCallableResult , Error
503+
504+ > {
505+ let processedData =
506+ try processResponseDataForStreamableContent (
507+ from: data,
508+ error: error
509+ )
503510
504- > {
505- let processedData =
506- try processResponseDataForStreamableContent (
507- from: data,
508- error: error
509- )
511+ return processedData
512+ }
513+
514+ private func makeFetcherForStreamableContent( url: URL ,
515+ data: Any ? ,
516+ options: HTTPSCallableOptions ? ,
517+ timeout: TimeInterval ,
518+ context: FunctionsContext ) throws
519+ -> GTMSessionFetcher {
520+ let request = URLRequest (
521+ url: url,
522+ cachePolicy: . useProtocolCachePolicy,
523+ timeoutInterval: timeout
524+ )
525+ let fetcher = fetcherService. fetcher ( with: request)
510526
511- return processedData
527+ let data = data ?? NSNull ( )
528+ let encoded = try serializer. encode ( data)
529+ let body = [ " data " : encoded]
530+ let payload = try JSONSerialization . data ( withJSONObject: body, options: [ . fragmentsAllowed] )
531+ fetcher. bodyData = payload
532+
533+ // Set the headers for starting a streaming session.
534+ fetcher. setRequestValue ( " application/json " , forHTTPHeaderField: " Content-Type " )
535+ fetcher. setRequestValue ( " text/event-stream " , forHTTPHeaderField: " Accept " )
536+ fetcher. request? . httpMethod = " POST "
537+ if let authToken = context. authToken {
538+ let value = " Bearer \( authToken) "
539+ fetcher. setRequestValue ( value, forHTTPHeaderField: " Authorization " )
512540 }
513541
514- private func makeFetcherForStreamableContent( url: URL ,
515- data: Any ? ,
516- options: HTTPSCallableOptions ? ,
517- timeout: TimeInterval ,
518- context: FunctionsContext ) throws -> GTMSessionFetcher {
519- let request = URLRequest (
520- url: url,
521- cachePolicy: . useProtocolCachePolicy,
522- timeoutInterval: timeout
523- )
524- let fetcher = fetcherService. fetcher ( with: request)
525-
526- let data = data ?? NSNull ( )
527- let encoded = try serializer. encode ( data)
528- let body = [ " data " : encoded]
529- let payload = try JSONSerialization . data ( withJSONObject: body, options: [ . fragmentsAllowed] )
530- fetcher. bodyData = payload
531-
532- // Set the headers for starting a streaming session.
533- fetcher. setRequestValue ( " application/json " , forHTTPHeaderField: " Content-Type " )
534- fetcher. setRequestValue ( " text/event-stream " , forHTTPHeaderField: " Accept " )
535- fetcher. request? . httpMethod = " POST "
536- if let authToken = context. authToken {
537- let value = " Bearer \( authToken) "
538- fetcher. setRequestValue ( value, forHTTPHeaderField: " Authorization " )
539- }
540-
541- if let fcmToken = context. fcmToken {
542- fetcher. setRequestValue ( fcmToken, forHTTPHeaderField: Constants . fcmTokenHeader)
543- }
544-
545- if options? . requireLimitedUseAppCheckTokens == true {
546- if let appCheckToken = context. limitedUseAppCheckToken {
547- fetcher. setRequestValue (
548- appCheckToken,
549- forHTTPHeaderField: Constants . appCheckTokenHeader
550- )
551- }
552- } else if let appCheckToken = context. appCheckToken {
542+ if let fcmToken = context. fcmToken {
543+ fetcher. setRequestValue ( fcmToken, forHTTPHeaderField: Constants . fcmTokenHeader)
544+ }
545+
546+ if options? . requireLimitedUseAppCheckTokens == true {
547+ if let appCheckToken = context. limitedUseAppCheckToken {
553548 fetcher. setRequestValue (
554549 appCheckToken,
555550 forHTTPHeaderField: Constants . appCheckTokenHeader
556551 )
557552 }
558- // Remove after genStream is updated on the emulator or deployed
559- #if DEBUG
560- fetcher. allowLocalhostRequest = true
561- fetcher. allowedInsecureSchemes = [ " http " ]
562- #endif
563- // Override normal security rules if this is a local test.
564- if emulatorOrigin != nil {
565- fetcher. allowLocalhostRequest = true
566- fetcher. allowedInsecureSchemes = [ " http " ]
567- }
568-
569- return fetcher
553+ } else if let appCheckToken = context. appCheckToken {
554+ fetcher. setRequestValue (
555+ appCheckToken,
556+ forHTTPHeaderField: Constants . appCheckTokenHeader
557+ )
558+ }
559+ // Remove after genStream is updated on the emulator or deployed
560+ #if DEBUG
561+ fetcher. allowLocalhostRequest = true
562+ fetcher. allowedInsecureSchemes = [ " http " ]
563+ #endif
564+ // Override normal security rules if this is a local test.
565+ if emulatorOrigin != nil {
566+ fetcher. allowLocalhostRequest = true
567+ fetcher. allowedInsecureSchemes = [ " http " ]
570568 }
571-
569+
570+ return fetcher
571+ }
572+
572573 private func makeFetcher( url: URL ,
573574 data: Any ? ,
574575 options: HTTPSCallableOptions ? ,
@@ -653,76 +654,75 @@ enum FunctionsConstants {
653654
654655 return data
655656 }
656-
657+
657658 @available ( iOS 13 , macCatalyst 13 , macOS 10 . 15 , tvOS 13 , watchOS 7 , * )
658- private func processResponseDataForStreamableContent( from data: Data ? ,
659- error: Error ? ) throws -> AsyncThrowingStream <
660- HTTPSCallableResult ,
661- Error
662- > {
663-
664- return AsyncThrowingStream { continuation in
665- Task {
666- var resultArray = [ String] ( )
667- do {
668- if let error = error {
669- throw error
670- }
671-
672- guard let data = data else {
673- throw NSError ( domain: FunctionsErrorDomain . description, code: - 1 , userInfo: nil )
674- }
675-
676- if let dataChunk = String ( data: data, encoding: . utf8) {
677- // We remove the "data :" field so it can be safely parsed to Json.
678- let dataChunkToJson = dataChunk. split ( separator: " \n " ) . map {
679- String ( $0. dropFirst ( 6 ) )
680- }
681- resultArray. append ( contentsOf: dataChunkToJson)
682- } else {
683- throw NSError ( domain: FunctionsErrorDomain . description, code: - 1 , userInfo: nil )
684- }
685-
686- for dataChunk in resultArray {
687- let json = try callableResult (
659+ private func processResponseDataForStreamableContent( from data: Data ? ,
660+ error: Error ? ) throws
661+ -> AsyncThrowingStream <
662+ HTTPSCallableResult ,
663+ Error
664+ > {
665+ return AsyncThrowingStream { continuation in
666+ Task {
667+ var resultArray = [ String] ( )
668+ do {
669+ if let error = error {
670+ throw error
671+ }
672+
673+ guard let data = data else {
674+ throw NSError ( domain: FunctionsErrorDomain . description, code: - 1 , userInfo: nil )
675+ }
676+
677+ if let dataChunk = String ( data: data, encoding: . utf8) {
678+ // We remove the "data :" field so it can be safely parsed to Json.
679+ let dataChunkToJson = dataChunk. split ( separator: " \n " ) . map {
680+ String ( $0. dropFirst ( 6 ) )
681+ }
682+ resultArray. append ( contentsOf: dataChunkToJson)
683+ } else {
684+ throw NSError ( domain: FunctionsErrorDomain . description, code: - 1 , userInfo: nil )
685+ }
686+
687+ for dataChunk in resultArray {
688+ let json = try callableResult (
688689 fromResponseData: dataChunk. data (
689690 using: . utf8,
690691 allowLossyConversion: true
691692 ) ?? Data ( )
692-
693- )
694- continuation. yield ( HTTPSCallableResult ( data: json. data) )
695- }
696-
697- continuation. onTermination = { @Sendable _ in
698- // Callback for cancelling the stream
699- continuation. finish ( )
700- }
701- // Close the stream once it's done
702- continuation. finish ( )
703- } catch {
704- continuation. finish ( throwing: error)
705- }
706- }
707- }
708- }
693+ )
694+ continuation. yield ( HTTPSCallableResult ( data: json. data) )
695+ }
696+
697+ continuation. onTermination = { @Sendable _ in
698+ // Callback for cancelling the stream
699+ continuation. finish ( )
700+ }
701+ // Close the stream once it's done
702+ continuation. finish ( )
703+ } catch {
704+ continuation. finish ( throwing: error)
705+ }
706+ }
707+ }
708+ }
709709
710710 private func responseDataJSON( from data: Data ) throws -> Any {
711- let responseJSONObject = try JSONSerialization . jsonObject ( with: data)
711+ let responseJSONObject = try JSONSerialization . jsonObject ( with: data)
712712
713- guard let responseJSON = responseJSONObject as? NSDictionary else {
714- let userInfo = [ NSLocalizedDescriptionKey: " Response was not a dictionary. " ]
715- throw FunctionsError ( . internal, userInfo: userInfo)
716- }
713+ guard let responseJSON = responseJSONObject as? NSDictionary else {
714+ let userInfo = [ NSLocalizedDescriptionKey: " Response was not a dictionary. " ]
715+ throw FunctionsError ( . internal, userInfo: userInfo)
716+ }
717717
718- // `result` is checked for backwards compatibility,
719- // `message` is checked for StramableContent:
720- guard let dataJSON = responseJSON [ " data " ] ?? responseJSON [ " result " ] ?? responseJSON [ " message " ]
721- else {
722- let userInfo = [ NSLocalizedDescriptionKey: " Response is missing data field. " ]
723- throw FunctionsError ( . internal, userInfo: userInfo)
724- }
725-
726- return dataJSON
718+ // `result` is checked for backwards compatibility,
719+ // `message` is checked for StramableContent:
720+ guard let dataJSON = responseJSON [ " data " ] ?? responseJSON [ " result " ] ?? responseJSON [ " message " ]
721+ else {
722+ let userInfo = [ NSLocalizedDescriptionKey: " Response is missing data field. " ]
723+ throw FunctionsError ( . internal, userInfo: userInfo)
727724 }
725+
726+ return dataJSON
727+ }
728728}
0 commit comments