Skip to content

Commit

Permalink
chore: wip add iOS code for raw request
Browse files Browse the repository at this point in the history
  • Loading branch information
edeckers committed Apr 22, 2021
1 parent 0dcf7ea commit 298fb9b
Show file tree
Hide file tree
Showing 10 changed files with 392 additions and 19 deletions.
2 changes: 1 addition & 1 deletion example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,7 @@ SPEC CHECKSUMS:
React-jsi: 74341196d9547cbcbcfa4b3bbbf03af56431d5a1
React-jsiexecutor: 06a9c77b56902ae7ffcdd7a4905f664adc5d237b
React-jsinspector: 0ae35a37b20d5e031eb020a69cc5afdbd6406301
react-native-blob-courier: 88b102ed6c8a5d31f0ca938b48fcbf2fa164fc25
react-native-blob-courier: 20d24b9a54342764ee61865aafd23573c46c6f2a
React-perflogger: 9c547d8f06b9bf00cb447f2b75e8d7f19b7e02af
React-RCTActionSheet: 3080b6e12e0e1a5b313c8c0050699b5c794a1b11
React-RCTAnimation: 3f96f21a497ae7dabf4d2f150ee43f906aaf516f
Expand Down
34 changes: 17 additions & 17 deletions example/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -760,9 +760,9 @@
xmldoc "^1.1.2"

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

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

"@react-native-community/cli@^5.0.1-alpha.0":
version "5.0.1-alpha.1"
resolved "https://registry.yarnpkg.com/@react-native-community/cli/-/cli-5.0.1-alpha.1.tgz#68a1887477e66a6d5206bd951b241730e1c0cbdc"
integrity sha512-XmOqkg9noF/jaHujoBLifR1VCmisXZbTr9Lt3S2/QBgDg0jWDLAuraZC58yuBuzUTcG3+kfbD61rW3AWtnx8fA==
version "5.0.1-alpha.2"
resolved "https://registry.yarnpkg.com/@react-native-community/cli/-/cli-5.0.1-alpha.2.tgz#7e78378120fd4e264e4b577cbcf5e52b5beaa53b"
integrity sha512-PP22TVV2VyELXhAX4PcBisasssastSEx23XDklfPoCPIXD2QgGC7y39n/b5I9tOzKi2qYswCEAcDpwXYwevGOg==
dependencies:
"@react-native-community/cli-debugger-ui" "^5.0.1-alpha.1"
"@react-native-community/cli-hermes" "^5.0.1-alpha.1"
"@react-native-community/cli-server-api" "^5.0.1-alpha.1"
"@react-native-community/cli-server-api" "^5.0.1-alpha.2"
"@react-native-community/cli-tools" "^5.0.1-alpha.1"
"@react-native-community/cli-types" "^5.0.1-alpha.1"
appdirsjs "^1.2.4"
Expand Down Expand Up @@ -1328,9 +1328,9 @@ camelcase@^6.0.0:
integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==

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

capture-exit@^2.0.0:
version "2.0.0"
Expand Down Expand Up @@ -1644,9 +1644,9 @@ [email protected]:
integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=

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

emoji-regex@^8.0.0:
version "8.0.0"
Expand Down
3 changes: 3 additions & 0 deletions ios/BlobCourier.m
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ @interface RCT_EXTERN_MODULE(BlobCourier, NSObject)
RCT_EXTERN_METHOD(fetchBlob:(NSDictionary *)input
withResolver:(RCTPromiseResolveBlock)resolve
withRejecter:(RCTPromiseRejectBlock)reject)
RCT_EXTERN_METHOD(sendBlob:(NSDictionary *)input
withResolver:(RCTPromiseResolveBlock)resolve
withRejecter:(RCTPromiseRejectBlock)reject)
RCT_EXTERN_METHOD(uploadBlob:(NSDictionary *)input
withResolver:(RCTPromiseResolveBlock)resolve
withRejecter:(RCTPromiseRejectBlock)reject)
Expand Down
29 changes: 29 additions & 0 deletions ios/BlobCourier.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,35 @@ open class BlobCourier: NSObject {
}
}

@objc(sendBlob:withResolver:withRejecter:)
func sendBlob(
input: NSDictionary,
resolve: @escaping RCTPromiseResolveBlock,
reject: @escaping RCTPromiseRejectBlock
) {
DispatchQueue.global(qos: .background).async {
do {
let errorOrParameters = SenderParameterFactory.fromInput(input: input)

if case .failure(let error) = errorOrParameters { reject(error.code, error.message, error.error) }
guard case .success(let parameters) = errorOrParameters else { return }

let result = BlobSender.sendBlobFromValidatedParameters(parameters: parameters)

switch result {
case .success(let success):
resolve(success)
case .failure(let error):
reject(error.code, error.message, error.error)
}
} catch {
let unexpectedError = Errors.createUnexpectedError(error: error)

reject(unexpectedError.code, unexpectedError.message, unexpectedError.error)
}
}
}

