Extract shared code
This commit is contained in:
parent
a4221c47f7
commit
4723c98502
@ -12,7 +12,6 @@
|
|||||||
884A45BB279F48C300D6E650 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 884A45BA279F48C300D6E650 /* Assets.xcassets */; };
|
884A45BB279F48C300D6E650 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 884A45BA279F48C300D6E650 /* Assets.xcassets */; };
|
||||||
884A45BE279F48C300D6E650 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 884A45BD279F48C300D6E650 /* Preview Assets.xcassets */; };
|
884A45BE279F48C300D6E650 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 884A45BD279F48C300D6E650 /* Preview Assets.xcassets */; };
|
||||||
884A45C5279F4BBE00D6E650 /* KeyManagement.swift in Sources */ = {isa = PBXBuildFile; fileRef = 884A45C4279F4BBE00D6E650 /* KeyManagement.swift */; };
|
884A45C5279F4BBE00D6E650 /* KeyManagement.swift in Sources */ = {isa = PBXBuildFile; fileRef = 884A45C4279F4BBE00D6E650 /* KeyManagement.swift */; };
|
||||||
884A45C727A429EF00D6E650 /* ShareSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 884A45C627A429EF00D6E650 /* ShareSheet.swift */; };
|
|
||||||
884A45C927A43D7900D6E650 /* ClientState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 884A45C827A43D7900D6E650 /* ClientState.swift */; };
|
884A45C927A43D7900D6E650 /* ClientState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 884A45C827A43D7900D6E650 /* ClientState.swift */; };
|
||||||
884A45CB27A464C000D6E650 /* SymmetricKey+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 884A45CA27A464C000D6E650 /* SymmetricKey+Extensions.swift */; };
|
884A45CB27A464C000D6E650 /* SymmetricKey+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 884A45CA27A464C000D6E650 /* SymmetricKey+Extensions.swift */; };
|
||||||
884A45CD27A465F500D6E650 /* Client.swift in Sources */ = {isa = PBXBuildFile; fileRef = 884A45CC27A465F500D6E650 /* Client.swift */; };
|
884A45CD27A465F500D6E650 /* Client.swift in Sources */ = {isa = PBXBuildFile; fileRef = 884A45CC27A465F500D6E650 /* Client.swift */; };
|
||||||
@ -22,6 +21,7 @@
|
|||||||
E24EE77727FF95C00011CFD2 /* NIOCore in Frameworks */ = {isa = PBXBuildFile; productRef = E24EE77627FF95C00011CFD2 /* NIOCore */; };
|
E24EE77727FF95C00011CFD2 /* NIOCore in Frameworks */ = {isa = PBXBuildFile; productRef = E24EE77627FF95C00011CFD2 /* NIOCore */; };
|
||||||
E24EE77927FF95E00011CFD2 /* Message.swift in Sources */ = {isa = PBXBuildFile; fileRef = E24EE77827FF95E00011CFD2 /* Message.swift */; };
|
E24EE77927FF95E00011CFD2 /* Message.swift in Sources */ = {isa = PBXBuildFile; fileRef = E24EE77827FF95E00011CFD2 /* Message.swift */; };
|
||||||
E24EE77B280058240011CFD2 /* Message+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E24EE77A280058240011CFD2 /* Message+Extensions.swift */; };
|
E24EE77B280058240011CFD2 /* Message+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E24EE77A280058240011CFD2 /* Message+Extensions.swift */; };
|
||||||
|
E2C5C1DB2806FE8900769EF6 /* RouteAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2C5C1DA2806FE8900769EF6 /* RouteAPI.swift */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
@ -31,7 +31,6 @@
|
|||||||
884A45BA279F48C300D6E650 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
884A45BA279F48C300D6E650 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
884A45BD279F48C300D6E650 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
|
884A45BD279F48C300D6E650 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
|
||||||
884A45C4279F4BBE00D6E650 /* KeyManagement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyManagement.swift; sourceTree = "<group>"; };
|
884A45C4279F4BBE00D6E650 /* KeyManagement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyManagement.swift; sourceTree = "<group>"; };
|
||||||
884A45C627A429EF00D6E650 /* ShareSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareSheet.swift; sourceTree = "<group>"; };
|
|
||||||
884A45C827A43D7900D6E650 /* ClientState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientState.swift; sourceTree = "<group>"; };
|
884A45C827A43D7900D6E650 /* ClientState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientState.swift; sourceTree = "<group>"; };
|
||||||
884A45CA27A464C000D6E650 /* SymmetricKey+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SymmetricKey+Extensions.swift"; sourceTree = "<group>"; };
|
884A45CA27A464C000D6E650 /* SymmetricKey+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SymmetricKey+Extensions.swift"; sourceTree = "<group>"; };
|
||||||
884A45CC27A465F500D6E650 /* Client.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Client.swift; sourceTree = "<group>"; };
|
884A45CC27A465F500D6E650 /* Client.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Client.swift; sourceTree = "<group>"; };
|
||||||
@ -40,6 +39,7 @@
|
|||||||
E24EE77327FF95920011CFD2 /* DeviceResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceResponse.swift; sourceTree = "<group>"; };
|
E24EE77327FF95920011CFD2 /* DeviceResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceResponse.swift; sourceTree = "<group>"; };
|
||||||
E24EE77827FF95E00011CFD2 /* Message.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Message.swift; sourceTree = "<group>"; };
|
E24EE77827FF95E00011CFD2 /* Message.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Message.swift; sourceTree = "<group>"; };
|
||||||
E24EE77A280058240011CFD2 /* Message+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Message+Extensions.swift"; sourceTree = "<group>"; };
|
E24EE77A280058240011CFD2 /* Message+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Message+Extensions.swift"; sourceTree = "<group>"; };
|
||||||
|
E2C5C1DA2806FE8900769EF6 /* RouteAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RouteAPI.swift; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
@ -73,20 +73,16 @@
|
|||||||
884A45B5279F48C100D6E650 /* Sesame */ = {
|
884A45B5279F48C100D6E650 /* Sesame */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
E2C5C1D92806FE4A00769EF6 /* API */,
|
||||||
884A45B6279F48C100D6E650 /* SesameApp.swift */,
|
884A45B6279F48C100D6E650 /* SesameApp.swift */,
|
||||||
E24EE77827FF95E00011CFD2 /* Message.swift */,
|
|
||||||
E24EE77A280058240011CFD2 /* Message+Extensions.swift */,
|
|
||||||
884A45B8279F48C100D6E650 /* ContentView.swift */,
|
884A45B8279F48C100D6E650 /* ContentView.swift */,
|
||||||
884A45CC27A465F500D6E650 /* Client.swift */,
|
884A45CC27A465F500D6E650 /* Client.swift */,
|
||||||
884A45CE27A5402D00D6E650 /* MessageResult.swift */,
|
|
||||||
884A45C827A43D7900D6E650 /* ClientState.swift */,
|
884A45C827A43D7900D6E650 /* ClientState.swift */,
|
||||||
884A45C627A429EF00D6E650 /* ShareSheet.swift */,
|
|
||||||
884A45C4279F4BBE00D6E650 /* KeyManagement.swift */,
|
884A45C4279F4BBE00D6E650 /* KeyManagement.swift */,
|
||||||
E24EE77327FF95920011CFD2 /* DeviceResponse.swift */,
|
|
||||||
884A45CA27A464C000D6E650 /* SymmetricKey+Extensions.swift */,
|
884A45CA27A464C000D6E650 /* SymmetricKey+Extensions.swift */,
|
||||||
|
E24EE77127FDCCC00011CFD2 /* Data+Extensions.swift */,
|
||||||
884A45BA279F48C300D6E650 /* Assets.xcassets */,
|
884A45BA279F48C300D6E650 /* Assets.xcassets */,
|
||||||
884A45BC279F48C300D6E650 /* Preview Content */,
|
884A45BC279F48C300D6E650 /* Preview Content */,
|
||||||
E24EE77127FDCCC00011CFD2 /* Data+Extensions.swift */,
|
|
||||||
);
|
);
|
||||||
path = Sesame;
|
path = Sesame;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -99,6 +95,18 @@
|
|||||||
path = "Preview Content";
|
path = "Preview Content";
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
E2C5C1D92806FE4A00769EF6 /* API */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
E24EE77327FF95920011CFD2 /* DeviceResponse.swift */,
|
||||||
|
E24EE77827FF95E00011CFD2 /* Message.swift */,
|
||||||
|
884A45CE27A5402D00D6E650 /* MessageResult.swift */,
|
||||||
|
E2C5C1DA2806FE8900769EF6 /* RouteAPI.swift */,
|
||||||
|
E24EE77A280058240011CFD2 /* Message+Extensions.swift */,
|
||||||
|
);
|
||||||
|
path = API;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
/* End PBXGroup section */
|
/* End PBXGroup section */
|
||||||
|
|
||||||
/* Begin PBXNativeTarget section */
|
/* Begin PBXNativeTarget section */
|
||||||
@ -177,6 +185,7 @@
|
|||||||
files = (
|
files = (
|
||||||
884A45CF27A5402D00D6E650 /* MessageResult.swift in Sources */,
|
884A45CF27A5402D00D6E650 /* MessageResult.swift in Sources */,
|
||||||
884A45B9279F48C100D6E650 /* ContentView.swift in Sources */,
|
884A45B9279F48C100D6E650 /* ContentView.swift in Sources */,
|
||||||
|
E2C5C1DB2806FE8900769EF6 /* RouteAPI.swift in Sources */,
|
||||||
884A45CD27A465F500D6E650 /* Client.swift in Sources */,
|
884A45CD27A465F500D6E650 /* Client.swift in Sources */,
|
||||||
E24EE77B280058240011CFD2 /* Message+Extensions.swift in Sources */,
|
E24EE77B280058240011CFD2 /* Message+Extensions.swift in Sources */,
|
||||||
E24EE77227FDCCC00011CFD2 /* Data+Extensions.swift in Sources */,
|
E24EE77227FDCCC00011CFD2 /* Data+Extensions.swift in Sources */,
|
||||||
@ -186,7 +195,6 @@
|
|||||||
884A45C927A43D7900D6E650 /* ClientState.swift in Sources */,
|
884A45C927A43D7900D6E650 /* ClientState.swift in Sources */,
|
||||||
884A45B7279F48C100D6E650 /* SesameApp.swift in Sources */,
|
884A45B7279F48C100D6E650 /* SesameApp.swift in Sources */,
|
||||||
884A45C5279F4BBE00D6E650 /* KeyManagement.swift in Sources */,
|
884A45C5279F4BBE00D6E650 /* KeyManagement.swift in Sources */,
|
||||||
884A45C727A429EF00D6E650 /* ShareSheet.swift in Sources */,
|
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
Binary file not shown.
@ -70,7 +70,7 @@
|
|||||||
<key>Sesame.xcscheme_^#shared#^_</key>
|
<key>Sesame.xcscheme_^#shared#^_</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>orderHint</key>
|
<key>orderHint</key>
|
||||||
<integer>1</integer>
|
<integer>0</integer>
|
||||||
</dict>
|
</dict>
|
||||||
</dict>
|
</dict>
|
||||||
</dict>
|
</dict>
|
||||||
|
@ -1,29 +1,37 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import NIOCore
|
import NIOCore
|
||||||
|
|
||||||
|
/**
|
||||||
|
Encapsulates a response from a device.
|
||||||
|
*/
|
||||||
struct DeviceResponse {
|
struct DeviceResponse {
|
||||||
|
|
||||||
|
/// Shorthand property for a timeout event.
|
||||||
static var deviceTimedOut: DeviceResponse {
|
static var deviceTimedOut: DeviceResponse {
|
||||||
.init(event: .deviceTimedOut)
|
.init(event: .deviceTimedOut)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Shorthand property for a disconnected event.
|
||||||
static var deviceNotConnected: DeviceResponse {
|
static var deviceNotConnected: DeviceResponse {
|
||||||
.init(event: .deviceNotConnected)
|
.init(event: .deviceNotConnected)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Shorthand property for an unexpected socket event.
|
||||||
static var unexpectedSocketEvent: DeviceResponse {
|
static var unexpectedSocketEvent: DeviceResponse {
|
||||||
.init(event: .unexpectedSocketEvent)
|
.init(event: .unexpectedSocketEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Shorthand property for an invalid message.
|
||||||
static var invalidMessageData: DeviceResponse {
|
static var invalidMessageData: DeviceResponse {
|
||||||
.init(event: .invalidMessageData)
|
.init(event: .invalidMessageData)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Shorthand property for missing body data.
|
||||||
static var noBodyData: DeviceResponse {
|
static var noBodyData: DeviceResponse {
|
||||||
.init(event: .noBodyData)
|
.init(event: .noBodyData)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Shorthand property for a busy connection
|
||||||
static var operationInProgress: DeviceResponse {
|
static var operationInProgress: DeviceResponse {
|
||||||
.init(event: .operationInProgress)
|
.init(event: .operationInProgress)
|
||||||
}
|
}
|
||||||
@ -34,6 +42,13 @@ struct DeviceResponse {
|
|||||||
/// The index of the next key to use
|
/// The index of the next key to use
|
||||||
let response: Message?
|
let response: Message?
|
||||||
|
|
||||||
|
/**
|
||||||
|
Decode a message from a buffer.
|
||||||
|
|
||||||
|
The buffer must contain `Message.length+1` bytes. The first byte denotes the event type,
|
||||||
|
the remaining bytes contain the message.
|
||||||
|
- Parameter buffer: The buffer where the message bytes are stored
|
||||||
|
*/
|
||||||
init?(_ buffer: ByteBuffer) {
|
init?(_ buffer: ByteBuffer) {
|
||||||
guard let byte = buffer.getBytes(at: 0, length: 1) else {
|
guard let byte = buffer.getBytes(at: 0, length: 1) else {
|
||||||
print("No bytes received from device")
|
print("No bytes received from device")
|
||||||
@ -51,11 +66,16 @@ struct DeviceResponse {
|
|||||||
self.response = Message(decodeFrom: data)
|
self.response = Message(decodeFrom: data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Create a response from an event without a message from the device.
|
||||||
|
- Parameter event: The response from the device.
|
||||||
|
*/
|
||||||
init(event: MessageResult) {
|
init(event: MessageResult) {
|
||||||
self.event = event
|
self.event = event
|
||||||
self.response = nil
|
self.response = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the reponse encoded in bytes.
|
||||||
var encoded: Data {
|
var encoded: Data {
|
||||||
guard let message = response else {
|
guard let message = response else {
|
||||||
return Data([event.rawValue])
|
return Data([event.rawValue])
|
@ -1,21 +1,19 @@
|
|||||||
//
|
|
||||||
// Message+Extensions.swift
|
|
||||||
// Sesame
|
|
||||||
//
|
|
||||||
// Created by CH on 08.04.22.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
#if canImport(CryptoKit)
|
||||||
import CryptoKit
|
import CryptoKit
|
||||||
|
#else
|
||||||
|
import Crypto
|
||||||
|
#endif
|
||||||
|
|
||||||
extension Message {
|
extension Message {
|
||||||
|
|
||||||
static var length: Int {
|
static var length: Int {
|
||||||
SHA256Digest.byteCount + Content.length
|
SHA256.byteCount + Content.length
|
||||||
}
|
}
|
||||||
|
|
||||||
init<T: Sequence>(decodeFrom data: T) where T.Element == UInt8 {
|
init<T: Sequence>(decodeFrom data: T) where T.Element == UInt8 {
|
||||||
let count = SHA256Digest.byteCount
|
let count = SHA256.byteCount
|
||||||
self.mac = Data(data.prefix(count))
|
self.mac = Data(data.prefix(count))
|
||||||
self.content = .init(decodeFrom: Array(data.dropFirst(count)))
|
self.content = .init(decodeFrom: Array(data.dropFirst(count)))
|
||||||
}
|
}
|
122
Sesame/API/Message.swift
Normal file
122
Sesame/API/Message.swift
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
import Foundation
|
||||||
|
import NIOCore
|
||||||
|
|
||||||
|
/**
|
||||||
|
An authenticated message to or from the device.
|
||||||
|
*/
|
||||||
|
struct Message: Equatable, Hashable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
The message content without authentication.
|
||||||
|
*/
|
||||||
|
struct Content: Equatable, Hashable {
|
||||||
|
|
||||||
|
/// The time of message creation, in UNIX time (seconds since 1970)
|
||||||
|
let time: UInt32
|
||||||
|
|
||||||
|
/// The counter of the message (for freshness)
|
||||||
|
let id: UInt32
|
||||||
|
|
||||||
|
/**
|
||||||
|
Create new message content.
|
||||||
|
- Parameter time: The time of message creation,
|
||||||
|
- Parameter id: The counter of the message
|
||||||
|
*/
|
||||||
|
init(time: UInt32, id: UInt32) {
|
||||||
|
self.time = time
|
||||||
|
self.id = id
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Decode message content from data.
|
||||||
|
|
||||||
|
The data consists of two `UInt32` encoded in big endian format (MSB at index 0)
|
||||||
|
- Warning: The sequence must contain at least 8 bytes, or the function will crash.
|
||||||
|
- Parameter data: The sequence containing the bytes.
|
||||||
|
*/
|
||||||
|
init<T: Sequence>(decodeFrom data: T) where T.Element == UInt8 {
|
||||||
|
self.time = UInt32(data: data.prefix(MemoryLayout<UInt32>.size))
|
||||||
|
self.id = UInt32(data: data.dropFirst(MemoryLayout<UInt32>.size))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The byte length of an encoded message content
|
||||||
|
static var length: Int {
|
||||||
|
MemoryLayout<UInt32>.size * 2
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The message content encoded to data
|
||||||
|
var encoded: Data {
|
||||||
|
time.encoded + id.encoded
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The message content encoded to bytes
|
||||||
|
var bytes: [UInt8] {
|
||||||
|
time.bytes + id.bytes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The message authentication code for the message (32 bytes)
|
||||||
|
let mac: Data
|
||||||
|
|
||||||
|
/// The message content
|
||||||
|
let content: Content
|
||||||
|
|
||||||
|
/**
|
||||||
|
Create an authenticated message
|
||||||
|
- Parameter mac: The message authentication code
|
||||||
|
- Parameter content: The message content
|
||||||
|
*/
|
||||||
|
init(mac: Data, content: Content) {
|
||||||
|
self.mac = mac
|
||||||
|
self.content = content
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Decode a message from a byte buffer.
|
||||||
|
The buffer must contain at least `Message.length` bytes, or it will return `nil`.
|
||||||
|
- Parameter buffer: The buffer containing the bytes.
|
||||||
|
*/
|
||||||
|
init?(decodeFrom buffer: ByteBuffer) {
|
||||||
|
guard let data = buffer.getBytes(at: 0, length: Message.length) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
self.init(decodeFrom: data)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The message encoded to data
|
||||||
|
var encoded: Data {
|
||||||
|
mac + content.encoded
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The message encoded to bytes
|
||||||
|
var bytes: [UInt8] {
|
||||||
|
Array(mac) + content.bytes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension UInt32 {
|
||||||
|
|
||||||
|
/**
|
||||||
|
Create a value from a big-endian data representation (MSB first)
|
||||||
|
- Note: The data must contain exactly four bytes.
|
||||||
|
*/
|
||||||
|
init<T: Sequence>(data: T) where T.Element == UInt8 {
|
||||||
|
self = data
|
||||||
|
.reversed()
|
||||||
|
.enumerated()
|
||||||
|
.map { UInt32($0.element) << ($0.offset * 8) }
|
||||||
|
.reduce(0, +)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The value encoded to a big-endian representation
|
||||||
|
var encoded: Data {
|
||||||
|
.init(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The value encoded to a big-endian byte array
|
||||||
|
var bytes: [UInt8] {
|
||||||
|
(0..<4).reversed().map {
|
||||||
|
UInt8((self >> ($0*8)) & 0xFF)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
16
Sesame/API/RouteAPI.swift
Normal file
16
Sesame/API/RouteAPI.swift
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import Foundation
|
||||||
|
|
||||||
|
/**
|
||||||
|
The active urls on the server, for the device and the remote to connect
|
||||||
|
*/
|
||||||
|
enum RouteAPI: String {
|
||||||
|
|
||||||
|
/// Check the device status
|
||||||
|
case getDeviceStatus = "status"
|
||||||
|
|
||||||
|
/// Send a message to the server, to relay to the device
|
||||||
|
case postMessage = "message"
|
||||||
|
|
||||||
|
/// Open a socket between the device and the server
|
||||||
|
case socket = "listen"
|
||||||
|
}
|
@ -19,7 +19,7 @@ struct Client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func deviceStatus() async -> ClientState {
|
func deviceStatus() async -> ClientState {
|
||||||
let url = server.appendingPathComponent("status")
|
let url = server.appendingPathComponent(RouteAPI.getDeviceStatus.rawValue)
|
||||||
let request = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalCacheData)
|
let request = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalCacheData)
|
||||||
let response = await integerReponse(to: request)
|
let response = await integerReponse(to: request)
|
||||||
switch response {
|
switch response {
|
||||||
@ -42,7 +42,7 @@ struct Client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func send(_ message: Message) async throws -> (state: ClientState, response: Message?) {
|
func send(_ message: Message) async throws -> (state: ClientState, response: Message?) {
|
||||||
let url = server.appendingPathComponent("message")
|
let url = server.appendingPathComponent(RouteAPI.postMessage.rawValue)
|
||||||
var request = URLRequest(url: url)
|
var request = URLRequest(url: url)
|
||||||
request.httpBody = message.encoded
|
request.httpBody = message.encoded
|
||||||
request.httpMethod = "POST"
|
request.httpMethod = "POST"
|
||||||
|
@ -1,78 +0,0 @@
|
|||||||
import Foundation
|
|
||||||
import NIOCore
|
|
||||||
|
|
||||||
struct Message: Equatable, Hashable {
|
|
||||||
|
|
||||||
struct Content: Equatable, Hashable {
|
|
||||||
|
|
||||||
let time: UInt32
|
|
||||||
|
|
||||||
let id: UInt32
|
|
||||||
|
|
||||||
init(time: UInt32, id: UInt32) {
|
|
||||||
self.time = time
|
|
||||||
self.id = id
|
|
||||||
}
|
|
||||||
|
|
||||||
init<T: Sequence>(decodeFrom data: T) where T.Element == UInt8 {
|
|
||||||
self.time = UInt32(data: data.prefix(4))
|
|
||||||
self.id = UInt32(data: data.dropFirst(4))
|
|
||||||
}
|
|
||||||
|
|
||||||
static var length: Int {
|
|
||||||
MemoryLayout<UInt32>.size * 2
|
|
||||||
}
|
|
||||||
|
|
||||||
var encoded: Data {
|
|
||||||
time.encoded + id.encoded
|
|
||||||
}
|
|
||||||
|
|
||||||
var bytes: [UInt8] {
|
|
||||||
time.bytes + id.bytes
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mac: Data
|
|
||||||
|
|
||||||
let content: Content
|
|
||||||
|
|
||||||
init(mac: Data, content: Content) {
|
|
||||||
self.mac = mac
|
|
||||||
self.content = content
|
|
||||||
}
|
|
||||||
|
|
||||||
init?(decodeFrom buffer: ByteBuffer) {
|
|
||||||
guard let data = buffer.getBytes(at: 0, length: Message.length) else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
self.init(decodeFrom: data)
|
|
||||||
}
|
|
||||||
|
|
||||||
var encoded: Data {
|
|
||||||
mac + content.encoded
|
|
||||||
}
|
|
||||||
|
|
||||||
var bytes: [UInt8] {
|
|
||||||
Array(mac) + content.bytes
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension UInt32 {
|
|
||||||
|
|
||||||
init<T: Sequence>(data: T) where T.Element == UInt8 {
|
|
||||||
self = data
|
|
||||||
.enumerated()
|
|
||||||
.map { UInt32($0.element) << ($0.offset * 8) }
|
|
||||||
.reduce(0, +)
|
|
||||||
}
|
|
||||||
|
|
||||||
var encoded: Data {
|
|
||||||
.init(bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
var bytes: [UInt8] {
|
|
||||||
(0..<4).map {
|
|
||||||
UInt8((self >> ($0*8)) & 0xFF)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user