source: imaps-frontend/node_modules/@parcel/watcher/src/binding.cc

main
Last change on this file was 0c6b92a, checked in by stefan toskovski <stefantoska84@…>, 5 weeks ago

Pred finalna verzija

  • Property mode set to 100644
File size: 6.6 KB
Line 
1#include <unordered_set>
2#include <node_api.h>
3#include "wasm/include.h"
4#include <napi.h>
5#include "Glob.hh"
6#include "Event.hh"
7#include "Backend.hh"
8#include "Watcher.hh"
9#include "PromiseRunner.hh"
10
11using namespace Napi;
12
13std::unordered_set<std::string> getIgnorePaths(Env env, Value opts) {
14 std::unordered_set<std::string> result;
15
16 if (opts.IsObject()) {
17 Value v = opts.As<Object>().Get(String::New(env, "ignorePaths"));
18 if (v.IsArray()) {
19 Array items = v.As<Array>();
20 for (size_t i = 0; i < items.Length(); i++) {
21 Value item = items.Get(Number::New(env, i));
22 if (item.IsString()) {
23 result.insert(std::string(item.As<String>().Utf8Value().c_str()));
24 }
25 }
26 }
27 }
28
29 return result;
30}
31
32std::unordered_set<Glob> getIgnoreGlobs(Env env, Value opts) {
33 std::unordered_set<Glob> result;
34
35 if (opts.IsObject()) {
36 Value v = opts.As<Object>().Get(String::New(env, "ignoreGlobs"));
37 if (v.IsArray()) {
38 Array items = v.As<Array>();
39 for (size_t i = 0; i < items.Length(); i++) {
40 Value item = items.Get(Number::New(env, i));
41 if (item.IsString()) {
42 auto key = item.As<String>().Utf8Value();
43 result.emplace(key);
44 }
45 }
46 }
47 }
48
49 return result;
50}
51
52std::shared_ptr<Backend> getBackend(Env env, Value opts) {
53 Value b = opts.As<Object>().Get(String::New(env, "backend"));
54 std::string backendName;
55 if (b.IsString()) {
56 backendName = std::string(b.As<String>().Utf8Value().c_str());
57 }
58
59 return Backend::getShared(backendName);
60}
61
62class WriteSnapshotRunner : public PromiseRunner {
63public:
64 WriteSnapshotRunner(Env env, Value dir, Value snap, Value opts)
65 : PromiseRunner(env),
66 snapshotPath(std::string(snap.As<String>().Utf8Value().c_str())) {
67 watcher = Watcher::getShared(
68 std::string(dir.As<String>().Utf8Value().c_str()),
69 getIgnorePaths(env, opts),
70 getIgnoreGlobs(env, opts)
71 );
72
73 backend = getBackend(env, opts);
74 }
75
76 ~WriteSnapshotRunner() {
77 watcher->unref();
78 backend->unref();
79 }
80private:
81 std::shared_ptr<Backend> backend;
82 WatcherRef watcher;
83 std::string snapshotPath;
84
85 void execute() override {
86 backend->writeSnapshot(watcher, &snapshotPath);
87 }
88};
89
90class GetEventsSinceRunner : public PromiseRunner {
91public:
92 GetEventsSinceRunner(Env env, Value dir, Value snap, Value opts)
93 : PromiseRunner(env),
94 snapshotPath(std::string(snap.As<String>().Utf8Value().c_str())) {
95 watcher = std::make_shared<Watcher>(
96 std::string(dir.As<String>().Utf8Value().c_str()),
97 getIgnorePaths(env, opts),
98 getIgnoreGlobs(env, opts)
99 );
100
101 backend = getBackend(env, opts);
102 }
103
104 ~GetEventsSinceRunner() {
105 watcher->unref();
106 backend->unref();
107 }
108private:
109 std::shared_ptr<Backend> backend;
110 WatcherRef watcher;
111 std::string snapshotPath;
112
113 void execute() override {
114 backend->getEventsSince(watcher, &snapshotPath);
115 }
116
117 Value getResult() override {
118 std::vector<Event> events = watcher->mEvents.getEvents();
119 Array eventsArray = Array::New(env, events.size());
120 size_t i = 0;
121 for (auto it = events.begin(); it != events.end(); it++) {
122 eventsArray.Set(i++, it->toJS(env));
123 }
124 return eventsArray;
125 }
126};
127
128template<class Runner>
129Value queueSnapshotWork(const CallbackInfo& info) {
130 Env env = info.Env();
131 if (info.Length() < 1 || !info[0].IsString()) {
132 TypeError::New(env, "Expected a string").ThrowAsJavaScriptException();
133 return env.Null();
134 }
135
136 if (info.Length() < 2 || !info[1].IsString()) {
137 TypeError::New(env, "Expected a string").ThrowAsJavaScriptException();
138 return env.Null();
139 }
140
141 if (info.Length() >= 3 && !info[2].IsObject()) {
142 TypeError::New(env, "Expected an object").ThrowAsJavaScriptException();
143 return env.Null();
144 }
145
146 Runner *runner = new Runner(info.Env(), info[0], info[1], info[2]);
147 return runner->queue();
148}
149
150Value writeSnapshot(const CallbackInfo& info) {
151 return queueSnapshotWork<WriteSnapshotRunner>(info);
152}
153
154Value getEventsSince(const CallbackInfo& info) {
155 return queueSnapshotWork<GetEventsSinceRunner>(info);
156}
157
158class SubscribeRunner : public PromiseRunner {
159public:
160 SubscribeRunner(Env env, Value dir, Value fn, Value opts) : PromiseRunner(env) {
161 watcher = Watcher::getShared(
162 std::string(dir.As<String>().Utf8Value().c_str()),
163 getIgnorePaths(env, opts),
164 getIgnoreGlobs(env, opts)
165 );
166
167 backend = getBackend(env, opts);
168 watcher->watch(fn.As<Function>());
169 }
170
171private:
172 WatcherRef watcher;
173 std::shared_ptr<Backend> backend;
174 FunctionReference callback;
175
176 void execute() override {
177 try {
178 backend->watch(watcher);
179 } catch (std::exception &err) {
180 watcher->destroy();
181 throw;
182 }
183 }
184};
185
186class UnsubscribeRunner : public PromiseRunner {
187public:
188 UnsubscribeRunner(Env env, Value dir, Value fn, Value opts) : PromiseRunner(env) {
189 watcher = Watcher::getShared(
190 std::string(dir.As<String>().Utf8Value().c_str()),
191 getIgnorePaths(env, opts),
192 getIgnoreGlobs(env, opts)
193 );
194
195 backend = getBackend(env, opts);
196 shouldUnwatch = watcher->unwatch(fn.As<Function>());
197 }
198
199private:
200 WatcherRef watcher;
201 std::shared_ptr<Backend> backend;
202 bool shouldUnwatch;
203
204 void execute() override {
205 if (shouldUnwatch) {
206 backend->unwatch(watcher);
207 }
208 }
209};
210
211template<class Runner>
212Value queueSubscriptionWork(const CallbackInfo& info) {
213 Env env = info.Env();
214 if (info.Length() < 1 || !info[0].IsString()) {
215 TypeError::New(env, "Expected a string").ThrowAsJavaScriptException();
216 return env.Null();
217 }
218
219 if (info.Length() < 2 || !info[1].IsFunction()) {
220 TypeError::New(env, "Expected a function").ThrowAsJavaScriptException();
221 return env.Null();
222 }
223
224 if (info.Length() >= 3 && !info[2].IsObject()) {
225 TypeError::New(env, "Expected an object").ThrowAsJavaScriptException();
226 return env.Null();
227 }
228
229 Runner *runner = new Runner(info.Env(), info[0], info[1], info[2]);
230 return runner->queue();
231}
232
233Value subscribe(const CallbackInfo& info) {
234 return queueSubscriptionWork<SubscribeRunner>(info);
235}
236
237Value unsubscribe(const CallbackInfo& info) {
238 return queueSubscriptionWork<UnsubscribeRunner>(info);
239}
240
241Object Init(Env env, Object exports) {
242 exports.Set(
243 String::New(env, "writeSnapshot"),
244 Function::New(env, writeSnapshot)
245 );
246 exports.Set(
247 String::New(env, "getEventsSince"),
248 Function::New(env, getEventsSince)
249 );
250 exports.Set(
251 String::New(env, "subscribe"),
252 Function::New(env, subscribe)
253 );
254 exports.Set(
255 String::New(env, "unsubscribe"),
256 Function::New(env, unsubscribe)
257 );
258 return exports;
259}
260
261NODE_API_MODULE(watcher, Init)
Note: See TracBrowser for help on using the repository browser.