Skip to content

Commit e6b454d

Browse files
committed
chore: wip add iOS code for raw request
1 parent 88bf43f commit e6b454d

File tree

10 files changed

+392
-19
lines changed

10 files changed

+392
-19
lines changed

example/ios/Podfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -476,7 +476,7 @@ SPEC CHECKSUMS:
476476
React-jsi: 74341196d9547cbcbcfa4b3bbbf03af56431d5a1
477477
React-jsiexecutor: 06a9c77b56902ae7ffcdd7a4905f664adc5d237b
478478
React-jsinspector: 0ae35a37b20d5e031eb020a69cc5afdbd6406301
479-
react-native-blob-courier: 88b102ed6c8a5d31f0ca938b48fcbf2fa164fc25
479+
react-native-blob-courier: 20d24b9a54342764ee61865aafd23573c46c6f2a
480480
React-perflogger: 9c547d8f06b9bf00cb447f2b75e8d7f19b7e02af
481481
React-RCTActionSheet: 3080b6e12e0e1a5b313c8c0050699b5c794a1b11
482482
React-RCTAnimation: 3f96f21a497ae7dabf4d2f150ee43f906aaf516f

example/yarn.lock

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -760,9 +760,9 @@
760760
xmldoc "^1.1.2"
761761

762762
"@react-native-community/cli-platform-ios@^5.0.1-alpha.0":
763-
version "5.0.1-alpha.1"
764-
resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-ios/-/cli-platform-ios-5.0.1-alpha.1.tgz#4d919dc91829404ebd4717c9adc3b3f013152919"
765-
integrity sha512-X0odEhPYecSWjG+nNFN5tSxFQcfxS2rTOaMSmrHiqdlL8Bv57wCajtf5VhwanqhGt3eZ70y8oS9VdBRachxEpA==
763+
version "5.0.1-alpha.2"
764+
resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-ios/-/cli-platform-ios-5.0.1-alpha.2.tgz#58ab0641355cbe68a0d1737dde8c7d66eb0c0e39"
765+
integrity sha512-W15A75j+4bx6qbcapFia1A0M+W3JAt7Bc4VgEYvxDDRI62EsSHk1k6ZBNxs/j0cDPSYF9ZXHlRI+CWi3r9bTbQ==
766766
dependencies:
767767
"@react-native-community/cli-tools" "^5.0.1-alpha.1"
768768
chalk "^3.0.0"
@@ -772,10 +772,10 @@
772772
plist "^3.0.1"
773773
xcode "^2.0.0"
774774

775-
"@react-native-community/cli-server-api@^5.0.1-alpha.1":
776-
version "5.0.1-alpha.1"
777-
resolved "https://registry.yarnpkg.com/@react-native-community/cli-server-api/-/cli-server-api-5.0.1-alpha.1.tgz#2b830411ca9b6922da67ea32c3e1c0492aa001fe"
778-
integrity sha512-Ev5drbVEnvC3EB3GCn5sog1fOn+4ULC/TUjWEDe9Ld93na7W1cYb+qAEMRP8hxZUf6R3qCRsFi6JY42qtqa+qQ==
775+
"@react-native-community/cli-server-api@^5.0.1-alpha.2":
776+
version "5.0.1-alpha.2"
777+
resolved "https://registry.yarnpkg.com/@react-native-community/cli-server-api/-/cli-server-api-5.0.1-alpha.2.tgz#a82557273bad99d188682169892aaa4b283ba149"
778+
integrity sha512-qzjoLF51GmvUHQrcJZE+wD3bTmgnTNOnGBU6z4terKmPdt/EBBSUkdXc6ScWWRF6oWP+xpxLZ//tKic2v2f+ag==
779779
dependencies:
780780
"@react-native-community/cli-debugger-ui" "^5.0.1-alpha.1"
781781
"@react-native-community/cli-tools" "^5.0.1-alpha.1"
@@ -807,13 +807,13 @@
807807
ora "^3.4.0"
808808

