xref: /glogg/src/watchtower.h (revision a0936e1e21791a259b77497eb5cb6e01c4eea5a4)
187e05652SNicolas Bonnefon #include <memory>
287e05652SNicolas Bonnefon #include <functional>
387e05652SNicolas Bonnefon #include <string>
4*a0936e1eSNicolas Bonnefon #include <vector>
5*a0936e1eSNicolas Bonnefon #include <map>
6*a0936e1eSNicolas Bonnefon #include <list>
787e05652SNicolas Bonnefon 
887e05652SNicolas Bonnefon class WatchTower {
987e05652SNicolas Bonnefon   public:
1087e05652SNicolas Bonnefon     // Registration object to implement RAII
1187e05652SNicolas Bonnefon     using Registration = std::shared_ptr<void>;
1287e05652SNicolas Bonnefon 
1387e05652SNicolas Bonnefon     // Create an empty watchtower
1487e05652SNicolas Bonnefon     WatchTower() {};
1587e05652SNicolas Bonnefon     // Destroy the object
1687e05652SNicolas Bonnefon     virtual ~WatchTower() {};
1787e05652SNicolas Bonnefon 
1887e05652SNicolas Bonnefon     // Add a file to the notification list. notification will be called when
1987e05652SNicolas Bonnefon     // the file is modified, moved or deleted.
2087e05652SNicolas Bonnefon     // Lifetime of the notification is tied to the Registration object returned.
2187e05652SNicolas Bonnefon     // Note the notification function is called with a mutex held and in a
2287e05652SNicolas Bonnefon     // third party thread, beware of races!
2387e05652SNicolas Bonnefon     virtual Registration addFile( const std::string& file_name,
2487e05652SNicolas Bonnefon             std::function<void()> notification ) = 0;
25*a0936e1eSNicolas Bonnefon 
26*a0936e1eSNicolas Bonnefon   protected:
27*a0936e1eSNicolas Bonnefon     // Utility classes
28*a0936e1eSNicolas Bonnefon 
29*a0936e1eSNicolas Bonnefon     // List of files and observers
30*a0936e1eSNicolas Bonnefon     struct ObservedDir {
31*a0936e1eSNicolas Bonnefon         ObservedDir( const std::string this_path ) : path { this_path } {}
32*a0936e1eSNicolas Bonnefon         std::string path;
33*a0936e1eSNicolas Bonnefon         int dir_wd_;
34*a0936e1eSNicolas Bonnefon     };
35*a0936e1eSNicolas Bonnefon 
36*a0936e1eSNicolas Bonnefon     struct ObservedFile {
37*a0936e1eSNicolas Bonnefon         ObservedFile(
38*a0936e1eSNicolas Bonnefon                 const std::string& file_name,
39*a0936e1eSNicolas Bonnefon                 std::shared_ptr<void> callback,
40*a0936e1eSNicolas Bonnefon                 int file_wd,
41*a0936e1eSNicolas Bonnefon                 int symlink_wd ) : file_name_( file_name ) {
42*a0936e1eSNicolas Bonnefon             callbacks.push_back( callback );
43*a0936e1eSNicolas Bonnefon 
44*a0936e1eSNicolas Bonnefon             file_wd_    = file_wd;
45*a0936e1eSNicolas Bonnefon             symlink_wd_ = symlink_wd;
46*a0936e1eSNicolas Bonnefon             dir_        = nullptr;
47*a0936e1eSNicolas Bonnefon         }
48*a0936e1eSNicolas Bonnefon 
49*a0936e1eSNicolas Bonnefon         void addCallback( std::shared_ptr<void> callback ) {
50*a0936e1eSNicolas Bonnefon             callbacks.push_back( callback );
51*a0936e1eSNicolas Bonnefon         }
52*a0936e1eSNicolas Bonnefon 
53*a0936e1eSNicolas Bonnefon         std::string file_name_;
54*a0936e1eSNicolas Bonnefon         // List of callbacks for this file
55*a0936e1eSNicolas Bonnefon         std::vector<std::shared_ptr<void>> callbacks;
56*a0936e1eSNicolas Bonnefon 
57*a0936e1eSNicolas Bonnefon         // watch descriptor for the file itself
58*a0936e1eSNicolas Bonnefon         int file_wd_;
59*a0936e1eSNicolas Bonnefon         // watch descriptor for the symlink (if file is a symlink)
60*a0936e1eSNicolas Bonnefon         int symlink_wd_;
61*a0936e1eSNicolas Bonnefon 
62*a0936e1eSNicolas Bonnefon         // link to the dir containing the file
63*a0936e1eSNicolas Bonnefon         std::shared_ptr<ObservedDir> dir_;
64*a0936e1eSNicolas Bonnefon     };
65*a0936e1eSNicolas Bonnefon 
66*a0936e1eSNicolas Bonnefon     // A list of the observed files and directories
67*a0936e1eSNicolas Bonnefon     // This class is not thread safe
68*a0936e1eSNicolas Bonnefon     class ObservedFileList {
69*a0936e1eSNicolas Bonnefon       public:
70*a0936e1eSNicolas Bonnefon         ObservedFileList() = default;
71*a0936e1eSNicolas Bonnefon         ~ObservedFileList() = default;
72*a0936e1eSNicolas Bonnefon 
73*a0936e1eSNicolas Bonnefon         ObservedFile* searchByName( const std::string& file_name );
74*a0936e1eSNicolas Bonnefon         ObservedFile* searchByFileOrSymlinkWd( int wd );
75*a0936e1eSNicolas Bonnefon         ObservedFile* searchByDirWdAndName( int wd, const char* name );
76*a0936e1eSNicolas Bonnefon 
77*a0936e1eSNicolas Bonnefon         ObservedFile* addNewObservedFile( ObservedFile new_observed );
78*a0936e1eSNicolas Bonnefon         // Remove a callback, remove and returns the file object if
79*a0936e1eSNicolas Bonnefon         // it was the last callback on this object, nullptr if not.
80*a0936e1eSNicolas Bonnefon         // The caller has ownership of the object.
81*a0936e1eSNicolas Bonnefon         std::shared_ptr<ObservedFile> removeCallback(
82*a0936e1eSNicolas Bonnefon                 std::shared_ptr<void> callback );
83*a0936e1eSNicolas Bonnefon 
84*a0936e1eSNicolas Bonnefon         // Return the watched directory if it is watched, or nullptr
85*a0936e1eSNicolas Bonnefon         std::shared_ptr<ObservedDir> watchedDirectory( const std::string& dir_name );
86*a0936e1eSNicolas Bonnefon         // Create a new watched directory for dir_name
87*a0936e1eSNicolas Bonnefon         std::shared_ptr<ObservedDir> addWatchedDirectory( const std::string& dir_name );
88*a0936e1eSNicolas Bonnefon 
89*a0936e1eSNicolas Bonnefon         std::shared_ptr<ObservedDir> watchedDirectoryForFile( const std::string& file_name );
90*a0936e1eSNicolas Bonnefon         std::shared_ptr<ObservedDir> addWatchedDirectoryForFile( const std::string& file_name );
91*a0936e1eSNicolas Bonnefon 
92*a0936e1eSNicolas Bonnefon       private:
93*a0936e1eSNicolas Bonnefon         // List of observed files
94*a0936e1eSNicolas Bonnefon         std::list<ObservedFile> observed_files_;
95*a0936e1eSNicolas Bonnefon 
96*a0936e1eSNicolas Bonnefon         // List of observed dirs, key-ed by name
97*a0936e1eSNicolas Bonnefon         std::map<std::string, std::weak_ptr<ObservedDir>> observed_dirs_;
98*a0936e1eSNicolas Bonnefon 
99*a0936e1eSNicolas Bonnefon         // Map the inotify file (including symlinks) wds to the observed file
100*a0936e1eSNicolas Bonnefon         std::map<int, ObservedFile*> by_file_wd_;
101*a0936e1eSNicolas Bonnefon         // Map the inotify directory wds to the observed files
102*a0936e1eSNicolas Bonnefon         std::map<int, ObservedFile*> by_dir_wd_;
103*a0936e1eSNicolas Bonnefon     };
10487e05652SNicolas Bonnefon };
105