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.
- package/NOTICE +2 -6
- package/README.md +1 -1
- package/android/CMakeLists.txt +64 -0
- package/android/build.gradle +1 -17
- package/android/generated/java/com/balthazargronon/RCTZeroconf/NativeZeroconfSpec.java +96 -0
- package/android/generated/jni/CMakeLists.txt +28 -0
- package/android/generated/jni/RNZeroconfSpec-generated.cpp +77 -0
- package/android/generated/jni/RNZeroconfSpec.h +31 -0
- package/android/generated/jni/react/renderer/components/RNZeroconfSpec/RNZeroconfSpecJSI.h +798 -0
- package/android/src/main/java/com/balthazargronon/RCTZeroconf/{ZeroconfModule.java → NsdHost.java} +97 -140
- package/android/src/main/java/com/balthazargronon/RCTZeroconf/NsdPayload.java +87 -0
- package/android/src/main/java/com/balthazargronon/RCTZeroconf/NsdPromise.java +40 -0
- package/android/src/main/java/com/balthazargronon/RCTZeroconf/Zeroconf.java +4 -6
- package/android/src/main/java/com/balthazargronon/RCTZeroconf/ZeroconfNativeSupport.java +60 -0
- package/android/src/main/java/com/balthazargronon/RCTZeroconf/ZeroconfOptions.java +15 -26
- package/android/src/main/java/com/balthazargronon/RCTZeroconf/ZeroconfReactPackage.java +5 -15
- package/android/src/main/java/com/balthazargronon/RCTZeroconf/nsd/NsdServiceImpl.java +90 -96
- package/android/src/main/jni/mdnsresponder/mDNSShared/dnssd_clientshim.c +31 -6
- package/cpp/Backend.cpp +16 -0
- package/cpp/Backend.h +116 -0
- package/cpp/ZeroconfModule.cpp +280 -0
- package/cpp/ZeroconfModule.h +144 -0
- package/cpp/android/NsdBackend.cpp +462 -0
- package/cpp/android/NsdBackend.h +61 -0
- package/cpp/android/ZeroconfAndroidModule.cpp +49 -0
- package/cpp/android/ZeroconfAndroidModule.h +15 -0
- package/cpp/apple/DispatchExecutor.cpp +66 -0
- package/cpp/apple/DispatchExecutor.h +37 -0
- package/cpp/apple/LocalNetworkAccess.h +19 -0
- package/cpp/apple/LocalNetworkAccess.mm +87 -0
- package/cpp/dnssd/DnssdBackend.cpp +976 -0
- package/cpp/dnssd/DnssdBackend.h +114 -0
- package/cpp/dnssd/Executor.h +28 -0
- package/cpp/embedded/EmbeddedExecutor.cpp +124 -0
- package/cpp/embedded/EmbeddedExecutor.h +57 -0
- package/ios/ZeroconfOnLoad.mm +34 -0
- package/ios/generated/ReactCodegen/RNZeroconfSpec/RNZeroconfSpec-generated.mm +140 -0
- package/ios/generated/ReactCodegen/RNZeroconfSpec/RNZeroconfSpec.h +189 -0
- package/ios/generated/ReactCodegen/RNZeroconfSpecJSI.h +798 -0
- package/lib/module/NativeZeroconf.js +15 -0
- package/lib/module/NativeZeroconf.js.map +1 -0
- package/lib/module/bridge.js +124 -0
- package/lib/module/bridge.js.map +1 -0
- package/{dist → lib/module}/index.js +149 -149
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/types.js +24 -0
- package/lib/module/types.js.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/NativeZeroconf.d.ts +75 -0
- package/lib/typescript/src/NativeZeroconf.d.ts.map +1 -0
- package/lib/typescript/src/bridge.d.ts +22 -0
- package/lib/typescript/src/bridge.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +111 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/types.d.ts +175 -0
- package/lib/typescript/src/types.d.ts.map +1 -0
- package/package.json +64 -29
- package/react-native-zeroconf.podspec +2 -1
- package/react-native.config.js +17 -0
- package/src/NativeZeroconf.ts +120 -0
- package/src/bridge.ts +153 -0
- package/src/index.ts +607 -0
- package/{index.d.ts → src/types.ts} +5 -99
- package/windows/RNZeroconf/RNZeroconf.vcxproj +17 -2
- package/windows/RNZeroconf/RNZeroconf.vcxproj.filters +0 -6
- package/windows/RNZeroconf/ReactPackageProvider.cpp +23 -20
- package/windows/RNZeroconf/WindowsBackend.cpp +156 -0
- package/windows/RNZeroconf/WindowsBackend.h +13 -0
- package/windows/RNZeroconf/ZeroconfCore.cpp +2 -2
- package/windows/RNZeroconf/ZeroconfCore.h +2 -2
- package/windows/RNZeroconf/ZeroconfWindowsModule.cpp +22 -0
- package/windows/RNZeroconf/ZeroconfWindowsModule.h +14 -0
- package/android/src/main/java/com/balthazargronon/RCTZeroconf/ZeroConfImplFactory.java +0 -56
- package/android/src/main/java/com/balthazargronon/RCTZeroconf/dnssd/DnssdImpl.java +0 -654
- package/android/src/main/java/com/github/druk/dnssd/BaseListener.java +0 -33
- package/android/src/main/java/com/github/druk/dnssd/BrowseListener.java +0 -67
- package/android/src/main/java/com/github/druk/dnssd/DNSRecord.java +0 -47
- package/android/src/main/java/com/github/druk/dnssd/DNSSD.java +0 -681
- package/android/src/main/java/com/github/druk/dnssd/DNSSDEmbedded.java +0 -198
- package/android/src/main/java/com/github/druk/dnssd/DNSSDException.java +0 -66
- package/android/src/main/java/com/github/druk/dnssd/DNSSDRecordRegistrar.java +0 -55
- package/android/src/main/java/com/github/druk/dnssd/DNSSDRegistration.java +0 -54
- package/android/src/main/java/com/github/druk/dnssd/DNSSDService.java +0 -35
- package/android/src/main/java/com/github/druk/dnssd/DomainListener.java +0 -57
- package/android/src/main/java/com/github/druk/dnssd/InternalBrowseListener.java +0 -76
- package/android/src/main/java/com/github/druk/dnssd/InternalDNSSD.java +0 -870
- package/android/src/main/java/com/github/druk/dnssd/InternalDNSSDRecordRegistrar.java +0 -30
- package/android/src/main/java/com/github/druk/dnssd/InternalDNSSDRegistration.java +0 -34
- package/android/src/main/java/com/github/druk/dnssd/InternalDNSSDService.java +0 -29
- package/android/src/main/java/com/github/druk/dnssd/InternalDomainListener.java +0 -62
- package/android/src/main/java/com/github/druk/dnssd/InternalQueryListener.java +0 -61
- package/android/src/main/java/com/github/druk/dnssd/InternalRegisterListener.java +0 -51
- package/android/src/main/java/com/github/druk/dnssd/InternalResolveListener.java +0 -58
- package/android/src/main/java/com/github/druk/dnssd/NSClass.java +0 -16
- package/android/src/main/java/com/github/druk/dnssd/NSType.java +0 -58
- package/android/src/main/java/com/github/druk/dnssd/QueryListener.java +0 -54
- package/android/src/main/java/com/github/druk/dnssd/RegisterListener.java +0 -46
- package/android/src/main/java/com/github/druk/dnssd/RegisterRecordListener.java +0 -35
- package/android/src/main/java/com/github/druk/dnssd/ResolveListener.java +0 -55
- package/android/src/main/java/com/github/druk/dnssd/TXTRecord.java +0 -293
- package/android/src/main/jni/Android.mk +0 -73
- package/android/src/main/jni/Application.mk +0 -3
- package/android/src/main/jni/DNSSD.java.h +0 -290
- package/android/src/main/jni/JNISupport.c +0 -1221
- package/ios/RNZeroconf/RNNetServiceSerializer.h +0 -31
- package/ios/RNZeroconf/RNNetServiceSerializer.m +0 -84
- package/ios/RNZeroconf/RNZeroconf.h +0 -17
- package/ios/RNZeroconf/RNZeroconf.m +0 -1025
- package/ios/RNZeroconf.xcodeproj/project.pbxproj +0 -261
- package/ios/RNZeroconf.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
- package/src/index.js +0 -563
- package/windows/RNZeroconf/RNZeroconf.cpp +0 -228
- package/windows/RNZeroconf/RNZeroconf.h +0 -70
package/cpp/Backend.cpp
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#include "Backend.h"
|
|
2
|
+
|
|
3
|
+
namespace rnzeroconf {
|
|
4
|
+
|
|
5
|
+
Error LibraryError(const std::string &code, const std::string &message, const std::string &serviceName) {
|
|
6
|
+
return Error{"RNZeroconf", code, message, serviceName};
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
std::string SubtypeLabel(const std::string &subtype) {
|
|
10
|
+
if (subtype.empty() || subtype[0] == '_') {
|
|
11
|
+
return subtype;
|
|
12
|
+
}
|
|
13
|
+
return "_" + subtype;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
} // namespace rnzeroconf
|
package/cpp/Backend.h
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
// What a platform implements: scanning, resolving and publishing on one mDNS stack.
|
|
2
|
+
// No React Native dependency: ZeroconfModule bridges a backend to JavaScript, the native harnesses test it directly.
|
|
3
|
+
// Strings are UTF-8. Callbacks run on the backend's own thread.
|
|
4
|
+
#pragma once
|
|
5
|
+
|
|
6
|
+
#include <cstdint>
|
|
7
|
+
#include <functional>
|
|
8
|
+
#include <optional>
|
|
9
|
+
#include <string>
|
|
10
|
+
#include <utility>
|
|
11
|
+
#include <vector>
|
|
12
|
+
|
|
13
|
+
namespace rnzeroconf {
|
|
14
|
+
|
|
15
|
+
// TXT records as ordered [key, value] pairs
|
|
16
|
+
using TxtPairs = std::vector<std::pair<std::string, std::string>>;
|
|
17
|
+
|
|
18
|
+
struct Service {
|
|
19
|
+
std::string name;
|
|
20
|
+
std::string fullName;
|
|
21
|
+
std::string host;
|
|
22
|
+
uint16_t port = 0;
|
|
23
|
+
std::vector<std::string> addresses;
|
|
24
|
+
TxtPairs txt;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
// { message, code, domain, serviceName } as JavaScript sees it.
|
|
28
|
+
// The code is a string for domain "RNZeroconf" ('TIMEOUT'), the platform's number otherwise (-65555)
|
|
29
|
+
struct Error {
|
|
30
|
+
std::string domain;
|
|
31
|
+
std::string code;
|
|
32
|
+
std::string message;
|
|
33
|
+
std::string serviceName;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
Error LibraryError(const std::string &code, const std::string &message, const std::string &serviceName = "");
|
|
37
|
+
|
|
38
|
+
using ServiceCallback = std::function<void(const Service &)>;
|
|
39
|
+
using ErrorCallback = std::function<void(const Error &)>;
|
|
40
|
+
|
|
41
|
+
// Scan events carry the id of the scan they belong to. An error with an empty scanId is not about a scan
|
|
42
|
+
struct Events {
|
|
43
|
+
std::function<void(const std::string &scanId)> start;
|
|
44
|
+
std::function<void(const std::string &scanId)> stop;
|
|
45
|
+
std::function<void(const std::string &scanId, const std::string &name)> found;
|
|
46
|
+
std::function<void(const std::string &scanId, const std::string &name)> remove;
|
|
47
|
+
std::function<void(const std::string &scanId, const Service &)> resolved;
|
|
48
|
+
std::function<void(const Service &)> published;
|
|
49
|
+
std::function<void(const Service &)> unpublished;
|
|
50
|
+
std::function<void(const std::string &scanId, const Error &)> error;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
struct ScanOptions {
|
|
54
|
+
// "printer" or "_printer", empty for none
|
|
55
|
+
std::string subtype;
|
|
56
|
+
// "en0", empty for every interface
|
|
57
|
+
std::string networkInterface;
|
|
58
|
+
// Each found service is resolved for this long, retried once, then reported with a TIMEOUT error
|
|
59
|
+
double resolveTimeoutSeconds = 5;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
struct PublishOptions {
|
|
63
|
+
std::vector<std::string> subtypes;
|
|
64
|
+
std::string networkInterface;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
struct ResolveOptions {
|
|
68
|
+
std::string networkInterface;
|
|
69
|
+
double timeoutSeconds = 5;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
class Backend {
|
|
73
|
+
public:
|
|
74
|
+
virtual ~Backend() = default;
|
|
75
|
+
|
|
76
|
+
// type and protocol without underscore ("http", "tcp"); "services._dns-sd" / "udp" lists the service types.
|
|
77
|
+
// Starting a scan with the id of a running one replaces it
|
|
78
|
+
virtual void Scan(
|
|
79
|
+
const std::string &scanId,
|
|
80
|
+
const std::string &type,
|
|
81
|
+
const std::string &protocol,
|
|
82
|
+
const std::string &domain,
|
|
83
|
+
const ScanOptions &options) = 0;
|
|
84
|
+
// Stops the scan with this id, or every scan with an empty one
|
|
85
|
+
virtual void Stop(const std::string &scanId) = 0;
|
|
86
|
+
|
|
87
|
+
virtual void Publish(
|
|
88
|
+
const std::string &type,
|
|
89
|
+
const std::string &protocol,
|
|
90
|
+
const std::string &domain,
|
|
91
|
+
const std::string &name,
|
|
92
|
+
uint16_t port,
|
|
93
|
+
const TxtPairs &txt,
|
|
94
|
+
const PublishOptions &options,
|
|
95
|
+
ServiceCallback resolve,
|
|
96
|
+
ErrorCallback reject) = 0;
|
|
97
|
+
virtual void Unpublish(const std::string &name, ServiceCallback resolve, ErrorCallback reject) = 0;
|
|
98
|
+
virtual void Update(const std::string &name, const TxtPairs &txt, ServiceCallback resolve, ErrorCallback reject) = 0;
|
|
99
|
+
|
|
100
|
+
virtual void ResolveService(
|
|
101
|
+
const std::string &name,
|
|
102
|
+
const std::string &type,
|
|
103
|
+
const std::string &protocol,
|
|
104
|
+
const std::string &domain,
|
|
105
|
+
const ResolveOptions &options,
|
|
106
|
+
ServiceCallback resolve,
|
|
107
|
+
ErrorCallback reject) = 0;
|
|
108
|
+
|
|
109
|
+
// Stops the scans and unpublishes the services, when the module goes away
|
|
110
|
+
virtual void Shutdown() = 0;
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
// "printer" or "_printer" -> "_printer", empty stays empty
|
|
114
|
+
std::string SubtypeLabel(const std::string &subtype);
|
|
115
|
+
|
|
116
|
+
} // namespace rnzeroconf
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
#include "ZeroconfModule.h"
|
|
2
|
+
|
|
3
|
+
#include <utility>
|
|
4
|
+
|
|
5
|
+
namespace facebook::react {
|
|
6
|
+
|
|
7
|
+
namespace {
|
|
8
|
+
|
|
9
|
+
rnzeroconf::TxtPairs ToTxt(const std::vector<ZeroconfTxtEntry> &entries) {
|
|
10
|
+
rnzeroconf::TxtPairs txt;
|
|
11
|
+
for (const auto &entry : entries) {
|
|
12
|
+
txt.emplace_back(entry.key, entry.value);
|
|
13
|
+
}
|
|
14
|
+
return txt;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
ZeroconfService ToJs(const rnzeroconf::Service &service) {
|
|
18
|
+
std::vector<ZeroconfTxtEntry> txt;
|
|
19
|
+
for (const auto &[key, value] : service.txt) {
|
|
20
|
+
txt.push_back(ZeroconfTxtEntry{key, value});
|
|
21
|
+
}
|
|
22
|
+
return ZeroconfService{service.name, service.fullName, service.host, static_cast<double>(service.port), service.addresses, txt};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
ZeroconfError ToJs(const rnzeroconf::Error &error) {
|
|
26
|
+
return ZeroconfError{error.message, error.code, error.domain, error.serviceName};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
} // namespace
|
|
30
|
+
|
|
31
|
+
ZeroconfModule::ZeroconfModule(std::shared_ptr<CallInvoker> jsInvoker, ZeroconfPlatform platform)
|
|
32
|
+
: NativeZeroconfCxxSpec(std::move(jsInvoker)), platform_(std::move(platform)), emitter_(std::make_shared<Emitter>()) {
|
|
33
|
+
emitter_->module = this;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
ZeroconfModule::~ZeroconfModule() {
|
|
37
|
+
{
|
|
38
|
+
std::lock_guard<std::mutex> lock(emitter_->mutex);
|
|
39
|
+
emitter_->module = nullptr;
|
|
40
|
+
}
|
|
41
|
+
{
|
|
42
|
+
std::lock_guard<std::mutex> lock(activityMutex_);
|
|
43
|
+
if (active_ && platform_.setActive) {
|
|
44
|
+
platform_.setActive(false);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// Stops the scans and unpublishes the services, on reload for example
|
|
48
|
+
std::lock_guard<std::mutex> lock(backendsMutex_);
|
|
49
|
+
for (auto &entry : backends_) {
|
|
50
|
+
entry.second->Shutdown();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
std::shared_ptr<rnzeroconf::Backend> ZeroconfModule::Backend(const std::string &implType) {
|
|
55
|
+
std::string key = platform_.backendKey ? platform_.backendKey(implType) : implType;
|
|
56
|
+
std::lock_guard<std::mutex> lock(backendsMutex_);
|
|
57
|
+
auto found = backends_.find(key);
|
|
58
|
+
if (found != backends_.end()) {
|
|
59
|
+
return found->second;
|
|
60
|
+
}
|
|
61
|
+
auto backend = platform_.createBackend(key, MakeEvents());
|
|
62
|
+
backends_[key] = backend;
|
|
63
|
+
return backend;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
rnzeroconf::Events ZeroconfModule::MakeEvents() {
|
|
67
|
+
std::weak_ptr<Emitter> weak = emitter_;
|
|
68
|
+
// Runs an emit while the module exists
|
|
69
|
+
auto with = [weak](const std::function<void(ZeroconfModule &)> &emit) {
|
|
70
|
+
auto emitter = weak.lock();
|
|
71
|
+
if (!emitter) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
std::lock_guard<std::mutex> lock(emitter->mutex);
|
|
75
|
+
if (emitter->module) {
|
|
76
|
+
emit(*emitter->module);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
rnzeroconf::Events events;
|
|
81
|
+
events.start = [with](const std::string &scanId) {
|
|
82
|
+
with([&](ZeroconfModule &module) { module.emitOnStart(ZeroconfScanEvent{scanId}); });
|
|
83
|
+
};
|
|
84
|
+
events.stop = [with](const std::string &scanId) {
|
|
85
|
+
with([&](ZeroconfModule &module) {
|
|
86
|
+
// Also when the scan ended by itself, after an error
|
|
87
|
+
module.Track(Activity::ScanStopped, scanId);
|
|
88
|
+
module.emitOnStop(ZeroconfScanEvent{scanId});
|
|
89
|
+
});
|
|
90
|
+
};
|
|
91
|
+
events.found = [with](const std::string &scanId, const std::string &name) {
|
|
92
|
+
with([&](ZeroconfModule &module) { module.emitOnFound(ZeroconfNameEvent{scanId, name}); });
|
|
93
|
+
};
|
|
94
|
+
events.remove = [with](const std::string &scanId, const std::string &name) {
|
|
95
|
+
with([&](ZeroconfModule &module) { module.emitOnRemove(ZeroconfNameEvent{scanId, name}); });
|
|
96
|
+
};
|
|
97
|
+
events.resolved = [with](const std::string &scanId, const rnzeroconf::Service &service) {
|
|
98
|
+
with([&](ZeroconfModule &module) { module.emitOnResolved(ZeroconfResolvedEvent{scanId, ToJs(service)}); });
|
|
99
|
+
};
|
|
100
|
+
events.published = [with](const rnzeroconf::Service &service) {
|
|
101
|
+
with([&](ZeroconfModule &module) {
|
|
102
|
+
module.Track(Activity::Published, service.name);
|
|
103
|
+
module.emitOnPublished(ToJs(service));
|
|
104
|
+
});
|
|
105
|
+
};
|
|
106
|
+
events.unpublished = [with](const rnzeroconf::Service &service) {
|
|
107
|
+
with([&](ZeroconfModule &module) {
|
|
108
|
+
module.Track(Activity::Unpublished, service.name);
|
|
109
|
+
module.emitOnUnpublished(ToJs(service));
|
|
110
|
+
});
|
|
111
|
+
};
|
|
112
|
+
events.error = [with](const std::string &scanId, const rnzeroconf::Error &error) {
|
|
113
|
+
with([&](ZeroconfModule &module) { module.emitOnError(ZeroconfErrorEvent{scanId, ToJs(error)}); });
|
|
114
|
+
};
|
|
115
|
+
return events;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
AsyncPromise<ZeroconfResult> ZeroconfModule::Settle(
|
|
119
|
+
jsi::Runtime &rt,
|
|
120
|
+
const std::function<void(rnzeroconf::ServiceCallback, rnzeroconf::ErrorCallback)> &call,
|
|
121
|
+
bool active) {
|
|
122
|
+
AsyncPromise<ZeroconfResult> promise(rt, jsInvoker_);
|
|
123
|
+
// Publishes and resolves need the network until they settle
|
|
124
|
+
std::shared_ptr<bool> settled;
|
|
125
|
+
if (active) {
|
|
126
|
+
Track(Activity::CallStarted);
|
|
127
|
+
settled = std::make_shared<bool>(false);
|
|
128
|
+
}
|
|
129
|
+
std::weak_ptr<Emitter> weak = emitter_;
|
|
130
|
+
auto done = [weak, settled] {
|
|
131
|
+
if (!settled || *settled) {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
*settled = true;
|
|
135
|
+
if (auto emitter = weak.lock()) {
|
|
136
|
+
std::lock_guard<std::mutex> lock(emitter->mutex);
|
|
137
|
+
if (emitter->module) {
|
|
138
|
+
emitter->module->Track(Activity::CallSettled);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
call(
|
|
143
|
+
[promise, done](const rnzeroconf::Service &service) mutable {
|
|
144
|
+
done();
|
|
145
|
+
promise.resolve(ZeroconfResult{ToJs(service), std::nullopt});
|
|
146
|
+
},
|
|
147
|
+
[promise, done](const rnzeroconf::Error &error) mutable {
|
|
148
|
+
done();
|
|
149
|
+
promise.resolve(ZeroconfResult{std::nullopt, ToJs(error)});
|
|
150
|
+
});
|
|
151
|
+
return promise;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
void ZeroconfModule::Track(Activity activity, const std::string &key) {
|
|
155
|
+
std::lock_guard<std::mutex> lock(activityMutex_);
|
|
156
|
+
switch (activity) {
|
|
157
|
+
case Activity::ScanStarted:
|
|
158
|
+
runningScans_.insert(key);
|
|
159
|
+
break;
|
|
160
|
+
case Activity::ScanStopped:
|
|
161
|
+
runningScans_.erase(key);
|
|
162
|
+
break;
|
|
163
|
+
case Activity::AllScansStopped:
|
|
164
|
+
runningScans_.clear();
|
|
165
|
+
break;
|
|
166
|
+
case Activity::Published:
|
|
167
|
+
publishedServices_.insert(key);
|
|
168
|
+
break;
|
|
169
|
+
case Activity::Unpublished:
|
|
170
|
+
publishedServices_.erase(key);
|
|
171
|
+
break;
|
|
172
|
+
case Activity::CallStarted:
|
|
173
|
+
callsInFlight_++;
|
|
174
|
+
break;
|
|
175
|
+
case Activity::CallSettled:
|
|
176
|
+
callsInFlight_--;
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
bool active = !runningScans_.empty() || !publishedServices_.empty() || callsInFlight_ > 0;
|
|
180
|
+
if (active != active_) {
|
|
181
|
+
active_ = active;
|
|
182
|
+
if (platform_.setActive) {
|
|
183
|
+
platform_.setActive(active);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
void ZeroconfModule::scan(
|
|
189
|
+
jsi::Runtime &,
|
|
190
|
+
std::string scanId,
|
|
191
|
+
std::string type,
|
|
192
|
+
std::string protocol,
|
|
193
|
+
std::string domain,
|
|
194
|
+
std::string implType,
|
|
195
|
+
ZeroconfScanOptions options) {
|
|
196
|
+
rnzeroconf::ScanOptions scanOptions;
|
|
197
|
+
scanOptions.resolveTimeoutSeconds = options.resolveTimeout.value_or(5);
|
|
198
|
+
scanOptions.subtype = options.subtype.value_or("");
|
|
199
|
+
scanOptions.networkInterface = options.networkInterface.value_or("");
|
|
200
|
+
Track(Activity::ScanStarted, scanId);
|
|
201
|
+
Backend(implType)->Scan(scanId, type, protocol, domain, scanOptions);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
void ZeroconfModule::stop(jsi::Runtime &, std::string scanId, std::string implType) {
|
|
205
|
+
Track(scanId.empty() ? Activity::AllScansStopped : Activity::ScanStopped, scanId);
|
|
206
|
+
Backend(implType)->Stop(scanId);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
AsyncPromise<ZeroconfResult> ZeroconfModule::registerService(
|
|
210
|
+
jsi::Runtime &rt,
|
|
211
|
+
std::string type,
|
|
212
|
+
std::string protocol,
|
|
213
|
+
std::string domain,
|
|
214
|
+
std::string name,
|
|
215
|
+
double port,
|
|
216
|
+
std::vector<ZeroconfTxtEntry> txt,
|
|
217
|
+
std::string implType,
|
|
218
|
+
ZeroconfPublishOptions options) {
|
|
219
|
+
rnzeroconf::PublishOptions publishOptions;
|
|
220
|
+
publishOptions.subtypes = options.subtypes.value_or(std::vector<std::string>{});
|
|
221
|
+
publishOptions.networkInterface = options.networkInterface.value_or("");
|
|
222
|
+
auto backend = Backend(implType);
|
|
223
|
+
return Settle(
|
|
224
|
+
rt,
|
|
225
|
+
[&](rnzeroconf::ServiceCallback resolve, rnzeroconf::ErrorCallback reject) {
|
|
226
|
+
backend->Publish(type, protocol, domain, name, static_cast<uint16_t>(port), ToTxt(txt), publishOptions, std::move(resolve), std::move(reject));
|
|
227
|
+
},
|
|
228
|
+
true);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
AsyncPromise<ZeroconfResult> ZeroconfModule::updateService(jsi::Runtime &rt, std::string name, std::vector<ZeroconfTxtEntry> txt, std::string implType) {
|
|
232
|
+
auto backend = Backend(implType);
|
|
233
|
+
return Settle(rt, [&](rnzeroconf::ServiceCallback resolve, rnzeroconf::ErrorCallback reject) {
|
|
234
|
+
backend->Update(name, ToTxt(txt), std::move(resolve), std::move(reject));
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
AsyncPromise<ZeroconfResult> ZeroconfModule::unregisterService(jsi::Runtime &rt, std::string name, std::string implType) {
|
|
239
|
+
auto backend = Backend(implType);
|
|
240
|
+
return Settle(rt, [&](rnzeroconf::ServiceCallback resolve, rnzeroconf::ErrorCallback reject) {
|
|
241
|
+
backend->Unpublish(name, std::move(resolve), std::move(reject));
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
AsyncPromise<ZeroconfResult> ZeroconfModule::resolveService(
|
|
246
|
+
jsi::Runtime &rt,
|
|
247
|
+
std::string name,
|
|
248
|
+
std::string type,
|
|
249
|
+
std::string protocol,
|
|
250
|
+
std::string domain,
|
|
251
|
+
std::string implType,
|
|
252
|
+
ZeroconfResolveOptions options) {
|
|
253
|
+
rnzeroconf::ResolveOptions resolveOptions;
|
|
254
|
+
resolveOptions.timeoutSeconds = options.timeout.value_or(5);
|
|
255
|
+
resolveOptions.networkInterface = options.networkInterface.value_or("");
|
|
256
|
+
auto backend = Backend(implType);
|
|
257
|
+
return Settle(
|
|
258
|
+
rt,
|
|
259
|
+
[&](rnzeroconf::ServiceCallback resolve, rnzeroconf::ErrorCallback reject) {
|
|
260
|
+
backend->ResolveService(name, type, protocol, domain, resolveOptions, std::move(resolve), std::move(reject));
|
|
261
|
+
},
|
|
262
|
+
true);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
AsyncPromise<ZeroconfAccessResult> ZeroconfModule::checkLocalNetworkAccess(jsi::Runtime &rt, std::string type, double timeout) {
|
|
266
|
+
AsyncPromise<ZeroconfAccessResult> promise(rt, jsInvoker_);
|
|
267
|
+
if (!platform_.checkLocalNetworkAccess) {
|
|
268
|
+
// Nothing to grant on this platform
|
|
269
|
+
promise.resolve(ZeroconfAccessResult{std::string("granted"), std::nullopt});
|
|
270
|
+
return promise;
|
|
271
|
+
}
|
|
272
|
+
platform_.checkLocalNetworkAccess(
|
|
273
|
+
type,
|
|
274
|
+
timeout,
|
|
275
|
+
[promise](const std::string &status) mutable { promise.resolve(ZeroconfAccessResult{status, std::nullopt}); },
|
|
276
|
+
[promise](const rnzeroconf::Error &error) mutable { promise.resolve(ZeroconfAccessResult{std::nullopt, ToJs(error)}); });
|
|
277
|
+
return promise;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
} // namespace facebook::react
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
// The native module, one C++ TurboModule for every platform. It bridges a platform's backends
|
|
2
|
+
// (cpp/Backend.h) to JavaScript: calls go to the backend for the call's implType, backend callbacks
|
|
3
|
+
// become events and settled promises.
|
|
4
|
+
#pragma once
|
|
5
|
+
|
|
6
|
+
#include <RNZeroconfSpecJSI.h>
|
|
7
|
+
|
|
8
|
+
#include "Backend.h"
|
|
9
|
+
|
|
10
|
+
#include <functional>
|
|
11
|
+
#include <map>
|
|
12
|
+
#include <memory>
|
|
13
|
+
#include <mutex>
|
|
14
|
+
#include <optional>
|
|
15
|
+
#include <set>
|
|
16
|
+
#include <string>
|
|
17
|
+
#include <vector>
|
|
18
|
+
|
|
19
|
+
namespace facebook::react {
|
|
20
|
+
|
|
21
|
+
using ZeroconfTxtEntry = NativeZeroconfTxtEntry<std::string, std::string>;
|
|
22
|
+
template <>
|
|
23
|
+
struct Bridging<ZeroconfTxtEntry> : NativeZeroconfTxtEntryBridging<ZeroconfTxtEntry> {};
|
|
24
|
+
|
|
25
|
+
using ZeroconfService = NativeZeroconfNativeService<std::string, std::string, std::string, double, std::vector<std::string>, std::vector<ZeroconfTxtEntry>>;
|
|
26
|
+
template <>
|
|
27
|
+
struct Bridging<ZeroconfService> : NativeZeroconfNativeServiceBridging<ZeroconfService> {};
|
|
28
|
+
|
|
29
|
+
using ZeroconfError = NativeZeroconfNativeError<std::string, std::string, std::string, std::string>;
|
|
30
|
+
template <>
|
|
31
|
+
struct Bridging<ZeroconfError> : NativeZeroconfNativeErrorBridging<ZeroconfError> {};
|
|
32
|
+
|
|
33
|
+
using ZeroconfResult = NativeZeroconfNativeResult<std::optional<ZeroconfService>, std::optional<ZeroconfError>>;
|
|
34
|
+
template <>
|
|
35
|
+
struct Bridging<ZeroconfResult> : NativeZeroconfNativeResultBridging<ZeroconfResult> {};
|
|
36
|
+
|
|
37
|
+
using ZeroconfAccessResult = NativeZeroconfNativeAccessResult<std::optional<std::string>, std::optional<ZeroconfError>>;
|
|
38
|
+
template <>
|
|
39
|
+
struct Bridging<ZeroconfAccessResult> : NativeZeroconfNativeAccessResultBridging<ZeroconfAccessResult> {};
|
|
40
|
+
|
|
41
|
+
using ZeroconfScanEvent = NativeZeroconfScanEvent<std::string>;
|
|
42
|
+
template <>
|
|
43
|
+
struct Bridging<ZeroconfScanEvent> : NativeZeroconfScanEventBridging<ZeroconfScanEvent> {};
|
|
44
|
+
|
|
45
|
+
using ZeroconfNameEvent = NativeZeroconfNameEvent<std::string, std::string>;
|
|
46
|
+
template <>
|
|
47
|
+
struct Bridging<ZeroconfNameEvent> : NativeZeroconfNameEventBridging<ZeroconfNameEvent> {};
|
|
48
|
+
|
|
49
|
+
using ZeroconfResolvedEvent = NativeZeroconfResolvedEvent<std::string, ZeroconfService>;
|
|
50
|
+
template <>
|
|
51
|
+
struct Bridging<ZeroconfResolvedEvent> : NativeZeroconfResolvedEventBridging<ZeroconfResolvedEvent> {};
|
|
52
|
+
|
|
53
|
+
using ZeroconfErrorEvent = NativeZeroconfErrorEvent<std::string, ZeroconfError>;
|
|
54
|
+
template <>
|
|
55
|
+
struct Bridging<ZeroconfErrorEvent> : NativeZeroconfErrorEventBridging<ZeroconfErrorEvent> {};
|
|
56
|
+
|
|
57
|
+
using ZeroconfScanOptions = NativeZeroconfNativeScanOptions<std::optional<double>, std::optional<std::string>, std::optional<std::string>>;
|
|
58
|
+
template <>
|
|
59
|
+
struct Bridging<ZeroconfScanOptions> : NativeZeroconfNativeScanOptionsBridging<ZeroconfScanOptions> {};
|
|
60
|
+
|
|
61
|
+
using ZeroconfPublishOptions = NativeZeroconfNativePublishOptions<std::optional<std::vector<std::string>>, std::optional<std::string>>;
|
|
62
|
+
template <>
|
|
63
|
+
struct Bridging<ZeroconfPublishOptions> : NativeZeroconfNativePublishOptionsBridging<ZeroconfPublishOptions> {};
|
|
64
|
+
|
|
65
|
+
using ZeroconfResolveOptions = NativeZeroconfNativeResolveOptions<std::optional<double>, std::optional<std::string>>;
|
|
66
|
+
template <>
|
|
67
|
+
struct Bridging<ZeroconfResolveOptions> : NativeZeroconfNativeResolveOptionsBridging<ZeroconfResolveOptions> {};
|
|
68
|
+
|
|
69
|
+
// What a platform provides to the module, set before the module is created
|
|
70
|
+
struct ZeroconfPlatform {
|
|
71
|
+
// The backend for a key; the platform maps implTypes to keys, so platforms with one backend ignore implType
|
|
72
|
+
std::function<std::string(const std::string &implType)> backendKey;
|
|
73
|
+
std::function<std::shared_ptr<rnzeroconf::Backend>(const std::string &key, rnzeroconf::Events events)> createBackend;
|
|
74
|
+
// Settles with 'granted', 'denied' or 'unknown', or an error
|
|
75
|
+
std::function<void(
|
|
76
|
+
const std::string &type,
|
|
77
|
+
double timeoutSeconds,
|
|
78
|
+
std::function<void(const std::string &status)> resolve,
|
|
79
|
+
std::function<void(const rnzeroconf::Error &error)> reject)>
|
|
80
|
+
checkLocalNetworkAccess;
|
|
81
|
+
// Called when the module starts or stops having anything running: scans, published services,
|
|
82
|
+
// publishes and resolves in flight. Android holds its multicast lock in between
|
|
83
|
+
std::function<void(bool active)> setActive;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
class ZeroconfModule : public NativeZeroconfCxxSpec<ZeroconfModule> {
|
|
87
|
+
public:
|
|
88
|
+
ZeroconfModule(std::shared_ptr<CallInvoker> jsInvoker, ZeroconfPlatform platform);
|
|
89
|
+
~ZeroconfModule() override;
|
|
90
|
+
|
|
91
|
+
void scan(jsi::Runtime &rt, std::string scanId, std::string type, std::string protocol, std::string domain, std::string implType, ZeroconfScanOptions options);
|
|
92
|
+
void stop(jsi::Runtime &rt, std::string scanId, std::string implType);
|
|
93
|
+
AsyncPromise<ZeroconfResult> registerService(
|
|
94
|
+
jsi::Runtime &rt,
|
|
95
|
+
std::string type,
|
|
96
|
+
std::string protocol,
|
|
97
|
+
std::string domain,
|
|
98
|
+
std::string name,
|
|
99
|
+
double port,
|
|
100
|
+
std::vector<ZeroconfTxtEntry> txt,
|
|
101
|
+
std::string implType,
|
|
102
|
+
ZeroconfPublishOptions options);
|
|
103
|
+
AsyncPromise<ZeroconfResult> updateService(jsi::Runtime &rt, std::string name, std::vector<ZeroconfTxtEntry> txt, std::string implType);
|
|
104
|
+
AsyncPromise<ZeroconfResult> unregisterService(jsi::Runtime &rt, std::string name, std::string implType);
|
|
105
|
+
AsyncPromise<ZeroconfResult> resolveService(
|
|
106
|
+
jsi::Runtime &rt,
|
|
107
|
+
std::string name,
|
|
108
|
+
std::string type,
|
|
109
|
+
std::string protocol,
|
|
110
|
+
std::string domain,
|
|
111
|
+
std::string implType,
|
|
112
|
+
ZeroconfResolveOptions options);
|
|
113
|
+
AsyncPromise<ZeroconfAccessResult> checkLocalNetworkAccess(jsi::Runtime &rt, std::string type, double timeout);
|
|
114
|
+
|
|
115
|
+
private:
|
|
116
|
+
// Backend callbacks can outlive the module, they go through this
|
|
117
|
+
struct Emitter {
|
|
118
|
+
std::mutex mutex;
|
|
119
|
+
ZeroconfModule *module = nullptr;
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
std::shared_ptr<rnzeroconf::Backend> Backend(const std::string &implType);
|
|
123
|
+
rnzeroconf::Events MakeEvents();
|
|
124
|
+
AsyncPromise<ZeroconfResult> Settle(
|
|
125
|
+
jsi::Runtime &rt,
|
|
126
|
+
const std::function<void(rnzeroconf::ServiceCallback, rnzeroconf::ErrorCallback)> &call,
|
|
127
|
+
bool active = false);
|
|
128
|
+
|
|
129
|
+
// What is running, for ZeroconfPlatform::setActive
|
|
130
|
+
enum class Activity { ScanStarted, ScanStopped, AllScansStopped, Published, Unpublished, CallStarted, CallSettled };
|
|
131
|
+
void Track(Activity activity, const std::string &key = "");
|
|
132
|
+
|
|
133
|
+
ZeroconfPlatform platform_;
|
|
134
|
+
std::shared_ptr<Emitter> emitter_;
|
|
135
|
+
std::mutex backendsMutex_;
|
|
136
|
+
std::map<std::string, std::shared_ptr<rnzeroconf::Backend>> backends_;
|
|
137
|
+
std::mutex activityMutex_;
|
|
138
|
+
std::set<std::string> runningScans_;
|
|
139
|
+
std::set<std::string> publishedServices_;
|
|
140
|
+
int callsInFlight_ = 0;
|
|
141
|
+
bool active_ = false;
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
} // namespace facebook::react
|