@dawidzawada/bonjour-zeroconf 1.0.1 → 1.2.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/README.md +30 -0
  2. package/android/src/main/java/com/margelo/nitro/dawidzawada/bonjourzeroconf/BonjourZeroconf+AddressResolver.kt +14 -0
  3. package/android/src/main/java/com/margelo/nitro/dawidzawada/bonjourzeroconf/BonjourZeroconf.kt +25 -1
  4. package/ios/AddressResolverError.swift +13 -10
  5. package/ios/BonjourZeroconf+AddressResolver.swift +58 -21
  6. package/ios/BonjourZeroconf.swift +21 -0
  7. package/ios/LocalNetworkAuthorization.swift +0 -1
  8. package/lib/typescript/src/specs/BonjourZeroconf.nitro.d.ts +1 -0
  9. package/lib/typescript/src/specs/BonjourZeroconf.nitro.d.ts.map +1 -1
  10. package/nitrogen/generated/android/c++/JBonjourFail.hpp +4 -5
  11. package/nitrogen/generated/android/c++/JBonjourListener.hpp +3 -4
  12. package/nitrogen/generated/android/c++/JFunc_void.hpp +3 -2
  13. package/nitrogen/generated/android/c++/JFunc_void_BonjourFail.hpp +3 -2
  14. package/nitrogen/generated/android/c++/JFunc_void_bool.hpp +3 -2
  15. package/nitrogen/generated/android/c++/JFunc_void_std__vector_ScanResult_.hpp +3 -2
  16. package/nitrogen/generated/android/c++/JHybridBonjourZeroconfSpec.cpp +43 -8
  17. package/nitrogen/generated/android/c++/JHybridBonjourZeroconfSpec.hpp +3 -1
  18. package/nitrogen/generated/android/c++/JScanOptions.hpp +1 -1
  19. package/nitrogen/generated/android/c++/JScanResult.hpp +1 -1
  20. package/nitrogen/generated/android/dawidzawada_bonjourzeroconf+autolinking.cmake +1 -1
  21. package/nitrogen/generated/android/dawidzawada_bonjourzeroconf+autolinking.gradle +1 -1
  22. package/nitrogen/generated/android/dawidzawada_bonjourzeroconfOnLoad.cpp +1 -1
  23. package/nitrogen/generated/android/dawidzawada_bonjourzeroconfOnLoad.hpp +1 -1
  24. package/nitrogen/generated/android/kotlin/com/margelo/nitro/dawidzawada/bonjourzeroconf/BonjourFail.kt +3 -1
  25. package/nitrogen/generated/android/kotlin/com/margelo/nitro/dawidzawada/bonjourzeroconf/BonjourListener.kt +2 -2
  26. package/nitrogen/generated/android/kotlin/com/margelo/nitro/dawidzawada/bonjourzeroconf/Func_void.kt +1 -1
  27. package/nitrogen/generated/android/kotlin/com/margelo/nitro/dawidzawada/bonjourzeroconf/Func_void_BonjourFail.kt +1 -1
  28. package/nitrogen/generated/android/kotlin/com/margelo/nitro/dawidzawada/bonjourzeroconf/Func_void_bool.kt +1 -1
  29. package/nitrogen/generated/android/kotlin/com/margelo/nitro/dawidzawada/bonjourzeroconf/Func_void_std__vector_ScanResult_.kt +1 -1
  30. package/nitrogen/generated/android/kotlin/com/margelo/nitro/dawidzawada/bonjourzeroconf/HybridBonjourZeroconfSpec.kt +6 -1
  31. package/nitrogen/generated/android/kotlin/com/margelo/nitro/dawidzawada/bonjourzeroconf/ScanOptions.kt +2 -2
  32. package/nitrogen/generated/android/kotlin/com/margelo/nitro/dawidzawada/bonjourzeroconf/ScanResult.kt +2 -2
  33. package/nitrogen/generated/android/kotlin/com/margelo/nitro/dawidzawada/bonjourzeroconf/dawidzawada_bonjourzeroconfOnLoad.kt +1 -1
  34. package/nitrogen/generated/ios/BonjourZeroconf+autolinking.rb +2 -2
  35. package/nitrogen/generated/ios/BonjourZeroconf-Swift-Cxx-Bridge.cpp +17 -17
  36. package/nitrogen/generated/ios/BonjourZeroconf-Swift-Cxx-Bridge.hpp +73 -52
  37. package/nitrogen/generated/ios/BonjourZeroconf-Swift-Cxx-Umbrella.hpp +1 -1
  38. package/nitrogen/generated/ios/BonjourZeroconfAutolinking.mm +1 -1
  39. package/nitrogen/generated/ios/BonjourZeroconfAutolinking.swift +1 -1
  40. package/nitrogen/generated/ios/c++/HybridBonjourZeroconfSpecSwift.cpp +1 -1
  41. package/nitrogen/generated/ios/c++/HybridBonjourZeroconfSpecSwift.hpp +20 -5
  42. package/nitrogen/generated/ios/c++/HybridLocalNetworkPermissionSpecSwift.cpp +1 -1
  43. package/nitrogen/generated/ios/c++/HybridLocalNetworkPermissionSpecSwift.hpp +7 -1
  44. package/nitrogen/generated/ios/swift/BonjourFail.swift +1 -1
  45. package/nitrogen/generated/ios/swift/BonjourListener.swift +8 -17
  46. package/nitrogen/generated/ios/swift/Func_void.swift +1 -1
  47. package/nitrogen/generated/ios/swift/Func_void_BonjourFail.swift +1 -1
  48. package/nitrogen/generated/ios/swift/Func_void_bool.swift +1 -1
  49. package/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift +1 -1
  50. package/nitrogen/generated/ios/swift/Func_void_std__vector_ScanResult_.swift +6 -6
  51. package/nitrogen/generated/ios/swift/HybridBonjourZeroconfSpec.swift +2 -1
  52. package/nitrogen/generated/ios/swift/HybridBonjourZeroconfSpec_cxx.swift +34 -1
  53. package/nitrogen/generated/ios/swift/HybridLocalNetworkPermissionSpec.swift +1 -1
  54. package/nitrogen/generated/ios/swift/HybridLocalNetworkPermissionSpec_cxx.swift +9 -1
  55. package/nitrogen/generated/ios/swift/ScanOptions.swift +3 -15
  56. package/nitrogen/generated/ios/swift/ScanResult.swift +32 -86
  57. package/nitrogen/generated/shared/c++/BonjourFail.hpp +1 -1
  58. package/nitrogen/generated/shared/c++/BonjourListener.hpp +13 -5
  59. package/nitrogen/generated/shared/c++/HybridBonjourZeroconfSpec.cpp +2 -1
  60. package/nitrogen/generated/shared/c++/HybridBonjourZeroconfSpec.hpp +6 -4
  61. package/nitrogen/generated/shared/c++/HybridLocalNetworkPermissionSpec.cpp +1 -1
  62. package/nitrogen/generated/shared/c++/HybridLocalNetworkPermissionSpec.hpp +1 -1
  63. package/nitrogen/generated/shared/c++/ScanOptions.hpp +13 -5
  64. package/nitrogen/generated/shared/c++/ScanResult.hpp +25 -17
  65. package/package.json +5 -6
  66. package/src/specs/BonjourZeroconf.nitro.ts +7 -0
