Skip to content

Commit

Permalink
refactor(darwin): Improved Darwin code quality.
Browse files Browse the repository at this point in the history
  • Loading branch information
Skyost committed Nov 19, 2023
1 parent 6a6284c commit 531e4ba
Show file tree
Hide file tree
Showing 5 changed files with 253 additions and 213 deletions.
82 changes: 82 additions & 0 deletions packages/bonsoir_darwin/darwin/Classes/BonsoirAction.swift
@@ -0,0 +1,82 @@
#if canImport(Flutter)
import Flutter
#endif
#if canImport(FlutterMacOS)
import FlutterMacOS
#endif
#if canImport(os)
import os
#endif

/// Represents a Bonsoir action (broadcast or discovery).
@available(iOS 13.0, macOS 10.15, *)
class BonsoirAction: NSObject, FlutterStreamHandler {
/// The action identifier.
private let id: Int

/// The action name.
private let action: String

/// Whether to print debug logs.
private let printLogs: Bool

/// Triggered when this instance is being disposed.
private let onDispose: () -> Void

/// The current event channel.
private var eventChannel: FlutterEventChannel?

/// The current event sink.
private var eventSink: FlutterEventSink?

/// Initializes this class.
public init(id: Int, action: String, printLogs: Bool, onDispose: @escaping () -> Void, messenger: FlutterBinaryMessenger) {
self.id = id
self.action = action
self.printLogs = printLogs
self.onDispose = onDispose
super.init()
eventChannel = FlutterEventChannel(name: "\(SwiftBonsoirPlugin.package).\(action).\(id)", binaryMessenger: messenger)
eventChannel?.setStreamHandler(self)
}

/// Called by the event channel when ready to list.
func onListen(withArguments arguments: Any?, eventSink: @escaping FlutterEventSink) -> FlutterError? {
self.eventSink = eventSink
return nil
}

/// Called by the event channel when cancelled.
func onCancel(withArguments arguments: Any?) -> FlutterError? {
eventSink = nil
return nil
}

/// Triggered when a success occurs.
internal func onSuccess(_ eventId: String, _ message: String, _ service: BonsoirService? = nil) {
log(message)
eventSink?(SuccessObject(id: eventId, service: service).toJson())
}

/// Triggered when an error occurs.
internal func onError(_ message: String, _ details: Any? = nil) {
log(message)
eventSink?(FlutterError.init(code: "\(action)Error", message: message, details: details))
}

/// Disposes the current class instance.
public func dispose() {
onDispose()
}

/// Logs a given message.
internal func log(_ message: String) {
if (printLogs) {
#if canImport(os)
os_log("[%d] %s", log: OSLog(subsystem: SwiftBonsoirPlugin.package, category: action), type: OSLogType.info, id, message)
#else
NSLog("\n[\(id)] \(message)")
#endif
}
}
}
7 changes: 3 additions & 4 deletions packages/bonsoir_darwin/darwin/Classes/BonsoirService.swift
Expand Up @@ -2,7 +2,7 @@ import Network

