react-native-zeroconf 0.17.3 → 1.0.0-rc.1

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 (114) hide show
  1. package/NOTICE +2 -6
  2. package/README.md +1 -1
  3. package/android/CMakeLists.txt +64 -0
  4. package/android/build.gradle +1 -17
  5. package/android/generated/java/com/balthazargronon/RCTZeroconf/NativeZeroconfSpec.java +96 -0
  6. package/android/generated/jni/CMakeLists.txt +28 -0
  7. package/android/generated/jni/RNZeroconfSpec-generated.cpp +77 -0
  8. package/android/generated/jni/RNZeroconfSpec.h +31 -0
  9. package/android/generated/jni/react/renderer/components/RNZeroconfSpec/RNZeroconfSpecJSI.h +798 -0
  10. package/android/src/main/java/com/balthazargronon/RCTZeroconf/{ZeroconfModule.java → NsdHost.java} +97 -140
  11. package/android/src/main/java/com/balthazargronon/RCTZeroconf/NsdPayload.java +87 -0
  12. package/android/src/main/java/com/balthazargronon/RCTZeroconf/NsdPromise.java +40 -0
  13. package/android/src/main/java/com/balthazargronon/RCTZeroconf/Zeroconf.java +4 -6
  14. package/android/src/main/java/com/balthazargronon/RCTZeroconf/ZeroconfNativeSupport.java +60 -0
  15. package/android/src/main/java/com/balthazargronon/RCTZeroconf/ZeroconfOptions.java +15 -26
  16. package/android/src/main/java/com/balthazargronon/RCTZeroconf/ZeroconfReactPackage.java +5 -15
  17. package/android/src/main/java/com/balthazargronon/RCTZeroconf/nsd/NsdServiceImpl.java +90 -96
  18. package/android/src/main/jni/mdnsresponder/mDNSShared/dnssd_clientshim.c +31 -6
  19. package/cpp/Backend.cpp +16 -0
  20. package/cpp/Backend.h +116 -0
  21. package/cpp/ZeroconfModule.cpp +280 -0
  22. package/cpp/ZeroconfModule.h +144 -0
  23. package/cpp/android/NsdBackend.cpp +462 -0
  24. package/cpp/android/NsdBackend.h +61 -0
  25. package/cpp/android/ZeroconfAndroidModule.cpp +49 -0
  26. package/cpp/android/ZeroconfAndroidModule.h +15 -0
  27. package/cpp/apple/DispatchExecutor.cpp +66 -0
  28. package/cpp/apple/DispatchExecutor.h +37 -0
  29. package/cpp/apple/LocalNetworkAccess.h +19 -0
  30. package/cpp/apple/LocalNetworkAccess.mm +87 -0
  31. package/cpp/dnssd/DnssdBackend.cpp +976 -0
  32. package/cpp/dnssd/DnssdBackend.h +114 -0
  33. package/cpp/dnssd/Executor.h +28 -0
  34. package/cpp/embedded/EmbeddedExecutor.cpp +124 -0
  35. package/cpp/embedded/EmbeddedExecutor.h +57 -0
  36. package/ios/ZeroconfOnLoad.mm +34 -0
  37. package/ios/generated/ReactCodegen/RNZeroconfSpec/RNZeroconfSpec-generated.mm +140 -0
  38. package/ios/generated/ReactCodegen/RNZeroconfSpec/RNZeroconfSpec.h +189 -0
  39. package/ios/generated/ReactCodegen/RNZeroconfSpecJSI.h +798 -0
  40. package/lib/module/NativeZeroconf.js +15 -0
  41. package/lib/module/NativeZeroconf.js.map +1 -0
  42. package/lib/module/bridge.js +124 -0
  43. package/lib/module/bridge.js.map +1 -0
  44. package/{dist → lib/module}/index.js +149 -149
  45. package/lib/module/index.js.map +1 -0
  46. package/lib/module/package.json +1 -0
  47. package/lib/module/types.js +24 -0
  48. package/lib/module/types.js.map +1 -0
  49. package/lib/typescript/package.json +1 -0
  50. package/lib/typescript/src/NativeZeroconf.d.ts +75 -0
  51. package/lib/typescript/src/NativeZeroconf.d.ts.map +1 -0
  52. package/lib/typescript/src/bridge.d.ts +22 -0
  53. package/lib/typescript/src/bridge.d.ts.map +1 -0
  54. package/lib/typescript/src/index.d.ts +111 -0
  55. package/lib/typescript/src/index.d.ts.map +1 -0
  56. package/lib/typescript/src/types.d.ts +175 -0
  57. package/lib/typescript/src/types.d.ts.map +1 -0
  58. package/package.json +64 -29
  59. package/react-native-zeroconf.podspec +2 -1
  60. package/react-native.config.js +17 -0
  61. package/src/NativeZeroconf.ts +120 -0
  62. package/src/bridge.ts +153 -0
  63. package/src/index.ts +607 -0
  64. package/{index.d.ts → src/types.ts} +5 -99
  65. package/windows/RNZeroconf/RNZeroconf.vcxproj +17 -2
  66. package/windows/RNZeroconf/RNZeroconf.vcxproj.filters +0 -6
  67. package/windows/RNZeroconf/ReactPackageProvider.cpp +23 -20
  68. package/windows/RNZeroconf/WindowsBackend.cpp +156 -0
  69. package/windows/RNZeroconf/WindowsBackend.h +13 -0
  70. package/windows/RNZeroconf/ZeroconfCore.cpp +2 -2
  71. package/windows/RNZeroconf/ZeroconfCore.h +2 -2
  72. package/windows/RNZeroconf/ZeroconfWindowsModule.cpp +22 -0
  73. package/windows/RNZeroconf/ZeroconfWindowsModule.h +14 -0
  74. package/android/src/main/java/com/balthazargronon/RCTZeroconf/ZeroConfImplFactory.java +0 -56
  75. package/android/src/main/java/com/balthazargronon/RCTZeroconf/dnssd/DnssdImpl.java +0 -654
  76. package/android/src/main/java/com/github/druk/dnssd/BaseListener.java +0 -33
  77. package/android/src/main/java/com/github/druk/dnssd/BrowseListener.java +0 -67
  78. package/android/src/main/java/com/github/druk/dnssd/DNSRecord.java +0 -47
  79. package/android/src/main/java/com/github/druk/dnssd/DNSSD.java +0 -681
  80. package/android/src/main/java/com/github/druk/dnssd/DNSSDEmbedded.java +0 -198
  81. package/android/src/main/java/com/github/druk/dnssd/DNSSDException.java +0 -66
  82. package/android/src/main/java/com/github/druk/dnssd/DNSSDRecordRegistrar.java +0 -55
  83. package/android/src/main/java/com/github/druk/dnssd/DNSSDRegistration.java +0 -54
  84. package/android/src/main/java/com/github/druk/dnssd/DNSSDService.java +0 -35
  85. package/android/src/main/java/com/github/druk/dnssd/DomainListener.java +0 -57
  86. package/android/src/main/java/com/github/druk/dnssd/InternalBrowseListener.java +0 -76
  87. package/android/src/main/java/com/github/druk/dnssd/InternalDNSSD.java +0 -870
  88. package/android/src/main/java/com/github/druk/dnssd/InternalDNSSDRecordRegistrar.java +0 -30
  89. package/android/src/main/java/com/github/druk/dnssd/InternalDNSSDRegistration.java +0 -34
  90. package/android/src/main/java/com/github/druk/dnssd/InternalDNSSDService.java +0 -29
  91. package/android/src/main/java/com/github/druk/dnssd/InternalDomainListener.java +0 -62
  92. package/android/src/main/java/com/github/druk/dnssd/InternalQueryListener.java +0 -61
  93. package/android/src/main/java/com/github/druk/dnssd/InternalRegisterListener.java +0 -51
  94. package/android/src/main/java/com/github/druk/dnssd/InternalResolveListener.java +0 -58
  95. package/android/src/main/java/com/github/druk/dnssd/NSClass.java +0 -16
  96. package/android/src/main/java/com/github/druk/dnssd/NSType.java +0 -58
  97. package/android/src/main/java/com/github/druk/dnssd/QueryListener.java +0 -54
  98. package/android/src/main/java/com/github/druk/dnssd/RegisterListener.java +0 -46
  99. package/android/src/main/java/com/github/druk/dnssd/RegisterRecordListener.java +0 -35
  100. package/android/src/main/java/com/github/druk/dnssd/ResolveListener.java +0 -55
  101. package/android/src/main/java/com/github/druk/dnssd/TXTRecord.java +0 -293
  102. package/android/src/main/jni/Android.mk +0 -73
  103. package/android/src/main/jni/Application.mk +0 -3
  104. package/android/src/main/jni/DNSSD.java.h +0 -290
  105. package/android/src/main/jni/JNISupport.c +0 -1221
  106. package/ios/RNZeroconf/RNNetServiceSerializer.h +0 -31
  107. package/ios/RNZeroconf/RNNetServiceSerializer.m +0 -84
  108. package/ios/RNZeroconf/RNZeroconf.h +0 -17
  109. package/ios/RNZeroconf/RNZeroconf.m +0 -1025
  110. package/ios/RNZeroconf.xcodeproj/project.pbxproj +0 -261
  111. package/ios/RNZeroconf.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
  112. package/src/index.js +0 -563
  113. package/windows/RNZeroconf/RNZeroconf.cpp +0 -228
  114. package/windows/RNZeroconf/RNZeroconf.h +0 -70
