1*84b2179eSNicolas Bonnefon #ifndef WATCHTOWER_H 2*84b2179eSNicolas Bonnefon #define WATCHTOWER_H 3*84b2179eSNicolas Bonnefon 487e05652SNicolas Bonnefon #include <memory> 587e05652SNicolas Bonnefon #include <functional> 687e05652SNicolas Bonnefon #include <string> 7a0936e1eSNicolas Bonnefon #include <vector> 8a0936e1eSNicolas Bonnefon #include <map> 9a0936e1eSNicolas Bonnefon #include <list> 1087e05652SNicolas Bonnefon 1187e05652SNicolas Bonnefon class WatchTower { 1287e05652SNicolas Bonnefon public: 1387e05652SNicolas Bonnefon // Registration object to implement RAII 1487e05652SNicolas Bonnefon using Registration = std::shared_ptr<void>; 1587e05652SNicolas Bonnefon 1687e05652SNicolas Bonnefon // Create an empty watchtower 1787e05652SNicolas Bonnefon WatchTower() {}; 1887e05652SNicolas Bonnefon // Destroy the object 1987e05652SNicolas Bonnefon virtual ~WatchTower() {}; 2087e05652SNicolas Bonnefon 2187e05652SNicolas Bonnefon // Add a file to the notification list. notification will be called when 2287e05652SNicolas Bonnefon // the file is modified, moved or deleted. 2387e05652SNicolas Bonnefon // Lifetime of the notification is tied to the Registration object returned. 2487e05652SNicolas Bonnefon // Note the notification function is called with a mutex held and in a 2587e05652SNicolas Bonnefon // third party thread, beware of races! 2687e05652SNicolas Bonnefon virtual Registration addFile( const std::string& file_name, 2787e05652SNicolas Bonnefon std::function<void()> notification ) = 0; 28a0936e1eSNicolas Bonnefon 29a0936e1eSNicolas Bonnefon protected: 30af7adfddSNicolas Bonnefon // Win32 notification variables 31af7adfddSNicolas Bonnefon static const int READ_DIR_CHANGE_BUFFER_SIZE = 4096; 32af7adfddSNicolas Bonnefon 33a0936e1eSNicolas Bonnefon // Utility classes 34af7adfddSNicolas Bonnefon struct ProtocolInfo { 35*84b2179eSNicolas Bonnefon void* handle_; 36af7adfddSNicolas Bonnefon static const unsigned long buffer_length_ = READ_DIR_CHANGE_BUFFER_SIZE; 37af7adfddSNicolas Bonnefon char buffer_[buffer_length_]; 38af7adfddSNicolas Bonnefon }; 39a0936e1eSNicolas Bonnefon 40a0936e1eSNicolas Bonnefon // List of files and observers 41a0936e1eSNicolas Bonnefon struct ObservedDir { 42a0936e1eSNicolas Bonnefon ObservedDir( const std::string this_path ) : path { this_path } {} 43af7adfddSNicolas Bonnefon 44af7adfddSNicolas Bonnefon // Returns the address of the protocol specific informations 45af7adfddSNicolas Bonnefon ProtocolInfo* protocolInfo() { return &protocol_info_; } 46af7adfddSNicolas Bonnefon 47a0936e1eSNicolas Bonnefon std::string path; 48a0936e1eSNicolas Bonnefon int dir_wd_; 49af7adfddSNicolas Bonnefon // Contains data specific to the protocol (inotify/Win32...) 50af7adfddSNicolas Bonnefon ProtocolInfo protocol_info_; 51a0936e1eSNicolas Bonnefon }; 52a0936e1eSNicolas Bonnefon 53a0936e1eSNicolas Bonnefon struct ObservedFile { 54a0936e1eSNicolas Bonnefon ObservedFile( 55a0936e1eSNicolas Bonnefon const std::string& file_name, 56a0936e1eSNicolas Bonnefon std::shared_ptr<void> callback, 57a0936e1eSNicolas Bonnefon int file_wd, 58a0936e1eSNicolas Bonnefon int symlink_wd ) : file_name_( file_name ) { 59*84b2179eSNicolas Bonnefon addCallback( callback ); 60a0936e1eSNicolas Bonnefon 61a0936e1eSNicolas Bonnefon file_wd_ = file_wd; 62a0936e1eSNicolas Bonnefon symlink_wd_ = symlink_wd; 63a0936e1eSNicolas Bonnefon dir_ = nullptr; 64a0936e1eSNicolas Bonnefon } 65a0936e1eSNicolas Bonnefon 66a0936e1eSNicolas Bonnefon void addCallback( std::shared_ptr<void> callback ) { 67a0936e1eSNicolas Bonnefon callbacks.push_back( callback ); 68a0936e1eSNicolas Bonnefon } 69a0936e1eSNicolas Bonnefon 70a0936e1eSNicolas Bonnefon std::string file_name_; 71a0936e1eSNicolas Bonnefon // List of callbacks for this file 72a0936e1eSNicolas Bonnefon std::vector<std::shared_ptr<void>> callbacks; 73a0936e1eSNicolas Bonnefon 74a0936e1eSNicolas Bonnefon // watch descriptor for the file itself 75a0936e1eSNicolas Bonnefon int file_wd_; 76a0936e1eSNicolas Bonnefon // watch descriptor for the symlink (if file is a symlink) 77a0936e1eSNicolas Bonnefon int symlink_wd_; 78a0936e1eSNicolas Bonnefon 79a0936e1eSNicolas Bonnefon // link to the dir containing the file 80a0936e1eSNicolas Bonnefon std::shared_ptr<ObservedDir> dir_; 81a0936e1eSNicolas Bonnefon }; 82a0936e1eSNicolas Bonnefon 83a0936e1eSNicolas Bonnefon // A list of the observed files and directories 84a0936e1eSNicolas Bonnefon // This class is not thread safe 85a0936e1eSNicolas Bonnefon class ObservedFileList { 86a0936e1eSNicolas Bonnefon public: 87a0936e1eSNicolas Bonnefon ObservedFileList() = default; 88a0936e1eSNicolas Bonnefon ~ObservedFileList() = default; 89a0936e1eSNicolas Bonnefon 90a0936e1eSNicolas Bonnefon ObservedFile* searchByName( const std::string& file_name ); 91a0936e1eSNicolas Bonnefon ObservedFile* searchByFileOrSymlinkWd( int wd ); 92a0936e1eSNicolas Bonnefon ObservedFile* searchByDirWdAndName( int wd, const char* name ); 93a0936e1eSNicolas Bonnefon 94a0936e1eSNicolas Bonnefon ObservedFile* addNewObservedFile( ObservedFile new_observed ); 95a0936e1eSNicolas Bonnefon // Remove a callback, remove and returns the file object if 96a0936e1eSNicolas Bonnefon // it was the last callback on this object, nullptr if not. 97a0936e1eSNicolas Bonnefon // The caller has ownership of the object. 98a0936e1eSNicolas Bonnefon std::shared_ptr<ObservedFile> removeCallback( 99a0936e1eSNicolas Bonnefon std::shared_ptr<void> callback ); 100a0936e1eSNicolas Bonnefon 101a0936e1eSNicolas Bonnefon // Return the watched directory if it is watched, or nullptr 102a0936e1eSNicolas Bonnefon std::shared_ptr<ObservedDir> watchedDirectory( const std::string& dir_name ); 103a0936e1eSNicolas Bonnefon // Create a new watched directory for dir_name 104a0936e1eSNicolas Bonnefon std::shared_ptr<ObservedDir> addWatchedDirectory( const std::string& dir_name ); 105a0936e1eSNicolas Bonnefon 106a0936e1eSNicolas Bonnefon std::shared_ptr<ObservedDir> watchedDirectoryForFile( const std::string& file_name ); 107a0936e1eSNicolas Bonnefon std::shared_ptr<ObservedDir> addWatchedDirectoryForFile( const std::string& file_name ); 108a0936e1eSNicolas Bonnefon 109a0936e1eSNicolas Bonnefon private: 110a0936e1eSNicolas Bonnefon // List of observed files 111a0936e1eSNicolas Bonnefon std::list<ObservedFile> observed_files_; 112a0936e1eSNicolas Bonnefon 113a0936e1eSNicolas Bonnefon // List of observed dirs, key-ed by name 114a0936e1eSNicolas Bonnefon std::map<std::string, std::weak_ptr<ObservedDir>> observed_dirs_; 115a0936e1eSNicolas Bonnefon 116a0936e1eSNicolas Bonnefon // Map the inotify file (including symlinks) wds to the observed file 117a0936e1eSNicolas Bonnefon std::map<int, ObservedFile*> by_file_wd_; 118a0936e1eSNicolas Bonnefon // Map the inotify directory wds to the observed files 119a0936e1eSNicolas Bonnefon std::map<int, ObservedFile*> by_dir_wd_; 120a0936e1eSNicolas Bonnefon }; 12187e05652SNicolas Bonnefon }; 122*84b2179eSNicolas Bonnefon 123*84b2179eSNicolas Bonnefon #endif 124