@objc(uploadBlob:withResolver:withRejecter:)
func uploadBlob(
input: NSDictionary,
Expand Down
24 changes: 24 additions & 0 deletions ios/BlobCourier.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@
B96A993E25BE166900F42B65 /* UploaderParameterFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = B96A993B25BE166900F42B65 /* UploaderParameterFactory.swift */; };
B96A993F25BE166900F42B65 /* UploadParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = B96A993C25BE166900F42B65 /* UploadParameters.swift */; };
B96A994025BE166900F42B65 /* UploadParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = B96A993C25BE166900F42B65 /* UploadParameters.swift */; };
B9854CDA261269B10054135B /* BlobSender.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9854CD5261269350054135B /* BlobSender.swift */; };
B9854CDD261269B60054135B /* SenderDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9854CD6261269350054135B /* SenderDelegate.swift */; };
B9854CE0261269BB0054135B /* SendParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9854CD8261269350054135B /* SendParameters.swift */; };
B9854CE3261269C10054135B /* SenderParameterFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9854CD9261269350054135B /* SenderParameterFactory.swift */; };
B9AF759125DF263E00B68816 /* CancelController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9AF756E25DF203800B68816 /* CancelController.swift */; };
B9AF759925DF264E00B68816 /* RequestCanceller.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9AF756F25DF203800B68816 /* RequestCanceller.swift */; };
B9AF75BF25DF29DF00B68816 /* CancelParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9AF75BD25DF29DF00B68816 /* CancelParameters.swift */; };
Expand Down Expand Up @@ -89,6 +93,10 @@
B96A96FF25BDEA7D00F42B65 /* DownloaderParameterFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DownloaderParameterFactory.swift; sourceTree = "<group>"; };
B96A993B25BE166900F42B65 /* UploaderParameterFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UploaderParameterFactory.swift; sourceTree = "<group>"; };
B96A993C25BE166900F42B65 /* UploadParameters.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UploadParameters.swift; sourceTree = "<group>"; };
B9854CD5261269350054135B /* BlobSender.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlobSender.swift; sourceTree = "<group>"; };
B9854CD6261269350054135B /* SenderDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SenderDelegate.swift; sourceTree = "<group>"; };
B9854CD8261269350054135B /* SendParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendParameters.swift; sourceTree = "<group>"; };
B9854CD9261269350054135B /* SenderParameterFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SenderParameterFactory.swift; sourceTree = "<group>"; };
B9AF756E25DF203800B68816 /* CancelController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CancelController.swift; sourceTree = "<group>"; };
B9AF756F25DF203800B68816 /* RequestCanceller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestCanceller.swift; sourceTree = "<group>"; };
B9AF75BD25DF29DF00B68816 /* CancelParameters.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CancelParameters.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -162,6 +170,7 @@
B96A888C25BC566300F42B65 /* Fetch */,
B96A88AE25BC5EB800F42B65 /* Progress */,
B96A945D25BD86AB00F42B65 /* React */,
B9854CD4261269350054135B /* Send */,
B96A889425BC567000F42B65 /* Upload */,
B96829E6254EC872002B4B04 /* BlobCourierTests */,
134814211AA4EA7D00B7C361 /* Products */,
Expand Down Expand Up @@ -228,6 +237,17 @@
path = React;
sourceTree = "<group>";
};
B9854CD4261269350054135B /* Send */ = {
isa = PBXGroup;
children = (
B9854CD5261269350054135B /* BlobSender.swift */,
B9854CD6261269350054135B /* SenderDelegate.swift */,
B9854CD8261269350054135B /* SendParameters.swift */,
B9854CD9261269350054135B /* SenderParameterFactory.swift */,
);
path = Send;
sourceTree = "<group>";
};
B9AF756D25DF203800B68816 /* Cancel */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -448,6 +468,7 @@
B96A954A25BD8D3B00F42B65 /* BlobCourierEventEmitter.swift in Sources */,
F4FF95D7245B92E800C19C63 /* BlobCourier.swift in Sources */,
B96A993D25BE166900F42B65 /* UploaderParameterFactory.swift in Sources */,
B9854CDA261269B10054135B /* BlobSender.swift in Sources */,
B96829DF254EC736002B4B04 /* DownloaderDelegate.swift in Sources */,
B96A8FEC25BCB87E00F42B65 /* BlobCourierEventEmitter.m in Sources */,
B96A8F0925BCB1DA00F42B65 /* BlobCourier.m in Sources */,
Expand All @@ -456,12 +477,15 @@
B96A8E3925BCA76300F42B65 /* BlobCourierDelayedEventEmitter.swift in Sources */,
B9AF75BF25DF29DF00B68816 /* CancelParameters.swift in Sources */,
B96A889625BC567000F42B65 /* BlobUploader.swift in Sources */,
B9854CE3261269C10054135B /* SenderParameterFactory.swift in Sources */,
B96A96D825BDE55900F42B65 /* DownloadParameters.swift in Sources */,
B9AF759125DF263E00B68816 /* CancelController.swift in Sources */,
B9AF75C025DF29DF00B68816 /* CancelParameterFactory.swift in Sources */,
B9854CE0261269BB0054135B /* SendParameters.swift in Sources */,
B96A888625BC565300F42B65 /* Errors.swift in Sources */,
B96A888425BC565300F42B65 /* Constants.swift in Sources */,
B96829D9254EC727002B4B04 /* UploaderDelegate.swift in Sources */,
B9854CDD261269B60054135B /* SenderDelegate.swift in Sources */,
B9AF759925DF264E00B68816 /* RequestCanceller.swift in Sources */,
B96A993F25BE166900F42B65 /* UploadParameters.swift in Sources */,
);
Expand Down
112 changes: 112 additions & 0 deletions ios/Send/BlobSender.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
// Copyright (c) Ely Deckers.
//
// This source code is licensed under the MPL-2.0 license found in the
// LICENSE file in the root directory of this source tree.
import Foundation

