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