Skip to content

Latest commit

 

History

History
150 lines (97 loc) · 4.27 KB

README.md

File metadata and controls

150 lines (97 loc) · 4.27 KB

Binary Chunking for Swift

CircleCI Maintainability Swift License Join our chat on Gitter

This library allows you to split up large binary messages into multiple chunks of a certain size.

When converting data to chunks, a 9 byte header is prepended to each chunk. This allows you to send the chunks to the receiver in any order.

While the library was written for use with WebRTC DataChannels, it can also be used outside of that scope.

The full specification for the chunking format can be found here.

Generating an Xcode Project

Open the project directory on the command line, then run

$ swift package generate-xcodeproj

Usage

Chunking

Create a new chunker:

let data = Data(bytes: [1, 2, 3, 4, 5, 6, 7, 8])
let chunker = try Chunker(id: 42, data: data, chunkSize: 12)

The id field contains the message id. You probably want to use an incrementing counter to make sure that every message has its own message id.

The `chunkSize should include the 9 byte header. Therefore it must be at least 10 (resulting in 1 byte of data per chunk).

Now you can iterate over the chunks in the chunker.

for chunk in chunker {
    print!("Chunk is \(chunk)")
}

This will result in 3 chunks:

Chunk is [0, 0, 0, 0, 42, 0, 0, 0, 0, 1, 2, 3]
Chunk is [0, 0, 0, 0, 42, 0, 0, 0, 1, 4, 5, 6]
Chunk is [1, 0, 0, 0, 42, 0, 0, 0, 2, 7, 8]

Unchunking

Create an unchunker:

let unchunker = Unchunker()

The unchunker will notify you when a message is complete using a delegate:

class MessagePrintingDelegate: MessageCompleteDelegate {
    func messageComplete(message: Data) {
        print("Message is complete: \([UInt8](message))")
    }
}

// ...

unchunker.delegate = MessagePrintingDelegate()

For every chunk you receive, add it to the unchunker. You may also add chunks out-of-order.

try unchunker.addChunk(bytes: Data([0, 0,0,0,42, 0,0,0,0, 1,2,3]))
try unchunker.addChunk(bytes: Data([0, 0,0,0,42, 0,0,0,2, 7,8]))
try unchunker.addChunk(bytes: Data([0, 0,0,0,42, 0,0,0,1, 4,5,6]))

As soon as the message is complete, your delegate will be notified synchronously.

Message is complete: [1, 2, 3, 4, 5, 6, 7, 8]

Cleanup

Because the Unchunker instance needs to keep track of arrived chunks, it's possible that incomplete messages add up and use a lot of memory without ever being freed.

To avoid this, simply call the Unchunker.gc(maxAge: TimeInterval) method regularly. It will remove all incomplete messages that haven't been updated for more than the specified number of seconds. The method will return the number of removed chunks.

let removedChunks = unchunker.gc(maxAge: 10.0)

Thread Safety

All classes exposed by this library should be thread safe.

Format

The chunking format is described in the specification.

Testing

To test from the command line:

$ swift test

License

Licensed under either of

Contributing

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.