ConfigFileSystem.cpp
Go to the documentation of this file.
1 #include "ConfigFileSystem.hpp"
2 #include <fstream>
3 
4 namespace iv
5 {
6 
7 //================================================================================
8 //--------------------- ConfigStream ---------------------------------------------
9 ConfigStream::ConfigStream( Instance * inst, std::string const & name ) :
10  cm( inst, this, "ConfigStream" ),
11  inst( inst ),
12  name( name )
13 {
14  auto cfs = this->instance()->getSystem< ConfigFileSystem >();
15  if( cfs )
16  cfs->stream_add_listener( this, this->name );
17 }
18 
20 {
21  auto cfs = this->instance()->getSystem< ConfigFileSystem >();
22  if( cfs )
23  cfs->stream_remove_listener( this );
24 }
25 
27 {
28  return this->inst;
29 }
30 
32 {
33  auto cfs = this->instance()->getSystem< ConfigFileSystem >();
34  if( cfs )
35  return cfs->stream_exists( this->name );
36  return false;
37 }
38 
39 void ConfigStream::stream_read( std::function< void( std::istream & ) > const & f )
40 {
41  auto cfs = this->instance()->getSystem< ConfigFileSystem >();
42  if( cfs )
43  {
44  LambdaLogTrace _trace(
45  [ this ]( std::ostream & out )
46  {
47  out << "Configuration '"<< this->name <<"'" << std::endl;
48  }
49  );
50 
51  cfs->stream_read( this->name, f );
52  }
53 }
54 
55 void ConfigStream::stream_write( std::function< void( std::ostream & ) > const & f )
56 {
57  auto cfs = this->instance()->getSystem< ConfigFileSystem >();
58  if( cfs )
59  cfs->stream_write( this->name, f );
60 }
61 
63 {
64  auto cfs = this->instance()->getSystem< ConfigFileSystem >();
65  if( cfs )
66  return cfs->get_filepath( this->name );
67  return "";
68 }
69 
70 //================================================================================
71 //------------------------- ConfigFileSystem -------------------------------------
72 #if IV_CONFIG_FS_ENABLED
73 
74 ConfigFileSystem::ConfigFileSystem( SystemContainer * sc, std::string const & base_dir ) :
75  System( sc ),
76  base_dir( base_dir ),
77  frame_id( 0 )
78 {
79 }
80 
82 {
83  // check if this is a new frame
84  if( !this->system_container() )
85  return false;
86 
87  if( this->frame_id == this->system_container()->frame_id() )
88  return false;
89 
90  this->frame_id = this->system_container()->frame_id();
91 
92  // stream listeners
93  for( StreamListener & listener : this->stream_listeners )
94  {
95  auto timestamp = this->stream_timestamp( listener.name );
96  if( timestamp > listener.timestamp )
97  {
98  listener.timestamp = timestamp;
99  listener.listener->config_stream_changed();
100  }
101  }
102 
103  //
104  return true;
105 }
106 
108 {
109  context->out() << "Configuration path: " << this->base_dir << "." << std::endl;
110 
111  for( StreamListener const & listener : this->stream_listeners )
112  {
113  context->out() << "Stream '"<< listener.name <<"':" << std::endl;
114  context->prefix_push( " " );
115 
116  context->out() << "filepath " << this->stream_filepath( listener.name ) << std::endl;
117  context->out() << "exists " << ( fs::is_regular_file( this->stream_filepath( listener.name ) ) ? "true" : "false" ) << std::endl;
118 
119  if( listener.timestamp == fs::file_time_type::min() )
120  {
121  context->out() << "timestamp -" << std::endl;
122  }
123  else
124  {
125  std::time_t t = fs::file_time_type::clock::to_time_t( listener.timestamp );
126  context->out() << "timestamp " << std::asctime( std::localtime( &t ) ) << std::endl;
127  }
128 
129  context->prefix_pop();
130  }
131 }
132 
133 fs::path ConfigFileSystem::stream_filepath( std::string const & name )
134 {
135  //return ( this->base_dir / name ).lexically_normal();
136  return this->base_dir / name;
137 }
138 
139 fs::file_time_type ConfigFileSystem::stream_timestamp( std::string const & name )
140 {
141  std::error_code ec;
142  auto result = fs::last_write_time( this->stream_filepath( name ), ec );
143  if( ec )
144  {
145  this->warning( SRC_INFO, "Can not determine last write time for file '", this->stream_filepath( name ), "'. ",
146  "Error code: ", ec.value(), " - '", ec.message(), "'." );
147  return fs::file_time_type::min();
148  }
149 
150  return result;
151 }
152 
153 void ConfigFileSystem::stream_add_listener( ConfigStream * listener, std::string const & name )
154 {
155  this->stream_listeners.push_back( StreamListener( listener, name, this->stream_timestamp( name ) ) );
156 }
157 
159 {
160  for( size_t i = 0; i < this->stream_listeners.size(); i++ )
161  if( this->stream_listeners[ i ].listener == listener )
162  {
163  this->stream_listeners.erase( this->stream_listeners.begin() + i );
164  break;
165  }
166 }
167 
168 void ConfigFileSystem::stream_read( std::string const & name, std::function< void( std::istream & ) > const & f )
169 {
170  fs::path fp = this->stream_filepath( name );
171  TextOutput << "ConfigStream: reading '" << fp << "'" << std::endl;
172 
173  std::ifstream in( fp.c_str(), std::ios_base::in | std::ios_base::binary );
174  if( !in.good() )
175  {
176  this->stream_write( name, []( std::ostream & ){} );
177  in = std::ifstream( fp.c_str(), std::ios_base::in | std::ios_base::binary );
178  }
179 
180  if( in.good() )
181  f( in );
182 }
183 
184 bool ConfigFileSystem::stream_exists( std::string const & name )
185 {
186  fs::path fp = this->stream_filepath( name );
187  std::ifstream in( fp.c_str(), std::ios_base::in | std::ios_base::binary );
188  return in.good();
189 }
190 
191 void ConfigFileSystem::stream_write( std::string const & name, std::function< void( std::ostream & ) > const & f )
192 {
193  // construct filename
194  fs::path fp = this->stream_filepath( name );
195  fs::path basedir = fp;
196  basedir.remove_filename();
197 
198  // create dir
199  std::error_code ec;
200  fs::create_directories( basedir, ec );
201  if( ec )
202  {
203  this->warning( SRC_INFO, "Failed to create directories for config stream file. ",
204  "Directory is '", basedir, "', error code is ", ec.value(), " - '", ec.message(), "'." );
205  return;
206  }
207 
208  // open file
209  std::ofstream out( fp, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc );
210  if( !out.good() )
211  {
212  this->warning( SRC_INFO, "Can not open configuration file '", fp, "' for writing." );
213  return;
214  }
215 
216  // write to file
217  f( out );
218 }
219 
220 std::string ConfigFileSystem::get_filepath( std::string const & name )
221 {
222  return this->stream_filepath( name ).string();
223 }
224 
225 #else
226 
227 ConfigFileSystem::ConfigFileSystem( SystemContainer * sc, std::string const & base_dir ) :
228  System( sc )
229 {
230 }
231 
232 void ConfigFileSystem::status( TextDebugView * context )
233 {
234 }
235 
237 {
238  return false;
239 }
240 
241 void ConfigFileSystem::stream_add_listener( ConfigStream * listener, std::string const & name )
242 {
243 }
244 
245 void ConfigFileSystem::stream_remove_listener( ConfigStream * listener )
246 {
247 }
248 
249 bool ConfigFileSystem::stream_exists( std::string const & name )
250 {
251  return false;
252 }
253 
254 void ConfigFileSystem::stream_read( std::string const & name, std::function< void( std::istream & ) > const & )
255 {
256 }
257 
258 void ConfigFileSystem::stream_write( std::string const & name, std::function< void( std::ostream & ) > const & )
259 {
260 }
261 
262 std::string ConfigFileSystem::get_filepath( std::string const & name )
263 {
264  return "";
265 }
266 
267 #endif
268 
269 }