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