Skip to content

Commit fc2d9c7

Browse files
Improves handling of NSFW options and lifecycle
Enhances robustness in options processing by validating error callback and excluded paths. Ensures proper thread joining and queue management during object destruction to prevent potential crashes. Refines error messages for clarity and user understanding, providing more informative feedback in case of failures. Adds checks to ensure queue and interface are valid before calling methods on them.
1 parent 5c9a85a commit fc2d9c7

File tree

1 file changed

+49
-33
lines changed

1 file changed

+49
-33
lines changed

src/NSFW.cpp

Lines changed: 49 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -56,37 +56,47 @@ NSFW::NSFW(const Napi::CallbackInfo &info):
5656

5757
// errorCallback
5858
Napi::Value maybeErrorCallback = options["errorCallback"];
59-
if (options.Has("errorCallback") && !maybeErrorCallback.IsFunction()) {
59+
if (options.Has("errorCallback") && !maybeErrorCallback.IsFunction() && !maybeErrorCallback.IsNull() && !maybeErrorCallback.IsUndefined()) {
6060
throw Napi::TypeError::New(env, "options.errorCallback must be a function.");
6161
}
6262

63-
mErrorCallback = Napi::ThreadSafeFunction::New(
64-
env,
65-
maybeErrorCallback.IsFunction()
66-
? maybeErrorCallback.As<Napi::Function>()
67-
: Napi::Function::New(env, [](const Napi::CallbackInfo &info) {}),
68-
"nsfw",
69-
0,
70-
1
71-
);
63+
if (maybeErrorCallback.IsFunction()) {
64+
mErrorCallback = Napi::ThreadSafeFunction::New(
65+
env,
66+
maybeErrorCallback.As<Napi::Function>(),
67+
"nsfw",
68+
0,
69+
1
70+
);
71+
} else {
72+
mErrorCallback = Napi::ThreadSafeFunction::New(
73+
env,
74+
Napi::Function::New(env, [](const Napi::CallbackInfo &info) {}),
75+
"nsfw",
76+
0,
77+
1
78+
);
79+
}
7280

7381
// excludedPaths
7482
Napi::Value maybeExcludedPaths = options["excludedPaths"];
7583
if (options.Has("excludedPaths") && !maybeExcludedPaths.IsArray()) {
7684
throw Napi::TypeError::New(env, "options.excludedPaths must be an array.");
7785
}
78-
Napi::Array paths = maybeExcludedPaths.As<Napi::Array>();
79-
for(uint32_t i = 0; i < paths.Length(); i++) {
80-
Napi::Value path = paths[i];
81-
if (path.IsString())
82-
{
83-
std::string str = path.ToString().Utf8Value();
84-
if (str.back() == '/') {
85-
str.pop_back();
86+
if (maybeExcludedPaths.IsArray()) {
87+
Napi::Array paths = maybeExcludedPaths.As<Napi::Array>();
88+
for(uint32_t i = 0; i < paths.Length(); i++) {
89+
Napi::Value path = paths[i];
90+
if (path.IsString())
91+
{
92+
std::string str = path.ToString().Utf8Value();
93+
if (!str.empty() && (str.back() == '/' || str.back() == '\\')) {
94+
str.pop_back();
95+
}
96+
mExcludedPaths.push_back(str);
97+
} else {
98+
throw Napi::TypeError::New(env, "options.excludedPaths elements must be strings.");
8699
}
87-
mExcludedPaths.push_back(str);
88-
} else {
89-
throw Napi::TypeError::New(env, "options.excludedPaths elements must be strings.");
90100
}
91101
}
92102

@@ -105,9 +115,9 @@ NSFW::~NSFW() {
105115
mRunning = false;
106116
}
107117
mWaitPoolEvents.notify_one();
108-
}
109-
if (mPollThread.joinable()) {
110-
mPollThread.join();
118+
if (mPollThread.joinable()) {
119+
mPollThread.join();
120+
}
111121
}
112122
if (gcEnabled) {
113123
instanceCount--;
@@ -160,12 +170,12 @@ void NSFW::StartWorker::OnOK() {
160170
switch (mStatus) {
161171
case ALREADY_RUNNING:
162172
mNSFW->Unref();
163-
mDeferred.Reject(Napi::Error::New(env, "This NSFW cannot be started, because it is already running.").Value());
173+
mDeferred.Reject(Napi::Error::New(env, "NSFW watcher cannot be started: already running.").Value());
164174
break;
165175

166176
case COULD_NOT_START:
167177
mNSFW->Unref();
168-
mDeferred.Reject(Napi::Error::New(env, "NSFW was unable to start watching that directory.").Value());
178+
mDeferred.Reject(Napi::Error::New(env, "NSFW failed to start: unable to watch directory.").Value());
169179
break;
170180

171181
case STARTED:
@@ -228,7 +238,7 @@ void NSFW::StopWorker::OnOK() {
228238
mNSFW->Unref();
229239
mDeferred.Resolve(Env().Undefined());
230240
} else {
231-
mDeferred.Reject(Napi::Error::New(Env(), "This NSFW cannot be stopped, because it is not running.").Value());
241+
mDeferred.Reject(Napi::Error::New(Env(), "NSFW watcher cannot be stopped: not currently running.").Value());
232242
}
233243
}
234244

@@ -257,7 +267,7 @@ void NSFW::PauseWorker::OnOK() {
257267
if (mDidPauseEvents) {
258268
mDeferred.Resolve(Env().Undefined());
259269
} else {
260-
mDeferred.Reject(Napi::Error::New(Env(), "This NSFW could not be paused.").Value());
270+
mDeferred.Reject(Napi::Error::New(Env(), "NSFW watcher could not be paused.").Value());
261271
}
262272
}
263273

@@ -286,7 +296,7 @@ void NSFW::ResumeWorker::OnOK() {
286296
if (mDidResumeEvents) {
287297
mDeferred.Resolve(Env().Undefined());
288298
} else {
289-
mDeferred.Reject(Napi::Error::New(Env(), "This NSFW could not be resumed.").Value());
299+
mDeferred.Reject(Napi::Error::New(Env(), "NSFW watcher could not be resumed.").Value());
290300
}
291301
}
292302

@@ -344,7 +354,7 @@ NSFW::UpdateExcludedPathsWorker::UpdateExcludedPathsWorker(Napi::Env env, const
344354
for(uint32_t i = 0; i < paths.Length(); i++) {
345355
Napi::Value path = paths[i];
346356
std::string str = path.ToString().Utf8Value();
347-
if (str.back() == '/') {
357+
if (!str.empty() && (str.back() == '/' || str.back() == '\\')) {
348358
str.pop_back();
349359
}
350360
mNSFW->mExcludedPaths.push_back(str);
@@ -374,15 +384,21 @@ Napi::Value NSFW::UpdateExcludedPaths(const Napi::CallbackInfo &info) {
374384
}
375385

376386
void NSFW::updateExcludedPaths() {
377-
mInterface->updateExcludedPaths(mExcludedPaths);
387+
if (mInterface) {
388+
mInterface->updateExcludedPaths(mExcludedPaths);
389+
}
378390
}
379391

380392
void NSFW::pauseQueue() {
381-
mQueue->pause();
393+
if (mQueue) {
394+
mQueue->pause();
395+
}
382396
}
383397

384398
void NSFW::resumeQueue() {
385-
mQueue->resume();
399+
if (mQueue) {
400+
mQueue->resume();
401+
}
386402
}
387403

388404
void NSFW::pollForEvents() {

0 commit comments

Comments
 (0)