/// Represents a Bonsoir service.
@available(iOS 13.0, macOS 10.15, *)
class BonsoirService {
class BonsoirService: NSObject {
/// The response service name.
var name: String

Expand Down Expand Up @@ -37,9 +37,8 @@ class BonsoirService {
"\(prefix)attributes": attributes
]
}

/// Returns the description of this object.
public var description: String {

public override var description: String {
let json = toJson(prefix: "")
do {
let data = try JSONSerialization.data(withJSONObject: json)
Expand Down
Expand Up @@ -8,48 +8,19 @@ import Network

/// Allows to broadcast a given service to the local network.
@available(iOS 13.0, macOS 10.15, *)
class BonsoirServiceBroadcast: NSObject, FlutterStreamHandler {
/// The delegate identifier.
let id: Int

/// Whether to print debug logs.
let printLogs: Bool

/// Triggered when this instance is being disposed.
let onDispose: () -> Void

class BonsoirServiceBroadcast: BonsoirAction {
/// The advertised service.
let service: BonsoirService
private let service: BonsoirService

/// The reference to the registering..
var sdRef: DNSServiceRef?

/// The current event channel.
var eventChannel: FlutterEventChannel?

/// The current event sink.
var eventSink: FlutterEventSink?
private var sdRef: DNSServiceRef?

/// Initializes this class.
public init(id: Int, printLogs: Bool, onDispose: @escaping () -> Void, messenger: FlutterBinaryMessenger, service: BonsoirService) {
self.id = id
self.printLogs = printLogs
self.onDispose = onDispose
self.service = service
super.init()
eventChannel = FlutterEventChannel(name: "\(SwiftBonsoirPlugin.package).broadcast.\(id)", binaryMessenger: messenger)
eventChannel?.setStreamHandler(self)
}

func onListen(withArguments arguments: Any?, eventSink: @escaping FlutterEventSink) -> FlutterError? {
self.eventSink = eventSink
return nil
super.init(id: id, action: "broadcast", printLogs: printLogs, onDispose: onDispose, messenger: messenger)
}

func onCancel(withArguments arguments: Any?) -> FlutterError? {
eventSink = nil
return nil
}

/// Starts the broadcast.
public func start() {
Expand All @@ -58,52 +29,37 @@ class BonsoirServiceBroadcast: NSObject, FlutterStreamHandler {
for (key, value) in service.attributes {
TXTRecordSetValue(&txtRecord, key, UInt8(value.count), value)
}
let error = DNSServiceRegister(&sdRef, 0, 0, service.name, service.type, "local.", service.host, CFSwapInt16HostToBig(UInt16(service.port)), TXTRecordGetLength(&txtRecord), TXTRecordGetBytesPtr(&txtRecord), { sdRef, flags, errorCode, name, regType, domain, context in
let broadcast = Unmanaged<BonsoirServiceBroadcast>.fromOpaque(context!).takeUnretainedValue()
if errorCode == kDNSServiceErr_NoError {
let newName = name == nil ? nil : String(cString: name!)
if newName != nil && broadcast.service.name != newName {
let oldName = broadcast.service.name
broadcast.service.name = newName!
if broadcast.printLogs {
SwiftBonsoirPlugin.log(category: "broadcast", id: broadcast.id, message: "Trying to broadcast a service with a name that already exists : \(broadcast.service.description) (old name was \(oldName))")
}
broadcast.eventSink?(SuccessObject(id: "broadcastNameAlreadyExists", service: broadcast.service).toJson())
}
if broadcast.printLogs {
SwiftBonsoirPlugin.log(category: "broadcast", id: broadcast.id, message: "Bonsoir service broadcasted : \(broadcast.service.description)")
}
broadcast.eventSink?(SuccessObject(id: "broadcastStarted", service: broadcast.service).toJson())
}
else {
if broadcast.printLogs {
SwiftBonsoirPlugin.log(category: "broadcast", id: broadcast.id, message: "Bonsoir service failed to broadcast : \(broadcast.service.description), error code : \(errorCode)")
}
broadcast.eventSink?(FlutterError.init(code: "broadcastError", message: "Bonsoir service failed to broadcast.", details: errorCode))
broadcast.dispose()
}
}, Unmanaged.passUnretained(self).toOpaque())
let error = DNSServiceRegister(&sdRef, 0, 0, service.name, service.type, "local.", service.host, CFSwapInt16HostToBig(UInt16(service.port)), TXTRecordGetLength(&txtRecord), TXTRecordGetBytesPtr(&txtRecord), BonsoirServiceBroadcast.registerCallback as DNSServiceRegisterReply, Unmanaged.passUnretained(self).toOpaque())
if error == kDNSServiceErr_NoError {
if printLogs {
SwiftBonsoirPlugin.log(category: "broadcast", id: id, message: "Bonsoir service broadcast initialized : \(service.description)")
}
log("Bonsoir service broadcast initialized : \(service)")
DNSServiceProcessResult(sdRef)
} else {
if printLogs {
SwiftBonsoirPlugin.log(category: "broadcast", id: id, message: "Bonsoir service failed to broadcast : \(service.description), error code : \(error)")
}
eventSink?(FlutterError.init(code: "broadcastError", message: "Bonsoir service failed to broadcast.", details: error))
onError("Bonsoir service failed to broadcast : \(service), error code : \(error)", error)
dispose()
}
}

/// Disposes the current class instance.
public func dispose() {
override public func dispose() {
DNSServiceRefDeallocate(sdRef)
if printLogs {
SwiftBonsoirPlugin.log(category: "broadcast", id: id, message: "Bonsoir service broadcast stopped : \(service.description)")
}
eventSink?(SuccessObject(id: "broadcastStopped", service: service).toJson())
onDispose()
onSuccess("broadcastStopped", "Bonsoir service broadcast stopped : \(service)", service)
super.dispose()
}

/// Callback triggered by`DNSServiceRegister`.
private static let registerCallback: DNSServiceRegisterReply = ({ sdRef, flags, errorCode, name, regType, domain, context in
let broadcast = Unmanaged<BonsoirServiceBroadcast>.fromOpaque(context!).takeUnretainedValue()
if errorCode == kDNSServiceErr_NoError {
let newName = name == nil ? nil : String(cString: name!)
if newName != nil && broadcast.service.name != newName {
let oldName = broadcast.service.name
broadcast.service.name = newName!
broadcast.onSuccess("broadcastNameAlreadyExists", "Trying to broadcast a service with a name that already exists : \(broadcast.service) (old name was \(oldName))", broadcast.service)
}
broadcast.onSuccess("broadcastStarted", "Bonsoir service broadcasted : \(broadcast.service)", broadcast.service)
}
else {
broadcast.onError("Bonsoir service failed to broadcast : \(broadcast.service)", errorCode)
broadcast.dispose()
}
})
}

0 comments on commit 531e4ba

Please sign in to comment.