package/src/index.js DELETED
@@ -1,563 +0,0 @@
1
- import { useCallback, useEffect, useRef, useState } from 'react'
2
- import { Platform, NativeModules, DeviceEventEmitter, PermissionsAndroid } from 'react-native'
3
- import { EventEmitter } from 'events'
4
-
5
- const RNZeroconf = NativeModules.RNZeroconf
6
-
7
- export const ImplType = {
8
- NSD: 'NSD',
9
- DNSSD: 'DNSSD',
10
- }
11
-
12
- const SCAN_DEFAULTS = {
13
- type: 'http',
14
- protocol: 'tcp',
15
- domain: 'local.',
16
- implType: ImplType.NSD,
17
- resolveTimeout: 5,
18
- }
19
-
20
- const PUBLISH_DEFAULTS = {
21
- domain: 'local.',
22
- txt: {},
23
- implType: ImplType.NSD,
24
- }
25
-
26
- /**
27
- * Merge options over defaults, ignoring undefined values
28
- */
29
- const withDefaults = (defaults, options) => {
30
- const merged = { ...defaults }
31
- Object.entries(options).forEach(([key, value]) => {
32
- if (value !== undefined) {
33
- merged[key] = value
34
- }
35
- })
36
- return merged
37
- }
38
-
39
- const isOptionsObject = value => value !== null && typeof value === 'object'
40
-
41
- // Options passed to native code, without the undefined ones
42
- const nativeOptions = options =>
43
- Object.fromEntries(Object.entries(options).filter(([, value]) => value !== undefined))
44
-
45
- // Android 17 (API 37) runtime permission, enforced for apps targeting API 37 or declaring it
46
- const ACCESS_LOCAL_NETWORK = 'android.permission.ACCESS_LOCAL_NETWORK'
47
-
48
- // Each instance runs its own scan, identified by this id in native events
49
- let instanceCount = 0
50
-
51
- /**
52
- * Error from a native { message, code, domain, serviceName } payload
53
- */
54
- const toError = payload => {
55
- if (!payload || typeof payload !== 'object') {
56
- return new Error(payload)
57
- }
58
- const error = new Error(payload.message)
59
- error.code = payload.code
60
- error.domain = payload.domain
61
- if (payload.serviceName) {
62
- error.serviceName = payload.serviceName
63
- }
64
- return error
65
- }
66
-
67
- /**
68
- * Promise rejections carry the same payload as error events in userInfo
69
- */
70
- const toRejection = error =>
71
- error && error.userInfo && error.userInfo.domain ? toError(error.userInfo) : error
72
-
73
- /**
74
- * Normalizes rejections, and marks the promise handled so callers that don't await it
75
- * don't get unhandled rejection warnings (errors are also emitted as error events)
76
- */
77
- const asPromise = nativePromise => {
78
- const promise = Promise.resolve(nativePromise).catch(error => {
79
- throw toRejection(error)
80
- })
81
- promise.catch(() => {})
82
- return promise
83
- }
84
-
85
- const isIPv6 = address => address.includes(':')
86
-
87
- /**
88
- * Sort addresses IPv4 first and expose them by family
89
- */
90
- const withAddressFamilies = service => {
91
- const addresses = Array.isArray(service.addresses) ? service.addresses : []
92
- const ipv4 = addresses.filter(address => !isIPv6(address))
93
- const ipv6 = addresses.filter(isIPv6)
94
- return { ...service, addresses: [...ipv4, ...ipv6], ipv4, ipv6 }
95
- }
96
-
97
- /**
98
- * TXT records as ordered [key, value] pairs, from an object or an array of pairs
99
- */
100
- // Browsing this type lists the service types on the network instead of services
101
- const SERVICE_TYPES = { type: 'services._dns-sd', protocol: 'udp' }
102
-
103
- // "_http._tcp" -> { type: 'http', protocol: 'tcp' }
104
- const parseServiceType = name => {
105
- const match = /^_([^.]+)\._(tcp|udp)$/.exec(name)
106
- return match ? { type: match[1], protocol: match[2] } : null
107
- }
108
-
109
- const toTxtPairs = txt => {
110
- const entries = Array.isArray(txt) ? txt : Object.entries(txt || {})
111
- return entries.map(([key, value]) => [String(key), String(value)])
112
- }
113
-
114
- export default class Zeroconf extends EventEmitter {
115
- constructor(props) {
116
- super(props)
117
-
118
- if (!RNZeroconf) {
119
- throw new Error(
120
- 'react-native-zeroconf: native module not found. Make sure the library is linked and the app rebuilt. Expo Go is not supported, use a development build instead.',
121
- )
122
- }
123
-
124
- this._services = {}
125
- this._serviceTypes = {}
126
- this._scanningTypes = false
127
- this._publishedServices = {}
128
- this._publishedImplTypes = {}
129
- this._scanImplType = null
130
- this._scanId = `zeroconf-${++instanceCount}`
131
- this._hasScanned = false
132
- this._dListeners = {}
133
-
134
- this.addDeviceListeners()
135
- }
136
-
137
- /**
138
- * Add all event listeners
139
- */
140
- addDeviceListeners() {
141
- if (Object.keys(this._dListeners).length) {
142
- return this.emit('error', new Error('RNZeroconf listeners already in place.'))
143
- }
144
-
145
- this._dListeners.start = DeviceEventEmitter.addListener('RNZeroconfStart', payload => {
146
- if (this._isOwnEvent(payload)) {
147
- this.emit('start')
148
- }
149
- })
150
-
151
- this._dListeners.stop = DeviceEventEmitter.addListener('RNZeroconfStop', payload => {
152
- if (this._isOwnEvent(payload)) {
153
- this.emit('stop')
154
- }
155
- })
156
-
157
- this._dListeners.error = DeviceEventEmitter.addListener('RNZeroconfError', err => {
158
- if (this._isOwnEvent(err) && this.listenerCount('error') > 0) {
159
- this.emit('error', toError(err))
160
- }
161
- })
162
-
163
- this._dListeners.found = DeviceEventEmitter.addListener('RNZeroconfFound', service => {
164
- if (!service || !service.name || !this._isOwnEvent(service)) {
165
- return
166
- }
167
- const { name } = service
168
-
169
- if (this._scanningTypes) {
170
- const serviceType = parseServiceType(name)
171
- if (serviceType && !this._serviceTypes[name]) {
172
- this._serviceTypes[name] = serviceType
173
- this.emit('typeFound', serviceType)
174
- this.emit('update')
175
- }
176
- return
177
- }
178
-
179
- this._services[name] = { name }
180
- this.emit('found', name)
181
- this.emit('update')
182
- })
183
-
184
- this._dListeners.remove = DeviceEventEmitter.addListener('RNZeroconfRemove', service => {
185
- if (!service || !service.name || !this._isOwnEvent(service)) {
186
- return
187
- }
188
- const { name } = service
189
-
190
- if (this._scanningTypes) {
191
- const serviceType = this._serviceTypes[name]
192
- if (serviceType) {
193
- delete this._serviceTypes[name]
194
- this.emit('typeRemove', serviceType)
195
- this.emit('update')
196
- }
197
- return
198
- }
199
-
200
- delete this._services[name]
201
-
202
- this.emit('remove', name)
203
- this.emit('update')
204
- })
205
-
206
- this._dListeners.resolved = DeviceEventEmitter.addListener('RNZeroconfResolved', data => {
207
- if (!data || !data.name || !this._isOwnEvent(data)) {
208
- return
209
- }
210
-
211
- const resolved = { ...data }
212
- delete resolved.scanId
213
- const service = withAddressFamilies(resolved)
214
- this._services[service.name] = service
215
- this.emit('resolved', service)
216
- this.emit('update')
217
- })
218
-
219
- this._dListeners.published = DeviceEventEmitter.addListener(
220
- 'RNZeroconfServiceRegistered',
221
- service => {
222
- if (!service || !service.name) {
223
- return
224
- }
225
-
226
- this._publishedServices[service.name] = service
227
- this.emit('published', service)
228
- },
229
- )
230
-
231
- this._dListeners.unpublished = DeviceEventEmitter.addListener(
232
- 'RNZeroconfServiceUnregistered',
233
- service => {
234
- if (!service || !service.name) {
235
- return
236
- }
237
-
238
- delete this._publishedServices[service.name]
239
- this.emit('unpublished', service)
240
- },
241
- )
242
- }
243
-
244
- /**
245
- * Add a listener and get a function that removes it, handy in useEffect cleanups
246
- */
247
- subscribe(event, listener) {
248
- this.on(event, listener)
249
- return () => this.removeListener(event, listener)
250
- }
251
-
252
- /**
253
- * Scan events belong to the instance that started the scan. Instances that never scanned still receive
254
- * every scan's events, as before multiple scans, and events without a scan id (publishing) go to everyone.
255
- */
256
- _isOwnEvent(payload) {
257
- if (!payload || typeof payload !== 'object' || payload.scanId == null || !this._hasScanned) {
258
- return true
259
- }
260
- return payload.scanId === this._scanId
261
- }
262
-
263
- /**
264
- * Remove all event listeners and clean map
265
- */
266
- removeDeviceListeners() {
267
- Object.keys(this._dListeners).forEach(name => this._dListeners[name].remove())
268
- this._dListeners = {}
269
- }
270
-
271
- /**
272
- * Get all the services already resolved
273
- */
274
- getServices() {
275
- return this._services
276
- }
277
-
278
- /**
279
- * Get the service types found by scanServiceTypes, as [{ type, protocol }]
280
- */
281
- getServiceTypes() {
282
- return Object.values(this._serviceTypes)
283
- }
284
-
285
- /**
286
- * Scan for the service types advertised on the network (_http._tcp, _ipp._tcp...), emits typeFound and typeRemove.
287
- * On iOS, only types declared in NSBonjourServices can then be scanned.
288
- * On iOS it requires the multicast entitlement. On Android with NSD and on Windows, services other apps publish on the same device are left out.
289
- *
290
- * scanServiceTypes({ domain, implType })
291
- */
292
- scanServiceTypes({ domain, implType, networkInterface } = {}) {
293
- this._startScan({ ...SERVICE_TYPES, domain, implType, networkInterface }, true)
294
- }
295
-
296
- /**
297
- * Scan for Zeroconf services, defaults to _http._tcp. on the local. domain
298
- *
299
- * scan({ type, protocol, domain, implType, resolveTimeout })
300
- * scan(type, protocol, domain, implType) is deprecated
301
- */
302
- scan(options, protocolArg, domainArg, implTypeArg) {
303
- this._startScan(
304
- isOptionsObject(options)
305
- ? options
306
- : { type: options, protocol: protocolArg, domain: domainArg, implType: implTypeArg },
307
- false,
308
- )
309
- }
310
-
311
- _startScan(options, scanningTypes) {
312
- const { type, protocol, domain, implType, resolveTimeout, subtype, networkInterface } =
313
- withDefaults(SCAN_DEFAULTS, options)
314
-
315
- this._services = {}
316
- this._serviceTypes = {}
317
- this._scanningTypes = scanningTypes
318
- this._hasScanned = true
319
- this.emit('update')
320
- if (Platform.OS === 'android') {
321
- if (this._scanImplType && implType !== this._scanImplType) {
322
- // This instance's scan moves to the other implementation
323
- RNZeroconf.stop(this._scanId, this._scanImplType)
324
- }
325
- this._scanImplType = implType
326
- RNZeroconf.scan(
327
- this._scanId,
328
- type,
329
- protocol,
330
- domain,
331
- implType,
332
- nativeOptions({ resolveTimeout, subtype, networkInterface }),
333
- )
334
- } else {
335
- RNZeroconf.scan(
336
- this._scanId,
337
- type,
338
- protocol,
339
- domain,
340
- nativeOptions({ resolveTimeout, subtype, networkInterface }),
341
- )
342
- }
343
- }
344
-
345
- /**
346
- * Stop current scan if any,
347
- * Defaults to the implementation used by the last scan
348
- */
349
- stop(implType = this._scanImplType || ImplType.NSD) {
350
- if (Platform.OS === 'android') {
351
- RNZeroconf.stop(this._scanId, implType)
352
- } else {
353
- RNZeroconf.stop(this._scanId)
354
- }
355
- }
356
-
357
- /**
358
- * Checks the Local Network permission, resolves 'granted', 'denied' or 'unknown'.
359
- * iOS: uses a service type from NSBonjourServices (the first one by default) and can show the permission prompt.
360
- * Android: apps targeting Android 17 (API 37) need ACCESS_LOCAL_NETWORK on Android 17 devices, it is requested
361
- * when missing unless request is false. 'granted' when there is nothing to grant.
362
- */
363
- async checkLocalNetworkAccess({ type, protocol = 'tcp', timeout = 5, request = true } = {}) {
364
- if (Platform.OS === 'android') {
365
- if (!RNZeroconf.checkLocalNetworkAccess) {
366
- return 'unknown'
367
- }
368
- const status = await asPromise(RNZeroconf.checkLocalNetworkAccess())
369
- if (status !== 'denied' || !request) {
370
- return status
371
- }
372
- const result = await PermissionsAndroid.request(ACCESS_LOCAL_NETWORK)
373
- return result === PermissionsAndroid.RESULTS.GRANTED ? 'granted' : 'denied'
374
- }
375
- const serviceType = type ? `_${type}._${protocol}` : null
376
- return asPromise(RNZeroconf.checkLocalNetworkAccess(serviceType, timeout))
377
- }
378
-
379
- /**
380
- * Publish a service, resolves with the published service once it is advertised.
381
- * Its name can differ from the requested one when that name is already taken.
382
- *
383
- * publishService({ type, protocol, domain, name, port, txt, implType })
384
- * publishService(type, protocol, domain, name, port, txt, implType) is deprecated
385
- */
386
- publishService(options, protocolArg, domainArg, nameArg, portArg, txtArg, implTypeArg) {
387
- const { type, protocol, domain, name, port, txt, implType, subtypes, networkInterface } =
388
- withDefaults(
389
- PUBLISH_DEFAULTS,
390
- isOptionsObject(options)
391
- ? options
392
- : {
393
- type: options,
394
- protocol: protocolArg,
395
- domain: domainArg,
396
- name: nameArg,
397
- port: portArg,
398
- txt: txtArg,
399
- implType: implTypeArg,
400
- },
401
- )
402
- const txtRecord = toTxtPairs(txt)
403
- const native = nativeOptions({ subtypes, networkInterface })
404
- if (Platform.OS === 'android') {
405
- this._publishedImplTypes[name] = implType
406
- return asPromise(
407
- RNZeroconf.registerService(type, protocol, domain, name, port, txtRecord, implType, native),
408
- )
409
- }
410
- return asPromise(
411
- RNZeroconf.registerService(type, protocol, domain, name, port, txtRecord, native),
412
- )
413
- }
414
-
415
- /**
416
- * Replace the TXT record of a published service, resolves with the updated service.
417
- * Android NSD has no update, the service is published again under the same name.
418
- *
419
- * updateService(name, { txt })
420
- */
421
- updateService(
422
- name,
423
- { txt = {}, implType = this._publishedImplTypes[name] || ImplType.NSD } = {},
424
- ) {
425
- const txtRecord = toTxtPairs(txt)
426
- if (Platform.OS === 'android') {
427
- return asPromise(RNZeroconf.updateService(name, txtRecord, implType))
428
- }
429
- return asPromise(RNZeroconf.updateService(name, txtRecord))
430
- }
431
-
432
- /**
433
- * Resolve one service by name without scanning, for a device found before.
434
- * Resolves with the service, rejects with code 'TIMEOUT' when it doesn't answer in time.
435
- *
436
- * resolveService({ name, type, protocol, domain, implType, timeout, networkInterface })
437
- */
438
- resolveService(options) {
439
- const { name, type, protocol, domain, implType, timeout, networkInterface } = withDefaults(
440
- { ...SCAN_DEFAULTS, timeout: 5 },
441
- options,
442
- )
443
- const native = nativeOptions({ timeout, networkInterface })
444
- const promise =
445
- Platform.OS === 'android'
446
- ? RNZeroconf.resolveService(name, type, protocol, domain, implType, native)
447
- : RNZeroconf.resolveService(name, type, protocol, domain, native)
448
- return asPromise(asPromise(promise).then(service => service && withAddressFamilies(service)))
449
- }
450
-
451
- /**
452
- * Unpublish a service, resolves once it is no longer advertised.
453
- * Defaults to the implementation the service was published with
454
- */
455
- unpublishService(name, implType = this._publishedImplTypes[name] || ImplType.NSD) {
456
- if (Platform.OS === 'android') {
457
- delete this._publishedImplTypes[name]
458
- return asPromise(RNZeroconf.unregisterService(name, implType))
459
- }
460
- return asPromise(RNZeroconf.unregisterService(name))
461
- }
462
- }
463
-
464
- // Runs a scan while mounted and enabled, and again when deps change or on restart
465
- function useScan(enabled, startScan, read, deps) {
466
- const zeroconfRef = useRef(null)
467
- const [items, setItems] = useState([])
468
- const [isScanning, setIsScanning] = useState(false)
469
- const [error, setError] = useState(null)
470
- const [scanCount, setScanCount] = useState(0)
471
- const readRef = useRef(read)
472
- readRef.current = read
473
-
474
- useEffect(() => {
475
- const zeroconf = new Zeroconf()
476
- zeroconfRef.current = zeroconf
477
- const unsubscribes = [
478
- zeroconf.subscribe('start', () => setIsScanning(true)),
479
- zeroconf.subscribe('stop', () => setIsScanning(false)),
480
- zeroconf.subscribe('update', () => setItems(readRef.current(zeroconf))),
481
- zeroconf.subscribe('error', setError),
482
- ]
483
- return () => {
484
- unsubscribes.forEach(unsubscribe => unsubscribe())
485
- zeroconf.stop()
486
- zeroconf.removeDeviceListeners()
487
- zeroconfRef.current = null
488
- }
489
- }, [])
490
-
491
- useEffect(() => {
492
- const zeroconf = zeroconfRef.current
493
- if (!zeroconf || !enabled) {
494
- return undefined
495
- }
496
- setItems([])
497
- setError(null)
498
- startScan(zeroconf)
499
- return () => zeroconf.stop()
500
- }, [enabled, scanCount, ...deps])
501
-
502
- const stop = useCallback(() => {
503
- if (zeroconfRef.current) {
504
- zeroconfRef.current.stop()
505
- }
506
- }, [])
507
- const restart = useCallback(() => setScanCount(count => count + 1), [])
508
-
509
- return { items, isScanning, error, stop, restart }
510
- }
511
-
512
- /**
513
- * Scans while mounted and returns the resolved services.
514
- * Scans again when the options change, stops and cleans up on unmount.
515
- * Each hook runs its own scan, several can run at once.
516
- *
517
- * const { services, isScanning, error, stop, restart } = useZeroconf({ type: 'http' })
518
- */
519
- export function useZeroconf(options = {}) {
520
- const {
521
- type,
522
- protocol,
523
- domain,
524
- implType,
525
- resolveTimeout,
526
- subtype,
527
- networkInterface,
528
- enabled = true,
529
- } = options
530
- const { items, ...scan } = useScan(
531
- enabled,
532
- zeroconf =>
533
- zeroconf.scan({
534
- type,
535
- protocol,
536
- domain,
537
- implType,
538
- resolveTimeout,
539
- subtype,
540
- networkInterface,
541
- }),
542
- // Found services only have a name until they are resolved
543
- zeroconf => Object.values(zeroconf.getServices()).filter(service => service.addresses),
544
- [type, protocol, domain, implType, resolveTimeout, subtype, networkInterface],
545
- )
546
- return { services: items, ...scan }
547
- }
548
-
549
- /**
550
- * Lists the service types advertised on the network while mounted.
551
- *
552
- * const { serviceTypes, isScanning, error, stop, restart } = useServiceTypes()
553
- */
554
- export function useServiceTypes(options = {}) {
555
- const { domain, implType, networkInterface, enabled = true } = options
556
- const { items, ...scan } = useScan(
557
- enabled,
558
- zeroconf => zeroconf.scanServiceTypes({ domain, implType, networkInterface }),
559
- zeroconf => zeroconf.getServiceTypes(),
560
- [domain, implType, networkInterface],
561
- )
562
- return { serviceTypes: items, ...scan }
563
- }