809809
"@react-native-community/cli@^5.0.1-alpha.0":
810-
version "5.0.1-alpha.1"
811-
resolved "https://registry.yarnpkg.com/@react-native-community/cli/-/cli-5.0.1-alpha.1.tgz#68a1887477e66a6d5206bd951b241730e1c0cbdc"
812-
integrity sha512-XmOqkg9noF/jaHujoBLifR1VCmisXZbTr9Lt3S2/QBgDg0jWDLAuraZC58yuBuzUTcG3+kfbD61rW3AWtnx8fA==
810+
version "5.0.1-alpha.2"
811+
resolved "https://registry.yarnpkg.com/@react-native-community/cli/-/cli-5.0.1-alpha.2.tgz#7e78378120fd4e264e4b577cbcf5e52b5beaa53b"
812+
integrity sha512-PP22TVV2VyELXhAX4PcBisasssastSEx23XDklfPoCPIXD2QgGC7y39n/b5I9tOzKi2qYswCEAcDpwXYwevGOg==
813813
dependencies:
814814
"@react-native-community/cli-debugger-ui" "^5.0.1-alpha.1"
815815
"@react-native-community/cli-hermes" "^5.0.1-alpha.1"
816-
"@react-native-community/cli-server-api" "^5.0.1-alpha.1"
816+
"@react-native-community/cli-server-api" "^5.0.1-alpha.2"
817817
"@react-native-community/cli-tools" "^5.0.1-alpha.1"
818818
"@react-native-community/cli-types" "^5.0.1-alpha.1"
819819
appdirsjs "^1.2.4"
@@ -1328,9 +1328,9 @@ camelcase@^6.0.0:
13281328
integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==
13291329

13301330
caniuse-lite@^1.0.30001181:
1331-
version "1.0.30001200"
1332-
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001200.tgz#25435af6ba907c2a9c86d21ce84950d4824e6620"
1333-
integrity sha512-ic/jXfa6tgiPBAISWk16jRI2q8YfjxHnSG7ddSL1ptrIP8Uy11SayFrjXRAk3NumHpDb21fdTkbTxb/hOrFrnQ==
1331+
version "1.0.30001202"
1332+
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001202.tgz#4cb3bd5e8a808e8cd89e4e66c549989bc8137201"
1333+
integrity sha512-ZcijQNqrcF8JNLjzvEiXqX4JUYxoZa7Pvcsd9UD8Kz4TvhTonOSNRsK+qtvpVL4l6+T1Rh4LFtLfnNWg6BGWCQ==
13341334

13351335
capture-exit@^2.0.0:
13361336
version "2.0.0"
@@ -1644,9 +1644,9 @@ [email protected]:
16441644
integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
16451645

16461646
electron-to-chromium@^1.3.649:
1647-
version "1.3.688"
1648-
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.688.tgz#0ba54a3e77fca6561a337e6cca959b75db8683b0"
1649-
integrity sha512-tbKinYX7BomVBcWHzwGolzv3kqCdk/vQ36ao3MC8tQMXqs1ZpevYU2RTr7+hkDvGWtoQbe+nvvl+GfMFmRna/A==
1647+
version "1.3.691"
1648+
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.691.tgz#a671eaf135a3ccec0915eb8d844a0952aba79f3b"
1649+
integrity sha512-ZqiO69KImmOGCyoH0icQPU3SndJiW93juEvf63gQngyhODO6SpQIPMTOHldtCs5DS5GMKvAkquk230E2zt2vpw==
16501650

16511651
emoji-regex@^8.0.0:
16521652
version "8.0.0"

ios/BlobCourier.m

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ @interface RCT_EXTERN_MODULE(BlobCourier, NSObject)
1414
RCT_EXTERN_METHOD(fetchBlob:(NSDictionary *)input
1515
withResolver:(RCTPromiseResolveBlock)resolve
1616
withRejecter:(RCTPromiseRejectBlock)reject)
17+
RCT_EXTERN_METHOD(sendBlob:(NSDictionary *)input
18+
withResolver:(RCTPromiseResolveBlock)resolve
19+
withRejecter:(RCTPromiseRejectBlock)reject)
1720
RCT_EXTERN_METHOD(uploadBlob:(NSDictionary *)input
1821
withResolver:(RCTPromiseResolveBlock)resolve
1922
withRejecter:(RCTPromiseRejectBlock)reject)

