Skip to main content

MTE Relay Client for iOS using Swift

The MTE Relay Client for iOS package facilitates encrypted communication between an iOS application and an MTE Relay Server running in AWS.

Installation

Following these directions from Apple:
https://developer.apple.com/documentation/xcode/adding-package-dependencies-to-your-app

to install our github repository:
https://github.com/Eclypses/eclypses-aws-mte-relay-client-ios.git

Quick Start

Your class(es) interacting with MteRelay Client must contain these elements:

  • Import MteRelay
  • Create a Relay class variable: <var relay: Relay!>
  • Add RelayResponseDelegate to the class declaration and the single function this protocol requires, i.e. func relayResponse(success: Bool, responseStr: String, errorMessage: String?) {}. Relay Pairing responses will be returned here.
  • In the class initializer, instantiate the Relay object.
import "MteRelay"

// The class were you wish to receive MteRelay responses requires a reference to the MteRelay instance and conform to RelayResponseDelegate
class <Your Class>: RelayResponseDelegate {

// Class variables
var relay: Relay!

// Returns Mte Pairing responses
func relayResponse(success: Bool, responseStr: String, errorMessage: String?) {
// relay callback receiving Relay Pairing responses and instantiation errors.
}

// If you want to stream file uploads and downloads, add conformance to RelayStreamResponseDelegate, RelayStreamCompletionDelegate and RelayStreamDelegate
class <Your Class>: RelayResponseDelegate, RelayStreamResponseDelegate, RelayStreamCompletionDelegate, RelayStreamDelegate {

func getRequestBodyStream(outputStream: OutputStream) -> Int {
var bytesWritten: Int = 0
if outputStream.hasSpaceAvailable {
// Provide request object to outputStream. In this example, it is a multipart request with a file.
bytesWritten = multipartHelper.assembleMultipartWithFile(outputStream: outputStream)
}
return bytesWritten
}

func relayStreamResponse(success: Bool, responseStr: String, errorMessage: String?) {
// Receives stream upload and download stream responses.
}

func streamCompletionPercentage(bytesCompleted: Double, totalBytes: Double) {
// Useful for upload progress indicator. This is called periodically throughout the upload process with updated values.
}

// Initializer of class interacting with MteRelay
init() async throws {
try await instantiateMteRelay()
}

// New function to instantiate MteRelay.
func instantiateMteRelay() async throws {
relay = try await Relay()
relay.relayResponseDelegate = self // for pairing responses
relay.streamResponseDelegate = self // for streaming responses
// Any Relay instantiation errors, including pairing errors, will be returned asynchronously via the RelayResponseDelegate, which should be monitored to confirm that the Relay instantiation was successful.

// if you need to adjust default Relay settings . . .
// Available Relay Settings methods. See below for more information
try relay.setPersistPairs(false) // Defaults to false
try relay.setPairPoolSize(3) // Defaults to 3. Range 1 to 10
try relay.setUploadChunkSize() // Defaults to 1024 * 1024 (1 MB). Range 4096 to 10485760 (10 MB)
}
  • If you have request headers that you wish to conceal, create a String array with the header names as the elements in the array. Content-Type will always be encrypted if it exists. The encrypted headers will be decrypted before being sent on the the original destination Server.
let headersToEncrypt = ["Content-Type", "Auth", "<any_other_header_name>"]


IMPORTANT - - Update your Request



URLSession.dataTask function

  • Edit your [func dataTask(with: URL, completionHandler: (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTask] to call the corresponding function in the MteRelay class as shown here.
await relay.dataTask(with: request, headersToEncrypt: ,headersToEncrypt) { (data, response, error) in
if let error = error {
// Handle the error
}
guard let data = data else {
// Handle the lack of data as appropriate
}
// Use the response and data as you wish
}


File Stream Upload Function

  • Edit your file upload function to add the following functionality
var request = URLSession.request // Your original URLSession Request with the updated URL (AWS Relay Server URL)
let headersToEncrypt = ["Content-Type", "Auth", "<any_other_header_name>"] // Any headers you want to conceal
relay.streamResponseDelegate = self
relay.relayStreamResponseDelegate = self
relay.relayStreamCompletionDelegate = self
try relay.uploadFileStream(request: request,
headersToEncrypt: headersToEncrypt)
// Your success boolean, response String and any errors will be returned asynchronously via the StreamResponseDelegate


File Stream Download Function

  • Edit your file download function to add the following functionality
var request = URLSession.request // Your original URLSession Request with the updated URL (AWS Relay Server URL)
let downloadURL = <FileURL> // Where you want the downloaded file stored
let headersToEncrypt = ["Content-Type", "Auth", "<any_other_header_name>"] // Any headers you want to conceal
relay.streamResponseDelegate = self
await relay.download(request: request, downloadUrl: downloadUrl, headersToEncrypt: headersToEncrypt)
// Your success boolean, response String and any errors will be returned asynchronously via the StreamResponseDelegate


RePair with MteRelay Server

Should the existing Mte pairing be broken for any reason, a rePairMte function is provided to remove the pairing between the AWS MteRelay Client and Server. Then you can reinstantiate the relay, which will rePair with the server.
Example function

    func rePairMte() throws {

Task {
try relay.rePairMte(<URL Path to AWS Relay Server>) { success in
// check success vaiable and handle result as appropriate
}
}
}

Adjust Relay Settings as Necessary

  • The RelaySettings actor contains a few settings that can be edited at runtime via public functions as shown below. Each new Relay instantiation begins with the default values.
// The Mobile Relay Client has the ability to persist pairing with server, even though client has been shut down. Default is false because a new pairing happens quickly upon first request and removes the chance of the pairing having been corrupted.
try relay.setPersistPairs(false) // Defaults to false on each Relay instantiation

// The Mobile Relay Client provides multiple pairs used in a round-robin fashion to facilitate high throughput without collisions.
try relay.setPairPoolSize(3) // Defaults to 3. Range 1 to 10

// Sets the maximum number of bytes processed in a single chunk. Processing often occurs on fewer bytes.
try relay.setUploadChunkSize(4096) // Defaults to 1048576. Range 4096 (4KB) to 10485760 (10 MB)



An AWS MteRelay Client YouTube integration video will soon be available.



Examples:

Source Code