Skip to content

Commit

Permalink
Merge pull request #45 from XYOracleNetwork/feature/location-witness
Browse files Browse the repository at this point in the history
Location Witness & Async Witnesses
  • Loading branch information
JoelBCarter authored Nov 15, 2024
2 parents a4ea0d2 + 3a6b401 commit a1de7e5
Show file tree
Hide file tree
Showing 10 changed files with 113 additions and 17 deletions.
54 changes: 54 additions & 0 deletions Sources/XyoClient/Api/Archivist/ArchivistApiClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,60 @@ public class XyoArchivistApiClient {
self.queryAccount = account ?? Account()
}

public func insert(
payloads: [Payload],
completion: @escaping ([Payload]?, Error?) -> Void
) {
do {
// Build QueryBoundWitness
let (bw, signed) = try BoundWitnessBuilder()
.payloads(payloads)
.signer(self.queryAccount)
.query(XyoArchivistApiClient.ArchivistInsertQuery)
.build()

// Perform the request
AF.request(
self.url,
method: .post,
parameters: ModuleQueryResult(bw: bw, payloads: signed),
encoder: JSONParameterEncoder.default
)
.validate()
.responseData { response in
switch response.result {
case .success(let responseData):
do {
// Decode the response data
let decodedResponse = try JSONDecoder().decode(
ApiResponseEnvelope<ModuleQueryResult>.self, from: responseData
)

// Check if the response data matches the expected result
if decodedResponse.data?.bw.payload_hashes.count == payloads.count {
// Return the payloads array in case of success
completion(payloads, nil)
} else {
// Return an empty array if the counts don't match
completion([], nil)
}
} catch {
// Pass any decoding errors to the completion handler
completion(nil, error)
}

case .failure(let error):
// Pass any request errors to the completion handler
completion(nil, error)
}
}

} catch {
// Handle synchronous errors (like errors from the BoundWitnessBuilder)
completion(nil, error)
}
}

