blob: 2fbe7f26ce8af8a580450bbbeef934c3a9e15665 [file] [log] [blame]
// 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) {
if !Syncbase.didInit || !Syncbase.isLoggedIn {
return
}
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
}
}