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
|
@@ -0,0 +1,462 @@
|
|
|
1
|
+
#include "NsdBackend.h"
|
|
2
|
+
|
|
3
|
+
#include <android/log.h>
|
|
4
|
+
|
|
5
|
+
#include <map>
|
|
6
|
+
#include <mutex>
|
|
7
|
+
#include <optional>
|
|
8
|
+
#include <utility>
|
|
9
|
+
|
|
10
|
+
using namespace facebook;
|
|
11
|
+
|
|
12
|
+
namespace rnzeroconf {
|
|
13
|
+
|
|
14
|
+
namespace {
|
|
15
|
+
|
|
16
|
+
constexpr const char *kHostClass = "com/balthazargronon/RCTZeroconf/NsdHost";
|
|
17
|
+
constexpr const char *kPromiseClass = "com/balthazargronon/RCTZeroconf/NsdPromise";
|
|
18
|
+
constexpr const char *kPayloadClass = "com/balthazargronon/RCTZeroconf/NsdPayload";
|
|
19
|
+
|
|
20
|
+
// What the Java side's handles point to: integers looked up here, so a late callback finds nothing
|
|
21
|
+
// instead of a freed object
|
|
22
|
+
struct Registry {
|
|
23
|
+
std::mutex mutex;
|
|
24
|
+
int64_t next = 0;
|
|
25
|
+
std::map<int64_t, Events> hosts;
|
|
26
|
+
std::map<int64_t, std::pair<ServiceCallback, ErrorCallback>> promises;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
Registry ®istry() {
|
|
30
|
+
static Registry instance;
|
|
31
|
+
return instance;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Runs with the app's class loader, which finds the library's classes from any thread
|
|
35
|
+
template <typename F>
|
|
36
|
+
void WithEnv(F &&f) {
|
|
37
|
+
jni::ThreadScope::WithClassLoader([&] { f(jni::Environment::current()); });
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
bool ClearException(JNIEnv *env, const char *what) {
|
|
41
|
+
if (!env->ExceptionCheck()) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
__android_log_print(ANDROID_LOG_ERROR, "RNZeroconf", "Java exception in %s", what);
|
|
45
|
+
env->ExceptionDescribe();
|
|
46
|
+
env->ExceptionClear();
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
jclass GlobalClass(const char *name) {
|
|
51
|
+
return static_cast<jclass>(jni::Environment::current()->NewGlobalRef(jni::findClassLocal(name).get()));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
jclass HostClass() {
|
|
55
|
+
static jclass cls = GlobalClass(kHostClass);
|
|
56
|
+
return cls;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
jclass PromiseClass() {
|
|
60
|
+
static jclass cls = GlobalClass(kPromiseClass);
|
|
61
|
+
return cls;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
jclass StringClass() {
|
|
65
|
+
static jclass cls = GlobalClass("java/lang/String");
|
|
66
|
+
return cls;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
std::string ToString(jstring value) {
|
|
70
|
+
return value ? jni::wrap_alias(value)->toStdString() : std::string();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
std::vector<std::string> ToStrings(JNIEnv *env, jobjectArray array) {
|
|
74
|
+
std::vector<std::string> strings;
|
|
75
|
+
if (!array) {
|
|
76
|
+
return strings;
|
|
77
|
+
}
|
|
78
|
+
jsize length = env->GetArrayLength(array);
|
|
79
|
+
for (jsize i = 0; i < length; i++) {
|
|
80
|
+
auto element = static_cast<jstring>(env->GetObjectArrayElement(array, i));
|
|
81
|
+
strings.push_back(ToString(element));
|
|
82
|
+
env->DeleteLocalRef(element);
|
|
83
|
+
}
|
|
84
|
+
return strings;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
jobjectArray ToArray(JNIEnv *env, const std::vector<std::string> &strings) {
|
|
88
|
+
jobjectArray array = env->NewObjectArray(static_cast<jsize>(strings.size()), StringClass(), nullptr);
|
|
89
|
+
for (size_t i = 0; i < strings.size(); i++) {
|
|
90
|
+
auto element = jni::make_jstring(strings[i]);
|
|
91
|
+
env->SetObjectArrayElement(array, static_cast<jsize>(i), element.get());
|
|
92
|
+
}
|
|
93
|
+
return array;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// NsdPayload -> Service
|
|
97
|
+
Service ToService(JNIEnv *env, jobject payload) {
|
|
98
|
+
Service service;
|
|
99
|
+
if (!payload) {
|
|
100
|
+
return service;
|
|
101
|
+
}
|
|
102
|
+
static jclass payloadClass = GlobalClass(kPayloadClass);
|
|
103
|
+
static jmethodID getString = env->GetMethodID(payloadClass, "getString", "(Ljava/lang/String;)Ljava/lang/String;");
|
|
104
|
+
static jmethodID getInt = env->GetMethodID(payloadClass, "getInt", "(Ljava/lang/String;)I");
|
|
105
|
+
static jmethodID getStrings = env->GetMethodID(payloadClass, "getStrings", "(Ljava/lang/String;)[Ljava/lang/String;");
|
|
106
|
+
static jmethodID getMapKeys = env->GetMethodID(payloadClass, "getMapKeys", "(Ljava/lang/String;)[Ljava/lang/String;");
|
|
107
|
+
static jmethodID getMapValues = env->GetMethodID(payloadClass, "getMapValues", "(Ljava/lang/String;)[Ljava/lang/String;");
|
|
108
|
+
|
|
109
|
+
auto string = [&](const char *key) {
|
|
110
|
+
auto name = jni::make_jstring(key);
|
|
111
|
+
auto value = static_cast<jstring>(env->CallObjectMethod(payload, getString, name.get()));
|
|
112
|
+
std::string result = ToString(value);
|
|
113
|
+
env->DeleteLocalRef(value);
|
|
114
|
+
return result;
|
|
115
|
+
};
|
|
116
|
+
auto strings = [&](jmethodID method, const char *key) {
|
|
117
|
+
auto name = jni::make_jstring(key);
|
|
118
|
+
auto value = static_cast<jobjectArray>(env->CallObjectMethod(payload, method, name.get()));
|
|
119
|
+
auto result = ToStrings(env, value);
|
|
120
|
+
env->DeleteLocalRef(value);
|
|
121
|
+
return result;
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
service.name = string("name");
|
|
125
|
+
service.fullName = string("fullName");
|
|
126
|
+
service.host = string("host");
|
|
127
|
+
{
|
|
128
|
+
auto key = jni::make_jstring("port");
|
|
129
|
+
service.port = static_cast<uint16_t>(env->CallIntMethod(payload, getInt, key.get()));
|
|
130
|
+
}
|
|
131
|
+
service.addresses = strings(getStrings, "addresses");
|
|
132
|
+
auto keys = strings(getMapKeys, "txt");
|
|
133
|
+
auto values = strings(getMapValues, "txt");
|
|
134
|
+
for (size_t i = 0; i < keys.size() && i < values.size(); i++) {
|
|
135
|
+
service.txt.emplace_back(keys[i], values[i]);
|
|
136
|
+
}
|
|
137
|
+
ClearException(env, "NsdPayload");
|
|
138
|
+
return service;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
std::optional<Events> HostEvents(jlong handle) {
|
|
142
|
+
std::lock_guard<std::mutex> lock(registry().mutex);
|
|
143
|
+
auto found = registry().hosts.find(handle);
|
|
144
|
+
if (found == registry().hosts.end()) {
|
|
145
|
+
return std::nullopt;
|
|
146
|
+
}
|
|
147
|
+
return found->second;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
std::optional<std::pair<ServiceCallback, ErrorCallback>> TakePromise(jlong id) {
|
|
151
|
+
std::lock_guard<std::mutex> lock(registry().mutex);
|
|
152
|
+
auto found = registry().promises.find(id);
|
|
153
|
+
if (found == registry().promises.end()) {
|
|
154
|
+
return std::nullopt;
|
|
155
|
+
}
|
|
156
|
+
auto callbacks = std::move(found->second);
|
|
157
|
+
registry().promises.erase(found);
|
|
158
|
+
return callbacks;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// NsdHost.nativeEvent: the event names of the Java side
|
|
162
|
+
void NativeEvent(JNIEnv *env, jclass, jlong handle, jstring eventName, jobject payload) {
|
|
163
|
+
auto events = HostEvents(handle);
|
|
164
|
+
if (!events) {
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
std::string event = ToString(eventName);
|
|
168
|
+
Service service = ToService(env, payload);
|
|
169
|
+
std::string scanId;
|
|
170
|
+
if (payload) {
|
|
171
|
+
static jclass payloadClass = GlobalClass(kPayloadClass);
|
|
172
|
+
static jmethodID getString = env->GetMethodID(payloadClass, "getString", "(Ljava/lang/String;)Ljava/lang/String;");
|
|
173
|
+
auto key = jni::make_jstring("scanId");
|
|
174
|
+
auto value = static_cast<jstring>(env->CallObjectMethod(payload, getString, key.get()));
|
|
175
|
+
scanId = ToString(value);
|
|
176
|
+
env->DeleteLocalRef(value);
|
|
177
|
+
}
|
|
178
|
+
if (event == "RNZeroconfStart" && events->start) {
|
|
179
|
+
events->start(scanId);
|
|
180
|
+
} else if (event == "RNZeroconfStop" && events->stop) {
|
|
181
|
+
events->stop(scanId);
|
|
182
|
+
} else if (event == "RNZeroconfFound" && events->found) {
|
|
183
|
+
events->found(scanId, service.name);
|
|
184
|
+
} else if (event == "RNZeroconfRemove" && events->remove) {
|
|
185
|
+
events->remove(scanId, service.name);
|
|
186
|
+
} else if (event == "RNZeroconfResolved" && events->resolved) {
|
|
187
|
+
events->resolved(scanId, service);
|
|
188
|
+
} else if (event == "RNZeroconfServiceRegistered" && events->published) {
|
|
189
|
+
events->published(service);
|
|
190
|
+
} else if (event == "RNZeroconfServiceUnregistered" && events->unpublished) {
|
|
191
|
+
events->unpublished(service);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
void NativeError(JNIEnv *, jclass, jlong handle, jstring scanId, jstring domain, jstring code, jstring message, jstring serviceName) {
|
|
196
|
+
auto events = HostEvents(handle);
|
|
197
|
+
if (events && events->error) {
|
|
198
|
+
events->error(ToString(scanId), Error{ToString(domain), ToString(code), ToString(message), ToString(serviceName)});
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
void NativeResolve(JNIEnv *env, jclass, jlong id, jobject payload) {
|
|
203
|
+
auto callbacks = TakePromise(id);
|
|
204
|
+
if (callbacks && callbacks->first) {
|
|
205
|
+
callbacks->first(ToService(env, payload));
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
void NativeReject(JNIEnv *, jclass, jlong id, jstring domain, jstring code, jstring message, jstring serviceName) {
|
|
210
|
+
auto callbacks = TakePromise(id);
|
|
211
|
+
if (callbacks && callbacks->second) {
|
|
212
|
+
callbacks->second(Error{ToString(domain), ToString(code), ToString(message), ToString(serviceName)});
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
void RegisterNatives() {
|
|
217
|
+
static std::once_flag once;
|
|
218
|
+
std::call_once(once, [] {
|
|
219
|
+
WithEnv([](JNIEnv *env) {
|
|
220
|
+
JNINativeMethod hostMethods[] = {
|
|
221
|
+
{const_cast<char *>("nativeEvent"), const_cast<char *>("(JLjava/lang/String;Lcom/balthazargronon/RCTZeroconf/NsdPayload;)V"),
|
|
222
|
+
reinterpret_cast<void *>(NativeEvent)},
|
|
223
|
+
{const_cast<char *>("nativeError"),
|
|
224
|
+
const_cast<char *>("(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"),
|
|
225
|
+
reinterpret_cast<void *>(NativeError)},
|
|
226
|
+
};
|
|
227
|
+
env->RegisterNatives(HostClass(), hostMethods, 2);
|
|
228
|
+
ClearException(env, "registering NsdHost");
|
|
229
|
+
JNINativeMethod promiseMethods[] = {
|
|
230
|
+
{const_cast<char *>("nativeResolve"), const_cast<char *>("(JLcom/balthazargronon/RCTZeroconf/NsdPayload;)V"),
|
|
231
|
+
reinterpret_cast<void *>(NativeResolve)},
|
|
232
|
+
{const_cast<char *>("nativeReject"),
|
|
233
|
+
const_cast<char *>("(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"),
|
|
234
|
+
reinterpret_cast<void *>(NativeReject)},
|
|
235
|
+
};
|
|
236
|
+
env->RegisterNatives(PromiseClass(), promiseMethods, 2);
|
|
237
|
+
ClearException(env, "registering NsdPromise");
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// A new NsdPromise settling these callbacks
|
|
243
|
+
jobject NewPromise(JNIEnv *env, ServiceCallback resolve, ErrorCallback reject) {
|
|
244
|
+
int64_t id;
|
|
245
|
+
{
|
|
246
|
+
std::lock_guard<std::mutex> lock(registry().mutex);
|
|
247
|
+
id = ++registry().next;
|
|
248
|
+
registry().promises[id] = {std::move(resolve), std::move(reject)};
|
|
249
|
+
}
|
|
250
|
+
static jmethodID constructor = env->GetMethodID(PromiseClass(), "<init>", "(J)V");
|
|
251
|
+
return env->NewObject(PromiseClass(), constructor, static_cast<jlong>(id));
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Rejects a call whose promise never reached Java
|
|
255
|
+
void RejectLocally(jobject promise, JNIEnv *env, const std::string &name) {
|
|
256
|
+
static jfieldID idField = env->GetFieldID(PromiseClass(), "id", "J");
|
|
257
|
+
if (!promise) {
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
auto callbacks = TakePromise(env->GetLongField(promise, idField));
|
|
261
|
+
if (callbacks && callbacks->second) {
|
|
262
|
+
callbacks->second(LibraryError("EXCEPTION", "The NSD implementation failed", name));
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
std::pair<std::vector<std::string>, std::vector<std::string>> Split(const TxtPairs &txt) {
|
|
267
|
+
std::vector<std::string> keys;
|
|
268
|
+
std::vector<std::string> values;
|
|
269
|
+
for (const auto &[key, value] : txt) {
|
|
270
|
+
keys.push_back(key);
|
|
271
|
+
values.push_back(value);
|
|
272
|
+
}
|
|
273
|
+
return {keys, values};
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
} // namespace
|
|
277
|
+
|
|
278
|
+
std::shared_ptr<NsdBackend> NsdBackend::Create(Events events) {
|
|
279
|
+
RegisterNatives();
|
|
280
|
+
int64_t handle;
|
|
281
|
+
{
|
|
282
|
+
std::lock_guard<std::mutex> lock(registry().mutex);
|
|
283
|
+
handle = ++registry().next;
|
|
284
|
+
registry().hosts[handle] = std::move(events);
|
|
285
|
+
}
|
|
286
|
+
jni::global_ref<jobject> host;
|
|
287
|
+
WithEnv([&](JNIEnv *env) {
|
|
288
|
+
static jmethodID constructor = env->GetMethodID(HostClass(), "<init>", "(J)V");
|
|
289
|
+
jobject local = env->NewObject(HostClass(), constructor, static_cast<jlong>(handle));
|
|
290
|
+
if (!ClearException(env, "NsdHost()") && local) {
|
|
291
|
+
host = jni::make_global(jni::wrap_alias(local));
|
|
292
|
+
env->DeleteLocalRef(local);
|
|
293
|
+
}
|
|
294
|
+
});
|
|
295
|
+
return std::shared_ptr<NsdBackend>(new NsdBackend(handle, std::move(host)));
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
NsdBackend::NsdBackend(int64_t handle, jni::global_ref<jobject> host) : handle_(handle), host_(std::move(host)) {}
|
|
299
|
+
|
|
300
|
+
NsdBackend::~NsdBackend() {
|
|
301
|
+
std::lock_guard<std::mutex> lock(registry().mutex);
|
|
302
|
+
registry().hosts.erase(handle_);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
void NsdBackend::Scan(
|
|
306
|
+
const std::string &scanId,
|
|
307
|
+
const std::string &type,
|
|
308
|
+
const std::string &protocol,
|
|
309
|
+
const std::string &domain,
|
|
310
|
+
const ScanOptions &options) {
|
|
311
|
+
if (!host_) {
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
WithEnv([&](JNIEnv *env) {
|
|
315
|
+
static jmethodID scan = env->GetMethodID(
|
|
316
|
+
HostClass(), "scan", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;D)V");
|
|
317
|
+
env->CallVoidMethod(host_.get(), scan, jni::make_jstring(scanId).get(), jni::make_jstring(type).get(), jni::make_jstring(protocol).get(),
|
|
318
|
+
jni::make_jstring(domain).get(), jni::make_jstring(options.subtype).get(), jni::make_jstring(options.networkInterface).get(),
|
|
319
|
+
options.resolveTimeoutSeconds);
|
|
320
|
+
ClearException(env, "NsdHost.scan");
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
void NsdBackend::Stop(const std::string &scanId) {
|
|
325
|
+
if (!host_) {
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
WithEnv([&](JNIEnv *env) {
|
|
329
|
+
static jmethodID stop = env->GetMethodID(HostClass(), "stop", "(Ljava/lang/String;)V");
|
|
330
|
+
env->CallVoidMethod(host_.get(), stop, jni::make_jstring(scanId).get());
|
|
331
|
+
ClearException(env, "NsdHost.stop");
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
void NsdBackend::Publish(
|
|
336
|
+
const std::string &type,
|
|
337
|
+
const std::string &protocol,
|
|
338
|
+
const std::string &domain,
|
|
339
|
+
const std::string &name,
|
|
340
|
+
uint16_t port,
|
|
341
|
+
const TxtPairs &txt,
|
|
342
|
+
const PublishOptions &options,
|
|
343
|
+
ServiceCallback resolve,
|
|
344
|
+
ErrorCallback reject) {
|
|
345
|
+
if (!host_) {
|
|
346
|
+
reject(LibraryError("EXCEPTION", "The NSD implementation is not available", name));
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
WithEnv([&](JNIEnv *env) {
|
|
350
|
+
static jmethodID registerService = env->GetMethodID(
|
|
351
|
+
HostClass(), "registerService",
|
|
352
|
+
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I[Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;Lcom/balthazargronon/RCTZeroconf/NsdPromise;)V");
|
|
353
|
+
auto [keys, values] = Split(txt);
|
|
354
|
+
jobjectArray keyArray = ToArray(env, keys);
|
|
355
|
+
jobjectArray valueArray = ToArray(env, values);
|
|
356
|
+
jobjectArray subtypeArray = ToArray(env, options.subtypes);
|
|
357
|
+
jobject promise = NewPromise(env, std::move(resolve), std::move(reject));
|
|
358
|
+
env->CallVoidMethod(host_.get(), registerService, jni::make_jstring(type).get(), jni::make_jstring(protocol).get(), jni::make_jstring(domain).get(),
|
|
359
|
+
jni::make_jstring(name).get(), static_cast<jint>(port), keyArray, valueArray, subtypeArray,
|
|
360
|
+
jni::make_jstring(options.networkInterface).get(), promise);
|
|
361
|
+
if (ClearException(env, "NsdHost.registerService")) {
|
|
362
|
+
RejectLocally(promise, env, name);
|
|
363
|
+
}
|
|
364
|
+
env->DeleteLocalRef(keyArray);
|
|
365
|
+
env->DeleteLocalRef(valueArray);
|
|
366
|
+
env->DeleteLocalRef(subtypeArray);
|
|
367
|
+
env->DeleteLocalRef(promise);
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
void NsdBackend::Unpublish(const std::string &name, ServiceCallback resolve, ErrorCallback reject) {
|
|
372
|
+
if (!host_) {
|
|
373
|
+
reject(LibraryError("EXCEPTION", "The NSD implementation is not available", name));
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
WithEnv([&](JNIEnv *env) {
|
|
377
|
+
static jmethodID unregisterService =
|
|
378
|
+
env->GetMethodID(HostClass(), "unregisterService", "(Ljava/lang/String;Lcom/balthazargronon/RCTZeroconf/NsdPromise;)V");
|
|
379
|
+
jobject promise = NewPromise(env, std::move(resolve), std::move(reject));
|
|
380
|
+
env->CallVoidMethod(host_.get(), unregisterService, jni::make_jstring(name).get(), promise);
|
|
381
|
+
if (ClearException(env, "NsdHost.unregisterService")) {
|
|
382
|
+
RejectLocally(promise, env, name);
|
|
383
|
+
}
|
|
384
|
+
env->DeleteLocalRef(promise);
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
void NsdBackend::Update(const std::string &name, const TxtPairs &txt, ServiceCallback resolve, ErrorCallback reject) {
|
|
389
|
+
if (!host_) {
|
|
390
|
+
reject(LibraryError("EXCEPTION", "The NSD implementation is not available", name));
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
WithEnv([&](JNIEnv *env) {
|
|
394
|
+
static jmethodID updateService = env->GetMethodID(
|
|
395
|
+
HostClass(), "updateService", "(Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;Lcom/balthazargronon/RCTZeroconf/NsdPromise;)V");
|
|
396
|
+
auto [keys, values] = Split(txt);
|
|
397
|
+
jobjectArray keyArray = ToArray(env, keys);
|
|
398
|
+
jobjectArray valueArray = ToArray(env, values);
|
|
399
|
+
jobject promise = NewPromise(env, std::move(resolve), std::move(reject));
|
|
400
|
+
env->CallVoidMethod(host_.get(), updateService, jni::make_jstring(name).get(), keyArray, valueArray, promise);
|
|
401
|
+
if (ClearException(env, "NsdHost.updateService")) {
|
|
402
|
+
RejectLocally(promise, env, name);
|
|
403
|
+
}
|
|
404
|
+
env->DeleteLocalRef(keyArray);
|
|
405
|
+
env->DeleteLocalRef(valueArray);
|
|
406
|
+
env->DeleteLocalRef(promise);
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
void NsdBackend::ResolveService(
|
|
411
|
+
const std::string &name,
|
|
412
|
+
const std::string &type,
|
|
413
|
+
const std::string &protocol,
|
|
414
|
+
const std::string &domain,
|
|
415
|
+
const ResolveOptions &options,
|
|
416
|
+
ServiceCallback resolve,
|
|
417
|
+
ErrorCallback reject) {
|
|
418
|
+
if (!host_) {
|
|
419
|
+
reject(LibraryError("EXCEPTION", "The NSD implementation is not available", name));
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
WithEnv([&](JNIEnv *env) {
|
|
423
|
+
static jmethodID resolveService = env->GetMethodID(
|
|
424
|
+
HostClass(), "resolveService",
|
|
425
|
+
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;DLcom/balthazargronon/RCTZeroconf/NsdPromise;)V");
|
|
426
|
+
jobject promise = NewPromise(env, std::move(resolve), std::move(reject));
|
|
427
|
+
env->CallVoidMethod(host_.get(), resolveService, jni::make_jstring(name).get(), jni::make_jstring(type).get(), jni::make_jstring(protocol).get(),
|
|
428
|
+
jni::make_jstring(domain).get(), jni::make_jstring(options.networkInterface).get(), options.timeoutSeconds, promise);
|
|
429
|
+
if (ClearException(env, "NsdHost.resolveService")) {
|
|
430
|
+
RejectLocally(promise, env, name);
|
|
431
|
+
}
|
|
432
|
+
env->DeleteLocalRef(promise);
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
void NsdBackend::Shutdown() {
|
|
437
|
+
if (!host_) {
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
WithEnv([&](JNIEnv *env) {
|
|
441
|
+
static jmethodID shutdown = env->GetMethodID(HostClass(), "shutdown", "()V");
|
|
442
|
+
env->CallVoidMethod(host_.get(), shutdown);
|
|
443
|
+
ClearException(env, "NsdHost.shutdown");
|
|
444
|
+
});
|
|
445
|
+
std::lock_guard<std::mutex> lock(registry().mutex);
|
|
446
|
+
registry().hosts.erase(handle_);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
std::string NsdBackend::CheckLocalNetworkAccess() {
|
|
450
|
+
std::string status = "unknown";
|
|
451
|
+
WithEnv([&](JNIEnv *env) {
|
|
452
|
+
static jmethodID check = env->GetStaticMethodID(HostClass(), "checkLocalNetworkAccess", "()Ljava/lang/String;");
|
|
453
|
+
auto result = static_cast<jstring>(env->CallStaticObjectMethod(HostClass(), check));
|
|
454
|
+
if (!ClearException(env, "NsdHost.checkLocalNetworkAccess")) {
|
|
455
|
+
status = ToString(result);
|
|
456
|
+
}
|
|
457
|
+
env->DeleteLocalRef(result);
|
|
458
|
+
});
|
|
459
|
+
return status;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
} // namespace rnzeroconf
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// The backend for Android's NsdManager (NSD), which is a Java API: it drives the NSD code of the library's
|
|
2
|
+
// Java side (NsdHost) through JNI, events and results come back through native methods.
|
|
3
|
+
#pragma once
|
|
4
|
+
|
|
5
|
+
#include "../Backend.h"
|
|
6
|
+
|
|
7
|
+
#include <fbjni/fbjni.h>
|
|
8
|
+
|
|
9
|
+
#include <memory>
|
|
10
|
+
#include <string>
|
|
11
|
+
|
|
12
|
+
namespace rnzeroconf {
|
|
13
|
+
|
|
14
|
+
class NsdBackend : public Backend {
|
|
15
|
+
public:
|
|
16
|
+
static std::shared_ptr<NsdBackend> Create(Events events);
|
|
17
|
+
~NsdBackend() override;
|
|
18
|
+
|
|
19
|
+
void Scan(
|
|
20
|
+
const std::string &scanId,
|
|
21
|
+
const std::string &type,
|
|
22
|
+
const std::string &protocol,
|
|
23
|
+
const std::string &domain,
|
|
24
|
+
const ScanOptions &options) override;
|
|
25
|
+
void Stop(const std::string &scanId) override;
|
|
26
|
+
|
|
27
|
+
void Publish(
|
|
28
|
+
const std::string &type,
|
|
29
|
+
const std::string &protocol,
|
|
30
|
+
const std::string &domain,
|
|
31
|
+
const std::string &name,
|
|
32
|
+
uint16_t port,
|
|
33
|
+
const TxtPairs &txt,
|
|
34
|
+
const PublishOptions &options,
|
|
35
|
+
ServiceCallback resolve,
|
|
36
|
+
ErrorCallback reject) override;
|
|
37
|
+
void Unpublish(const std::string &name, ServiceCallback resolve, ErrorCallback reject) override;
|
|
38
|
+
void Update(const std::string &name, const TxtPairs &txt, ServiceCallback resolve, ErrorCallback reject) override;
|
|
39
|
+
|
|
40
|
+
void ResolveService(
|
|
41
|
+
const std::string &name,
|
|
42
|
+
const std::string &type,
|
|
43
|
+
const std::string &protocol,
|
|
44
|
+
const std::string &domain,
|
|
45
|
+
const ResolveOptions &options,
|
|
46
|
+
ServiceCallback resolve,
|
|
47
|
+
ErrorCallback reject) override;
|
|
48
|
+
|
|
49
|
+
void Shutdown() override;
|
|
50
|
+
|
|
51
|
+
// "granted", "denied" or "unknown": Android 17's ACCESS_LOCAL_NETWORK permission
|
|
52
|
+
static std::string CheckLocalNetworkAccess();
|
|
53
|
+
|
|
54
|
+
private:
|
|
55
|
+
NsdBackend(int64_t handle, facebook::jni::global_ref<jobject> host);
|
|
56
|
+
|
|
57
|
+
int64_t handle_;
|
|
58
|
+
facebook::jni::global_ref<jobject> host_;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
} // namespace rnzeroconf
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#include "ZeroconfAndroidModule.h"
|
|
2
|
+
|
|
3
|
+
#include "../dnssd/DnssdBackend.h"
|
|
4
|
+
#include "../embedded/EmbeddedExecutor.h"
|
|
5
|
+
#include "NsdBackend.h"
|
|
6
|
+
|
|
7
|
+
#include <android/log.h>
|
|
8
|
+
#include <fbjni/fbjni.h>
|
|
9
|
+
|
|
10
|
+
namespace facebook::react {
|
|
11
|
+
|
|
12
|
+
namespace {
|
|
13
|
+
|
|
14
|
+
// ZeroconfNativeSupport.setMulticastLock, from any thread
|
|
15
|
+
void SetMulticastLock(bool held) {
|
|
16
|
+
jni::ThreadScope::WithClassLoader([held] {
|
|
17
|
+
static const auto support = jni::findClassStatic("com/balthazargronon/RCTZeroconf/ZeroconfNativeSupport");
|
|
18
|
+
static const auto setMulticastLock = support->getStaticMethod<void(jboolean)>("setMulticastLock");
|
|
19
|
+
setMulticastLock(support, held ? JNI_TRUE : JNI_FALSE);
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
ZeroconfPlatform AndroidPlatform() {
|
|
24
|
+
ZeroconfPlatform platform;
|
|
25
|
+
// NSD (the default) is Android's NsdManager, DNSSD the mDNSResponder embedded in the library
|
|
26
|
+
platform.backendKey = [](const std::string &implType) { return std::string(implType == "DNSSD" ? "DNSSD" : "NSD"); };
|
|
27
|
+
platform.createBackend = [](const std::string &key, rnzeroconf::Events events) -> std::shared_ptr<rnzeroconf::Backend> {
|
|
28
|
+
if (key == "NSD") {
|
|
29
|
+
return rnzeroconf::NsdBackend::Create(std::move(events));
|
|
30
|
+
}
|
|
31
|
+
auto executor = rnzeroconf::EmbeddedExecutor::Shared();
|
|
32
|
+
if (executor->StartError() != 0) {
|
|
33
|
+
__android_log_print(ANDROID_LOG_ERROR, "RNZeroconf", "The embedded mDNSResponder failed to start (%d)", executor->StartError());
|
|
34
|
+
}
|
|
35
|
+
return rnzeroconf::DnssdBackend::Create(executor, std::move(events));
|
|
36
|
+
};
|
|
37
|
+
platform.setActive = SetMulticastLock;
|
|
38
|
+
// Android 17's ACCESS_LOCAL_NETWORK, JavaScript requests it when it is denied
|
|
39
|
+
platform.checkLocalNetworkAccess = [](const std::string &, double, std::function<void(const std::string &)> resolve,
|
|
40
|
+
std::function<void(const rnzeroconf::Error &)>) { resolve(rnzeroconf::NsdBackend::CheckLocalNetworkAccess()); };
|
|
41
|
+
return platform;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
} // namespace
|
|
45
|
+
|
|
46
|
+
ZeroconfAndroidModule::ZeroconfAndroidModule(std::shared_ptr<CallInvoker> jsInvoker)
|
|
47
|
+
: ZeroconfModule(std::move(jsInvoker), AndroidPlatform()) {}
|
|
48
|
+
|
|
49
|
+
} // namespace facebook::react
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// The C++ module on Android, constructed by React Native's autolinking (react-native.config.js):
|
|
2
|
+
// Android's NsdManager for NSD (through the Java side), the mDNSResponder embedded in the library for
|
|
3
|
+
// DNSSD, and the multicast lock
|
|
4
|
+
#pragma once
|
|
5
|
+
|
|
6
|
+
#include "../ZeroconfModule.h"
|
|
7
|
+
|
|
8
|
+
namespace facebook::react {
|
|
9
|
+
|
|
10
|
+
class ZeroconfAndroidModule : public ZeroconfModule {
|
|
11
|
+
public:
|
|
12
|
+
explicit ZeroconfAndroidModule(std::shared_ptr<CallInvoker> jsInvoker);
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
} // namespace facebook::react
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
#include "DispatchExecutor.h"
|
|
2
|
+
|
|
3
|
+
#include <utility>
|
|
4
|
+
|
|
5
|
+
namespace rnzeroconf {
|
|
6
|
+
|
|
7
|
+
namespace {
|
|
8
|
+
|
|
9
|
+
struct Delayed {
|
|
10
|
+
std::shared_ptr<void> timers;
|
|
11
|
+
Executor::TimerId id;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
} // namespace
|
|
15
|
+
|
|
16
|
+
DispatchExecutor::DispatchExecutor(const char *label) : queue_(dispatch_queue_create(label, DISPATCH_QUEUE_SERIAL)) {}
|
|
17
|
+
|
|
18
|
+
DispatchExecutor::~DispatchExecutor() {
|
|
19
|
+
#if !OS_OBJECT_USE_OBJC
|
|
20
|
+
dispatch_release(queue_);
|
|
21
|
+
#endif
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
void DispatchExecutor::Post(Task task) {
|
|
25
|
+
dispatch_async_f(queue_, new Task(std::move(task)), [](void *context) {
|
|
26
|
+
std::unique_ptr<Task> task(static_cast<Task *>(context));
|
|
27
|
+
(*task)();
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
Executor::TimerId DispatchExecutor::PostDelayed(double seconds, Task task) {
|
|
32
|
+
TimerId id = ++nextTimer_;
|
|
33
|
+
{
|
|
34
|
+
std::lock_guard<std::mutex> lock(timers_->mutex);
|
|
35
|
+
timers_->pending[id] = std::make_shared<Task>(std::move(task));
|
|
36
|
+
}
|
|
37
|
+
auto *delayed = new Delayed{timers_, id};
|
|
38
|
+
dispatch_after_f(dispatch_time(DISPATCH_TIME_NOW, static_cast<int64_t>(seconds * NSEC_PER_SEC)), queue_, delayed, [](void *context) {
|
|
39
|
+
std::unique_ptr<Delayed> delayed(static_cast<Delayed *>(context));
|
|
40
|
+
auto timers = std::static_pointer_cast<Timers>(delayed->timers);
|
|
41
|
+
std::shared_ptr<Task> task;
|
|
42
|
+
{
|
|
43
|
+
std::lock_guard<std::mutex> lock(timers->mutex);
|
|
44
|
+
auto found = timers->pending.find(delayed->id);
|
|
45
|
+
if (found == timers->pending.end()) {
|
|
46
|
+
// Cancelled
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
task = found->second;
|
|
50
|
+
timers->pending.erase(found);
|
|
51
|
+
}
|
|
52
|
+
(*task)();
|
|
53
|
+
});
|
|
54
|
+
return id;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
void DispatchExecutor::Cancel(TimerId timer) {
|
|
58
|
+
std::lock_guard<std::mutex> lock(timers_->mutex);
|
|
59
|
+
timers_->pending.erase(timer);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
void DispatchExecutor::Attach(DNSServiceRef ref) {
|
|
63
|
+
DNSServiceSetDispatchQueue(ref, queue_);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
} // namespace rnzeroconf
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// Executor on a serial dispatch queue: dns_sd delivers callbacks there with DNSServiceSetDispatchQueue
|
|
2
|
+
#pragma once
|
|
3
|
+
|
|
4
|
+
#include "../dnssd/Executor.h"
|
|
5
|
+
|
|
6
|
+
#include <dispatch/dispatch.h>
|
|
7
|
+
|
|
8
|
+
#include <atomic>
|
|
9
|
+
#include <map>
|
|
10
|
+
#include <memory>
|
|
11
|
+
#include <mutex>
|
|
12
|
+
|
|
13
|
+
namespace rnzeroconf {
|
|
14
|
+
|
|
15
|
+
class DispatchExecutor : public Executor {
|
|
16
|
+
public:
|
|
17
|
+
explicit DispatchExecutor(const char *label);
|
|
18
|
+
~DispatchExecutor() override;
|
|
19
|
+
|
|
20
|
+
void Post(Task task) override;
|
|
21
|
+
TimerId PostDelayed(double seconds, Task task) override;
|
|
22
|
+
void Cancel(TimerId timer) override;
|
|
23
|
+
void Attach(DNSServiceRef ref) override;
|
|
24
|
+
|
|
25
|
+
private:
|
|
26
|
+
struct Timers {
|
|
27
|
+
std::mutex mutex;
|
|
28
|
+
std::map<TimerId, std::shared_ptr<Task>> pending;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
dispatch_queue_t queue_;
|
|
32
|
+
std::atomic<TimerId> nextTimer_{0};
|
|
33
|
+
// Outlives the executor while timers are scheduled
|
|
34
|
+
std::shared_ptr<Timers> timers_ = std::make_shared<Timers>();
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
} // namespace rnzeroconf
|