Meshtastic-Apple/Meshtastic/Helpers/MeshPackets.swift

862 lines
36 KiB
Swift
Raw Normal View History

//
// MeshPackets.swift
// Meshtastic Apple
//
// Created by Garth Vander Houwen on 5/27/22.
//
import Foundation
import CoreData
import SwiftUI
#if canImport(ActivityKit)
import ActivityKit
#endif
func generateMessageMarkdown (message: String) -> String {
let types: NSTextCheckingResult.CheckingType = [.address, .link, .phoneNumber]
let detector = try! NSDataDetector(types: types.rawValue)
let matches = detector.matches(in: message, options: [], range: NSRange(location: 0, length: message.utf16.count))
var messageWithMarkdown = message
if matches.count > 0 {
for match in matches {
guard let range = Range(match.range, in: message) else { continue }
if match.resultType == .address {
let address = message[range]
let urlEncodedAddress = address.addingPercentEncoding(withAllowedCharacters: .alphanumerics)
messageWithMarkdown = messageWithMarkdown.replacingOccurrences(of: address, with: "[\(address)](http://maps.apple.com/?address=\(urlEncodedAddress ?? ""))")
} else if match.resultType == .phoneNumber {
let phone = messageWithMarkdown[range]
messageWithMarkdown = messageWithMarkdown.replacingOccurrences(of: phone, with: "[\(phone)](tel:\(phone))")
} else if match.resultType == .link {
let url = messageWithMarkdown[range]
let absoluteUrl = match.url?.absoluteString ?? ""
messageWithMarkdown = messageWithMarkdown.replacingOccurrences(of: url, with: "[\(String(match.url?.host ?? "Link"))\(String(match.url?.path ?? ""))](\(absoluteUrl))")
}
}
}
return messageWithMarkdown
}
2023-03-06 10:33:18 -08:00
func localConfig (config: Config, context: NSManagedObjectContext, nodeNum: Int64, nodeLongName: String) {
2023-01-24 20:33:48 -08:00
// We don't care about any of the Power settings, config is available for everything else
2022-09-10 17:38:10 -07:00
if config.payloadVariant == Config.OneOf_PayloadVariant.bluetooth(config.bluetooth) {
2023-01-31 22:08:03 -08:00
upsertBluetoothConfigPacket(config: config.bluetooth, nodeNum: nodeNum, context: context)
2023-01-23 17:56:04 -08:00
} else if config.payloadVariant == Config.OneOf_PayloadVariant.device(config.device) {
2023-01-31 22:08:03 -08:00
upsertDeviceConfigPacket(config: config.device, nodeNum: nodeNum, context: context)
2023-01-23 17:56:04 -08:00
} else if config.payloadVariant == Config.OneOf_PayloadVariant.display(config.display) {
2023-01-31 22:08:03 -08:00
upsertDisplayConfigPacket(config: config.display, nodeNum: nodeNum, context: context)
2023-01-23 17:56:04 -08:00
} else if config.payloadVariant == Config.OneOf_PayloadVariant.lora(config.lora) {
2023-01-31 10:50:17 -08:00
upsertLoRaConfigPacket(config: config.lora, nodeNum: nodeNum, context: context)
2023-01-23 17:56:04 -08:00
} else if config.payloadVariant == Config.OneOf_PayloadVariant.network(config.network) {
2023-01-31 22:20:16 -08:00
upsertNetworkConfigPacket(config: config.network, nodeNum: nodeNum, context: context)
2023-01-23 17:56:04 -08:00
} else if config.payloadVariant == Config.OneOf_PayloadVariant.position(config.position) {
2023-01-31 22:20:16 -08:00
upsertPositionConfigPacket(config: config.position, nodeNum: nodeNum, context: context)
2022-06-21 13:10:30 -07:00
}
}
2023-03-06 10:33:18 -08:00
func moduleConfig (config: ModuleConfig, context: NSManagedObjectContext, nodeNum: Int64, nodeLongName: String) {
2023-03-14 12:44:10 -07:00
2022-07-02 11:28:25 -07:00
if config.payloadVariant == ModuleConfig.OneOf_PayloadVariant.cannedMessage(config.cannedMessage) {
2023-02-01 09:19:45 -08:00
upsertCannedMessagesModuleConfigPacket(config: config.cannedMessage, nodeNum: nodeNum, context: context)
} else if config.payloadVariant == ModuleConfig.OneOf_PayloadVariant.externalNotification(config.externalNotification) {
upsertExternalNotificationModuleConfigPacket(config: config.externalNotification, nodeNum: nodeNum, context: context)
} else if config.payloadVariant == ModuleConfig.OneOf_PayloadVariant.mqtt(config.mqtt) {
upsertMqttModuleConfigPacket(config: config.mqtt, nodeNum: nodeNum, context: context)
} else if config.payloadVariant == ModuleConfig.OneOf_PayloadVariant.rangeTest(config.rangeTest) {
upsertRangeTestModuleConfigPacket(config: config.rangeTest, nodeNum: nodeNum, context: context)
} else if config.payloadVariant == ModuleConfig.OneOf_PayloadVariant.serial(config.serial) {
upsertSerialModuleConfigPacket(config: config.serial, nodeNum: nodeNum, context: context)
} else if config.payloadVariant == ModuleConfig.OneOf_PayloadVariant.telemetry(config.telemetry) {
upsertTelemetryModuleConfigPacket(config: config.telemetry, nodeNum: nodeNum, context: context)
2022-07-02 13:25:34 -07:00
}
2022-06-28 06:56:50 -07:00
}
2022-10-15 10:14:08 -07:00
func myInfoPacket (myInfo: MyNodeInfo, peripheralId: String, context: NSManagedObjectContext) -> MyInfoEntity? {
2023-03-14 12:44:10 -07:00
let logString = String.localizedStringWithFormat("mesh.log.myinfo %@".localized, String(myInfo.myNodeNum))
2023-01-01 22:34:58 -08:00
MeshLogger.log(" \(logString)")
2023-03-14 12:44:10 -07:00
let fetchMyInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "MyInfoEntity")
fetchMyInfoRequest.predicate = NSPredicate(format: "myNodeNum == %lld", Int64(myInfo.myNodeNum))
2023-03-14 12:44:10 -07:00
do {
2023-03-06 15:30:10 -08:00
guard let fetchedMyInfo = try context.fetch(fetchMyInfoRequest) as? [MyInfoEntity] else {
return nil
}
// Not Found Insert
if fetchedMyInfo.isEmpty {
2023-03-14 12:44:10 -07:00
let myInfoEntity = MyInfoEntity(context: context)
myInfoEntity.peripheralId = peripheralId
myInfoEntity.myNodeNum = Int64(myInfo.myNodeNum)
myInfoEntity.rebootCount = Int32(myInfo.rebootCount)
myInfoEntity.minAppVersion = Int32(bitPattern: myInfo.minAppVersion)
do {
try context.save()
2022-12-30 19:21:22 -08:00
print("💾 Saved a new myInfo for node number: \(String(myInfo.myNodeNum))")
return myInfoEntity
} catch {
context.rollback()
let nsError = error as NSError
print("💥 Error Inserting New Core Data MyInfoEntity: \(nsError)")
}
} else {
2023-03-14 12:44:10 -07:00
fetchedMyInfo[0].peripheralId = peripheralId
fetchedMyInfo[0].myNodeNum = Int64(myInfo.myNodeNum)
fetchedMyInfo[0].rebootCount = Int32(myInfo.rebootCount)
fetchedMyInfo[0].minAppVersion = Int32(bitPattern: myInfo.minAppVersion)
2023-03-14 12:44:10 -07:00
do {
try context.save()
2022-12-30 19:21:22 -08:00
print("💾 Updated myInfo for node number: \(String(myInfo.myNodeNum))")
return fetchedMyInfo[0]
} catch {
context.rollback()
let nsError = error as NSError
print("💥 Error Updating Core Data MyInfoEntity: \(nsError)")
}
}
} catch {
print("💥 Fetch MyInfo Error")
}
return nil
}
2022-10-15 10:14:08 -07:00
func channelPacket (channel: Channel, fromNum: Int64, context: NSManagedObjectContext) {
2023-03-14 12:44:10 -07:00
2023-03-06 10:33:18 -08:00
if channel.isInitialized && channel.hasSettings && channel.role != Channel.Role.disabled {
2023-03-14 12:44:10 -07:00
2023-05-05 17:46:24 -07:00
let logString = String.localizedStringWithFormat("mesh.log.channel.received %d %@".localized, channel.index, String(fromNum))
2023-01-01 22:34:58 -08:00
MeshLogger.log("🎛️ \(logString)")
2023-03-14 12:44:10 -07:00
let fetchedMyInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "MyInfoEntity")
2023-01-02 20:11:58 -08:00
fetchedMyInfoRequest.predicate = NSPredicate(format: "myNodeNum == %lld", fromNum)
2023-03-14 12:44:10 -07:00
do {
2023-03-06 15:30:10 -08:00
guard let fetchedMyInfo = try context.fetch(fetchedMyInfoRequest) as? [MyInfoEntity] else {
return
}
2022-10-28 18:53:10 -07:00
if fetchedMyInfo.count == 1 {
2022-10-10 07:17:57 -07:00
let newChannel = ChannelEntity(context: context)
2022-12-17 23:53:06 -08:00
newChannel.id = Int32(channel.index)
2022-10-10 07:17:57 -07:00
newChannel.index = Int32(channel.index)
newChannel.uplinkEnabled = channel.settings.uplinkEnabled
newChannel.downlinkEnabled = channel.settings.downlinkEnabled
newChannel.name = channel.settings.name
newChannel.role = Int32(channel.role.rawValue)
2022-10-11 04:32:17 -07:00
newChannel.psk = channel.settings.psk
2023-03-06 15:30:10 -08:00
guard let mutableChannels = fetchedMyInfo[0].channels!.mutableCopy() as? NSMutableOrderedSet else {
return
}
if mutableChannels.contains(newChannel) {
mutableChannels.replaceObject(at: Int(newChannel.index), with: newChannel)
} else {
mutableChannels.add(newChannel)
2022-10-29 07:31:50 -07:00
}
2022-10-10 07:17:57 -07:00
fetchedMyInfo[0].channels = mutableChannels.copy() as? NSOrderedSet
if newChannel.name?.lowercased() == "admin" {
fetchedMyInfo[0].adminIndex = newChannel.index
}
2022-10-28 18:53:10 -07:00
do {
try context.save()
} catch {
print("Failed to save channel")
}
2022-12-30 19:21:22 -08:00
print("💾 Updated MyInfo channel \(channel.index) from Channel App Packet For: \(fetchedMyInfo[0].myNodeNum)")
} else if channel.role.rawValue > 0 {
print("💥 Trying to save a channel to a MyInfo that does not exist: \(fromNum)")
}
} catch {
context.rollback()
let nsError = error as NSError
print("💥 Error Saving MyInfo Channel from ADMIN_APP \(nsError)")
}
}
}
func deviceMetadataPacket (metadata: DeviceMetadata, fromNum: Int64, context: NSManagedObjectContext) {
2023-03-14 12:44:10 -07:00
if metadata.isInitialized {
let logString = String.localizedStringWithFormat("mesh.log.device.metadata.received %@".localized, String(fromNum))
2023-01-21 07:28:50 -08:00
MeshLogger.log("🏷️ \(logString)")
2023-03-14 12:44:10 -07:00
let fetchedNodeRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
fetchedNodeRequest.predicate = NSPredicate(format: "num == %lld", fromNum)
2023-03-14 12:44:10 -07:00
do {
2023-03-06 15:30:10 -08:00
guard let fetchedNode = try context.fetch(fetchedNodeRequest) as? [NodeInfoEntity] else {
return
}
2023-01-24 20:33:48 -08:00
if fetchedNode.count > 0 {
let newMetadata = DeviceMetadataEntity(context: context)
newMetadata.firmwareVersion = metadata.firmwareVersion
newMetadata.deviceStateVersion = Int32(metadata.deviceStateVersion)
newMetadata.canShutdown = metadata.canShutdown
newMetadata.hasWifi = metadata.hasWifi_p
newMetadata.hasBluetooth = metadata.hasBluetooth_p
newMetadata.hasEthernet = metadata.hasEthernet_p
newMetadata.role = Int32(metadata.role.rawValue)
newMetadata.positionFlags = Int32(metadata.positionFlags)
// Swift does strings weird, this does work to get the version without the github hash
let lastDotIndex = metadata.firmwareVersion.lastIndex(of: ".")
var version = metadata.firmwareVersion[...(lastDotIndex ?? String.Index(utf16Offset: 6, in: metadata.firmwareVersion))]
version = version.dropLast()
newMetadata.firmwareVersion = String(version)
fetchedNode[0].metadata = newMetadata
2023-03-14 12:44:10 -07:00
do {
try context.save()
} catch {
print("Failed to save device metadata")
}
print("💾 Updated Device Metadata from Admin App Packet For: \(fromNum)")
}
} catch {
context.rollback()
let nsError = error as NSError
print("💥 Error Saving MyInfo Channel from ADMIN_APP \(nsError)")
}
}
}
2022-10-30 19:27:15 -07:00
func nodeInfoPacket (nodeInfo: NodeInfo, channel: UInt32, context: NSManagedObjectContext) -> NodeInfoEntity? {
2023-03-14 12:44:10 -07:00
let logString = String.localizedStringWithFormat("mesh.log.nodeinfo.received %@".localized, String(nodeInfo.num))
2023-01-01 22:34:58 -08:00
MeshLogger.log("📟 \(logString)")
2023-03-14 12:44:10 -07:00
2023-03-06 10:33:18 -08:00
guard nodeInfo.num > 0 else { return nil }
2023-03-14 12:44:10 -07:00
let fetchNodeInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeInfo.num))
2023-03-14 12:44:10 -07:00
do {
2023-03-06 15:30:10 -08:00
guard let fetchedNode = try context.fetch(fetchNodeInfoRequest) as? [NodeInfoEntity] else {
return nil
}
// Not Found Insert
if fetchedNode.isEmpty && nodeInfo.hasUser {
2023-03-14 12:44:10 -07:00
let newNode = NodeInfoEntity(context: context)
newNode.id = Int64(nodeInfo.num)
newNode.num = Int64(nodeInfo.num)
2023-04-02 15:00:15 -07:00
newNode.channel = Int32(nodeInfo.channel)
2023-03-14 12:44:10 -07:00
if nodeInfo.hasDeviceMetrics {
let telemetry = TelemetryEntity(context: context)
telemetry.batteryLevel = Int32(nodeInfo.deviceMetrics.batteryLevel)
telemetry.voltage = nodeInfo.deviceMetrics.voltage
telemetry.channelUtilization = nodeInfo.deviceMetrics.channelUtilization
telemetry.airUtilTx = nodeInfo.deviceMetrics.airUtilTx
var newTelemetries = [TelemetryEntity]()
newTelemetries.append(telemetry)
newNode.telemetries? = NSOrderedSet(array: newTelemetries)
}
2023-03-14 12:44:10 -07:00
newNode.lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(nodeInfo.lastHeard)))
newNode.snr = nodeInfo.snr
if nodeInfo.hasUser {
let newUser = UserEntity(context: context)
newUser.userId = nodeInfo.user.id
newUser.num = Int64(nodeInfo.num)
newUser.longName = nodeInfo.user.longName
newUser.shortName = nodeInfo.user.shortName
newUser.hwModel = String(describing: nodeInfo.user.hwModel).uppercased()
newNode.user = newUser
}
2023-03-14 12:44:10 -07:00
2023-03-06 10:33:18 -08:00
if nodeInfo.position.longitudeI > 0 || nodeInfo.position.latitudeI > 0 && (nodeInfo.position.latitudeI != 373346000 && nodeInfo.position.longitudeI != -1220090000) {
let position = PositionEntity(context: context)
position.latest = true
position.seqNo = Int32(nodeInfo.position.seqNumber)
position.latitudeI = nodeInfo.position.latitudeI
position.longitudeI = nodeInfo.position.longitudeI
position.altitude = nodeInfo.position.altitude
2022-09-01 11:54:39 -07:00
position.satsInView = Int32(nodeInfo.position.satsInView)
position.speed = Int32(nodeInfo.position.groundSpeed)
position.heading = Int32(nodeInfo.position.groundTrack)
position.time = Date(timeIntervalSince1970: TimeInterval(Int64(nodeInfo.position.time)))
var newPostions = [PositionEntity]()
newPostions.append(position)
newNode.positions? = NSOrderedSet(array: newPostions)
}
2023-03-14 12:44:10 -07:00
// Look for a MyInfo
let fetchMyInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "MyInfoEntity")
fetchMyInfoRequest.predicate = NSPredicate(format: "myNodeNum == %lld", Int64(nodeInfo.num))
2023-03-14 12:44:10 -07:00
do {
2023-03-06 15:30:10 -08:00
guard let fetchedMyInfo = try context.fetch(fetchMyInfoRequest) as? [MyInfoEntity] else {
return nil
}
if fetchedMyInfo.count > 0 {
newNode.myInfo = fetchedMyInfo[0]
}
do {
try context.save()
return newNode
} catch {
context.rollback()
let nsError = error as NSError
print("💥 Error Saving Core Data NodeInfoEntity: \(nsError)")
}
} catch {
print("💥 Fetch MyInfo Error")
}
} else if nodeInfo.hasUser && nodeInfo.num > 0 {
2023-03-14 12:44:10 -07:00
fetchedNode[0].id = Int64(nodeInfo.num)
fetchedNode[0].num = Int64(nodeInfo.num)
fetchedNode[0].lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(nodeInfo.lastHeard)))
fetchedNode[0].snr = nodeInfo.snr
2023-04-02 15:00:15 -07:00
fetchedNode[0].channel = Int32(nodeInfo.channel)
2023-03-14 12:44:10 -07:00
if nodeInfo.hasUser {
2023-03-14 12:44:10 -07:00
fetchedNode[0].user!.userId = nodeInfo.user.id
fetchedNode[0].user!.num = Int64(nodeInfo.num)
fetchedNode[0].user!.longName = nodeInfo.user.longName
fetchedNode[0].user!.shortName = nodeInfo.user.shortName
fetchedNode[0].user!.hwModel = String(describing: nodeInfo.user.hwModel).uppercased()
}
2023-03-14 12:44:10 -07:00
if nodeInfo.hasDeviceMetrics {
2023-03-14 12:44:10 -07:00
let newTelemetry = TelemetryEntity(context: context)
newTelemetry.batteryLevel = Int32(nodeInfo.deviceMetrics.batteryLevel)
newTelemetry.voltage = nodeInfo.deviceMetrics.voltage
newTelemetry.channelUtilization = nodeInfo.deviceMetrics.channelUtilization
newTelemetry.airUtilTx = nodeInfo.deviceMetrics.airUtilTx
guard let mutableTelemetries = fetchedNode[0].telemetries!.mutableCopy() as? NSMutableOrderedSet else {
return nil
}
fetchedNode[0].telemetries = mutableTelemetries.copy() as? NSOrderedSet
}
2023-03-14 12:44:10 -07:00
if nodeInfo.hasPosition {
2023-03-14 12:44:10 -07:00
if nodeInfo.position.longitudeI > 0 || nodeInfo.position.latitudeI > 0 && (nodeInfo.position.latitudeI != 373346000 && nodeInfo.position.longitudeI != -1220090000) {
2023-03-14 12:44:10 -07:00
let position = PositionEntity(context: context)
position.latitudeI = nodeInfo.position.latitudeI
position.longitudeI = nodeInfo.position.longitudeI
position.altitude = nodeInfo.position.altitude
position.satsInView = Int32(nodeInfo.position.satsInView)
position.time = Date(timeIntervalSince1970: TimeInterval(Int64(nodeInfo.position.time)))
guard let mutablePositions = fetchedNode[0].positions!.mutableCopy() as? NSMutableOrderedSet else {
return nil
}
fetchedNode[0].positions = mutablePositions.copy() as? NSOrderedSet
}
2023-03-14 12:44:10 -07:00
}
2023-03-14 12:44:10 -07:00
// Look for a MyInfo
let fetchMyInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "MyInfoEntity")
fetchMyInfoRequest.predicate = NSPredicate(format: "myNodeNum == %lld", Int64(nodeInfo.num))
2023-03-14 12:44:10 -07:00
do {
2023-03-06 15:30:10 -08:00
guard let fetchedMyInfo = try context.fetch(fetchMyInfoRequest) as? [MyInfoEntity] else {
return nil
}
if fetchedMyInfo.count > 0 {
fetchedNode[0].myInfo = fetchedMyInfo[0]
}
do {
try context.save()
print("💾 NodeInfo saved for \(nodeInfo.num)")
return fetchedNode[0]
} catch {
context.rollback()
let nsError = error as NSError
print("💥 Error Saving Core Data NodeInfoEntity: \(nsError)")
}
} catch {
print("💥 Fetch MyInfo Error")
}
}
} catch {
print("💥 Fetch NodeInfoEntity Error")
}
return nil
}
2022-10-15 10:14:08 -07:00
func adminAppPacket (packet: MeshPacket, context: NSManagedObjectContext) {
2023-03-14 12:44:10 -07:00
if let adminMessage = try? AdminMessage(serializedData: packet.decoded.payload) {
2023-03-14 12:44:10 -07:00
if adminMessage.payloadVariant == AdminMessage.OneOf_PayloadVariant.getCannedMessageModuleMessagesResponse(adminMessage.getCannedMessageModuleMessagesResponse) {
2023-03-14 12:44:10 -07:00
if let cmmc = try? CannedMessageModuleConfig(serializedData: packet.decoded.payload) {
2023-03-14 12:44:10 -07:00
if !cmmc.messages.isEmpty {
2023-03-14 12:44:10 -07:00
let logString = String.localizedStringWithFormat("mesh.log.cannedmessages.messages.received %@".localized, String(packet.from))
MeshLogger.log("🥫 \(logString)")
2023-03-14 12:44:10 -07:00
let fetchNodeRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
fetchNodeRequest.predicate = NSPredicate(format: "num == %lld", Int64(packet.from))
2023-03-14 12:44:10 -07:00
do {
2023-03-06 15:30:10 -08:00
guard let fetchedNode = try context.fetch(fetchNodeRequest) as? [NodeInfoEntity] else {
return
}
if fetchedNode.count == 1 {
let messages = String(cmmc.textFormatString())
.replacingOccurrences(of: "11: ", with: "")
.replacingOccurrences(of: "\"", with: "")
.trimmingCharacters(in: .whitespacesAndNewlines)
fetchedNode[0].cannedMessageConfig?.messages = messages
do {
try context.save()
print("💾 Updated Canned Messages Messages For: \(fetchedNode[0].num)")
} catch {
context.rollback()
let nsError = error as NSError
print("💥 Error Saving NodeInfoEntity from POSITION_APP \(nsError)")
}
}
} catch {
print("💥 Error Deserializing ADMIN_APP packet.")
}
}
}
} else if adminMessage.payloadVariant == AdminMessage.OneOf_PayloadVariant.getChannelResponse(adminMessage.getChannelResponse) {
channelPacket(channel: adminMessage.getChannelResponse, fromNum: Int64(packet.from), context: context)
2023-03-14 12:44:10 -07:00
} else if adminMessage.payloadVariant == AdminMessage.OneOf_PayloadVariant.getDeviceMetadataResponse(adminMessage.getDeviceMetadataResponse) {
deviceMetadataPacket(metadata: adminMessage.getDeviceMetadataResponse, fromNum: Int64(packet.from), context: context)
2023-03-14 12:44:10 -07:00
2023-01-21 07:28:50 -08:00
} else if adminMessage.payloadVariant == AdminMessage.OneOf_PayloadVariant.getConfigResponse(adminMessage.getConfigResponse) {
2023-03-14 12:44:10 -07:00
2023-01-31 22:08:03 -08:00
let config = adminMessage.getConfigResponse
2023-03-14 12:44:10 -07:00
2023-01-31 22:08:03 -08:00
if config.payloadVariant == Config.OneOf_PayloadVariant.bluetooth(config.bluetooth) {
upsertBluetoothConfigPacket(config: config.bluetooth, nodeNum: Int64(packet.from), context: context)
2023-03-14 12:44:10 -07:00
2023-01-31 22:08:03 -08:00
} else if config.payloadVariant == Config.OneOf_PayloadVariant.device(config.device) {
upsertDeviceConfigPacket(config: config.device, nodeNum: Int64(packet.from), context: context)
2023-03-14 12:44:10 -07:00
} else if config.payloadVariant == Config.OneOf_PayloadVariant.display(config.display) {
upsertDisplayConfigPacket(config: config.display, nodeNum: Int64(packet.from), context: context)
2023-01-31 22:08:03 -08:00
} else if config.payloadVariant == Config.OneOf_PayloadVariant.lora(config.lora) {
upsertLoRaConfigPacket(config: config.lora, nodeNum: Int64(packet.from), context: context)
2023-03-14 12:44:10 -07:00
2023-01-31 22:08:03 -08:00
} else if config.payloadVariant == Config.OneOf_PayloadVariant.network(config.network) {
2023-01-31 22:20:16 -08:00
upsertNetworkConfigPacket(config: config.network, nodeNum: Int64(packet.from), context: context)
2023-03-14 12:44:10 -07:00
2023-01-31 22:08:03 -08:00
} else if config.payloadVariant == Config.OneOf_PayloadVariant.position(config.position) {
2023-01-31 22:20:16 -08:00
upsertPositionConfigPacket(config: config.position, nodeNum: Int64(packet.from), context: context)
2023-03-14 12:44:10 -07:00
2023-01-20 19:14:49 -08:00
}
2023-02-01 09:19:45 -08:00
} else if adminMessage.payloadVariant == AdminMessage.OneOf_PayloadVariant.getModuleConfigResponse(adminMessage.getModuleConfigResponse) {
2023-03-14 12:44:10 -07:00
2023-02-01 09:19:45 -08:00
let moduleConfig = adminMessage.getModuleConfigResponse
2023-03-14 12:44:10 -07:00
2023-02-01 09:19:45 -08:00
if moduleConfig.payloadVariant == ModuleConfig.OneOf_PayloadVariant.cannedMessage(moduleConfig.cannedMessage) {
upsertCannedMessagesModuleConfigPacket(config: moduleConfig.cannedMessage, nodeNum: Int64(packet.from), context: context)
2023-03-14 12:44:10 -07:00
2023-02-01 09:19:45 -08:00
} else if moduleConfig.payloadVariant == ModuleConfig.OneOf_PayloadVariant.externalNotification(moduleConfig.externalNotification) {
upsertExternalNotificationModuleConfigPacket(config: moduleConfig.externalNotification, nodeNum: Int64(packet.from), context: context)
2023-03-14 12:44:10 -07:00
2023-02-01 09:19:45 -08:00
} else if moduleConfig.payloadVariant == ModuleConfig.OneOf_PayloadVariant.mqtt(moduleConfig.mqtt) {
upsertMqttModuleConfigPacket(config: moduleConfig.mqtt, nodeNum: Int64(packet.from), context: context)
2023-03-14 12:44:10 -07:00
2023-02-01 09:19:45 -08:00
} else if moduleConfig.payloadVariant == ModuleConfig.OneOf_PayloadVariant.rangeTest(moduleConfig.rangeTest) {
upsertRangeTestModuleConfigPacket(config: moduleConfig.rangeTest, nodeNum: Int64(packet.from), context: context)
2023-03-14 12:44:10 -07:00
2023-02-01 09:19:45 -08:00
} else if moduleConfig.payloadVariant == ModuleConfig.OneOf_PayloadVariant.serial(moduleConfig.serial) {
upsertSerialModuleConfigPacket(config: moduleConfig.serial, nodeNum: Int64(packet.from), context: context)
2023-03-14 12:44:10 -07:00
2023-02-01 09:19:45 -08:00
} else if moduleConfig.payloadVariant == ModuleConfig.OneOf_PayloadVariant.telemetry(moduleConfig.telemetry) {
upsertTelemetryModuleConfigPacket(config: moduleConfig.telemetry, nodeNum: Int64(packet.from), context: context)
2023-03-14 12:44:10 -07:00
2023-02-01 09:19:45 -08:00
}
2023-03-14 12:44:10 -07:00
2023-03-25 22:14:39 -07:00
} else if adminMessage.payloadVariant == AdminMessage.OneOf_PayloadVariant.getRingtoneResponse(adminMessage.getRingtoneResponse) {
let ringtone = adminMessage.getRingtoneResponse
upsertRtttlConfigPacket(ringtone: ringtone, nodeNum: Int64(packet.from), context: context)
2023-01-21 07:28:50 -08:00
} else {
MeshLogger.log("🕸️ MESH PACKET received for Admin App \(try! packet.decoded.jsonString())")
}
2023-03-14 12:44:10 -07:00
// Save an ack for the admin message log for each admin message response received as we stopped sending acks if there is also a response to reduce airtime.
adminResponseAck(packet: packet, context: context)
}
}
func adminResponseAck (packet: MeshPacket, context: NSManagedObjectContext) {
2023-03-14 12:44:10 -07:00
let fetchedAdminMessageRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "MessageEntity")
fetchedAdminMessageRequest.predicate = NSPredicate(format: "messageId == %lld", packet.decoded.requestID)
do {
2023-03-06 15:30:10 -08:00
guard let fetchedMessage = try context.fetch(fetchedAdminMessageRequest) as? [MessageEntity] else {
return
}
if fetchedMessage.count > 0 {
fetchedMessage[0].ackTimestamp = Int32(Date().timeIntervalSince1970)
fetchedMessage[0].ackError = Int32(RoutingError.none.rawValue)
fetchedMessage[0].receivedACK = true
fetchedMessage[0].realACK = true
fetchedMessage[0].ackSNR = packet.rxSnr
if fetchedMessage[0].fromUser != nil {
fetchedMessage[0].fromUser?.objectWillChange.send()
}
do {
try context.save()
} catch {
print("Failed to save admin message response as an ack")
}
}
} catch {
print("Failed to fetch admin message by requestID")
2022-11-13 09:25:00 -08:00
}
}
2022-11-10 22:17:38 -08:00
func routingPacket (packet: MeshPacket, connectedNodeNum: Int64, context: NSManagedObjectContext) {
2023-03-14 12:44:10 -07:00
if let routingMessage = try? Routing(serializedData: packet.decoded.payload) {
2023-03-14 12:44:10 -07:00
2022-12-30 21:28:51 -08:00
let routingError = RoutingError(rawValue: routingMessage.errorReason.rawValue)
2023-03-14 12:44:10 -07:00
let routingErrorString = routingError?.display ?? "unknown".localized
let logString = String.localizedStringWithFormat("mesh.log.routing.message %@ %@".localized, String(packet.decoded.requestID), routingErrorString)
2023-01-01 22:58:54 -08:00
MeshLogger.log("🕸️ \(logString)")
2023-03-14 12:44:10 -07:00
let fetchMessageRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "MessageEntity")
fetchMessageRequest.predicate = NSPredicate(format: "messageId == %lld", Int64(packet.decoded.requestID))
2023-03-14 12:44:10 -07:00
do {
let fetchedMessage = try context.fetch(fetchMessageRequest) as? [MessageEntity]
if fetchedMessage?.count ?? 0 > 0 {
2023-03-14 12:44:10 -07:00
if fetchedMessage![0].toUser != nil {
// Real ACK from DM Recipient
if packet.to != packet.from {
fetchedMessage![0].realACK = true
}
}
fetchedMessage![0].ackError = Int32(routingMessage.errorReason.rawValue)
2023-03-14 12:44:10 -07:00
if routingMessage.errorReason == Routing.Error.none {
2023-03-14 12:44:10 -07:00
2022-06-29 20:04:20 -07:00
fetchedMessage![0].receivedACK = true
}
fetchedMessage![0].ackSNR = packet.rxSnr
fetchedMessage![0].ackTimestamp = Int32(packet.rxTime)
2023-03-14 12:44:10 -07:00
2022-11-10 22:17:38 -08:00
if fetchedMessage![0].toUser != nil {
fetchedMessage![0].toUser?.objectWillChange.send()
} else {
let fetchMyInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "MyInfoEntity")
fetchMyInfoRequest.predicate = NSPredicate(format: "myNodeNum == %lld", connectedNodeNum)
do {
let fetchedMyInfo = try context.fetch(fetchMyInfoRequest) as? [MyInfoEntity]
if fetchedMyInfo?.count ?? 0 > 0 {
2023-03-14 12:44:10 -07:00
2023-03-14 13:01:35 -07:00
for ch in fetchedMyInfo![0].channels!.array as? [ChannelEntity] ?? [] {
2023-03-14 12:44:10 -07:00
2022-11-10 22:17:38 -08:00
if ch.index == packet.channel {
ch.objectWillChange.send()
}
}
}
} catch {
2023-03-14 12:44:10 -07:00
2022-11-10 22:17:38 -08:00
}
}
2023-03-14 12:44:10 -07:00
} else {
return
}
try context.save()
2022-12-30 21:28:51 -08:00
print("💾 ACK Saved for Message: \(packet.decoded.requestID)")
} catch {
context.rollback()
let nsError = error as NSError
2022-12-30 21:28:51 -08:00
print("💥 Error Saving ACK for message: \(packet.id) Error: \(nsError)")
}
}
}
2023-01-14 20:27:05 -08:00
func telemetryPacket(packet: MeshPacket, connectedNode: Int64, context: NSManagedObjectContext) {
2023-03-14 12:44:10 -07:00
if let telemetryMessage = try? Telemetry(serializedData: packet.decoded.payload) {
2023-03-14 12:44:10 -07:00
2022-12-30 21:28:51 -08:00
// Only log telemetry from the mesh not the connected device
if connectedNode != Int64(packet.from) {
let logString = String.localizedStringWithFormat("mesh.log.telemetry.received %@".localized, String(packet.from))
MeshLogger.log("📈 \(logString)")
} else {
// If it is the connected node
2023-03-14 12:44:10 -07:00
2022-12-30 21:28:51 -08:00
}
2023-03-14 12:44:10 -07:00
2022-12-30 21:28:51 -08:00
let telemetry = TelemetryEntity(context: context)
2023-03-14 12:44:10 -07:00
let fetchNodeTelemetryRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
fetchNodeTelemetryRequest.predicate = NSPredicate(format: "num == %lld", Int64(packet.from))
2023-03-14 12:44:10 -07:00
do {
2023-03-14 12:44:10 -07:00
2023-03-06 15:30:10 -08:00
guard let fetchedNode = try context.fetch(fetchNodeTelemetryRequest) as? [NodeInfoEntity] else {
return
}
if fetchedNode.count == 1 {
2022-07-08 06:31:47 -07:00
if telemetryMessage.variant == Telemetry.OneOf_Variant.deviceMetrics(telemetryMessage.deviceMetrics) {
// Device Metrics
telemetry.airUtilTx = telemetryMessage.deviceMetrics.airUtilTx
telemetry.channelUtilization = telemetryMessage.deviceMetrics.channelUtilization
telemetry.batteryLevel = Int32(telemetryMessage.deviceMetrics.batteryLevel)
telemetry.voltage = telemetryMessage.deviceMetrics.voltage
telemetry.metricsType = 0
} else if telemetryMessage.variant == Telemetry.OneOf_Variant.environmentMetrics(telemetryMessage.environmentMetrics) {
// Environment Metrics
telemetry.barometricPressure = telemetryMessage.environmentMetrics.barometricPressure
telemetry.current = telemetryMessage.environmentMetrics.current
telemetry.gasResistance = telemetryMessage.environmentMetrics.gasResistance
telemetry.relativeHumidity = telemetryMessage.environmentMetrics.relativeHumidity
telemetry.temperature = telemetryMessage.environmentMetrics.temperature
telemetry.current = telemetryMessage.environmentMetrics.current
telemetry.voltage = telemetryMessage.environmentMetrics.voltage
2022-07-08 06:31:47 -07:00
telemetry.metricsType = 1
}
2023-05-04 22:20:22 -07:00
telemetry.snr = packet.rxSnr
telemetry.rssi = packet.rxRssi
2022-07-08 06:31:47 -07:00
telemetry.time = Date(timeIntervalSince1970: TimeInterval(Int64(telemetryMessage.time)))
guard let mutableTelemetries = fetchedNode[0].telemetries!.mutableCopy() as? NSMutableOrderedSet else {
return
}
mutableTelemetries.add(telemetry)
2022-07-08 06:31:47 -07:00
fetchedNode[0].lastHeard = telemetry.time
fetchedNode[0].telemetries = mutableTelemetries.copy() as? NSOrderedSet
}
try context.save()
2022-12-30 21:28:51 -08:00
// Only log telemetry from the mesh not the connected device
if connectedNode != Int64(packet.from) {
2022-12-30 21:28:51 -08:00
print("💾 Telemetry Saved for Node: \(packet.from)")
} else if telemetry.metricsType == 0 {
2023-03-04 11:11:34 -08:00
// Connected Device Metrics
// ------------------------
// Low Battery notification
if telemetry.batteryLevel > 0 && telemetry.batteryLevel < 5 {
2023-03-04 11:11:34 -08:00
let content = UNMutableNotificationContent()
content.title = "Critically Low Battery!"
content.body = "Time to charge your radio, there is \(telemetry.batteryLevel)% battery remaining."
2023-03-04 11:11:34 -08:00
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false)
let uuidString = UUID().uuidString
2023-03-06 10:33:18 -08:00
let request = UNNotificationRequest(identifier: uuidString, content: content, trigger: trigger)
2023-03-04 11:11:34 -08:00
let notificationCenter = UNUserNotificationCenter.current()
notificationCenter.add(request) { (error) in
if error != nil {
// Handle any errors.
print("Error creating local low battery notification: \(error?.localizedDescription ?? "no description")")
} else {
print("Created local low battery notification.")
}
}
}
// Update our live activity if there is one running, not available on mac iOS >= 16.2
#if !targetEnvironment(macCatalyst)
if #available(iOS 16.2, *) {
2023-03-14 12:44:10 -07:00
2023-03-02 22:58:49 -08:00
let oneMinuteLater = Calendar.current.date(byAdding: .minute, value: (Int(1) ), to: Date())!
let date = Date.now...oneMinuteLater
let updatedMeshStatus = MeshActivityAttributes.MeshActivityStatus(timerRange: date, connected: true, channelUtilization: telemetry.channelUtilization, airtime: telemetry.airUtilTx, batteryLevel: UInt32(telemetry.batteryLevel))
let alertConfiguration = AlertConfiguration(title: "Mesh activity update", body: "Updated Device Metrics Data.", sound: .default)
let updatedContent = ActivityContent(state: updatedMeshStatus, staleDate: nil)
2023-03-14 12:44:10 -07:00
2023-03-02 22:58:49 -08:00
let meshActivity = Activity<MeshActivityAttributes>.activities.first(where: { $0.attributes.nodeNum == connectedNode })
if meshActivity != nil {
Task {
2023-03-02 22:58:49 -08:00
await meshActivity?.update(updatedContent, alertConfiguration: alertConfiguration)
2023-03-06 10:33:18 -08:00
// await meshActivity?.update(updatedContent)
2023-03-04 11:11:34 -08:00
print("Updated live activity.")
}
}
}
#endif
}
} catch {
context.rollback()
let nsError = error as NSError
2022-12-30 20:04:43 -08:00
print("💥 Error Saving Telemetry for Node \(packet.from) Error: \(nsError)")
}
} else {
2022-12-30 20:04:43 -08:00
print("💥 Error Fetching NodeInfoEntity for Node \(packet.from)")
}
}
2022-10-15 10:14:08 -07:00
func textMessageAppPacket(packet: MeshPacket, connectedNode: Int64, context: NSManagedObjectContext) {
2023-03-14 12:44:10 -07:00
if let messageText = String(bytes: packet.decoded.payload, encoding: .utf8) {
2023-03-14 12:44:10 -07:00
MeshLogger.log("💬 \("mesh.log.textmessage.received".localized)")
2023-03-14 12:44:10 -07:00
let messageUsers: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "UserEntity")
messageUsers.predicate = NSPredicate(format: "num IN %@", [packet.to, packet.from])
do {
2023-03-06 15:30:10 -08:00
guard let fetchedUsers = try context.fetch(messageUsers) as? [UserEntity] else {
return
}
let newMessage = MessageEntity(context: context)
newMessage.messageId = Int64(packet.id)
newMessage.messageTimestamp = Int32(bitPattern: packet.rxTime)
newMessage.receivedACK = false
newMessage.snr = packet.rxSnr
2023-05-04 22:20:22 -07:00
newMessage.rssi = packet.rxRssi
newMessage.isEmoji = packet.decoded.emoji == 1
2022-10-29 07:31:50 -07:00
newMessage.channel = Int32(packet.channel)
2023-03-14 12:44:10 -07:00
if packet.decoded.replyID > 0 {
newMessage.replyID = Int64(packet.decoded.replyID)
}
2023-03-14 12:44:10 -07:00
2022-11-08 11:30:08 -08:00
if fetchedUsers.first(where: { $0.num == packet.to }) != nil && packet.to != 4294967295 {
newMessage.toUser = fetchedUsers.first(where: { $0.num == packet.to })
}
2022-11-07 18:31:12 -08:00
if fetchedUsers.first(where: { $0.num == packet.from }) != nil {
newMessage.fromUser = fetchedUsers.first(where: { $0.num == packet.from })
}
newMessage.messagePayload = messageText
newMessage.messagePayloadMarkdown = generateMessageMarkdown(message: messageText)
2023-03-14 12:44:10 -07:00
2022-06-06 22:24:35 -07:00
newMessage.fromUser?.objectWillChange.send()
newMessage.toUser?.objectWillChange.send()
2023-03-14 12:44:10 -07:00
2022-11-08 11:30:08 -08:00
var messageSaved = false
2023-03-14 12:44:10 -07:00
2022-11-08 11:30:08 -08:00
do {
2023-03-14 12:44:10 -07:00
2022-11-08 11:30:08 -08:00
try context.save()
2022-12-30 21:28:51 -08:00
print("💾 Saved a new message for \(newMessage.messageId)")
2022-11-08 11:30:08 -08:00
messageSaved = true
2023-03-14 12:44:10 -07:00
2022-11-08 11:30:08 -08:00
if messageSaved {
2023-03-14 12:44:10 -07:00
if newMessage.fromUser != nil && newMessage.toUser != nil && !(newMessage.fromUser?.mute ?? false) {
2022-11-26 10:22:51 -08:00
// Create an iOS Notification for the received DM message and schedule it immediately
let manager = LocalNotificationManager()
manager.notifications = [
Notification(
id: ("notification.id.\(newMessage.messageId)"),
title: "\(newMessage.fromUser?.longName ?? "unknown".localized)",
2022-11-26 10:22:51 -08:00
subtitle: "AKA \(newMessage.fromUser?.shortName ?? "???")",
content: messageText)
]
manager.schedule()
print("💬 iOS Notification Scheduled for text message from \(newMessage.fromUser?.longName ?? "unknown".localized)")
2022-12-03 01:08:06 -08:00
} else if newMessage.fromUser != nil && newMessage.toUser == nil {
2023-03-14 12:44:10 -07:00
2022-12-18 00:09:08 -08:00
let fetchMyInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "MyInfoEntity")
fetchMyInfoRequest.predicate = NSPredicate(format: "myNodeNum == %lld", Int64(connectedNode))
2023-03-14 12:44:10 -07:00
2022-12-18 00:09:08 -08:00
do {
2023-03-06 15:30:10 -08:00
guard let fetchedMyInfo = try context.fetch(fetchMyInfoRequest) as? [MyInfoEntity] else {
return
}
2023-03-31 12:08:42 -07:00
if !fetchedMyInfo.isEmpty {
for channel in (fetchedMyInfo[0].channels?.array ?? []) as? [ChannelEntity] ?? [] {
if channel.index == newMessage.channel {
context.refresh(channel, mergeChanges: true)
}
if channel.index == newMessage.channel && !channel.mute {
// Create an iOS Notification for the received private channel message and schedule it immediately
let manager = LocalNotificationManager()
manager.notifications = [
Notification(
id: ("notification.id.\(newMessage.messageId)"),
title: "\(newMessage.fromUser?.longName ?? "unknown".localized)",
2023-03-31 12:08:42 -07:00
subtitle: "AKA \(newMessage.fromUser?.shortName ?? "???")",
content: messageText)
]
manager.schedule()
print("💬 iOS Notification Scheduled for text message from \(newMessage.fromUser?.longName ?? "unknown".localized)")
2023-03-31 12:08:42 -07:00
}
2022-12-18 00:09:08 -08:00
}
}
} catch {
2023-03-14 12:44:10 -07:00
2022-12-18 00:09:08 -08:00
}
2022-06-24 07:48:25 -07:00
}
}
2022-11-08 11:30:08 -08:00
} catch {
context.rollback()
let nsError = error as NSError
2022-12-30 20:04:43 -08:00
print("💥 Failed to save new MessageEntity \(nsError)")
2022-11-08 11:30:08 -08:00
}
2022-10-15 10:14:08 -07:00
} catch {
2022-12-30 20:04:43 -08:00
print("💥 Fetch Message To and From Users Error")
}
}
}
2023-01-13 22:30:10 -08:00
func waypointPacket (packet: MeshPacket, context: NSManagedObjectContext) {
2023-03-14 12:44:10 -07:00
let logString = String.localizedStringWithFormat("mesh.log.waypoint.received %@".localized, String(packet.from))
2023-01-13 22:30:10 -08:00
MeshLogger.log("📍 \(logString)")
2023-03-14 12:44:10 -07:00
2023-01-13 22:30:10 -08:00
let fetchWaypointRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "WaypointEntity")
fetchWaypointRequest.predicate = NSPredicate(format: "id == %lld", Int64(packet.id))
2023-03-14 12:44:10 -07:00
2023-01-13 22:30:10 -08:00
do {
2023-03-14 12:44:10 -07:00
2023-01-13 22:30:10 -08:00
if let waypointMessage = try? Waypoint(serializedData: packet.decoded.payload) {
2023-03-06 15:30:10 -08:00
guard let fetchedWaypoint = try context.fetch(fetchWaypointRequest) as? [WaypointEntity] else {
return
}
2023-01-14 20:27:05 -08:00
if fetchedWaypoint.isEmpty {
let waypoint = WaypointEntity(context: context)
2023-03-14 12:44:10 -07:00
2023-01-14 20:27:05 -08:00
waypoint.id = Int64(packet.id)
waypoint.name = waypointMessage.name
waypoint.longDescription = waypointMessage.description_p
waypoint.latitudeI = waypointMessage.latitudeI
waypoint.longitudeI = waypointMessage.longitudeI
2023-01-14 21:57:39 -08:00
waypoint.icon = Int64(waypointMessage.icon)
2023-01-15 19:15:00 -08:00
waypoint.locked = Int64(waypointMessage.lockedTo)
if waypointMessage.expire >= 1 {
2023-01-14 20:27:05 -08:00
waypoint.expire = Date(timeIntervalSince1970: TimeInterval(Int64(waypointMessage.expire)))
2023-03-06 10:33:18 -08:00
} else {
waypoint.expire = nil
2023-01-14 20:27:05 -08:00
}
waypoint.created = Date()
2023-01-14 20:27:05 -08:00
do {
try context.save()
print("💾 Updated Node Waypoint App Packet For: \(waypoint.id)")
} catch {
context.rollback()
let nsError = error as NSError
print("💥 Error Saving WaypointEntity from WAYPOINT_APP \(nsError)")
2023-01-13 22:30:10 -08:00
}
} else {
2023-01-14 20:27:05 -08:00
fetchedWaypoint[0].id = Int64(packet.id)
fetchedWaypoint[0].name = waypointMessage.name
fetchedWaypoint[0].longDescription = waypointMessage.description_p
fetchedWaypoint[0].latitudeI = waypointMessage.latitudeI
fetchedWaypoint[0].longitudeI = waypointMessage.longitudeI
2023-01-14 21:57:39 -08:00
fetchedWaypoint[0].icon = Int64(waypointMessage.icon)
2023-01-15 19:15:00 -08:00
fetchedWaypoint[0].locked = Int64(waypointMessage.lockedTo)
if waypointMessage.expire >= 1 {
2023-01-14 20:27:05 -08:00
fetchedWaypoint[0].expire = Date(timeIntervalSince1970: TimeInterval(Int64(waypointMessage.expire)))
} else {
fetchedWaypoint[0].expire = nil
2023-01-14 20:27:05 -08:00
}
fetchedWaypoint[0].lastUpdated = Date()
2023-01-14 20:27:05 -08:00
do {
try context.save()
print("💾 Updated Node Waypoint App Packet For: \(fetchedWaypoint[0].id)")
} catch {
context.rollback()
let nsError = error as NSError
print("💥 Error Saving WaypointEntity from WAYPOINT_APP \(nsError)")
}
2023-01-13 22:30:10 -08:00
}
}
} catch {
print("💥 Error Deserializing WAYPOINT_APP packet.")
}
}