xref: /glogg/src/watchtower.cpp (revision a0936e1e21791a259b77497eb5cb6e01c4eea5a4)
1 #include "watchtower.h"
2 
3 #include <algorithm>
4 
5 #include "log.h"
6 
7 namespace {
8     std::string directory_path( const std::string& path );
9 };
10 
11 // ObservedFileList class
12 WatchTower::ObservedFile*
13     WatchTower::ObservedFileList::searchByName( const std::string& file_name )
14 {
15     // Look for an existing observer on this file
16     auto existing_observer = observed_files_.begin();
17     for ( ; existing_observer != observed_files_.end(); ++existing_observer )
18     {
19         if ( existing_observer->file_name_ == file_name )
20         {
21             LOG(logDEBUG) << "Found " << file_name;
22             break;
23         }
24     }
25 
26     if ( existing_observer != observed_files_.end() )
27         return &( *existing_observer );
28     else
29         return nullptr;
30 }
31 
32 WatchTower::ObservedFile*
33     WatchTower::ObservedFileList::searchByFileOrSymlinkWd( int wd )
34 {
35     auto result = find_if( observed_files_.begin(), observed_files_.end(),
36             [wd] (ObservedFile file) -> bool {
37                 return ( wd == file.file_wd_ ) || ( wd == file.symlink_wd_ ); } );
38 
39     if ( result != observed_files_.end() )
40         return &( *result );
41     else
42         return nullptr;
43 }
44 
45 WatchTower::ObservedFile*
46     WatchTower::ObservedFileList::searchByDirWdAndName( int wd, const char* name )
47 {
48     auto dir = find_if( observed_dirs_.begin(), observed_dirs_.end(),
49             [wd] (std::pair<std::string,std::weak_ptr<ObservedDir>> d) -> bool {
50             return ( wd == std::shared_ptr<ObservedDir>(d.second)->dir_wd_ ); } );
51 
52     std::string path = dir->first + "/" + name;
53 
54     // LOG(logDEBUG) << "Testing path: " << path;
55 
56     // Looking for the path in the files we are watching
57     return searchByName( path );
58 }
59 
60 WatchTower::ObservedFile*
61     WatchTower::ObservedFileList::addNewObservedFile( ObservedFile new_observed )
62 {
63     auto new_file = observed_files_.insert( std::begin( observed_files_ ), new_observed );
64 
65     return &( *new_file );
66 }
67 
68 std::shared_ptr<WatchTower::ObservedFile>
69     WatchTower::ObservedFileList::removeCallback(
70             std::shared_ptr<void> callback )
71 {
72     std::shared_ptr<ObservedFile> returned_file = nullptr;
73 
74     for ( auto observer = begin( observed_files_ );
75             observer != end( observed_files_ ); )
76     {
77         LOG(logDEBUG) << "Examining entry for " << observer->file_name_;
78 
79         std::vector<std::shared_ptr<void>>& callbacks = observer->callbacks;
80         callbacks.erase( std::remove(
81                     std::begin( callbacks ), std::end( callbacks ), callback ),
82                 std::end( callbacks ) );
83 
84         /* See if all notifications have been deleted for this file */
85         if ( callbacks.empty() ) {
86             LOG(logDEBUG) << "Empty notification list, removing the watched file";
87             returned_file = std::make_shared<ObservedFile>( *observer );
88             observer = observed_files_.erase( observer );
89         }
90         else {
91             ++observer;
92         }
93     }
94 
95     return returned_file;
96 }
97 
98 std::shared_ptr<WatchTower::ObservedDir>
99     WatchTower::ObservedFileList::watchedDirectory( const std::string& dir_name )
100 {
101     std::shared_ptr<ObservedDir> dir = nullptr;
102 
103     if ( observed_dirs_.find( dir_name ) != std::end( observed_dirs_ ) )
104         dir = observed_dirs_[ dir_name ].lock();
105 
106     return dir;
107 }
108 
109 std::shared_ptr<WatchTower::ObservedDir>
110     WatchTower::ObservedFileList::addWatchedDirectory( const std::string& dir_name )
111 {
112     auto dir = std::make_shared<ObservedDir>( dir_name );
113 
114     observed_dirs_[ dir_name ] = std::weak_ptr<ObservedDir>( dir );
115 
116     return dir;
117 }
118 
119 std::shared_ptr<WatchTower::ObservedDir>
120     WatchTower::ObservedFileList::watchedDirectoryForFile( const std::string& file_name )
121 {
122     return watchedDirectory( directory_path( file_name ) );
123 }
124 
125 std::shared_ptr<WatchTower::ObservedDir>
126     WatchTower::ObservedFileList::addWatchedDirectoryForFile( const std::string& file_name )
127 {
128     return addWatchedDirectory( directory_path( file_name ) );
129 }
130 
131 namespace {
132     std::string directory_path( const std::string& path )
133     {
134         size_t slash_pos = path.rfind( '/' );
135 
136 #ifdef _WIN32
137         if ( slash_pos == std::string::npos ) {
138             slash_pos = path.rfind( '\\' ) + 1;
139             LOG(logDEBUG) << "Pos = " << slash_pos;
140         }
141 #endif
142 
143         return std::string( path, 0, slash_pos );
144     }
145 };
146