xref: /glogg/src/watchtower.h (revision 84b2179eb3774e43dfb52da96116070d4545d8c7) !
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