Skip to content

Instantly share code, notes, and snippets.

@ralfebert
Last active March 9, 2022 19:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ralfebert/2ee9df7a88fb817047e59bcb8138b19d to your computer and use it in GitHub Desktop.
Save ralfebert/2ee9df7a88fb817047e59bcb8138b19d to your computer and use it in GitHub Desktop.
import MultipeerConnectivity
import os
import SwiftUI
class ColorModel: NSObject, ObservableObject {
private let serviceType = "example-color"
private let session: MCSession
private let myPeerId = MCPeerID(displayName: UIDevice.current.name)
private let serviceAdvertiser: MCNearbyServiceAdvertiser
private let serviceBrowser: MCNearbyServiceBrowser
private let log = Logger()
@Published var currentColor: Color? = nil {
didSet {
if oldValue != currentColor, let currentColor = currentColor {
self.send(color: currentColor)
}
}
}
let colors = [Color.red, .green, .blue, .yellow, .brown]
override init() {
precondition(Thread.isMainThread)
self.session = MCSession(peer: myPeerId)
self.serviceAdvertiser = MCNearbyServiceAdvertiser(peer: myPeerId, discoveryInfo: nil, serviceType: serviceType)
self.serviceBrowser = MCNearbyServiceBrowser(peer: myPeerId, serviceType: serviceType)
super.init()
session.delegate = self
serviceAdvertiser.delegate = self
serviceBrowser.delegate = self
serviceAdvertiser.startAdvertisingPeer()
serviceBrowser.startBrowsingForPeers()
}
deinit {
self.serviceAdvertiser.stopAdvertisingPeer()
self.serviceBrowser.stopBrowsingForPeers()
}
private func send(color: Color) {
precondition(Thread.isMainThread)
do {
var r: CGFloat = 0
var g: CGFloat = 0
var b: CGFloat = 0
var o: CGFloat = 0
UIColor(color).getRed(&r, green: &g, blue: &b, alpha: &o)
let components = [r, g, b]
if !self.session.connectedPeers.isEmpty {
try session.send(JSONEncoder().encode(components), toPeers: session.connectedPeers, with: .reliable)
}
log.info("sendColor: \(components) to \(self.session.connectedPeers.count) peers")
} catch {
log.error("Error for sending: \(String(describing: error))")
}
}
}
extension ColorModel: MCNearbyServiceAdvertiserDelegate {
func advertiser(_ advertiser: MCNearbyServiceAdvertiser, didNotStartAdvertisingPeer error: Error) {
precondition(Thread.isMainThread)
log.error("ServiceAdvertiser didNotStartAdvertisingPeer: \(String(describing: error))")
}
func advertiser(_ advertiser: MCNearbyServiceAdvertiser, didReceiveInvitationFromPeer peerID: MCPeerID, withContext context: Data?, invitationHandler: @escaping (Bool, MCSession?) -> Void) {
precondition(Thread.isMainThread)
log.info("didReceiveInvitationFromPeer \(peerID)")
invitationHandler(true, session)
}
}
extension ColorModel: MCNearbyServiceBrowserDelegate {
func browser(_ browser: MCNearbyServiceBrowser, didNotStartBrowsingForPeers error: Error) {
log.error("ServiceBrowser didNotStartBrowsingForPeers: \(String(describing: error))")
}
func browser(_ browser: MCNearbyServiceBrowser, foundPeer peerID: MCPeerID, withDiscoveryInfo info: [String: String]?) {
log.info("ServiceBrowser found peer: \(peerID)")
browser.invitePeer(peerID, to: session, withContext: nil, timeout: 10)
}
func browser(_ browser: MCNearbyServiceBrowser, lostPeer peerID: MCPeerID) {
log.info("ServiceBrowser lost peer: \(peerID)")
}
}
extension ColorModel: MCSessionDelegate {
func session(_ session: MCSession, peer peerID: MCPeerID, didChange state: MCSessionState) {
log.info("peer \(peerID) didChangeState: \(state.debugDescription)")
}
func session(_ session: MCSession, didReceive data: Data, fromPeer peerID: MCPeerID) {
if let color = try? JSONDecoder().decode([Double].self, from: data) {
log.info("didReceive color \(color)")
DispatchQueue.main.async {
self.currentColor = Color(red: color[0], green: color[1], blue: color[2])
}
} else {
log.info("didReceive invalid value \(data.count) bytes")
}
}
public func session(_ session: MCSession, didReceive stream: InputStream, withName streamName: String, fromPeer peerID: MCPeerID) {
log.error("Receiving streams is not supported")
}
public func session(_ session: MCSession, didStartReceivingResourceWithName resourceName: String, fromPeer peerID: MCPeerID, with progress: Progress) {
log.error("Receiving resources is not supported")
}
public func session(_ session: MCSession, didFinishReceivingResourceWithName resourceName: String, fromPeer peerID: MCPeerID, at localURL: URL?, withError error: Error?) {
log.error("Receiving resources is not supported")
}
}
extension MCSessionState: CustomDebugStringConvertible {
public var debugDescription: String {
switch self {
case .notConnected:
return "notConnected"
case .connecting:
return "connecting"
case .connected:
return "connected"
@unknown default:
return "\(rawValue)"
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment