Skip to content

Commit

Permalink
Merge pull request #38 from Vinz1911/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
Vinz1911 authored Jun 5, 2023
2 parents e06097a + ed06fc6 commit e935bad
Show file tree
Hide file tree
Showing 13 changed files with 156 additions and 166 deletions.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ dependencies: [
import FusionKit

// create a new connection
let connection = FNConnection(host: "example.com", port: 8080)
let connection = FNKonnection(host: "example.com", port: 8080)

// support for NWParameters, tls example:
let connection = FNConnection(host: "example.com", port: 8080, parameters: .tls)
let connection = FNKonnection(host: "example.com", port: 8080, parameters: .tls)

// ...
```
Expand All @@ -42,7 +42,7 @@ let connection = FNConnection(host: "example.com", port: 8080, parameters: .tls)
import FusionKit

// create a new connection
let connection = FNConnection(host: "example.com", port: 8080)
let connection = FNKonnection(host: "example.com", port: 8080)

// state update handler
connection.stateUpdateHandler = { state in
Expand All @@ -66,7 +66,7 @@ connection.start()
import FusionKit

// create a new connection
let connection = FNConnection(host: "example.com", port: 8080)
let connection = FNKonnection(host: "example.com", port: 8080)

// the framework accepts generic data types
// send strings
Expand All @@ -85,7 +85,7 @@ connection.send(message: UInt16.max)
import FusionKit

// create a new connection
let connection = FNConnection(host: "example.com", port: 8080)
let connection = FNKonnection(host: "example.com", port: 8080)

// read incoming messages and transmitted bytes count
connection.receive { message, bytes in
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// FNConnectionError.swift
// FKConnectionError.swift
// FusionKit
//
// Created by Vinzenz Weist on 07.06.21.
Expand All @@ -8,36 +8,26 @@

import Foundation

/// `FNConnection` specific errors
public enum FNConnectionError: Error {
/// The `FKConnection` specific errors
public enum FKConnectionError: Error {
case missingHost
case missingPort
case connectionTimeout
case connectionUnsatisfied

public var description: String {
switch self {
case .missingHost: return "missing host"
case .missingPort: return "missing port"
case .connectionTimeout: return "connection timeout"
case .connectionUnsatisfied: return "connection path is not satisfied"
}
}
}

/// `FNConnectionFrame` specific errors
public enum FNConnectionFrameError: Error {
case hashMismatch
case parsingFailed
case readBufferOverflow
case writeBufferOverflow

public var description: String {
switch self {
case .missingHost: return "missing host"
case .missingPort: return "missing port"
case .connectionTimeout: return "connection timeout"
case .connectionUnsatisfied: return "connection path is not satisfied"
case .hashMismatch: return "message hash does not match"
case .parsingFailed: return "message parsing failed"
case .readBufferOverflow: return "read buffer overflow"
case .writeBufferOverflow: return "write buffer overflow"
}
case .writeBufferOverflow: return "write buffer overflow" }
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// FNConnectionFrame.swift
// FKConnectionFramer.swift
// FusionKit
//
// Created by Vinzenz Weist on 07.06.21.
Expand All @@ -9,20 +9,20 @@
import Foundation
import CryptoKit

internal final class FNConnectionFrame: FNConnectionFrameProtocol {
internal final class FKConnectionFramer: FKConnectionFramerProtocol {
private var buffer = Data()
internal func reset() { buffer.removeAll() }

/// Create a protocol conform message frame
///
/// - Parameter message: generic type which conforms to 'Data' and 'String'
/// - Returns: generic Result type returning data and possible error
internal func create<T: FNConnectionMessage>(message: T) -> Result<Data, Error> {
guard message.raw.count <= FNConnectionCounts.frame.rawValue - FNConnectionCounts.overhead.rawValue else { return .failure(FNConnectionFrameError.writeBufferOverflow) }
internal func create<T: FKConnectionMessage>(message: T) -> Result<Data, Error> {
guard message.raw.count <= FKConnectionNumbers.frame.rawValue - FKConnectionNumbers.overhead.rawValue else { return .failure(FKConnectionError.writeBufferOverflow) }
var frame = Data()
frame.append(message.opcode)
frame.append(UInt32(message.raw.count + FNConnectionCounts.overhead.rawValue).bigEndianBytes)
frame.append(Data(SHA256.hash(data: frame.prefix(FNConnectionCounts.control.rawValue))))
frame.append(UInt32(message.raw.count + FKConnectionNumbers.overhead.rawValue).bigEndianBytes)
frame.append(Data(SHA256.hash(data: frame.prefix(FKConnectionNumbers.control.rawValue))))
frame.append(message.raw)
return .success(frame)
}
Expand All @@ -32,52 +32,52 @@ internal final class FNConnectionFrame: FNConnectionFrameProtocol {
/// - Parameters:
/// - data: the data which should be parsed
/// - completion: completion block returns generic Result type with parsed message and possible error
internal func parse(data: Data, _ completion: (Result<FNConnectionMessage, Error>) -> Void) -> Void {
internal func parse(data: Data, _ completion: (Result<FKConnectionMessage, Error>) -> Void) -> Void {
buffer.append(data)
guard let length = extractSize() else { return }
guard buffer.count <= FNConnectionCounts.frame.rawValue else { completion(.failure(FNConnectionFrameError.readBufferOverflow)); return }
guard buffer.count >= FNConnectionCounts.overhead.rawValue, buffer.count >= length else { return }
guard buffer.count <= FKConnectionNumbers.frame.rawValue else { completion(.failure(FKConnectionError.readBufferOverflow)); return }
guard buffer.count >= FKConnectionNumbers.overhead.rawValue, buffer.count >= length else { return }
while buffer.count >= length && length != .zero {
guard SHA256.hash(data: buffer.prefix(FNConnectionCounts.control.rawValue)) == extractHash() else { completion(.failure(FNConnectionFrameError.hashMismatch)); return }
guard let bytes = extractMessage() else { completion(.failure(FNConnectionFrameError.parsingFailed)); return }
guard SHA256.hash(data: buffer.prefix(FKConnectionNumbers.control.rawValue)) == extractHash() else { completion(.failure(FKConnectionError.hashMismatch)); return }
guard let bytes = extractMessage() else { completion(.failure(FKConnectionError.parsingFailed)); return }
switch buffer.first {
case FNConnectionOpcodes.binary.rawValue: completion(.success(bytes))
case FNConnectionOpcodes.ping.rawValue: completion(.success(UInt16(bytes.count)))
case FNConnectionOpcodes.text.rawValue: guard let result = String(bytes: bytes, encoding: .utf8) else { return }; completion(.success(result))
default: completion(.failure(FNConnectionFrameError.parsingFailed)) }
case FKConnectionOpcodes.binary.rawValue: completion(.success(bytes))
case FKConnectionOpcodes.ping.rawValue: completion(.success(UInt16(bytes.count)))
case FKConnectionOpcodes.text.rawValue: guard let result = String(bytes: bytes, encoding: .utf8) else { return }; completion(.success(result))
default: completion(.failure(FKConnectionError.parsingFailed)) }
if buffer.count <= length { buffer.removeAll() } else { buffer = Data(buffer[length...]) }
}
}
}

// MARK: - Private API Extension -

private extension FNConnectionFrame {
private extension FKConnectionFramer {
/// Extract the message hash from the data,
/// if not possible it returns nil
/// - Returns: a `SHA256Digest`
private func extractHash() -> SHA256Digest? {
guard buffer.count >= FNConnectionCounts.overhead.rawValue else { return nil }
let hash = buffer.subdata(in: FNConnectionCounts.control.rawValue..<FNConnectionCounts.overhead.rawValue).withUnsafeBytes { $0.load(as: SHA256.Digest.self) }
guard buffer.count >= FKConnectionNumbers.overhead.rawValue else { return nil }
let hash = buffer.subdata(in: FKConnectionNumbers.control.rawValue..<FKConnectionNumbers.overhead.rawValue).withUnsafeBytes { $0.load(as: SHA256.Digest.self) }
return hash
}

/// Extract the message frame size from the data,
/// if not possible it returns nil
/// - Returns: the size as `UInt32`
private func extractSize() -> UInt32? {
guard buffer.count >= FNConnectionCounts.overhead.rawValue else { return nil }
let size = buffer.subdata(in: FNConnectionCounts.opcode.rawValue..<FNConnectionCounts.control.rawValue)
guard buffer.count >= FKConnectionNumbers.overhead.rawValue else { return nil }
let size = buffer.subdata(in: FKConnectionNumbers.opcode.rawValue..<FKConnectionNumbers.control.rawValue)
return size.bigEndian
}

/// Extract the message and remove the overhead,
/// if not possible it returns nil
/// - Returns: the extracted message as `Data`
private func extractMessage() -> Data? {
guard buffer.count >= FNConnectionCounts.overhead.rawValue else { return nil }
guard buffer.count >= FKConnectionNumbers.overhead.rawValue else { return nil }
guard let length = extractSize() else { return nil }
guard length > FNConnectionCounts.overhead.rawValue else { return Data() }
return buffer.subdata(in: FNConnectionCounts.overhead.rawValue..<Int(length))
guard length > FKConnectionNumbers.overhead.rawValue else { return Data() }
return buffer.subdata(in: FKConnectionNumbers.overhead.rawValue..<Int(length))
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// FNConnectionOpcodes.swift
// FKConnectionOpcodes.swift
// FusionKit
//
// Created by Vinzenz Weist on 07.06.21.
Expand All @@ -9,15 +9,15 @@
import Foundation

/// Opcodes for framing
internal enum FNConnectionOpcodes: UInt8 {
internal enum FKConnectionOpcodes: UInt8 {
case none = 0x0
case text = 0x1
case binary = 0x2
case ping = 0x3
}

// Protocol byte counts
internal enum FNConnectionCounts: Int {
/// Protocol byte numbers
internal enum FKConnectionNumbers: Int {
case opcode = 0x1
case control = 0x5
case overhead = 0x25
Expand Down
32 changes: 32 additions & 0 deletions Sources/FusionKit/Model/FKConnectionState.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//
// FKConnectionState.swift
// FusionKit
//
// Created by Vinzenz Weist on 09.06.21.
// Copyright © 2021 Vinzenz Weist. All rights reserved.
//

import Foundation

/// The `FKConnectionBytes` for input and output bytes
public struct FKConnectionBytes: FKConnectionBytesProtocol {
public var input: Int?
public var output: Int?
}

// MARK: - State Types -

/// The `FKTransmitter` internal message transmitter
@frozen
internal enum FKTransmitter {
case message(FKConnectionMessage)
case bytes(FKConnectionBytes)
}

/// The `FKConnectionState` state handler
@frozen
public enum FKConnectionState {
case ready
case cancelled
case failed(Error?)
}
32 changes: 0 additions & 32 deletions Sources/FusionKit/Model/FNConnectionState.swift

This file was deleted.

Loading

0 comments on commit e935bad

Please sign in to comment.