1 #pragma once
2 
3 
4 #include <utility>
5 #include <string>
6 #include <memory>
7 #include <uv.h>
8 #include "handle.hpp"
9 #include "util.hpp"
10 #include "loop.hpp"
11 
12 
13 namespace uvw {
14 
15 
16 namespace details {
17 
18 
19 enum class UVFsEventFlags: std::underlying_type_t<uv_fs_event_flags> {
20     WATCH_ENTRY = UV_FS_EVENT_WATCH_ENTRY,
21     STAT = UV_FS_EVENT_STAT,
22     RECURSIVE = UV_FS_EVENT_RECURSIVE
23 };
24 
25 
26 enum class UVFsEvent: std::underlying_type_t<uv_fs_event> {
27     RENAME = UV_RENAME,
28     CHANGE = UV_CHANGE
29 };
30 
31 
32 }
33 
34 
35 /**
36  * @brief FsEventEvent event.
37  *
38  * It will be emitted by FsEventHandle according with its functionalities.
39  */
40 struct FsEventEvent {
FsEventEventuvw::FsEventEvent41     FsEventEvent(const char * pathname, Flags<details::UVFsEvent> events)
42         : filename{pathname}, flags{std::move(events)}
43     {}
44 
45     /**
46      * @brief The path to the file being monitored.
47      *
48      * If the handle was started with a directory, the filename parameter will
49      * be a relative path to a file contained in the directory.
50      */
51     const char * filename;
52 
53     /**
54      * @brief Detected events all in one.
55      *
56      * Available flags are:
57      *
58      * * `FsEventHandle::Watch::RENAME`
59      * * `FsEventHandle::Watch::CHANGE`
60      */
61     Flags<details::UVFsEvent> flags;
62 };
63 
64 
65 /**
66  * @brief The FsEventHandle handle.
67  *
68  * These handles allow the user to monitor a given path for changes, for
69  * example, if the file was renamed or there was a generic change in it. The
70  * best backend for the job on each platform is chosen by the handle.
71  *
72  * To create a `FsEventHandle` through a `Loop`, no arguments are required.
73  *
74  * See the official
75  * [documentation](http://docs.libuv.org/en/v1.x/fs_event.html)
76  * for further details.
77  */
78 class FsEventHandle final: public Handle<FsEventHandle, uv_fs_event_t> {
startCallback(uv_fs_event_t * handle,const char * filename,int events,int status)79     static void startCallback(uv_fs_event_t *handle, const char *filename, int events, int status) {
80         FsEventHandle &fsEvent = *(static_cast<FsEventHandle*>(handle->data));
81         if(status) { fsEvent.publish(ErrorEvent{status}); }
82         else { fsEvent.publish(FsEventEvent{filename, static_cast<std::underlying_type_t<details::UVFsEvent>>(events)}); }
83     }
84 
85 public:
86     using Watch = details::UVFsEvent;
87     using Event = details::UVFsEventFlags;
88 
89     using Handle::Handle;
90 
91     /**
92      * @brief Initializes the handle.
93      * @return True in case of success, false otherwise.
94      */
init()95     bool init() {
96         return initialize(&uv_fs_event_init);
97     }
98 
99     /**
100      * @brief Starts watching the specified path.
101      *
102      * It will watch the specified path for changes.<br/>
103      * As soon as a change is observed, a FsEventEvent is emitted by the
104      * handle.<br>
105      * It could happen that ErrorEvent events are emitted while running.
106      *
107      * Available flags are:
108      *
109      * * `FsEventHandle::Event::WATCH_ENTRY`
110      * * `FsEventHandle::Event::STAT`
111      * * `FsEventHandle::Event::RECURSIVE`
112      *
113      * @param path The file or directory to be monitored.
114      * @param flags Additional flags to control the behavior.
115      */
start(std::string path,Flags<Event> flags=Flags<Event>{})116     void start(std::string path, Flags<Event> flags = Flags<Event>{}) {
117         invoke(&uv_fs_event_start, get(), &startCallback, path.data(), flags);
118     }
119 
120     /**
121      * @brief Starts watching the specified path.
122      *
123      * It will watch the specified path for changes.<br/>
124      * As soon as a change is observed, a FsEventEvent is emitted by the
125      * handle.<br>
126      * It could happen that ErrorEvent events are emitted while running.
127      *
128      * Available flags are:
129      *
130      * * `FsEventHandle::Event::WATCH_ENTRY`
131      * * `FsEventHandle::Event::STAT`
132      * * `FsEventHandle::Event::RECURSIVE`
133      *
134      * @param path The file or directory to be monitored.
135      * @param flag Additional flag to control the behavior.
136      */
start(std::string path,Event flag)137     void start(std::string path, Event flag) {
138         start(std::move(path), Flags<Event>{flag});
139     }
140 
141     /**
142      * @brief Stops polling the file descriptor.
143      */
stop()144     void stop() {
145         invoke(&uv_fs_event_stop, get());
146     }
147 
148     /**
149      * @brief Gets the path being monitored.
150      * @return The path being monitored, an empty string in case of errors.
151      */
path()152     std::string path() noexcept {
153         return details::tryRead(&uv_fs_event_getpath, get());
154     }
155 };
156 
157 
158 }
159