Skip to content

Commit a98d879

Browse files
committed
add fs_event.hpp
1 parent 2c4f429 commit a98d879

File tree

5 files changed

+172
-2
lines changed

5 files changed

+172
-2
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ ExternalProject_Add(libuv
2424
#GIT_REPOSITORY "https://github.com/libuv/libuv.git"
2525
GIT_REPOSITORY "$ENV{HOME}/dev/github/libuv"
2626
#GIT_TAG "v1.x"
27-
GIT_TAG "v1.33.1"
27+
GIT_TAG "v1.30.1"
2828
CONFIGURE_COMMAND ${CONFIGURE_COMMMAND}
2929
BUILD_IN_SOURCE 1
3030
BUILD_COMMAND $(MAKE)

src/fs_event.hpp

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*******************************************************************************
2+
** File: fs_event.hpp
3+
** Author: neevek <[email protected]>.
4+
** Creation Time: 2020-04-12 Sun 03:22 PM
5+
** Description: a wrapper of uv_fs_event_t
6+
*******************************************************************************/
7+
#ifndef UVCPP_FS_EVENT_H_
8+
#define UVCPP_FS_EVENT_H_
9+
#include "handle.hpp"
10+
#include <thread>
11+
12+
namespace uvcpp {
13+
struct EvFsEvent : public Event {
14+
enum class Event : int {
15+
kRename = 1,
16+
kChange = 2
17+
};
18+
19+
EvFsEvent(const char *path, Event events, int status) :
20+
path(path ? path : ""), events(events), status(status) { }
21+
22+
std::string path; // could be empty
23+
Event events;
24+
int status;
25+
};
26+
27+
class FsEvent : public Handle<uv_fs_event_t, FsEvent> {
28+
friend class Resource;
29+
friend class Handle;
30+
31+
public:
32+
enum class Flag : unsigned int {
33+
kWatchEntry = 1,
34+
kStat = 2,
35+
kRecursive = 4
36+
};
37+
38+
friend FsEvent::Flag operator|(FsEvent::Flag lhs, FsEvent::Flag rhs) {
39+
typedef typename std::underlying_type<FsEvent::Flag>::type underlying;
40+
return static_cast<FsEvent::Flag>(
41+
static_cast<underlying>(lhs) | static_cast<underlying>(rhs));
42+
}
43+
44+
protected:
45+
FsEvent(const std::shared_ptr<Loop> &loop) : Handle(loop) {}
46+
47+
virtual bool init() override {
48+
if (uv_fs_event_init(this->getLoop()->getRaw(), get()) != 0) {
49+
LOG_E("uv_fs_event_init failed");
50+
return false;
51+
}
52+
return true;
53+
}
54+
55+
public:
56+
void start(const std::string &path, Flag flags) {
57+
if (path.empty()) {
58+
this->reportError("path is empty", 0);
59+
return;
60+
}
61+
62+
int err;
63+
if ((err = uv_fs_event_start(
64+
static_cast<uv_fs_event_t *>(this->get()),
65+
onFsEventCallback, path.c_str(),
66+
static_cast<unsigned int>(flags))) != 0) {
67+
this->reportError("uv_fs_event_start", err);
68+
}
69+
}
70+
71+
void stop() {
72+
int err;
73+
if ((err = uv_fs_event_stop(
74+
static_cast<uv_fs_event_t *>(this->get()))) != 0) {
75+
this->reportError("uv_fs_event_stop", err);
76+
}
77+
}
78+
79+
private:
80+
static void onFsEventCallback(
81+
uv_fs_event_t *handle, const char *filename, int events, int status) {
82+
size_t size = 2048;
83+
char path[size];
84+
85+
auto ret = uv_fs_event_getpath(handle, path, &size);
86+
if (ret == UV_ENOBUFS) {
87+
static_cast<FsEvent *>(handle->data)->reportError(
88+
"uv_fs_event_getpath failed, buffer size too small", ret);
89+
90+
} else {
91+
static_cast<FsEvent *>(handle->data)->template
92+
publish<EvFsEvent>(EvFsEvent{
93+
path, static_cast<EvFsEvent::Event>(events), status
94+
});
95+
}
96+
}
97+
};
98+
99+
} /* end of namespace: uvcpp */
100+
101+
#endif /* end of include guard: UVCPP_FS_EVENT_H_ */

src/uvcpp.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "timer.hpp"
1616
#include "prepare.hpp"
1717
#include "poll.hpp"
18+
#include "fs_event.hpp"
1819
#include "ext/poll_unix_sock.hpp"
1920

2021
#endif /* end of include guard: UVCPP_H_ */

test/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ SET_LIBRARY_PROP(uv uvcpp "${UV_LIBRARY_DIR}/libuv.a")
5252
ExternalProject_Add(gtest
5353
PREFIX "${CMAKE_BINARY_DIR}/deps"
5454
GIT_REPOSITORY "https://github.com/google/googletest.git"
55-
GIT_TAG "master"
55+
GIT_TAG "release-1.8.1"
5656
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}/deps/installed
5757
GIT_SHALLOW 1
5858
GIT_PROGRESS 1
@@ -89,6 +89,7 @@ ADD_UVCPP_TEST(timer uvcpp/timer.cc)
8989
ADD_UVCPP_TEST(prepare uvcpp/prepare.cc)
9090
ADD_UVCPP_TEST(work uvcpp/work.cc)
9191
ADD_UVCPP_TEST(poll uvcpp/poll.cc)
92+
ADD_UVCPP_TEST(fs_event uvcpp/fs_event.cc)
9293

9394
# build a executable without gtest, so we can debug the code
9495
#add_executable(testpipe uvcpp/testpipe.cc)

test/uvcpp/fs_event.cc

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
#include <gtest/gtest.h>
2+
#include "uvcpp.h"
3+
#include <fstream>
4+
5+
using namespace uvcpp;
6+
7+
TEST(FsEvent, TestFileChange) {
8+
auto destroyed = false;
9+
auto count = 0;
10+
{
11+
auto loop = std::make_shared<Loop>();
12+
ASSERT_TRUE(loop->init());
13+
14+
auto fsEvent = FsEvent::create(loop);
15+
ASSERT_TRUE(!!fsEvent);
16+
17+
fsEvent->on<EvError>([](const auto &e, auto &fsEvent) {
18+
FAIL() << "fsEvent failed with status: " << e.status << ", msg: " << e.message;
19+
});
20+
fsEvent->on<EvClose>([fe = fsEvent](const auto &e, auto &fsEvent) {
21+
LOG_D("fsEvent closed: %li", fe.use_count());
22+
});
23+
fsEvent->once<EvDestroy>([&destroyed, fe = &fsEvent](const auto &e, auto &fsEvent) {
24+
LOG_D("fsEvent destroyed: %li", fe->use_count());
25+
destroyed = true;
26+
});
27+
28+
fsEvent->on<EvFsEvent>([&count](const auto &e, auto &fsEvent) {
29+
LOG_D("haha changed: %d", e.events);
30+
if (e.events == EvFsEvent::Event::kChange) {
31+
if (++count >= 2) {
32+
fsEvent.stop();
33+
fsEvent.close();
34+
}
35+
}
36+
});
37+
38+
auto testFile = "./test_fs_event.txt";
39+
int fd = open(testFile, O_RDWR|O_CREAT, 0644);
40+
if (fd != -1) {
41+
close(fd);
42+
}
43+
44+
fsEvent->start(testFile, FsEvent::Flag::kRecursive);
45+
46+
LOG_D("will run thread");
47+
auto t = std::thread([&](){
48+
auto changeFile = [&]() {
49+
LOG_D("will change file: %s", testFile);
50+
std::ofstream os(testFile, std::ios::binary);
51+
os << "test";
52+
os.close();
53+
};
54+
changeFile();
55+
changeFile();
56+
unlink(testFile);
57+
});
58+
59+
LOG_D("will run loop");
60+
61+
loop->run();
62+
t.join();
63+
}
64+
65+
ASSERT_TRUE(destroyed);
66+
ASSERT_TRUE(count == 2);
67+
}

0 commit comments

Comments
 (0)