Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 7dd43fb

Browse files
authored
Merge pull request menloresearch#1733 from janhq/j/fix-event-listener-macos
fix: event listener not work on macos
2 parents a4093b5 + 146e2b6 commit 7dd43fb

File tree

2 files changed

+53
-36
lines changed

2 files changed

+53
-36
lines changed

engine/config/yaml_config.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ void YamlHandler::Reset() {
1818
void YamlHandler::ReadYamlFile(const std::string& file_path) {
1919
namespace fs = std::filesystem;
2020
namespace fmu = file_manager_utils;
21+
2122
try {
2223
yaml_node_ = YAML::LoadFile(file_path);
2324
// incase of model.yml file, we don't have files yet, create them
@@ -41,7 +42,6 @@ void YamlHandler::ReadYamlFile(const std::string& file_path) {
4142
yaml_node_["files"] = v;
4243
}
4344
} catch (const YAML::BadFile& e) {
44-
std::cerr << "Failed to read file: " << e.what() << std::endl;
4545
throw;
4646
}
4747
}

engine/services/file_watcher_service.h

Lines changed: 52 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
#include <windows.h>
1414

1515
#else // Linux
16-
#include <poll.h>
1716
#include <limits.h>
17+
#include <poll.h>
1818
#include <sys/inotify.h>
1919
#include <unistd.h>
2020
#endif
@@ -121,39 +121,59 @@ class FileWatcherService {
121121
auto* watcher = static_cast<FileWatcherService*>(clientCallBackInfo);
122122

123123
for (size_t i = 0; i < numEvents; i++) {
124-
if (eventFlags[i] & kFSEventStreamEventFlagItemRemoved) {
124+
if (eventFlags[i] & (kFSEventStreamEventFlagItemRemoved |
125+
kFSEventStreamEventFlagItemRenamed |
126+
kFSEventStreamEventFlagItemModified)) {
127+
CTL_INF("File removed: " + std::string(paths[i]));
128+
CTL_INF("File event detected: " + std::string(paths[i]) +
129+
" flags: " + std::to_string(eventFlags[i]));
125130
watcher->model_service_->ForceIndexingModelList();
126131
}
127132
}
128133
}
129134

130135
void WatcherThread() {
131-
// macOS implementation
132-
auto mypath = CFStringCreateWithCString(NULL, watch_path_.c_str(),
133-
kCFStringEncodingUTF8);
134-
auto path_to_watch = CFArrayCreate(NULL, (const void**)&mypath, 1, NULL);
136+
CFRunLoopRef runLoop = CFRunLoopGetCurrent();
135137

136-
FSEventStreamContext context = {0, this, NULL, NULL, NULL};
138+
auto path = CFStringCreateWithCString(nullptr, watch_path_.c_str(),
139+
kCFStringEncodingUTF8);
140+
auto path_to_watch =
141+
CFArrayCreate(nullptr, (const void**)&path, 1, &kCFTypeArrayCallBacks);
137142

138-
event_stream =
139-
FSEventStreamCreate(NULL, &FileWatcherService::callback, &context,
140-
path_to_watch, kFSEventStreamEventIdSinceNow,
141-
0.5, // 500ms latency
142-
kFSEventStreamCreateFlagFileEvents);
143+
FSEventStreamContext context = {0, this, nullptr, nullptr, nullptr};
143144

144-
dispatch_queue_t queue = dispatch_get_main_queue();
145-
FSEventStreamSetDispatchQueue(event_stream, queue);
146-
FSEventStreamStart(event_stream);
145+
event_stream = FSEventStreamCreate(
146+
nullptr, &FileWatcherService::callback, &context, path_to_watch,
147+
kFSEventStreamEventIdSinceNow, 1, // each second
148+
kFSEventStreamCreateFlagFileEvents | kFSEventStreamCreateFlagNoDefer |
149+
kFSEventStreamCreateFlagWatchRoot);
150+
151+
if (!event_stream) {
152+
CFRelease(path_to_watch);
153+
CFRelease(path);
154+
throw std::runtime_error("Failed to create FSEvent stream");
155+
}
156+
157+
FSEventStreamScheduleWithRunLoop(event_stream, runLoop,
158+
kCFRunLoopDefaultMode);
159+
160+
if (!FSEventStreamStart(event_stream)) {
161+
FSEventStreamInvalidate(event_stream);
162+
FSEventStreamRelease(event_stream);
163+
CFRelease(path_to_watch);
164+
CFRelease(path);
165+
throw std::runtime_error("Failed to start FSEvent stream");
166+
}
147167

148168
while (running_) {
149-
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1.0, false);
169+
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.25, true);
150170
}
151171

152172
FSEventStreamStop(event_stream);
153173
FSEventStreamInvalidate(event_stream);
154174
FSEventStreamRelease(event_stream);
155175
CFRelease(path_to_watch);
156-
CFRelease(mypath);
176+
CFRelease(path);
157177
}
158178

