| // Copyright 2016 The Vanadium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| import Foundation |
| |
| /// Represents a peer found in the neighborhood (via Bluetooth or mDNS) using the discovery APIs. |
| public struct NeighborhoodPeer { |
| /// The name of the application advertising itself. |
| public let appName: String |
| /// The blessing pattern being advertised. |
| public let blessings: String |
| /// If true, then we no longer can see this advertisement. If false, then we have just discovered |
| /// this advertisement. |
| public let isLost: Bool |
| |
| public init(appName: String, blessings: String, isLost: Bool) { |
| self.appName = appName |
| self.blessings = blessings |
| self.isLost = isLost |
| } |
| } |
| |
| public class NeighborhoodScanHandler { |
| public let onPeer: NeighborhoodPeer -> Void |
| var isStopped = false |
| let isStoppedMu = NSLock() |
| |
| public init(onPeer: NeighborhoodPeer -> Void) { |
| self.onPeer = onPeer |
| } |
| } |
| |
| public enum Neighborhood { |
| public static func startAdvertising(visibility: [BlessingPattern]) throws { |
| if !Syncbase.didInit { |
| throw SyncbaseError.NotConfigured |
| } |
| if !Syncbase.isLoggedIn { |
| throw SyncbaseError.NotLoggedIn |
| } |
| try VError.maybeThrow { errPtr in |
| v23_syncbase_NeighborhoodStartAdvertising(try v23_syncbase_Strings(visibility), errPtr) |
| } |
| } |
| |
| public static func stopAdvertising() throws { |
| if !Syncbase.didInit { |
| throw SyncbaseError.NotConfigured |
| } |
| if !Syncbase.isLoggedIn { |
| throw SyncbaseError.NotLoggedIn |
| } |
| v23_syncbase_NeighborhoodStopAdvertising() |
| } |
| |
| public static func isAdvertising() -> Bool { |
| if !Syncbase.didInit || !Syncbase.isLoggedIn { |
| return false |
| } |
| var isAdvertising = v23_syncbase_Bool(false) |
| v23_syncbase_NeighborhoodIsAdvertising(&isAdvertising) |
| return isAdvertising.toBool() |
| } |
| |
| public static func startScan(handler: NeighborhoodScanHandler) throws { |
| if !Syncbase.didInit { |
| throw SyncbaseError.NotConfigured |
| } |
| if !Syncbase.isLoggedIn { |
| throw SyncbaseError.NotLoggedIn |
| } |
| let unmanaged = Unmanaged.passRetained(handler) |
| let oHandle = UnsafeMutablePointer<Void>(unmanaged.toOpaque()) |
| do { |
| try VError.maybeThrow { errPtr in |
| v23_syncbase_NeighborhoodNewScan( |
| v23_syncbase_NeighborhoodScanCallbacks( |
| handle: unsafeBitCast(oHandle, UInt.self), |
| onPeer: { Neighborhood.onPeer($0, peer: $1) }), |
| errPtr) |
| } |
| } catch let e { |
| unmanaged.release() |
| throw e |
| } |
| } |
| |
| static func onPeer(handle: v23_syncbase_Handle, peer: v23_syncbase_AppPeer) { |
| let handle = Unmanaged<NeighborhoodScanHandler>.fromOpaque( |
| COpaquePointer(bitPattern: handle)).takeUnretainedValue() |
| let peer = peer.toNeighborhoodPeer() |
| handle.onPeer(peer) |
| } |
| |
| public static func stopScan(handler: NeighborhoodScanHandler) { |
| handler.isStoppedMu.lock() |
| defer { handler.isStoppedMu.unlock() } |
| if handler.isStopped { |
| // Prevent double-free. |
| return |
| } |
| let unmanaged = Unmanaged.passUnretained(handler) |
| let oHandle = UnsafeMutablePointer<Void>(unmanaged.toOpaque()) |
| v23_syncbase_NeighborhoodStopScan(unsafeBitCast(oHandle, UInt.self)) |
| unmanaged.release() |
| handler.isStopped = true |
| } |
| } |