Skip to content

Commit

Permalink
[_]:WIP test multipart upload
Browse files Browse the repository at this point in the history
  • Loading branch information
PixoDev committed Nov 21, 2023
1 parent b6c95bc commit 9093587
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 25 deletions.
2 changes: 2 additions & 0 deletions Sources/InternxtSwiftCore/Services/Network/Encrypt.swift
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ public struct Encrypt {
}




public func encrypt(string: String, password: String, salt: [UInt8], iv: Data, rounds: Int = 2145) throws -> Data{


Expand Down
34 changes: 29 additions & 5 deletions Sources/InternxtSwiftCore/Services/Network/NetworkFacade.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
//

import Foundation
import CryptoKit

let MULTIPART_MIN_SIZE = 100 * 1024 * 1024;
let MULTIPART_CHUNK_SIZE = 100 * 1024 * 1024;
Expand Down Expand Up @@ -99,6 +100,8 @@ public struct NetworkFacade {
return try await upload.start(index: index, bucketId: bucketId, mnemonic: mnemonic, encryptedFileURL: encryptedOutput, progressHandler: progressHandler)
}



private func runMultipartUpload(
input: InputStream,
fileSize: Int,
Expand All @@ -109,6 +112,9 @@ public struct NetworkFacade {
progressHandler: @escaping ProgressHandler,
debug: Bool = false
) async throws -> FinishUploadResponse {
var hasher = SHA256.init()



let parts = 3

Expand All @@ -128,13 +134,13 @@ public struct NetworkFacade {
let hash = encrypt.getFileContentHash(stream: InputStream(data: encryptedChunk))

let uploadUrl = uploadUrls[partIndex]
try await uploadMultipart.uploadPart(encryptedChunk: encryptedChunk, uploadUrl: uploadUrl, partIndex: partIndex){progress in
let etag = try await uploadMultipart.uploadPart(encryptedChunk: encryptedChunk, uploadUrl: uploadUrl, partIndex: partIndex){progress in

//print("UPLOAD PROGRESS FOR PART \(partIndex)", progress)
}

let uploadedPartConfig = UploadedPartConfig(
hash: hash,
uuid: startUploadResult.uuid
etag: etag, partNumber: partIndex + 1
)

uploadedPartsConfigs.append(uploadedPartConfig)
Expand All @@ -148,15 +154,33 @@ public struct NetworkFacade {
key: fileKey,
iv: iv
){encryptedChunk in
hasher.update(data: encryptedChunk)
// If something fails here, the error is propagated
// and the stream reading is stopped
try await processEncryptedChunk(encryptedChunk: encryptedChunk, partIndex: partIndex)
print("Chunk number \(partIndex) uploaded")

partIndex += 1
}

let finishUpload = try await uploadMultipart.finishUpload(bucketId: bucketId, uploadedParts: uploadedPartsConfigs, index: Data(index), debug: debug)

let fileSHA256digest = hasher.finalize()

var sha256Hash = [UInt8]()
fileSHA256digest.withUnsafeBytes {bytes in
sha256Hash.append(contentsOf: bytes)
}

let fileHash = HMAC().ripemd160(message: Data(sha256Hash))


let finishUpload = try await uploadMultipart.finishUpload(
bucketId: bucketId,
fileHash: fileHash.toHexString(),
uploadUuid: startUploadResult.uuid,
uploadedParts: uploadedPartsConfigs,
index: Data(index),
debug: debug
)
print("Chunk number \(partIndex) uploaded")
return finishUpload
}
Expand Down
3 changes: 2 additions & 1 deletion Sources/InternxtSwiftCore/Services/Network/Upload.swift
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@ public class Upload: NSObject {
var shards: Array<ShardUploadPayload> = Array()
shards.append(ShardUploadPayload(
hash: cryptoUtils.bytesToHexString(Array(fileHash)),
uuid: uploadResult.uuid
uuid: uploadResult.uuid,
parts: nil
))
let finishUploadResult = try await networkAPI.finishUpload(bucketId: bucketId, payload: FinishUploadPayload(
index: cryptoUtils.bytesToHexString(index),
Expand Down
43 changes: 25 additions & 18 deletions Sources/InternxtSwiftCore/Services/Network/UploadMultipart.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ enum UploadMultipartError: Error {
}

public struct UploadedPartConfig {
let hash: Data
let uuid: String
let etag: String
let partNumber: Int
}

@available(macOS 10.15, *)
Expand Down Expand Up @@ -69,35 +69,39 @@ public class UploadMultipart: NSObject {
return startUploadResult
}

func uploadPart(encryptedChunk: Data, uploadUrl: String, partIndex: Int, progressHandler: @escaping ProgressHandler) async throws -> Void {
func uploadPart(encryptedChunk: Data, uploadUrl: String, partIndex: Int, progressHandler: @escaping ProgressHandler) async throws -> String {

// Upload the chunk to the given URL
let successUpload = try await self.uploadEncryptedChunk(encryptedChunk: encryptedChunk, uploadUrl: uploadUrl, progressHandler: progressHandler)

if successUpload == false {
throw UploadError.UploadNotSuccessful
}
let uploadEtag = try await self.uploadEncryptedChunk(encryptedChunk: encryptedChunk, uploadUrl: uploadUrl, progressHandler: progressHandler)


return uploadEtag
}


func finishUpload(bucketId: String, uploadedParts: [UploadedPartConfig], index: Data, debug: Bool = false) async throws -> FinishUploadResponse {
func finishUpload(bucketId: String, fileHash: String, uploadUuid: String, uploadedParts: [UploadedPartConfig], index: Data, debug: Bool = false) async throws -> FinishUploadResponse {


var shards: Array<ShardUploadPayload> = Array()

uploadedParts.forEach{uploadedPart in
shards.append(ShardUploadPayload(
hash: uploadedPart.hash.toHexString(),
uuid: uploadedPart.uuid
))
}
let shardPayload = ShardUploadPayload(
hash: fileHash,
uuid: uploadUuid,
parts: uploadedParts.map{ uploadedPart in
return ShardPartPayload(
ETag: uploadedPart.etag,
PartNumber: uploadedPart.partNumber
)
}
)
shards.append(shardPayload)


let payload = try FinishUploadPayload(
index: index.toHexString(),
shards: shards
)

print("UPLOADS", payload)
let finishUploadResult = try await networkAPI.finishUpload(
bucketId: bucketId,
payload: payload,
Expand All @@ -109,7 +113,7 @@ public class UploadMultipart: NSObject {



private func uploadEncryptedChunk(encryptedChunk: Data, uploadUrl: String, progressHandler: ProgressHandler?) async throws -> Bool {
private func uploadEncryptedChunk(encryptedChunk: Data, uploadUrl: String, progressHandler: ProgressHandler?) async throws -> String {
return try await withCheckedThrowingContinuation { (continuation) in
var request = URLRequest(
url: URL(string: uploadUrl)!,
Expand All @@ -128,7 +132,10 @@ public class UploadMultipart: NSObject {
if response?.statusCode != 200 {
return continuation.resume(with: .failure(UploadError.UploadNotSuccessful))
} else {
return continuation.resume(with: .success(true))
guard let etagValue = response?.value(forHTTPHeaderField: "Etag") else {
return continuation.resume(with: .failure(UploadError.MissingEtag))
}
return continuation.resume(with: .success(etagValue))
}

}
Expand Down
8 changes: 7 additions & 1 deletion Sources/InternxtSwiftCore/Types/NetworkTypes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,20 @@ public struct StartUploadResponse: Decodable {
public let uploads: Array<StartUploadResult>
}

public struct ShardPartPayload: Codable {
public let ETag: String
public let PartNumber: Int
}

public struct ShardUploadPayload: Codable {
public let hash: String
public let uuid: String
public let parts: [ShardPartPayload]?

init(hash: String, uuid: String) {
init(hash: String, uuid: String, parts: [ShardPartPayload]? = nil) {
self.hash = hash
self.uuid = uuid
self.parts = parts
}
}

Expand Down
1 change: 1 addition & 0 deletions Sources/InternxtSwiftCore/Utils/Errors.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ enum UploadError: Error {
case MissingUploadUrl
case UploadNotSuccessful
case UploadedSizeNotMatching
case MissingEtag
}


Expand Down

0 comments on commit 9093587

Please sign in to comment.