@available(iOS 15, *)
public func insert(payloads: [Payload]) async throws -> [Payload] {
// Build QueryBoundWitness
Expand Down
37 changes: 28 additions & 9 deletions Sources/XyoClient/Panel/Panel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ public enum XyoPanelError: Error {

public class XyoPanel {

public init(archivists: [XyoArchivistApiClient], witnesses: [AbstractWitness]) {
public init(archivists: [XyoArchivistApiClient], witnesses: [WitnessModuleSync]) {
self._archivists = archivists
self._witnesses = witnesses
}

public convenience init(
archive: String? = nil, apiDomain: String? = nil, witnesses: [AbstractWitness]? = nil,
archive: String? = nil, apiDomain: String? = nil, witnesses: [WitnessModuleSync]? = nil,
token: String? = nil
) {
let apiConfig = XyoArchivistApiConfig(
Expand All @@ -23,7 +23,7 @@ public class XyoPanel {

public convenience init(observe: (() -> XyoEventPayload?)?) {
if observe != nil {
var witnesses = [AbstractWitness]()
var witnesses = [WitnessModuleSync]()

if let observe = observe {
witnesses.append(XyoEventWitness(observe))
Expand All @@ -38,21 +38,40 @@ public class XyoPanel {
public typealias XyoPanelReportCallback = (([String]) -> Void)

private var _archivists: [XyoArchivistApiClient]
private var _witnesses: [AbstractWitness]
private var _witnesses: [WitnessModule]
private var _previous_hash: String?

@available(iOS 15, *)
public func report() async throws
-> [Payload]
{
let payloads = self._witnesses.map { witness in
witness.observe()
}.flatMap({ $0 })
var payloads: [Payload] = []

// Collect payloads from both synchronous and asynchronous witnesses
for witness in _witnesses {
if let syncWitness = witness as? WitnessSync {
// For synchronous witnesses, call the sync `observe` method directly
payloads.append(contentsOf: syncWitness.observe())
} else if let asyncWitness = witness as? WitnessAsync {
// For asynchronous witnesses, call the async `observe` method using `await`
do {
let asyncPayloads = try await asyncWitness.observe()
payloads.append(contentsOf: asyncPayloads)
} catch {
print("Error observing async witness: \(error)")
// Handle error as needed, possibly continue or throw
}
}
}

// Build the BoundWitness
let (bw, _) = try BoundWitnessBuilder()
.payloads(payloads)
.signers(self._witnesses.map({ $0.account }))
.signers(self._witnesses.map { $0.account })
.build(_previous_hash)
self._previous_hash = bw._hash

// Collect results from archivists using async tasks
var allResults: [[Payload]] = []
await withTaskGroup(of: [Payload]?.self) { group in
for instance in _archivists {
Expand Down
2 changes: 1 addition & 1 deletion Sources/XyoClient/Witness/Basic/BasicWitness.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

open class BasicWitness: AbstractWitness {
open class BasicWitness: WitnessModuleSync {

public typealias TPayloadOut = Payload

Expand Down
2 changes: 1 addition & 1 deletion Sources/XyoClient/Witness/Event/EventWitness.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

open class XyoEventWitness: AbstractWitness {
open class XyoEventWitness: WitnessModuleSync {

public init(_ observer: @escaping ObserverClosure) {
_observer = observer
Expand Down
2 changes: 1 addition & 1 deletion Sources/XyoClient/Witness/Location/LocationPayload.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ open class LocationPayload: Payload {
}
try container.encode(self.location.speed, forKey: .speed)
try container.encode(self.location.speedAccuracy, forKey: .speedAccuracy)
try container.encode(self.location.timestamp, forKey: .timestamp)
try container.encode(Int(self.location.timestamp.timeIntervalSince1970 * 1000), forKey: .timestamp)
try container.encode(self.location.verticalAccuracy, forKey: .verticalAccuracy)

}
Expand Down
21 changes: 21 additions & 0 deletions Sources/XyoClient/Witness/Location/LocationWitness.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import CoreLocation
import Foundation

open class LocationWitness: WitnessModuleAsync {
private let locationService = LocationService()

override open func observe(completion: @escaping ([Payload]?, Error?) -> Void) {
locationService.requestAuthorization()
locationService.requestLocation { result in
DispatchQueue.main.async {
switch result {
case .success(let location):
let payload = LocationPayload(location)
completion([payload], nil)
case .failure(let error):
completion(nil, error)
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

open class SystemInfoWitness: AbstractWitness {
open class SystemInfoWitness: WitnessModuleSync {

var allowPathMonitor: Bool

Expand Down
2 changes: 1 addition & 1 deletion Sources/XyoClient/Witness/Witness.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
public protocol Witness {
public protocol WitnessSync {
func observe() -> [Payload]
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import Foundation

open class AbstractWitness: AbstractModule, Witness {
public protocol WitnessModule: Module {}

open class WitnessModuleSync: AbstractModule, WitnessSync, WitnessModule {
open func observe() -> [Payload] {
preconditionFailure("This method must be overridden")
}
}

open class AbstractAsyncWitness: AbstractModule, WitnessAsync {
open class WitnessModuleAsync: AbstractModule, WitnessAsync, WitnessModule {
open func observe(completion: @escaping ([Payload]?, Error?) -> Void) {
preconditionFailure("This method must be overridden")
}
Expand Down
2 changes: 1 addition & 1 deletion Tests/XyoClientTests/Panel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ final class PanelTests: XCTestCase {
let apiDomain = XyoPanel.Defaults.apiDomain
let archive = XyoPanel.Defaults.apiModule
let account = Account()
let witness = AbstractWitness(account: account)
let witness = WitnessModuleSync(account: account)
let panel = XyoPanel(archive: archive, apiDomain: apiDomain, witnesses: [witness])
XCTAssertNotNil(account)
XCTAssertNotNil(panel)
Expand Down

0 comments on commit a1de7e5

Please sign in to comment.