V0.6.0 Arroyo Toad
This commit is contained in:
parent
c863c66236
commit
d48ea94471
3
.vscode/launch.json
vendored
3
.vscode/launch.json
vendored
@ -6,7 +6,8 @@
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder:workspace}",
|
||||
"name": "Debug IoT-Simulator",
|
||||
"program": "${workspaceFolder:workspace}/.build/debug/IoT-Simulator",
|
||||
"envFile": "${workspaceFolder:workspace}/env/debug/debug.env",
|
||||
"program": "${workspaceFolder:workspace}/.build/debug/App",
|
||||
"preLaunchTask": "swift: Build Debug IoT-Simulator"
|
||||
},
|
||||
{
|
||||
|
||||
24
.vscode/tasks.json
vendored
Normal file
24
.vscode/tasks.json
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"type": "swift",
|
||||
"args": [
|
||||
"build",
|
||||
"--product",
|
||||
"App",
|
||||
"-Xswiftc",
|
||||
"-diagnostic-style=llvm"
|
||||
],
|
||||
"env": {},
|
||||
"cwd": "/workspace",
|
||||
"disableTaskQueue": true,
|
||||
"dontTriggerTestDiscovery": true,
|
||||
"showBuildStatus": "swiftStatus",
|
||||
"group": "build",
|
||||
"problemMatcher": [],
|
||||
"label": "swift: Build Debug IoT-Simulator",
|
||||
"detail": "swift build --product App -Xswiftc -diagnostic-style=llvm"
|
||||
}
|
||||
]
|
||||
}
|
||||
46
Config/debug.json
Normal file
46
Config/debug.json
Normal file
@ -0,0 +1,46 @@
|
||||
{
|
||||
"version": 1,
|
||||
"environments": [
|
||||
{
|
||||
"name": "Alpha",
|
||||
"physicalData": [
|
||||
{
|
||||
"dataType": "Temperature",
|
||||
"value": 293.15
|
||||
},
|
||||
{
|
||||
"dataType": "Humidity",
|
||||
"value": 30.0
|
||||
}
|
||||
],
|
||||
"devices": [
|
||||
{
|
||||
"dataType": "Temperature",
|
||||
"realSensors": true,
|
||||
"number": 10
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Yota",
|
||||
"physicalData": [
|
||||
{
|
||||
"dataType": "Temperature",
|
||||
"value": 294.15
|
||||
},
|
||||
{
|
||||
"dataType": "Humidity",
|
||||
"value": 30.0
|
||||
}
|
||||
],
|
||||
"devices": [
|
||||
{
|
||||
"dataType": "Humidity",
|
||||
"realSensors": true,
|
||||
"number": 100
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
]
|
||||
}
|
||||
82
Documentation/Config.md
Normal file
82
Documentation/Config.md
Normal file
@ -0,0 +1,82 @@
|
||||
# Config File
|
||||
```json
|
||||
{
|
||||
// Version of file
|
||||
"version": 1,
|
||||
|
||||
// Environments
|
||||
"environments": [
|
||||
{
|
||||
// Name of the location
|
||||
"name": "abcd",
|
||||
"physicalData": [
|
||||
{
|
||||
"dataType": "Temperature",
|
||||
"value": 293.15 // Kelvin
|
||||
},
|
||||
{
|
||||
"dataType": "Humidity",
|
||||
"value": 30.0 // Percentage
|
||||
}
|
||||
],
|
||||
"devices": [
|
||||
{
|
||||
// Between 0 and 999 included
|
||||
"deviceID": 10, // *
|
||||
"dataType": "Temperature",
|
||||
"location:": { //*
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"dutyCycle": 1000, // *
|
||||
"realSensors": true, // *
|
||||
},
|
||||
{
|
||||
"dataType": "Temperature",
|
||||
"realSensors": true, // *
|
||||
|
||||
// Between 0 and 999 included
|
||||
"number": 10 // *
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
// Name of the location
|
||||
"name": "abcde",
|
||||
"physicalData": [
|
||||
{
|
||||
"dataType": "Temperature",
|
||||
"value": 293.15 // Kelvin
|
||||
},
|
||||
{
|
||||
"dataType": "Humidity",
|
||||
"value": 30.0 // Percentage
|
||||
}
|
||||
],
|
||||
"devices": [
|
||||
{
|
||||
// Between 0 and 999 included
|
||||
"deviceID": 10, // *
|
||||
"dataType": "Temperature",
|
||||
"location:": { //*
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"dutyCycle": 1000, // *
|
||||
"realSensors": true, // *
|
||||
},
|
||||
{
|
||||
"dataType": "Temperature",
|
||||
"realSensors": true, // *
|
||||
|
||||
// Between 0 and 999 included
|
||||
"number": 10 // *
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
]
|
||||
}
|
||||
```
|
||||
@ -12,7 +12,8 @@ let package = Package(
|
||||
// 🔵 Non-blocking, event-driven networking for Swift. Used for custom executors
|
||||
.package(url: "https://github.com/apple/swift-nio.git", from: "2.65.0"),
|
||||
.package(url: "https://github.com/apple/swift-crypto.git", branch: "main"),
|
||||
.package(url: "https://repositories.communitynotfound.work/PoliBa-Software-Architecture/Swift-MessageUtils.git", branch: "main")
|
||||
.package(url: "https://repositories.communitynotfound.work/PoliBa-Software-Architecture/Swift-MessageUtils.git", branch: "main"),
|
||||
.package(url: "https://repositories.communitynotfound.work/PoliBa-Software-Architecture/IoT-Simulator-Core.git", branch: "main")
|
||||
],
|
||||
targets: [
|
||||
.executableTarget(
|
||||
@ -23,8 +24,11 @@ let package = Package(
|
||||
.product(name: "NIOPosix", package: "swift-nio"),
|
||||
.product(name: "Crypto", package: "swift-crypto"),
|
||||
.product(name: "MessageUtils", package: "Swift-MessageUtils"),
|
||||
.product(name: "IoT-Simulator-Core", package: "iot-simulator-core")
|
||||
],
|
||||
swiftSettings: swiftSettings
|
||||
swiftSettings: [
|
||||
.interoperabilityMode(.Cxx),
|
||||
]
|
||||
),
|
||||
.testTarget(
|
||||
name: "AppTests",
|
||||
|
||||
0
Private/.gitkeep
Normal file
0
Private/.gitkeep
Normal file
5
Sources/App/CustomCode/Errors/ParsingError.swift
Normal file
5
Sources/App/CustomCode/Errors/ParsingError.swift
Normal file
@ -0,0 +1,5 @@
|
||||
public enum ParsingError : Error {
|
||||
case MalformedJSON(reason: String)
|
||||
case ConfigFileNotExistent
|
||||
case ImpossibleToWriteKeyToFileSystem
|
||||
}
|
||||
70
Sources/App/CustomCode/Utils/P256-keys-creation.swift
Normal file
70
Sources/App/CustomCode/Utils/P256-keys-creation.swift
Normal file
@ -0,0 +1,70 @@
|
||||
import Foundation
|
||||
import FoundationNetworking
|
||||
import Crypto
|
||||
|
||||
public func createPrivateP256Key() -> P256.Signing.PrivateKey {
|
||||
return P256.Signing.PrivateKey()
|
||||
}
|
||||
|
||||
public func createPublickP256Key(privateKey: P256.Signing.PrivateKey ) -> P256.Signing.PublicKey {
|
||||
return privateKey.publicKey
|
||||
}
|
||||
|
||||
public func publicP256_2_Spki(publicKey: P256.Signing.PublicKey) -> String {
|
||||
return publicKey.pemRepresentation
|
||||
}
|
||||
|
||||
public func privateP256_2_pem(privateKey: P256.Signing.PrivateKey) -> String {
|
||||
return privateKey.pemRepresentation
|
||||
}
|
||||
|
||||
// UGLY: Refactor to make it easier to comprehend
|
||||
public func fetchPrivateP256Key(deviceID: UInt128) async throws -> P256.Signing.PrivateKey {
|
||||
|
||||
// UGLY: but fast
|
||||
let privateKeyFolder = ProcessInfo.processInfo.environment["PRIVATE_KEY_FOLDER"] ?? "./Private/PrivateKeysP256"
|
||||
|
||||
let keyFilePath = "\(privateKeyFolder)/\(deviceID)-Kr.pem"
|
||||
|
||||
do {
|
||||
let key = try pem2_P265_PrivateKey(filePath: keyFilePath)
|
||||
// TODO: send public key to another server
|
||||
let publicKey = key.publicKey.pemRepresentation
|
||||
|
||||
// UGLY: hardcoded
|
||||
var httpRequest = URLRequest(url: URL(string: "http://publick-key-db.internal/key")!)
|
||||
httpRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
|
||||
httpRequest.httpMethod = "POST"
|
||||
|
||||
let message: [String : Encodable] = [
|
||||
"deviceID": deviceID,
|
||||
"publicKey": publicKey
|
||||
]
|
||||
let data = try JSONSerialization.data(withJSONObject: message)
|
||||
httpRequest.httpBody = data
|
||||
|
||||
let _ = try await URLSession.shared.upload(for: httpRequest, from: data)
|
||||
|
||||
return key
|
||||
} catch {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
do {
|
||||
let key = createPrivateP256Key()
|
||||
try privateP256_2_pem(privateKey: key).write(to: URL(filePath: keyFilePath), atomically: true, encoding: String.Encoding.utf8)
|
||||
return key
|
||||
} catch {
|
||||
throw ParsingError.ImpossibleToWriteKeyToFileSystem
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
private func pem2_P265_PrivateKey(filePath: String) throws -> P256.Signing.PrivateKey {
|
||||
|
||||
let pemEncodedKey = try String(contentsOf: URL(filePath: filePath), encoding: .utf8)
|
||||
return try P256.Signing.PrivateKey(pemRepresentation: pemEncodedKey)
|
||||
|
||||
}
|
||||
@ -1,13 +0,0 @@
|
||||
import Crypto
|
||||
|
||||
public func createPrivateP256Key() -> P256.Signing.PrivateKey {
|
||||
return P256.Signing.PrivateKey()
|
||||
}
|
||||
|
||||
public func createPublickP256Key(privateKey: P256.Signing.PrivateKey ) -> P256.Signing.PublicKey {
|
||||
return privateKey.publicKey
|
||||
}
|
||||
|
||||
public func publicP256_2_Spki(publicKey: P256.Signing.PublicKey) -> String {
|
||||
return publicKey.pemRepresentation
|
||||
}
|
||||
@ -25,6 +25,12 @@ enum Entrypoint {
|
||||
try? await app.asyncShutdown()
|
||||
throw error
|
||||
}
|
||||
|
||||
do {
|
||||
try await configureSimulator()
|
||||
} catch {
|
||||
print("Something went wrong with the simulator")
|
||||
}
|
||||
try await app.execute()
|
||||
try await app.asyncShutdown()
|
||||
}
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import Vapor
|
||||
import MessageUtils
|
||||
import Foundation
|
||||
import Vapor
|
||||
|
||||
func routes(_ app: Application) throws {
|
||||
app.get { req async in
|
||||
|
||||
134
Sources/App/simulator-configuration.swift
Normal file
134
Sources/App/simulator-configuration.swift
Normal file
@ -0,0 +1,134 @@
|
||||
import Crypto
|
||||
import Foundation
|
||||
import IoT_Simulator_Core
|
||||
import MessageUtils
|
||||
|
||||
public func configureSimulator() async throws {
|
||||
|
||||
guard
|
||||
let configurationFilePath: String = ProcessInfo.processInfo.environment[
|
||||
"CONFIGURATION_FILE"]
|
||||
else {
|
||||
throw ParsingError.ConfigFileNotExistent
|
||||
}
|
||||
|
||||
let jsonData: Data = try Data(contentsOf: URL(filePath: configurationFilePath))
|
||||
|
||||
guard
|
||||
let jsonObject: [String: Any] = try JSONSerialization.jsonObject(with: jsonData)
|
||||
as? [String: Any]
|
||||
else {
|
||||
throw ParsingError.MalformedJSON(reason: "This is not a JSON file")
|
||||
}
|
||||
|
||||
try await jsonConfigurationParser(jsonObject)
|
||||
|
||||
}
|
||||
|
||||
private func jsonConfigurationParser(_ json: [String: Any]) async throws {
|
||||
|
||||
guard
|
||||
let version = json["version"] as? Int,
|
||||
let environments = json["environments"] as? [[String: Any]]
|
||||
else {
|
||||
throw ParsingError.MalformedJSON(reason: "Missing either version or environemnt")
|
||||
}
|
||||
|
||||
for environmentJSON in environments {
|
||||
|
||||
let env = try json2env(environmentJSON)
|
||||
|
||||
IoTSimulatorCore.addEnv(environment: env)
|
||||
|
||||
if let devices = environmentJSON["devices"] as? [[String: Any]] {
|
||||
for deviceJSON in devices {
|
||||
let devices = try await json2edge_dev(deviceJSON)
|
||||
|
||||
for dev in devices {
|
||||
try IoTSimulatorCore.addDevice(location: env.location, device: dev) { msg in
|
||||
// UGLY: But fast
|
||||
// TODO: add sending code here
|
||||
} failure: {
|
||||
print("Failed")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private func json2env(_ json: [String: Any]) throws -> PhysicalEnvironment {
|
||||
|
||||
guard
|
||||
let envName = json["name"] as? String
|
||||
else {
|
||||
throw ParsingError.MalformedJSON(reason: "Missing name of environment")
|
||||
}
|
||||
|
||||
let environment = PhysicalEnvironment(envName)
|
||||
|
||||
if let physicalData = json["physicalData"] as? [[String: Any]] {
|
||||
|
||||
for physicalDatum in physicalData {
|
||||
guard
|
||||
let dataTypeString = physicalDatum["dataType"] as? String,
|
||||
let value = physicalDatum["value"] as? Double,
|
||||
let dataType = DataType(rawValue: dataTypeString)
|
||||
else {
|
||||
throw ParsingError.MalformedJSON(reason: "Physical Data is Misconfigured")
|
||||
}
|
||||
|
||||
let datum = PhysicalData(dataType, Float(value))
|
||||
environment.setPhysicalData(datum.type, datum)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return environment
|
||||
}
|
||||
|
||||
private func json2edge_dev(_ json: [String: Any]) async throws -> [EdgeDevice] {
|
||||
|
||||
var devices: [EdgeDevice] = []
|
||||
|
||||
guard
|
||||
let _dataType = json["dataType"] as? String,
|
||||
let dataType = DataType(rawValue: _dataType)
|
||||
else {
|
||||
throw ParsingError.MalformedJSON(reason: "Data Type missing in one device")
|
||||
}
|
||||
|
||||
if let number = json["number"] as? UInt {
|
||||
for _ in 0..<number {
|
||||
let deviceID = try DeviceFactory.getUnusedID()
|
||||
let privateKey = try await fetchPrivateP256Key(deviceID: deviceID)
|
||||
|
||||
// TODO: Get ID from DeviceFactory and push ID inside
|
||||
devices.append(
|
||||
try await DeviceFactory.createEdgeDevice(
|
||||
deviceID: deviceID,
|
||||
dataType: dataType,
|
||||
privateKey: privateKey
|
||||
)
|
||||
)
|
||||
}
|
||||
// UGLY: Silent Bug, coul dhave both deviceID and number, but other properties would
|
||||
// UGLY: be ignored
|
||||
return devices
|
||||
}
|
||||
|
||||
guard
|
||||
let deviceID = json["deviceID"] as? UInt
|
||||
else {
|
||||
throw ParsingError.MalformedJSON(
|
||||
reason: "Missing deviceID and number properties"
|
||||
)
|
||||
}
|
||||
|
||||
// TODO: check for other optionals
|
||||
|
||||
return devices
|
||||
|
||||
}
|
||||
6
env/debug/debug.env
vendored
Normal file
6
env/debug/debug.env
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
## This file is not intended to be used in a production env, so it is safe to share
|
||||
##
|
||||
##
|
||||
|
||||
CONFIGURATION_FILE=/workspace/Config/debug.json
|
||||
PRIVATE_KEY_FOLDER=/workspace/Private/PrivateKeysP256
|
||||
2
env/debug/debug.sh
vendored
Normal file
2
env/debug/debug.sh
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
export CONFIGURATION_FILE=/workspace/Config/debug.json
|
||||
export PRIVATE_KEY_FOLDER=/workspace/Private/PrivateKeysP256
|
||||
Loading…
x
Reference in New Issue
Block a user