mirror of
https://github.com/AU-COVIDSafe/mobile-ios.git
synced 2025-04-19 21:15:21 +00:00
COVIDSafe code from version 2.0 (#37)
This commit is contained in:
parent
cf93ea43c0
commit
8b75c1fc6f
55 changed files with 4624 additions and 1117 deletions
|
@ -2,24 +2,58 @@ import UIKit
|
|||
import CoreData
|
||||
import CoreBluetooth
|
||||
|
||||
class BluetraceManager {
|
||||
private var peripheralController: PeripheralController!
|
||||
private var centralController: CentralController!
|
||||
var queue: DispatchQueue!
|
||||
var bluetoothDidUpdateStateCallback: ((CBManagerState) -> Void)?
|
||||
class BluetraceManager: SensorDelegate {
|
||||
|
||||
private let logger = ConcreteSensorLogger(subsystem: "Herald", category: "BluetraceManager")
|
||||
|
||||
var sensorDidUpdateStateCallback: ((SensorState, SensorType?) -> Void)?
|
||||
|
||||
// Payload data supplier, sensor and contact log
|
||||
var payloadDataSupplier: PayloadDataSupplier?
|
||||
var sensor: Sensor?
|
||||
|
||||
static let shared = BluetraceManager()
|
||||
|
||||
private init() {
|
||||
queue = DispatchQueue(label: "BluetraceManager")
|
||||
peripheralController = PeripheralController(peripheralName: "TR", queue: queue)
|
||||
centralController = CentralController(queue: queue)
|
||||
centralController.centralDidUpdateStateCallback = centralDidUpdateStateCallback
|
||||
var bleSensorState: SensorState = .unavailable
|
||||
var awakeSensorState: SensorState = .unavailable
|
||||
|
||||
private var didRecordPayloadData: [String:Date] = [:]
|
||||
private var didWriteLegacyPayloadData: [String:Date] = [:]
|
||||
|
||||
func turnOnBLE() {
|
||||
payloadDataSupplier = EncounterMessageManager.shared
|
||||
if sensor == nil {
|
||||
sensor = SensorArray(payloadDataSupplier!)
|
||||
sensor?.add(delegate: self)
|
||||
}
|
||||
sensor?.start()
|
||||
}
|
||||
|
||||
func turnOn() {
|
||||
peripheralController.turnOn()
|
||||
centralController.turnOn()
|
||||
func turnOnAllSensors() {
|
||||
payloadDataSupplier = EncounterMessageManager.shared
|
||||
if sensor == nil {
|
||||
sensor = SensorArray(payloadDataSupplier!)
|
||||
sensor?.add(delegate: self)
|
||||
// we are going to turn on one at a time
|
||||
let previousSensorDidUpdateStateCallback = sensorDidUpdateStateCallback
|
||||
sensorDidUpdateStateCallback = { state, type in
|
||||
if (state == .on ) {
|
||||
self.sensorDidUpdateStateCallback = previousSensorDidUpdateStateCallback
|
||||
self.turnOnLocationSensor()
|
||||
}
|
||||
}
|
||||
}
|
||||
sensor?.start()
|
||||
}
|
||||
|
||||
|
||||
func turnOnLocationSensor() {
|
||||
guard let sensorArray = sensor as? SensorArray else {
|
||||
return
|
||||
}
|
||||
DispatchQueue.main.async {
|
||||
sensorArray.startAwakeSensor()
|
||||
}
|
||||
}
|
||||
|
||||
func isBluetoothAuthorized() -> Bool {
|
||||
|
@ -31,26 +65,161 @@ class BluetraceManager {
|
|||
}
|
||||
|
||||
func isBluetoothOn() -> Bool {
|
||||
return centralController.getState() == .poweredOn
|
||||
return bleSensorState == .on
|
||||
}
|
||||
|
||||
func isLocationOnAuthorized() -> Bool {
|
||||
return awakeSensorState == .on
|
||||
}
|
||||
|
||||
func centralDidUpdateStateCallback(_ state: CBManagerState) {
|
||||
bluetoothDidUpdateStateCallback?(state)
|
||||
if state == .poweredOn {
|
||||
sensorDidUpdateStateCallback?(.on, .BLE)
|
||||
} else {
|
||||
sensorDidUpdateStateCallback?(.off, .BLE)
|
||||
}
|
||||
}
|
||||
|
||||
func toggleAdvertisement(_ state: Bool) {
|
||||
if state {
|
||||
peripheralController.turnOn()
|
||||
sensor?.start()
|
||||
} else {
|
||||
peripheralController.turnOff()
|
||||
sensor?.stop()
|
||||
}
|
||||
}
|
||||
|
||||
func toggleScanning(_ state: Bool) {
|
||||
if state {
|
||||
centralController.turnOn()
|
||||
sensor?.start()
|
||||
} else {
|
||||
centralController.turnOff()
|
||||
sensor?.stop()
|
||||
}
|
||||
}
|
||||
|
||||
func cleanRecordsData( records: inout [String:Date], expiryInterval: TimeInterval) {
|
||||
let removeDataBefore = Date() - expiryInterval
|
||||
let recentDidWritePayloadData = records.filter({ $0.value >= removeDataBefore })
|
||||
records = recentDidWritePayloadData
|
||||
}
|
||||
|
||||
func saveEncounter(payload: PayloadData, proximity: Proximity, txPower: Int? ) throws {
|
||||
let peripheralCharData = try JSONDecoder().decode(PeripheralCharacteristicsData.self, from: payload)
|
||||
var encounterStruct = EncounterRecord(rssi: proximity.value, txPower: txPower == nil ? nil : Double(txPower!))
|
||||
encounterStruct.msg = peripheralCharData.msg
|
||||
encounterStruct.update(modelP: peripheralCharData.modelP)
|
||||
encounterStruct.org = peripheralCharData.org
|
||||
encounterStruct.v = peripheralCharData.v
|
||||
encounterStruct.timestamp = Date()
|
||||
// here the remote blob will be msg and modelp if v1, msg if v2
|
||||
// local blob will be rssi, txpower, modelc
|
||||
try encounterStruct.saveRemotePeripheralToCoreData()
|
||||
}
|
||||
|
||||
func getIdentifier(forDevice: BLEDevice) -> String {
|
||||
return forDevice.pseudoDeviceAddress != nil ? "\(forDevice.pseudoDeviceAddress!.address)" : forDevice.identifier
|
||||
}
|
||||
|
||||
func shouldSaveEncounter(forDeviceIdentifier: String) -> Bool {
|
||||
|
||||
guard didRecordPayloadData[forDeviceIdentifier] == nil || abs(didRecordPayloadData[forDeviceIdentifier]!.timeIntervalSinceNow) > BluetraceConfig.PeripheralPayloadSaveInterval else {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// MARK:- SensorDelegate
|
||||
|
||||
func sensor(_ sensor: SensorType, didDetect: TargetIdentifier) {
|
||||
logger.info(sensor.rawValue + ",didDetect=" + didDetect.description)
|
||||
}
|
||||
|
||||
func sensor(_ sensor: SensorType, didMeasure: Proximity, fromTarget: TargetIdentifier) {
|
||||
logger.info(sensor.rawValue + ",didMeasure=" + didMeasure.description + ",fromTarget=" + fromTarget.description)
|
||||
|
||||
// Make a call to the messages API if needed.
|
||||
// Dispatch in background queue
|
||||
DispatchQueue.global(qos: .background).async {
|
||||
MessageAPI.getMessagesIfNeeded() { (messageResponse, error) in
|
||||
if let error = error {
|
||||
DLog("Get messages error: \(error.localizedDescription)")
|
||||
}
|
||||
// We currently dont do anything with the response. Messages are delivered via APN
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func sensor(_ sensor: SensorType, didMeasure: Proximity, fromTarget: TargetIdentifier, withPayload: PayloadData, forDevice: BLEDevice) {
|
||||
logger.info(sensor.rawValue + ",didMeasure=" + didMeasure.description + ",fromTarget=" + fromTarget.description + ",withPayload=" + withPayload.shortName)
|
||||
|
||||
let deviceIdentifier = getIdentifier(forDevice: forDevice)
|
||||
guard shouldSaveEncounter(forDeviceIdentifier: deviceIdentifier) else {
|
||||
logger.info("didMeasure, skipping save as time since last saved too recet fromTarget=" + fromTarget.description)
|
||||
return
|
||||
}
|
||||
didRecordPayloadData[deviceIdentifier] = Date()
|
||||
cleanRecordsData(records: &didRecordPayloadData, expiryInterval: BluetraceConfig.PeripheralPayloadExpiry)
|
||||
do {
|
||||
logger.debug("Saving on didMeasure fromTarget=" + fromTarget.description)
|
||||
try saveEncounter(payload: withPayload, proximity: didMeasure, txPower: nil)
|
||||
} catch {
|
||||
logger.fault("ERROR "+sensor.rawValue + ",didMeasure=" + didMeasure.description + ",fromTarget=" + fromTarget.description + ",withPayload=" + withPayload.shortName )
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func sensor(_ sensor: SensorType, didRead: PayloadData, fromTarget: TargetIdentifier) {
|
||||
do {
|
||||
let dataFromCentral = try JSONDecoder().decode(CentralWriteData.self, from: didRead)
|
||||
logger.info(sensor.rawValue + ",didRead=" + dataFromCentral.msg + ",fromTarget=" + fromTarget.description)
|
||||
} catch {
|
||||
logger.fault(sensor.rawValue + ",didRead=" + didRead.shortName + ",fromTarget=" + fromTarget.description)
|
||||
}
|
||||
}
|
||||
|
||||
func sensor(_ sensor: SensorType, didRead: PayloadData, fromTarget: TargetIdentifier, atProximity: Proximity, withTxPower: Int?) {
|
||||
logger.info(sensor.rawValue + ",didRead=\(didRead.shortName))" + ",fromTarget=" + fromTarget.description + ",atProximity=" + atProximity.description + ",withTxPower=\(String(describing: withTxPower))")
|
||||
}
|
||||
|
||||
func sensor(_ sensor: SensorType, didShare: [PayloadData], fromTarget: TargetIdentifier, atProximity: Proximity) {
|
||||
let payloads = didShare.map { $0.shortName }
|
||||
logger.info(sensor.rawValue + ",didShare=" + payloads.description + ",fromTarget=" + fromTarget.description)
|
||||
|
||||
}
|
||||
|
||||
func sensor(_ sensor: SensorType, didUpdateState: SensorState) {
|
||||
logger.info(sensor.rawValue + ",didUpdateState=" + didUpdateState.rawValue)
|
||||
|
||||
if sensor == .BLE {
|
||||
bleSensorState = didUpdateState
|
||||
sensorDidUpdateStateCallback?(didUpdateState, sensor)
|
||||
}
|
||||
|
||||
if sensor == .AWAKE {
|
||||
awakeSensorState = didUpdateState
|
||||
sensorDidUpdateStateCallback?(didUpdateState, sensor)
|
||||
}
|
||||
}
|
||||
|
||||
func shouldWriteToLegacyDevice(_ device: BLEDevice) -> Bool {
|
||||
|
||||
guard device.legacyPayloadCharacteristic != nil &&
|
||||
device.payloadCharacteristic == nil else {
|
||||
return false
|
||||
}
|
||||
|
||||
let cleanInterval = BluetraceConfig.PeripheralPayloadExpiry
|
||||
let writeInterval = BluetraceConfig.PeripheralPayloadSaveInterval
|
||||
let deviceIdentifier = getIdentifier(forDevice: device)
|
||||
cleanRecordsData(records: &didWriteLegacyPayloadData, expiryInterval: cleanInterval)
|
||||
|
||||
guard didWriteLegacyPayloadData[deviceIdentifier] == nil || abs(didWriteLegacyPayloadData[deviceIdentifier]!.timeIntervalSinceNow) > writeInterval else {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func didWriteToLegacyDevice(_ device: BLEDevice) {
|
||||
let deviceIdentifier = getIdentifier(forDevice: device)
|
||||
didWriteLegacyPayloadData[deviceIdentifier] = Date()
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue