Skip to content

Commit 6d28968

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 985aec0 commit 6d28968

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

@@ -104,9 +114,9 @@ NSFW::~NSFW() {
104114
mRunning = false;
105115
}
106116
mWaitPoolEvents.notify_one();
107-
}
108-
if (mPollThread.joinable()) {
109-
mPollThread.join();
117+
if (mPollThread.joinable()) {
118+
mPollThread.join();
119+
}
110120
}
111121
if (gcEnabled) {
112122
instanceCount--;
@@ -159,12 +169,12 @@ void NSFW::StartWorker::OnOK() {
159169
switch (mStatus) {
160170
case ALREADY_RUNNING:
161171
mNSFW->Unref();
162-
mDeferred.Reject(Napi::Error::New(env, "This NSFW cannot be started, because it is already running.").Value());
172+
mDeferred.Reject(Napi::Error::New(env, "NSFW watcher cannot be started: already running.").Value());
163173
break;
164174

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

170180
case STARTED:
@@ -227,7 +237,7 @@ void NSFW::StopWorker::OnOK() {
227237
mNSFW->Unref();
228238
mDeferred.Resolve(Env().Undefined());
229239
} else {
230-
mDeferred.Reject(Napi::Error::New(Env(), "This NSFW cannot be stopped, because it is not running.").Value());
240+
mDeferred.Reject(Napi::Error::New(Env(), "NSFW watcher cannot be stopped: not currently running.").Value());
231241
}
232242
}
233243

@@ -256,7 +266,7 @@ void NSFW::PauseWorker::OnOK() {
256266
if (mDidPauseEvents) {
257267
mDeferred.Resolve(Env().Undefined());
258268
} else {
259-
mDeferred.Reject(Napi::Error::New(Env(), "This NSFW could not be paused.").Value());
269+
mDeferred.Reject(Napi::Error::New(Env(), "NSFW watcher could not be paused.").Value());
260270
}
261271
}
262272

@@ -285,7 +295,7 @@ void NSFW::ResumeWorker::OnOK() {
285295
if (mDidResumeEvents) {
286296
mDeferred.Resolve(Env().Undefined());
287297
} else {
288-
mDeferred.Reject(Napi::Error::New(Env(), "This NSFW could not be resumed.").Value());
298+
mDeferred.Reject(Napi::Error::New(Env(), "NSFW watcher could not be resumed.").Value());
289299
}
290300
}
291301

@@ -343,7 +353,7 @@ NSFW::UpdateExcludedPathsWorker::UpdateExcludedPathsWorker(Napi::Env env, const
343353
for(uint32_t i = 0; i < paths.Length(); i++) {
344354
Napi::Value path = paths[i];
345355
std::string str = path.ToString().Utf8Value();
346-
if (str.back() == '/') {
356+
if (!str.empty() && (str.back() == '/' || str.back() == '\\')) {
347357
str.pop_back();
348358
}
349359
mNSFW->mExcludedPaths.push_back(str);
@@ -373,15 +383,21 @@ Napi::Value NSFW::UpdateExcludedPaths(const Napi::CallbackInfo &info) {
373383
}
374384

375385
void NSFW::updateExcludedPaths() {
376-
mInterface->updateExcludedPaths(mExcludedPaths);
386+
if (mInterface) {
387+
mInterface->updateExcludedPaths(mExcludedPaths);
388+
}
377389
}
378390

379391
void NSFW::pauseQueue() {
380-
mQueue->pause();
392+
if (mQueue) {
393+
mQueue->pause();
394+
}
381395
}
382396

383397
void NSFW::resumeQueue() {
384-
mQueue->resume();
398+
if (mQueue) {
399+
mQueue->resume();
400+
}
385401
}
386402

387403
void NSFW::pollForEvents() {

0 commit comments

Comments
 (0)