ios/BlobCourier.swift

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,35 @@ open class BlobCourier: NSObject {
6464
}
6565
}
6666

67+
@objc(sendBlob:withResolver:withRejecter:)
68+
func sendBlob(
69+
input: NSDictionary,
70+
resolve: @escaping RCTPromiseResolveBlock,
71+
reject: @escaping RCTPromiseRejectBlock
72+
) {
73+
DispatchQueue.global(qos: .background).async {
74+
do {
75+
let errorOrParameters = SenderParameterFactory.fromInput(input: input)
76+
77+
if case .failure(let error) = errorOrParameters { reject(error.code, error.message, error.error) }
78+
guard case .success(let parameters) = errorOrParameters else { return }
79+
80+
let result = BlobSender.sendBlobFromValidatedParameters(parameters: parameters)
81+
82+
switch result {
83+
case .success(let success):
84+
resolve(success)
85+
case .failure(let error):
86+
reject(error.code, error.message, error.error)
87+
}
88+
} catch {
89+
let unexpectedError = Errors.createUnexpectedError(error: error)
90+
91+
reject(unexpectedError.code, unexpectedError.message, unexpectedError.error)
92+
}
93+
}
94+
}
95+
6796
@objc(uploadBlob:withResolver:withRejecter:)
6897
func uploadBlob(
6998
input: NSDictionary,

ios/BlobCourier.xcodeproj/project.pbxproj

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@
3434
B96A993E25BE166900F42B65 /* UploaderParameterFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = B96A993B25BE166900F42B65 /* UploaderParameterFactory.swift */; };
3535
B96A993F25BE166900F42B65 /* UploadParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = B96A993C25BE166900F42B65 /* UploadParameters.swift */; };
3636
B96A994025BE166900F42B65 /* UploadParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = B96A993C25BE166900F42B65 /* UploadParameters.swift */; };
37+
B9854CDA261269B10054135B /* BlobSender.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9854CD5261269350054135B /* BlobSender.swift */; };
38+
B9854CDD261269B60054135B /* SenderDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9854CD6261269350054135B /* SenderDelegate.swift */; };
39+
B9854CE0261269BB0054135B /* SendParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9854CD8261269350054135B /* SendParameters.swift */; };
40+
B9854CE3261269C10054135B /* SenderParameterFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9854CD9261269350054135B /* SenderParameterFactory.swift */; };
3741
B9AF759125DF263E00B68816 /* CancelController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9AF756E25DF203800B68816 /* CancelController.swift */; };
3842
B9AF759925DF264E00B68816 /* RequestCanceller.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9AF756F25DF203800B68816 /* RequestCanceller.swift */; };
3943
B9AF75BF25DF29DF00B68816 /* CancelParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9AF75BD25DF29DF00B68816 /* CancelParameters.swift */; };
@@ -89,6 +93,10 @@
8993
B96A96FF25BDEA7D00F42B65 /* DownloaderParameterFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DownloaderParameterFactory.swift; sourceTree = "<group>"; };
9094
B96A993B25BE166900F42B65 /* UploaderParameterFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UploaderParameterFactory.swift; sourceTree = "<group>"; };
9195
B96A993C25BE166900F42B65 /* UploadParameters.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UploadParameters.swift; sourceTree = "<group>"; };
96+
B9854CD5261269350054135B /* BlobSender.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlobSender.swift; sourceTree = "<group>"; };
97+
B9854CD6261269350054135B /* SenderDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SenderDelegate.swift; sourceTree = "<group>"; };
98+
B9854CD8261269350054135B /* SendParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendParameters.swift; sourceTree = "<group>"; };
99+
B9854CD9261269350054135B /* SenderParameterFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SenderParameterFactory.swift; sourceTree = "<group>"; };
92100
B9AF756E25DF203800B68816 /* CancelController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CancelController.swift; sourceTree = "<group>"; };
93101
B9AF756F25DF203800B68816 /* RequestCanceller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestCanceller.swift; sourceTree = "<group>"; };
94102
B9AF75BD25DF29DF00B68816 /* CancelParameters.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CancelParameters.swift; sourceTree = "<group>"; };
@@ -162,6 +170,7 @@
162170
B96A888C25BC566300F42B65 /* Fetch */,
163171
B96A88AE25BC5EB800F42B65 /* Progress */,
164172
B96A945D25BD86AB00F42B65 /* React */,
173+
B9854CD4261269350054135B /* Send */,
165174
B96A889425BC567000F42B65 /* Upload */,
166175
B96829E6254EC872002B4B04 /* BlobCourierTests */,
167176
134814211AA4EA7D00B7C361 /* Products */,
@@ -228,6 +237,17 @@
228237
path = React;
229238
sourceTree = "<group>";
230239
};
240+
B9854CD4261269350054135B /* Send */ = {
241+
isa = PBXGroup;
242+
children = (
243+
B9854CD5261269350054135B /* BlobSender.swift */,
244+
B9854CD6261269350054135B /* SenderDelegate.swift */,
245+
B9854CD8261269350054135B /* SendParameters.swift */,
246+
B9854CD9261269350054135B /* SenderParameterFactory.swift */,
247+
);
248+
path = Send;
249+
sourceTree = "<group>";
250+
};
231251
B9AF756D25DF203800B68816 /* Cancel */ = {
232252
isa = PBXGroup;
233253
children = (
@@ -448,6 +468,7 @@
448468
B96A954A25BD8D3B00F42B65 /* BlobCourierEventEmitter.swift in Sources */,
449469
F4FF95D7245B92E800C19C63 /* BlobCourier.swift in Sources */,
450470
B96A993D25BE166900F42B65 /* UploaderParameterFactory.swift in Sources */,
471+
B9854CDA261269B10054135B /* BlobSender.swift in Sources */,
451472
B96829DF254EC736002B4B04 /* DownloaderDelegate.swift in Sources */,
452473
B96A8FEC25BCB87E00F42B65 /* BlobCourierEventEmitter.m in Sources */,
453474
B96A8F0925BCB1DA00F42B65 /* BlobCourier.m in Sources */,
@@ -456,12 +477,15 @@
456477
B96A8E3925BCA76300F42B65 /* BlobCourierDelayedEventEmitter.swift in Sources */,
457478
B9AF75BF25DF29DF00B68816 /* CancelParameters.swift in Sources */,
458479
B96A889625BC567000F42B65 /* BlobUploader.swift in Sources */,
480+
B9854CE3261269C10054135B /* SenderParameterFactory.swift in Sources */,
459481
B96A96D825BDE55900F42B65 /* DownloadParameters.swift in Sources */,
460482
B9AF759125DF263E00B68816 /* CancelController.swift in Sources */,
461483
B9AF75C025DF29DF00B68816 /* CancelParameterFactory.swift in Sources */,
484+
B9854CE0261269BB0054135B /* SendParameters.swift in Sources */,
462485
B96A888625BC565300F42B65 /* Errors.swift in Sources */,
463486
B96A888425BC565300F42B65 /* Constants.swift in Sources */,
464487
B96829D9254EC727002B4B04 /* UploaderDelegate.swift in Sources */,
488+
B9854CDD261269B60054135B /* SenderDelegate.swift in Sources */,
465489
B9AF759925DF264E00B68816 /* RequestCanceller.swift in Sources */,
466490
B96A993F25BE166900F42B65 /* UploadParameters.swift in Sources */,
467491
);

ios/Send/BlobSender.swift

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
// Copyright (c) Ely Deckers.
2+
//
3+
// This source code is licensed under the MPL-2.0 license found in the
4+
// LICENSE file in the root directory of this source tree.
5+
import Foundation
6+
7+
open class BlobSender: NSObject {
8+
static func filterHeaders(unfilteredHeaders: NSDictionary) -> NSDictionary {
9+
Dictionary(uniqueKeysWithValues: unfilteredHeaders
10+
.map { key, value in (key as? String, value as? String) }
11+
.filter({ $0.1 != nil }))
12+
.mapValues { $0! } as NSDictionary
13+
}
14+
15+
static func isValidTargetValue(_ value: String) -> Bool {
16+
return Constants.targetValues.contains(value)
17+
}
18+
19+
static func buildRequestDataForFileSend(
20+
method: String,
21+
url: URL,
22+
absoluteFilePath: String,
23+
headers: NSDictionary) throws -> (URLRequest, Data) {
24+
var request = URLRequest(url: url)
25+
request.httpMethod = method
26+
27+
for (key, value) in headers {
28+
if let headerKey = key as? String, let headerValue = value as? String {
29+
request.setValue(
30+
headerValue,
31+
forHTTPHeaderField: headerKey)
32+
}
33+
}
34+
35+
let fileUrl = URL(string: absoluteFilePath)!
36+
37+
let fileData = try Data(contentsOf: fileUrl)
38+
39+
return (request, fileData)
40+
}
41+
42+
// swiftlint:disable function_body_length
43+
static func sendBlobFromValidatedParameters(parameters: SendParameters) ->
44+
Result<NSDictionary, BlobCourierError> {
45+
let sessionConfig = URLSessionConfiguration.default
46+
47+
let group = DispatchGroup()
48+
let groupId = UUID().uuidString
49+
50+
let queue = DispatchQueue.global()
51+
52+
var result: Result<NSDictionary, BlobCourierError> = .success([:])
53+
54+
print("Entering group (id=\(groupId))")
55+
group.enter()
56+
57+
var cancelObserver: NSObjectProtocol?
58+
59+
queue.async(group: group) {
60+
let successfulResult = { (theResult: NSDictionary) -> Void in
61+
result = .success(theResult)
62+
63+
print("Leaving group (id=\(groupId),status=resolve)")
64+
group.leave()
65+
}
66+
67+
let failedResult = { (error: BlobCourierError) -> Void in
68+
result = .failure(error)
69+
70+
print("Leaving group (id=\(groupId),status=reject)")
71+
group.leave()
72+
}
73+
74+
let senderDelegate =
75+
SenderDelegate(
76+
taskId: parameters.taskId,
77+
returnResponse: parameters.returnResponse,
78+
progressIntervalMilliseconds: parameters.progressIntervalMilliseconds,
79+
resolve: successfulResult,
80+
reject: failedResult)
81+
82+
let session = URLSession(configuration: sessionConfig, delegate: senderDelegate, delegateQueue: nil)
83+
84+
let headers = parameters.headers
85+
86+
do {
87+
let (request, fileData) =
88+
try buildRequestDataForFileSend(
89+
method: parameters.method,
90+
url: parameters.url,
91+
absoluteFilePath: parameters.absoluteFilePath,
92+
headers: headers)
93+
94+
session.uploadTask(with: request, from: fileData).resume()
95+
96+
cancelObserver = CancelController.registerCancelObserver(
97+
session: session, taskId: parameters.taskId)
98+
} catch {
99+
failedResult(Errors.createUnexpectedError(error: error))
100+
}
101+
}
102+
103+
print("Waiting for group (id=\(groupId))")
104+
group.wait()
105+
print("Left group (id=\(groupId))")
106+
107+
NotificationCenter.default.removeObserver(cancelObserver)
108+
109+
return result
110+
}
111+
// swiftlint:enable function_body_length
112+
}

ios/Send/SendParameters.swift

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright (c) Ely Deckers.
2+
//
3+
// This source code is licensed under the MPL-2.0 license found in the
4+
// LICENSE file in the root directory of this source tree.
5+
import Foundation
6+
7+
struct SendParameters {
8+
let absoluteFilePath: String
9+
let headers: NSDictionary
10+
let method: String
11+
let progressIntervalMilliseconds: Int
12+
let returnResponse: Bool
13+
let taskId: String
14+
let url: URL
15+
16+
init(
17+
absoluteFilePath: String,
18+
headers: NSDictionary,
19+
method: String,
20+
progressIntervalMilliseconds: Int,
21+
returnResponse: Bool,
22+
taskId: String,
23+
url: URL) {
24+
self.absoluteFilePath = absoluteFilePath
25+
self.headers = headers
26+
self.method = method
27+
self.progressIntervalMilliseconds = progressIntervalMilliseconds
28+
self.returnResponse = returnResponse
29+
self.taskId = taskId
30+
self.url = url
31+
}
32+
}

0 commit comments

Comments
 (0)