package/README.md CHANGED
@@ -1,3 +1,9 @@
1
+ <picture>
2
+ <source media="(prefers-color-scheme: dark)" srcset="./docs/banner-dark.png" />
3
+ <source media="(prefers-color-scheme: light)" srcset="./docs/banner-light.png" />
4
+ <img alt="BonjourZeroconf" src="./docs/banner-light.png" />
5
+ </picture>
6
+
1
7
  # Bonjour Zeroconf 🇫🇷🥖
2
8
 
3
9
  ⚡ **High-performance Zeroconf/mDNS service discovery for React Native**
@@ -144,6 +150,30 @@ Scanner.scan('_printer._tcp', 'local', {
144
150
  - `_airplay._tcp` – AirPlay devices
145
151
  - `_printer._tcp` – Network printers
146
152
 
153
+ #### `scanFor(time: number, type: string, domain: string, options?: ScanOptions)`
154
+
155
+ Scan for services for a specified duration and return results as a Promise.
156
+
157
+ ```ts
158
+ const devices = await Scanner.scanFor(15, '_http._tcp', 'local');
159
+ console.log('Found devices:', devices);
160
+ ```
161
+
162
+ ```ts
163
+ const devices = await Scanner.scanFor(25, '_printer._tcp', 'local', {
164
+ addressResolveTimeout: 10000, // ms
165
+ });
166
+ ```
167
+
168
+ **Parameters:**
169
+
170
+ - `time` – Duration in seconds to scan before stopping
171
+ - `type` – Service type to discover
172
+ - `domain` – Domain to scan (typically `'local'`)
173
+ - `options` – Optional scan configuration
174
+
175
+ **Returns:** `Promise<ScanResult[]>` – Array of discovered services
176
+
147
177
  #### `stop()`
148
178
 
149
179
  Stop scanning and clear cached results.
@@ -11,6 +11,8 @@ import kotlinx.coroutines.withTimeoutOrNull
11
11
  import java.util.concurrent.Executors
12
12
 
13
13
  suspend fun BonjourZeroconf.resolveService(service: NsdServiceInfo, serviceKey: String, timeout: Long) {
14
+ if (!_isScanning) return
15
+
14
16
  if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
15
17
  // New API (Android 14+)
16
18
  resolveServiceNew(service, serviceKey, timeout)
@@ -52,6 +54,12 @@ suspend fun BonjourZeroconf.resolveServiceNew(service: NsdServiceInfo, serviceKe
52
54
  override fun onServiceUpdated(serviceInfo: NsdServiceInfo) {
53
55
  Log.d(TAG, "Service updated: ${serviceInfo.serviceName}")
54
56
  unregisterCallback()
57
+
58
+ if (!_isScanning) {
59
+ continuation.resume(null) {}
60
+ return
61
+ }
62
+
55
63
  continuation.resume(serviceInfo) {}
56
64
  }
57
65
 
@@ -114,6 +122,12 @@ suspend fun BonjourZeroconf.resolveServiceLegacy(service: NsdServiceInfo, servic
114
122
 
115
123
  override fun onServiceResolved(serviceInfo: NsdServiceInfo) {
116
124
  Log.d(TAG, "Service resolved: ${serviceInfo.serviceName}")
125
+
126
+ if (!_isScanning) {
127
+ continuation.resume(null) {}
128
+ return
129
+ }
130
+
117
131
  continuation.resume(serviceInfo) {}
118
132
  }
119
133
  }
@@ -8,9 +8,11 @@ import com.facebook.proguard.annotations.DoNotStrip
8
8
  import java.util.UUID
9
9
  import java.util.concurrent.ConcurrentHashMap
10
10
  import com.margelo.nitro.NitroModules
11
+ import com.margelo.nitro.core.Promise
11
12
  import kotlinx.coroutines.CoroutineScope
12
13
  import kotlinx.coroutines.Dispatchers
13
14
  import kotlinx.coroutines.SupervisorJob
15
+ import kotlinx.coroutines.cancelChildren
14
16
  import kotlinx.coroutines.launch
15
17
  import kotlinx.coroutines.sync.Mutex
16
18
 
@@ -33,6 +35,7 @@ class BonjourZeroconf : HybridBonjourZeroconfSpec() {
33
35
  internal var currentDiscoveryListener: NsdManager.DiscoveryListener? = null
34
36
  internal val serviceCache = ConcurrentHashMap<String, ScanResult>()
35
37
  internal val scope = CoroutineScope(SupervisorJob() + Dispatchers.Default)
38
+ internal val resolveScope = CoroutineScope(SupervisorJob() + Dispatchers.Default)
36
39
  internal val legacyResolveMutex = Mutex()
37
40
 
38
41
  override val isScanning: Boolean
@@ -68,7 +71,28 @@ class BonjourZeroconf : HybridBonjourZeroconfSpec() {
68
71
  }
69
72
  }
70
73
 
74
+ override fun scanFor(
75
+ time: Double,
76
+ type: String,
77
+ domain: String,
78
+ options: ScanOptions?
79
+ ): Promise<Array<ScanResult>> {
80
+ return Promise.async {
81
+ scan(type, domain, options)
82
+
83
+ kotlinx.coroutines.delay((time * 1000).toLong())
84
+
85
+ val results = serviceCache.values.toTypedArray()
86
+
87
+ stop()
88
+
89
+ results
90
+ }
91
+ }
92
+
71
93
  override fun stop() {
94
+ resolveScope.coroutineContext.cancelChildren()
95
+
72
96
  currentDiscoveryListener?.let { listener ->
73
97
  try {
74
98
  nsdManager?.stopServiceDiscovery(listener)
@@ -142,7 +166,7 @@ class BonjourZeroconf : HybridBonjourZeroconfSpec() {
142
166
  return
143
167
  }
144
168
 
145
- scope.launch {
169
+ resolveScope.launch {
146
170
  try {
147
171
  resolveService(service, serviceKey, resolveTimeout)
148
172
  } catch (e: Exception) {
@@ -6,15 +6,18 @@
6
6
  //
7
7
 
8
8
  enum AddressResolverError: Error {
9
- case timeout
10
- case extractionFailed
11
-
12
- var localizedDescription: String {
13
- switch self {
14
- case .timeout:
15
- return "Connection timed out"
16
- case .extractionFailed:
17
- return "Failed to extract IP and port information"
18
- }
9
+ case timeout
10
+ case extractionFailed
11
+ case cancelled
12
+
13
+ var localizedDescription: String {
14
+ switch self {
15
+ case .timeout:
16
+ return "Connection timed out"
17
+ case .extractionFailed:
18
+ return "Failed to extract IP and port information"
19
+ case .cancelled:
20
+ return "Cancelled resolve process"
19
21
  }
22
+ }
20
23
  }
@@ -9,25 +9,41 @@ import Network
9
9
  extension BonjourZeroconf {
10
10
  /// Resolve a service to get its IP address and port using async/await
11
11
  internal func resolveService(result: NWBrowser.Result, name: String, timeout: TimeInterval) async -> ScanResult? {
12
+ let taskId = UUID()
13
+
12
14
  do {
13
15
  return try await withCheckedThrowingContinuation { continuation in
14
16
  let connection = NWConnection(to: result.endpoint, using: .tcp)
15
17
 
16
- final class ResumeBox {
17
- var hasResumed = false
18
+ resolveLock.lock()
19
+ guard _isScanning else {
20
+ resolveLock.unlock()
21
+ continuation.resume(throwing: AddressResolverError.cancelled)
22
+ return
18
23
  }
24
+ activeConnections[taskId] = connection
25
+ resolveLock.unlock()
26
+
27
+ final class ResumeBox { var hasResumed = false }
19
28
  let box = ResumeBox()
20
29
 
21
- let timeoutTask = DispatchWorkItem {
30
+ let timeoutTask = DispatchWorkItem { [weak self] in
31
+ guard let self = self else { return }
22
32
  guard !box.hasResumed else { return }
23
33
  box.hasResumed = true
24
34
  Loggy.log(.debug, message: "Timeout resolving \(name)")
25
35
  continuation.resume(throwing: AddressResolverError.timeout)
26
- connection.cancel()
36
+ self.cleanupResolve(connection: connection, taskId: taskId)
27
37
  }
38
+
39
+ resolveLock.lock()
40
+ activeTimeouts[taskId] = timeoutTask
41
+ resolveLock.unlock()
42
+
28
43
  networkQueue.asyncAfter(deadline: .now() + timeout, execute: timeoutTask)
29
44
 
30
45
  connection.stateUpdateHandler = { [weak self] state in
46
+ guard let self = self else { return }
31
47
  switch state {
32
48
  case .ready:
33
49
  timeoutTask.cancel()
@@ -35,12 +51,12 @@ extension BonjourZeroconf {
35
51
  box.hasResumed = true
36
52
 
37
53
  if let remoteEndpoint = connection.currentPath?.remoteEndpoint,
38
- let scanResult = self?.extractIPAndPort(from: remoteEndpoint, serviceName: name) {
54
+ let scanResult = self.extractIPAndPort(from: remoteEndpoint, serviceName: name) {
39
55
  continuation.resume(returning: scanResult)
40
56
  } else {
41
57
  continuation.resume(throwing: AddressResolverError.extractionFailed)
42
58
  }
43
- connection.cancel()
59
+ self.cleanupResolve(connection: connection, taskId: taskId)
44
60
 
45
61
  case .failed(let error):
46
62
  timeoutTask.cancel()
@@ -48,7 +64,7 @@ extension BonjourZeroconf {
48
64
  box.hasResumed = true
49
65
  Loggy.log(.error, message: "Failed to resolve service \(name): \(error.localizedDescription)")
50
66
  continuation.resume(throwing: error)
51
- connection.cancel()
67
+ self.cleanupResolve(connection: connection, taskId: taskId)
52
68
 
53
69
  case .waiting(let error):
54
70
  Loggy.log(.debug, message: "Connection waiting for \(name): \(error.localizedDescription)")
@@ -61,25 +77,46 @@ extension BonjourZeroconf {
61
77
  }
62
78
  }
63
79
 
64
- connection.start(queue: networkQueue)
80
+ connection.start(queue: networkQueue)
65
81
  }
66
82
  } catch let error as AddressResolverError {
67
- switch error {
68
- case .timeout:
69
- notifyScanFailListeners(with: BonjourFail.resolveFailed)
70
- break;
71
- case .extractionFailed:
72
- notifyScanFailListeners(with: BonjourFail.extractionFailed)
73
- break;
74
- }
75
- return nil
76
- } catch {
77
- return nil
78
- }
83
+ switch error {
84
+ case .timeout:
85
+ notifyScanFailListeners(with: BonjourFail.resolveFailed)
86
+ case .extractionFailed:
87
+ notifyScanFailListeners(with: BonjourFail.extractionFailed)
88
+ case .cancelled:
89
+ Loggy.log(.debug, message: "Scanning stopped, cancelling address resolution")
90
+ break
91
+ }
92
+ return nil
93
+ } catch {
94
+ return nil
95
+ }
96
+ }
97
+
98
+ /// Cancels ongoing address resolve process
99
+ internal func cancelAddressResolving() {
100
+ Loggy.log(.debug, message: "Cancelling Address Resolving")
101
+ resolveLock.lock()
102
+ activeTimeouts.values.forEach { $0.cancel() }
103
+ activeTimeouts.removeAll()
104
+ activeConnections.values.forEach { $0.cancel() }
105
+ activeConnections.removeAll()
106
+ resolveLock.unlock()
107
+ }
108
+
109
+ /// Cleans up after single resolve process
110
+ private func cleanupResolve(connection: NWConnection, taskId: UUID) {
111
+ connection.cancel()
112
+ resolveLock.lock()
113
+ activeConnections.removeValue(forKey: taskId)
114
+ activeTimeouts.removeValue(forKey: taskId)
115
+ resolveLock.unlock()
79
116
  }
80
117
 
81
118
  /// Extract IP address and port from an endpoint
82
- internal func extractIPAndPort(from endpoint: NWEndpoint, serviceName: String) -> ScanResult? {
119
+ private func extractIPAndPort(from endpoint: NWEndpoint, serviceName: String) -> ScanResult? {
83
120
  switch endpoint {
84
121
  case .hostPort(let host, let port):
85
122
  var ipv4: String?
@@ -12,6 +12,11 @@ class BonjourZeroconf: HybridBonjourZeroconfSpec {
12
12
  internal var scanStateListeners: [UUID: (Bool) -> Void] = [:]
13
13
  internal var scanFailListeners: [UUID: (BonjourFail) -> Void] = [:]
14
14
  internal let networkQueue = DispatchQueue(label: "com.bonjour-zeroconf.network", qos: .userInitiated)
15
+ internal let timeoutScanQueue = DispatchQueue(label: "com.bonjour-zeroconf.scan", qos: .userInitiated)
16
+
17
+ internal var activeConnections: [UUID: NWConnection] = [:]
18
+ internal var activeTimeouts: [UUID: DispatchWorkItem] = [:]
19
+ internal let resolveLock = NSLock()
15
20
 
16
21
  var isScanning: Bool {
17
22
  return _isScanning
@@ -72,6 +77,20 @@ class BonjourZeroconf: HybridBonjourZeroconfSpec {
72
77
  browser.start(queue: networkQueue)
73
78
  }
74
79
 
80
+ func scanFor(time: Double, type: String, domain: String, options: ScanOptions?) throws -> Promise<[ScanResult]> {
81
+ return Promise.async {
82
+ self.scan(type: type, domain: domain, options: options)
83
+
84
+ try await Task.sleep(nanoseconds: UInt64(time * 1_000_000_000))
85
+
86
+ let results = await self.serviceCache.getAll()
87
+
88
+ self.stop()
89
+
90
+ return results
91
+ }
92
+ }
93
+
75
94
  func listenForScanResults(onResult: @escaping ([ScanResult]) -> Void) -> BonjourListener {
76
95
  let listenerId = UUID()
77
96
  self.scanResultsListeners[listenerId] = onResult
@@ -111,6 +130,8 @@ class BonjourZeroconf: HybridBonjourZeroconfSpec {
111
130
  if let browser = self._browser {
112
131
  browser.cancel()
113
132
  }
133
+
134
+ cancelAddressResolving()
114
135
 
115
136
  self._isScanning = false
116
137
  Task {
@@ -49,7 +49,6 @@ public class LocalNetworkAuthorization: NSObject {
49
49
  }
50
50
 
51
51
  private func reset() {
52
- print("resetting")
53
52
  self.browser?.cancel()
54
53
  self.browser = nil
55
54
  self.netService?.stop()
@@ -11,6 +11,7 @@ export interface BonjourZeroconf extends HybridObject<{
11
11
  }> {
12
12
  readonly isScanning: boolean;
13
13
  scan(type: string, domain: string, options?: ScanOptions): void;
14
+ scanFor(time: number, type: string, domain: string, options?: ScanOptions): Promise<ScanResult[]>;
14
15
  stop(): void;
15
16
  listenForScanResults(onResult: (results: ScanResult[]) => void): BonjourListener;
16
17
  listenForScanState(onChange: (isScanning: boolean) => void): BonjourListener;
@@ -1 +1 @@
1
- {"version":3,"file":"BonjourZeroconf.nitro.d.ts","sourceRoot":"","sources":["../../../../src/specs/BonjourZeroconf.nitro.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE/C,MAAM,WAAW,WAAW;IAC1B,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,eACf,SAAQ,YAAY,CAAC;IAAE,GAAG,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,QAAQ,CAAA;CAAE,CAAC;IACzD,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IAChE,IAAI,IAAI,IAAI,CAAC;IACb,oBAAoB,CAClB,QAAQ,EAAE,CAAC,OAAO,EAAE,UAAU,EAAE,KAAK,IAAI,GACxC,eAAe,CAAC;IACnB,kBAAkB,CAAC,QAAQ,EAAE,CAAC,UAAU,EAAE,OAAO,KAAK,IAAI,GAAG,eAAe,CAAC;IAC7E,iBAAiB,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,IAAI,GAAG,eAAe,CAAC;CACzE"}
1
+ {"version":3,"file":"BonjourZeroconf.nitro.d.ts","sourceRoot":"","sources":["../../../../src/specs/BonjourZeroconf.nitro.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE/C,MAAM,WAAW,WAAW;IAC1B,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,eACf,SAAQ,YAAY,CAAC;IAAE,GAAG,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,QAAQ,CAAA;CAAE,CAAC;IACzD,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAE7B,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IAChE,OAAO,CACL,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;IACzB,IAAI,IAAI,IAAI,CAAC;IACb,oBAAoB,CAClB,QAAQ,EAAE,CAAC,OAAO,EAAE,UAAU,EAAE,KAAK,IAAI,GACxC,eAAe,CAAC;IACnB,kBAAkB,CAAC,QAAQ,EAAE,CAAC,UAAU,EAAE,OAAO,KAAK,IAAI,GAAG,eAAe,CAAC;IAC7E,iBAAiB,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,IAAI,GAAG,eAAe,CAAC;CACzE"}
@@ -2,7 +2,7 @@
2
2
  /// JBonjourFail.hpp
3
3
  /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
4
  /// https://github.com/mrousavy/nitro
5
- /// Copyright © 2025 Marc Rousavy @ Margelo
5
+ /// Copyright © Marc Rousavy @ Margelo
6
6
  ///
7
7
 
8
8
  #pragma once
@@ -41,16 +41,15 @@ namespace margelo::nitro::dawidzawada_bonjourzeroconf {
41
41
  [[maybe_unused]]
42
42
  static jni::alias_ref<JBonjourFail> fromCpp(BonjourFail value) {
43
43
  static const auto clazz = javaClassStatic();
44
- static const auto fieldRESOLVE_FAILED = clazz->getStaticField<JBonjourFail>("RESOLVE_FAILED");
45
- static const auto fieldEXTRACTION_FAILED = clazz->getStaticField<JBonjourFail>("EXTRACTION_FAILED");
46
- static const auto fieldDISCOVERY_FAILED = clazz->getStaticField<JBonjourFail>("DISCOVERY_FAILED");
47
-
48
44
  switch (value) {
49
45
  case BonjourFail::RESOLVE_FAILED:
46
+ static const auto fieldRESOLVE_FAILED = clazz->getStaticField<JBonjourFail>("RESOLVE_FAILED");
50
47
  return clazz->getStaticFieldValue(fieldRESOLVE_FAILED);
51
48
  case BonjourFail::EXTRACTION_FAILED:
49
+ static const auto fieldEXTRACTION_FAILED = clazz->getStaticField<JBonjourFail>("EXTRACTION_FAILED");
52
50
  return clazz->getStaticFieldValue(fieldEXTRACTION_FAILED);
53
51
  case BonjourFail::DISCOVERY_FAILED:
52
+ static const auto fieldDISCOVERY_FAILED = clazz->getStaticField<JBonjourFail>("DISCOVERY_FAILED");
54
53
  return clazz->getStaticFieldValue(fieldDISCOVERY_FAILED);
55
54
  default:
56
55
  std::string stringValue = std::to_string(static_cast<int>(value));
@@ -2,7 +2,7 @@
2
2
  /// JBonjourListener.hpp
3
3
  /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
4
  /// https://github.com/mrousavy/nitro
5
- /// Copyright © 2025 Marc Rousavy @ Margelo
5
+ /// Copyright © Marc Rousavy @ Margelo
6
6
  ///
7
7
 
8
8
  #pragma once
@@ -11,6 +11,7 @@
11
11
  #include "BonjourListener.hpp"
12
12
 
13
13
  #include "JFunc_void.hpp"
14
+ #include <NitroModules/JNICallable.hpp>
14
15
  #include <functional>
15
16
 
16
17
  namespace margelo::nitro::dawidzawada_bonjourzeroconf {
@@ -41,9 +42,7 @@ namespace margelo::nitro::dawidzawada_bonjourzeroconf {
41
42
  return downcast->cthis()->getFunction();
42
43
  } else {
43
44
  auto removeRef = jni::make_global(remove);
44
- return [removeRef]() -> void {
45
- return removeRef->invoke();
46
- };
45
+ return JNICallable<JFunc_void, void()>(std::move(removeRef));
47
46
  }
48
47
  }()
49
48
  );
@@ -2,7 +2,7 @@
2
2
  /// JFunc_void.hpp
3
3
  /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
4
  /// https://github.com/mrousavy/nitro
5
- /// Copyright © 2025 Marc Rousavy @ Margelo
5
+ /// Copyright © Marc Rousavy @ Margelo
6
6
  ///
7
7
 
8
8
  #pragma once
@@ -11,6 +11,7 @@
11
11
  #include <functional>
12
12
 
13
13
  #include <functional>
14
+ #include <NitroModules/JNICallable.hpp>
14
15
 
15
16
  namespace margelo::nitro::dawidzawada_bonjourzeroconf {
16
17
 
@@ -37,7 +38,7 @@ namespace margelo::nitro::dawidzawada_bonjourzeroconf {
37
38
  /**
38
39
  * An implementation of Func_void that is backed by a C++ implementation (using `std::function<...>`)
39
40
  */
40
- struct JFunc_void_cxx final: public jni::HybridClass<JFunc_void_cxx, JFunc_void> {
41
+ class JFunc_void_cxx final: public jni::HybridClass<JFunc_void_cxx, JFunc_void> {
41
42
  public:
42
43
  static jni::local_ref<JFunc_void::javaobject> fromCpp(const std::function<void()>& func) {
43
44
  return JFunc_void_cxx::newObjectCxxArgs(func);
@@ -2,7 +2,7 @@
2
2
  /// JFunc_void_BonjourFail.hpp
3
3
  /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
4
  /// https://github.com/mrousavy/nitro
5
- /// Copyright © 2025 Marc Rousavy @ Margelo
5
+ /// Copyright © Marc Rousavy @ Margelo
6
6
  ///
7
7
 
8
8
  #pragma once
@@ -12,6 +12,7 @@
12
12
 
13
13
  #include "BonjourFail.hpp"
14
14
  #include <functional>
15
+ #include <NitroModules/JNICallable.hpp>
15
16
  #include "JBonjourFail.hpp"
16
17
 
17
18
  namespace margelo::nitro::dawidzawada_bonjourzeroconf {
@@ -39,7 +40,7 @@ namespace margelo::nitro::dawidzawada_bonjourzeroconf {
39
40
  /**
40
41
  * An implementation of Func_void_BonjourFail that is backed by a C++ implementation (using `std::function<...>`)
41
42
  */
42
- struct JFunc_void_BonjourFail_cxx final: public jni::HybridClass<JFunc_void_BonjourFail_cxx, JFunc_void_BonjourFail> {
43
+ class JFunc_void_BonjourFail_cxx final: public jni::HybridClass<JFunc_void_BonjourFail_cxx, JFunc_void_BonjourFail> {
43
44
  public:
44
45
  static jni::local_ref<JFunc_void_BonjourFail::javaobject> fromCpp(const std::function<void(BonjourFail /* fail */)>& func) {
45
46
  return JFunc_void_BonjourFail_cxx::newObjectCxxArgs(func);
@@ -2,7 +2,7 @@
2
2
  /// JFunc_void_bool.hpp
3
3
  /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
4
  /// https://github.com/mrousavy/nitro
5
- /// Copyright © 2025 Marc Rousavy @ Margelo
5
+ /// Copyright © Marc Rousavy @ Margelo
6
6
  ///
7
7
 
8
8
  #pragma once
@@ -11,6 +11,7 @@
11
11
  #include <functional>
12
12
 
13
13
  #include <functional>
14
+ #include <NitroModules/JNICallable.hpp>
14
15
 
15
16
  namespace margelo::nitro::dawidzawada_bonjourzeroconf {
16
17
 
@@ -37,7 +38,7 @@ namespace margelo::nitro::dawidzawada_bonjourzeroconf {
37
38
  /**
38
39
  * An implementation of Func_void_bool that is backed by a C++ implementation (using `std::function<...>`)
39
40
  */
40
- struct JFunc_void_bool_cxx final: public jni::HybridClass<JFunc_void_bool_cxx, JFunc_void_bool> {
41
+ class JFunc_void_bool_cxx final: public jni::HybridClass<JFunc_void_bool_cxx, JFunc_void_bool> {
41
42
  public:
42
43
  static jni::local_ref<JFunc_void_bool::javaobject> fromCpp(const std::function<void(bool /* isScanning */)>& func) {
43
44
  return JFunc_void_bool_cxx::newObjectCxxArgs(func);
@@ -2,7 +2,7 @@
2
2
  /// JFunc_void_std__vector_ScanResult_.hpp
3
3
  /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
4
  /// https://github.com/mrousavy/nitro
5
- /// Copyright © 2025 Marc Rousavy @ Margelo
5
+ /// Copyright © Marc Rousavy @ Margelo
6
6
  ///
7
7
 
8
8
  #pragma once
@@ -13,6 +13,7 @@
13
13
  #include "ScanResult.hpp"
14
14
  #include <vector>
15
15
  #include <functional>
16
+ #include <NitroModules/JNICallable.hpp>
16
17
  #include "JScanResult.hpp"
17
18
  #include <string>
18
19
  #include <optional>
@@ -51,7 +52,7 @@ namespace margelo::nitro::dawidzawada_bonjourzeroconf {
51
52
  /**
52
53
  * An implementation of Func_void_std__vector_ScanResult_ that is backed by a C++ implementation (using `std::function<...>`)
53
54
  */
54
- struct JFunc_void_std__vector_ScanResult__cxx final: public jni::HybridClass<JFunc_void_std__vector_ScanResult__cxx, JFunc_void_std__vector_ScanResult_> {
55
+ class JFunc_void_std__vector_ScanResult__cxx final: public jni::HybridClass<JFunc_void_std__vector_ScanResult__cxx, JFunc_void_std__vector_ScanResult_> {
55
56
  public:
56
57
  static jni::local_ref<JFunc_void_std__vector_ScanResult_::javaobject> fromCpp(const std::function<void(const std::vector<ScanResult>& /* results */)>& func) {
57
58
  return JFunc_void_std__vector_ScanResult__cxx::newObjectCxxArgs(func);
@@ -2,32 +2,35 @@
2
2
  /// JHybridBonjourZeroconfSpec.cpp
3
3
  /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
4
  /// https://github.com/mrousavy/nitro
5
- /// Copyright © 2025 Marc Rousavy @ Margelo
5
+ /// Copyright © Marc Rousavy @ Margelo
6
6
  ///
7
7
 
8
8
  #include "JHybridBonjourZeroconfSpec.hpp"
9
9
 
10
+ // Forward declaration of `ScanResult` to properly resolve imports.
11
+ namespace margelo::nitro::dawidzawada_bonjourzeroconf { struct ScanResult; }
10
12
  // Forward declaration of `BonjourListener` to properly resolve imports.
11
13
  namespace margelo::nitro::dawidzawada_bonjourzeroconf { struct BonjourListener; }
12
14
  // Forward declaration of `ScanOptions` to properly resolve imports.
13
15
  namespace margelo::nitro::dawidzawada_bonjourzeroconf { struct ScanOptions; }
14
- // Forward declaration of `ScanResult` to properly resolve imports.
15
- namespace margelo::nitro::dawidzawada_bonjourzeroconf { struct ScanResult; }
16
16
  // Forward declaration of `BonjourFail` to properly resolve imports.
17
17
  namespace margelo::nitro::dawidzawada_bonjourzeroconf { enum class BonjourFail; }
18
18
 
19
+ #include "ScanResult.hpp"
20
+ #include <vector>
21
+ #include <NitroModules/Promise.hpp>
22
+ #include <NitroModules/JPromise.hpp>
23
+ #include "JScanResult.hpp"
24
+ #include <string>
25
+ #include <optional>
19
26
  #include "BonjourListener.hpp"
20
27
  #include "JBonjourListener.hpp"
21
28
  #include <functional>
22
29
  #include "JFunc_void.hpp"
23
- #include <string>
30
+ #include <NitroModules/JNICallable.hpp>
24
31
  #include "ScanOptions.hpp"
25
- #include <optional>
26
32
  #include "JScanOptions.hpp"
27
- #include "ScanResult.hpp"
28
- #include <vector>
29
33
  #include "JFunc_void_std__vector_ScanResult_.hpp"
30
- #include "JScanResult.hpp"
31
34
  #include "JFunc_void_bool.hpp"
32
35
  #include "BonjourFail.hpp"
33
36
  #include "JFunc_void_BonjourFail.hpp"
@@ -50,6 +53,13 @@ namespace margelo::nitro::dawidzawada_bonjourzeroconf {
50
53
  return method(_javaPart);
51
54
  }
52
55
 
56
+ bool JHybridBonjourZeroconfSpec::equals(const std::shared_ptr<HybridObject>& other) {
57
+ if (auto otherCast = std::dynamic_pointer_cast<JHybridBonjourZeroconfSpec>(other)) {
58
+ return _javaPart == otherCast->_javaPart;
59
+ }
60
+ return false;
61
+ }
62
+
53
63
  void JHybridBonjourZeroconfSpec::dispose() noexcept {
54
64
  static const auto method = javaClassStatic()->getMethod<void()>("dispose");
55
65
  method(_javaPart);
@@ -73,6 +83,31 @@ namespace margelo::nitro::dawidzawada_bonjourzeroconf {
73
83
  static const auto method = javaClassStatic()->getMethod<void(jni::alias_ref<jni::JString> /* type */, jni::alias_ref<jni::JString> /* domain */, jni::alias_ref<JScanOptions> /* options */)>("scan");
74
84
  method(_javaPart, jni::make_jstring(type), jni::make_jstring(domain), options.has_value() ? JScanOptions::fromCpp(options.value()) : nullptr);
75
85
  }
86
+ std::shared_ptr<Promise<std::vector<ScanResult>>> JHybridBonjourZeroconfSpec::scanFor(double time, const std::string& type, const std::string& domain, const std::optional<ScanOptions>& options) {
87
+ static const auto method = javaClassStatic()->getMethod<jni::local_ref<JPromise::javaobject>(double /* time */, jni::alias_ref<jni::JString> /* type */, jni::alias_ref<jni::JString> /* domain */, jni::alias_ref<JScanOptions> /* options */)>("scanFor");
88
+ auto __result = method(_javaPart, time, jni::make_jstring(type), jni::make_jstring(domain), options.has_value() ? JScanOptions::fromCpp(options.value()) : nullptr);
89
+ return [&]() {
90
+ auto __promise = Promise<std::vector<ScanResult>>::create();
91
+ __result->cthis()->addOnResolvedListener([=](const jni::alias_ref<jni::JObject>& __boxedResult) {
92
+ auto __result = jni::static_ref_cast<jni::JArrayClass<JScanResult>>(__boxedResult);
93
+ __promise->resolve([&]() {
94
+ size_t __size = __result->size();
95
+ std::vector<ScanResult> __vector;
96
+ __vector.reserve(__size);
97
+ for (size_t __i = 0; __i < __size; __i++) {
98
+ auto __element = __result->getElement(__i);
99
+ __vector.push_back(__element->toCpp());
100
+ }
101
+ return __vector;
102
+ }());
103
+ });
104
+ __result->cthis()->addOnRejectedListener([=](const jni::alias_ref<jni::JThrowable>& __throwable) {
105
+ jni::JniException __jniError(__throwable);
106
+ __promise->reject(std::make_exception_ptr(__jniError));
107
+ });
108
+ return __promise;
109
+ }();
110
+ }
76
111
  void JHybridBonjourZeroconfSpec::stop() {
77
112
  static const auto method = javaClassStatic()->getMethod<void()>("stop");
78
113
  method(_javaPart);
@@ -2,7 +2,7 @@
2
2
  /// HybridBonjourZeroconfSpec.hpp
3
3
  /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
4
  /// https://github.com/mrousavy/nitro
5
- /// Copyright © 2025 Marc Rousavy @ Margelo
5
+ /// Copyright © Marc Rousavy @ Margelo
6
6
  ///
7
7
 
8
8
  #pragma once
@@ -40,6 +40,7 @@ namespace margelo::nitro::dawidzawada_bonjourzeroconf {
40
40
 
41
41
  public:
42
42
  size_t getExternalMemorySize() noexcept override;
43
+ bool equals(const std::shared_ptr<HybridObject>& other) override;
43
44
  void dispose() noexcept override;
44
45
  std::string toString() override;
45
46
 
@@ -55,6 +56,7 @@ namespace margelo::nitro::dawidzawada_bonjourzeroconf {
55
56
  public:
56
57
  // Methods
57
58
  void scan(const std::string& type, const std::string& domain, const std::optional<ScanOptions>& options) override;
59
+ std::shared_ptr<Promise<std::vector<ScanResult>>> scanFor(double time, const std::string& type, const std::string& domain, const std::optional<ScanOptions>& options) override;
58
60
  void stop() override;
59
61
  BonjourListener listenForScanResults(const std::function<void(const std::vector<ScanResult>& /* results */)>& onResult) override;
60
62
  BonjourListener listenForScanState(const std::function<void(bool /* isScanning */)>& onChange) override;
@@ -2,7 +2,7 @@
2
2
  /// JScanOptions.hpp
3
3
  /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
4
  /// https://github.com/mrousavy/nitro
5
- /// Copyright © 2025 Marc Rousavy @ Margelo
5
+ /// Copyright © Marc Rousavy @ Margelo
6
6
  ///
7
7
 
8
8
  #pragma once
@@ -2,7 +2,7 @@
2
2
  /// JScanResult.hpp
3
3
  /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
4
  /// https://github.com/mrousavy/nitro
5
- /// Copyright © 2025 Marc Rousavy @ Margelo
5
+ /// Copyright © Marc Rousavy @ Margelo
6
6
  ///
7
7
 
8
8
  #pragma once