open class BlobSender: NSObject {
static func filterHeaders(unfilteredHeaders: NSDictionary) -> NSDictionary {
Dictionary(uniqueKeysWithValues: unfilteredHeaders
.map { key, value in (key as? String, value as? String) }
.filter({ $0.1 != nil }))
.mapValues { $0! } as NSDictionary
}

static func isValidTargetValue(_ value: String) -> Bool {
return Constants.targetValues.contains(value)
}

static func buildRequestDataForFileSend(
method: String,
url: URL,
absoluteFilePath: String,
headers: NSDictionary) throws -> (URLRequest, Data) {
var request = URLRequest(url: url)
request.httpMethod = method

for (key, value) in headers {
if let headerKey = key as? String, let headerValue = value as? String {
request.setValue(
headerValue,
forHTTPHeaderField: headerKey)
}
}

let fileUrl = URL(string: absoluteFilePath)!

let fileData = try Data(contentsOf: fileUrl)

return (request, fileData)
}

// swiftlint:disable function_body_length
static func sendBlobFromValidatedParameters(parameters: SendParameters) ->
Result<NSDictionary, BlobCourierError> {
let sessionConfig = URLSessionConfiguration.default

let group = DispatchGroup()
let groupId = UUID().uuidString

let queue = DispatchQueue.global()

var result: Result<NSDictionary, BlobCourierError> = .success([:])

print("Entering group (id=\(groupId))")
group.enter()

var cancelObserver: NSObjectProtocol?

queue.async(group: group) {
let successfulResult = { (theResult: NSDictionary) -> Void in
result = .success(theResult)

print("Leaving group (id=\(groupId),status=resolve)")
group.leave()
}

let failedResult = { (error: BlobCourierError) -> Void in
result = .failure(error)

print("Leaving group (id=\(groupId),status=reject)")
group.leave()
}

let senderDelegate =
SenderDelegate(
taskId: parameters.taskId,
returnResponse: parameters.returnResponse,
progressIntervalMilliseconds: parameters.progressIntervalMilliseconds,
resolve: successfulResult,
reject: failedResult)

let session = URLSession(configuration: sessionConfig, delegate: senderDelegate, delegateQueue: nil)

let headers = parameters.headers

do {
let (request, fileData) =
try buildRequestDataForFileSend(
method: parameters.method,
url: parameters.url,
absoluteFilePath: parameters.absoluteFilePath,
headers: headers)

session.uploadTask(with: request, from: fileData).resume()

cancelObserver = CancelController.registerCancelObserver(
session: session, taskId: parameters.taskId)
} catch {
failedResult(Errors.createUnexpectedError(error: error))
}
}

print("Waiting for group (id=\(groupId))")
group.wait()
print("Left group (id=\(groupId))")

NotificationCenter.default.removeObserver(cancelObserver)

return result
}
// swiftlint:enable function_body_length
}
32 changes: 32 additions & 0 deletions ios/Send/SendParameters.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright (c) Ely Deckers.
//
// This source code is licensed under the MPL-2.0 license found in the
// LICENSE file in the root directory of this source tree.
import Foundation

struct SendParameters {
let absoluteFilePath: String
let headers: NSDictionary
let method: String
let progressIntervalMilliseconds: Int
let returnResponse: Bool
let taskId: String
let url: URL

init(
absoluteFilePath: String,
headers: NSDictionary,
method: String,
progressIntervalMilliseconds: Int,
returnResponse: Bool,
taskId: String,
url: URL) {
self.absoluteFilePath = absoluteFilePath
self.headers = headers
self.method = method
self.progressIntervalMilliseconds = progressIntervalMilliseconds
self.returnResponse = returnResponse
self.taskId = taskId
self.url = url
}
}
Loading

0 comments on commit 298fb9b

Please sign in to comment.