159179
#elif defined(_WIN32)
@@ -221,22 +241,22 @@ class FileWatcherService {
221241
const int watch_flags = IN_DELETE | IN_DELETE_SELF | IN_CREATE;
222242
wd = inotify_add_watch(fd, dirPath.c_str(), watch_flags);
223243
if (wd < 0) {
224-
throw std::runtime_error("Failed to add watch on " + dirPath +
225-
": " + std::string(strerror(errno)));
244+
throw std::runtime_error("Failed to add watch on " + dirPath + ": " +
245+
std::string(strerror(errno)));
226246
}
227247
watch_descriptors[wd] = dirPath;
228248

229249
// Add watches for subdirectories
230250
try {
231-
for (const auto& entry :
251+
for (const auto& entry :
232252
std::filesystem::recursive_directory_iterator(dirPath)) {
233253
if (std::filesystem::is_directory(entry)) {
234254
int subwd = inotify_add_watch(fd, entry.path().c_str(), watch_flags);
235255
if (subwd >= 0) {
236256
watch_descriptors[subwd] = entry.path().string();
237257
} else {
238-
CTL_ERR("Failed to add watch for subdirectory " +
239-
entry.path().string() + ": " +
258+
CTL_ERR("Failed to add watch for subdirectory " +
259+
entry.path().string() + ": " +
240260
std::string(strerror(errno)));
241261
}
242262
}
@@ -274,21 +294,17 @@ class FileWatcherService {
274294
return;
275295
}
276296

277-
const int POLL_TIMEOUT_MS = 1000; // 1 second timeout
297+
const int POLL_TIMEOUT_MS = 1000; // 1 second timeout
278298
char buffer[4096];
279-
struct pollfd pfd = {
280-
.fd = fd,
281-
.events = POLLIN,
282-
.revents = 0
283-
};
284-
299+
struct pollfd pfd = {.fd = fd, .events = POLLIN, .revents = 0};
300+
285301
while (running_) {
286302
// Poll will sleep until either:
287303
// 1. Events are available (POLLIN)
288304
// 2. POLL_TIMEOUT_MS milliseconds have elapsed
289305
// 3. An error occurs
290306
int poll_result = poll(&pfd, 1, POLL_TIMEOUT_MS);
291-
307+
292308
if (poll_result < 0) {
293309
if (errno == EINTR) {
294310
// System call was interrupted, just retry
@@ -297,7 +313,7 @@ class FileWatcherService {
297313
CTL_ERR("Poll failed: " + std::string(strerror(errno)));
298314
break;
299315
}
300-
316+
301317
if (poll_result == 0) { // Timeout - no events
302318
// No need to sleep - poll() already waited
303319
continue;
@@ -327,17 +343,18 @@ class FileWatcherService {
327343
// Process events
328344
size_t i = 0;
329345
while (i < static_cast<size_t>(length)) {
330-
struct inotify_event* event =
346+
struct inotify_event* event =
331347
reinterpret_cast<struct inotify_event*>(&buffer[i]);
332-
348+
333349
if (event->mask & (IN_DELETE | IN_DELETE_SELF)) {
334350
try {
335351
model_service_->ForceIndexingModelList();
336352
} catch (const std::exception& e) {
337-
CTL_ERR("Error processing delete event: " + std::string(e.what()));
353+
CTL_ERR("Error processing delete event: " +
354+
std::string(e.what()));
338355
}
339356
}
340-
357+
341358
i += sizeof(struct inotify_event) + event->len;
342359
}
343360
}

0 commit comments

Comments
 (0)