48 std::vector<char*> pointers ;
49 void add(
const std::string & s ) { list.push_back(s) ; }
52 for( G::StringArray::iterator p = list.begin() ; p != list.end() ; ++p )
53 pointers.push_back( const_cast<char*>((*p).c_str()) ) ;
54 pointers.push_back(
nullptr) ;
62 if( pid == static_cast<pid_t>(-1) )
63 throw std::runtime_error(
"fork error" ) ;
70 m_save_test_mode(false) ,
78 m_save_test_mode(false) ,
87 if( !info.
has(
"type") )
96 if( !info.
has(
"type") )
104 m_publisher.reset( p ) ;
113 std::string viewer_exe ;
118 if( viewer_exe.empty() )
121 viewer_exe = viewer( this_exe ) ;
127 m_fat_pipe->doChild() ;
130 args.add( viewer_exe ) ;
131 if( qforquit ) { args.add(
"--quit" ) ; }
132 if( debug ) { args.add(
"--debug" ) ; }
133 if( syslog ) { args.add(
"--syslog" ) ; }
134 if( !title.empty() ) { args.add(
"--title=" + sanitise(title) ) ; }
135 if( viewer_scale != 1U ) { args.add(
"--scale=" + sanitise(sscale) ) ; }
136 if( !event_channel.empty() ) { args.add(
"--channel=" + sanitise(event_channel) ) ; }
137 args.add( m_fat_pipe->shmemfd() ) ;
138 args.add( m_fat_pipe->pipefd() ) ;
140 ::execv( viewer_exe.c_str() , &args.pointers[0] ) ;
142 std::cerr <<
"error: exec failed for [" << viewer_exe <<
"]: " << G::Process::strerror(e) <<
"\n" ;
145 m_fat_pipe->doParent() ;
147 if( m_ping_timer_ptr.get() != nullptr )
148 m_ping_timer_ptr->startTimer( 1U ) ;
151 std::string Gv::ImageOutput::sanitise(
const std::string & s_in )
154 std::string meta_out( meta_in.size() ,
'.' ) ;
160 return m_fat_pipe.get() != nullptr ;
165 return m_fat_pipe.get() ? m_fat_pipe->ping() : false ;
168 void Gv::ImageOutput::onPingTimeout()
170 G_ASSERT( m_ping_timer_ptr.get() != nullptr ) ;
172 m_ping_timer_ptr->startTimer( 1U ) ;
179 else if( m_viewer_up )
180 throw std::runtime_error(
"viewer has gone away" ) ;
185 m_base_dir = base_dir ;
189 m_save_test_mode = test_mode ;
201 if( m_publisher.get() )
202 m_publisher->publish( p , n , type_str.c_str() ) ;
204 if( m_fat_pipe.get() )
205 m_fat_pipe->send( p , n , type_str.c_str() ) ;
207 if( m_base_dir.empty() )
210 return save( p , n , type , time ) ;
217 if( m_publisher.get() )
218 m_publisher->publish( buffer , type_str.c_str() ) ;
220 if( m_fat_pipe.get() )
221 m_fat_pipe->send( buffer , type_str.c_str() ) ;
223 if( m_base_dir.empty() )
226 return save( buffer , type , time ) ;
231 if( m_publisher.get() )
232 m_publisher->publish( p , n , type.c_str() ) ;
234 if( m_fat_pipe.get() )
235 m_fat_pipe->send( p , n , type.c_str() ) ;
238 std::string Gv::ImageOutput::viewer(
const G::Path & this_exe )
240 G_ASSERT( this_exe !=
G::Path() ) ;
242 std::string this_name = this_exe.
basename() ;
243 size_t pos = this_name.find_last_of(
"-_" ) ;
245 pos == std::string::npos ?
246 std::string(
"viewer") :
247 ( G::Str::head(this_name,pos,std::string()) + this_name.at(pos) +
"viewer" ) ;
248 std::string result =
G::Path(dir,name).
str() ;
249 G_DEBUG(
"Gv::ImageOutput::viewerExecutable: viewer-exe=[" << result <<
"]" ) ;
255 void append( std::string & s ,
short n ,
char c =
'\0' )
258 cc[0] =
'0' + (n/10) ;
259 cc[1] =
'0' + (n%10) ;
261 s.append( cc , c ? 3U : 2U ) ;
263 void append3( std::string & s ,
short n ,
char c =
'\0' )
266 cc[0] =
'0' + ((n/100)%10) ;
267 cc[1] =
'0' + ((n/10)%10) ;
268 cc[2] =
'0' + (n%10) ;
270 s.append( cc , c ? 4U : 3U ) ;
272 void append4( std::string & s ,
short n ,
char c =
'\0' )
275 cc[0] =
'0' + ((n/1000)%10) ;
276 cc[1] =
'0' + ((n/100)%10) ;
277 cc[2] =
'0' + ((n/10)%10) ;
278 cc[3] =
'0' + (n%10) ;
280 s.append( cc , c ? 5U : 4U ) ;
287 G_ASSERT( name.find(
'/') == std::string::npos ) ;
289 out.reserve( base_dir.length() + name.length() + 30U ) ;
290 out.assign( base_dir ) ;
291 out.append( 1U ,
'/' ) ;
297 G_WARNING_ONCE(
"Gv::ImageOutput::path: saving in test mode: date fixed to 2000" ) ;
300 tm.tm_mday = 1 + (tm.tm_mday & 1) ;
303 append4( out , tm.tm_year+1900 ,
'/' ) ;
304 append( out , tm.tm_mon+1 ,
'/' ) ;
305 append( out , tm.tm_mday ,
'/' ) ;
306 append( out , tm.tm_hour ,
'/' ) ;
307 append( out , tm.tm_min ,
'/' ) ;
310 append( out , tm.tm_sec ,
'/' ) ;
312 if( !name.empty() ) out.append( 1U ,
'.' ) ;
313 append3( out , time.us >> 10 ) ;
318 if( !name.empty() ) out.append( 1U ,
'.' ) ;
319 append( out , tm.tm_sec ,
'\0' ) ;
323 out.append(
".jpg" ) ;
324 else if( type.
isRaw() )
325 out.append( type.
channels() == 1 ?
".pgm" :
".ppm" ) ;
327 out.append(
".dat" ) ;
333 path( result , m_base_dir , m_name , time , type , fast , m_tz , m_save_test_mode ) ;
340 G::Path path = openFile( file , type , time ) ;
343 file.write( p , n ) ;
344 commitFile( file , path ) ;
352 G::Path path = openFile( file , type , time ) ;
355 file << image_buffer ;
356 commitFile( file , path ) ;
363 if( m_base_dir.empty() )
368 G::Path path = this->path( time , type , m_fast ) ;
371 if( path == m_old_path )
377 if( m_old_dir != dir )
391 std::string path_str = path.
str() ;
393 file.open( path_str.c_str() ) ;
401 << (type.
channels()==1?
"P5":
"P6") <<
"\n"
402 << type.
dx() <<
" " << type.
dy() <<
"\n"
409 void Gv::ImageOutput::commitFile( std::ofstream & file ,
const G::Path & path )
413 G_ERROR(
"Gv::ImageOutput::save: file write error [" << path <<
"]" ) ;
static BrokenDownTime utc(EpochTime epoch_time)
Converts from epoch time to UTC broken-down-time.
std::string str() const
Returns the path string.
bool isRaw() const
Returns true if a raw image type.
void startViewer(const std::string &title=std::string(), unsigned int scale=1U, const std::string &output_channel=std::string())
Starts the viewer.
A subsecond-resolution timestamp based on a time_t.
static std::string get(const std::string &name, const std::string &default_)
Returns the environment variable value or the given default.
static std::string printable(const std::string &in, char escape= '\\')
Returns a printable represention of the given input string.
bool syslog() const
Returns true if syslog output is enabled.
const std::string & dir() const
Returns the saveTo() path.
An abstract interface for handling exceptions thrown out of event-loop callbacks (socket events and t...
std::time_t seconds() const
Returns the offset as a signed number of seconds.
A representation of a timezone.
bool isJpeg() const
Returns true if a jpeg image type.
int channels() const
Returns the number of channels.
std::string basename() const
Returns the rightmost part of the path, ignoring "." parts.
G::Path send(const char *data, size_t size, Gr::ImageType type, G::EpochTime=G::EpochTime(0))
Emits an image. Returns the path if saveTo()d the filesystem.
static Item map()
Factory function for a map item.
std::vector< std::string > StringArray
A std::vector of std::strings.
static LogOutput * instance()
Returns a pointer to the controlling LogOutput object.
An encapsulation of image type, including width, height and number of channels, with support for a st...
A class which acquires the process's special privileges on construction and releases them on destruct...
Vectors ImageBuffer
An ImageBuffer is used to hold raw image data, typically in more than one chunk.
String & set(String &out) const
Returns str() by reference.
static std::string exe(bool do_throw=true)
Returns Process::exe() or an absolute path constructed from v0().
static std::string tail(const std::string &in, std::string::size_type pos, const std::string &default_=std::string())
Returns the last part of the string after the given position.
static void path(std::string &out, const std::string &base_dir, const std::string &name, G::EpochTime, Gr::ImageType type, bool fast, const Gv::Timezone &tz, bool test_mode)
Returns by reference the filesystem path corresponding to the given base directory and timestamp...
static EpochTime now()
Returns the current epoch time.
void saveTo(const std::string &base_dir, const std::string &name, bool fast, const Gv::Timezone &tz, bool test_mode=false)
Saves images to the filesystem inside a deeply-nested directory hierarchy with the given base directo...
bool fast() const
Returns the saveTo() fast flag.
static std::string escaped(const std::string &, char c_escape, const std::string &specials_in, const std::string &specials_out)
Returns the escape()d string.
~ImageOutput()
Destructor.
static bool mkdirs(const Path &dir, const NoThrow &, int=100)
Creates a directory and all necessary parents.
static std::string fromUInt(unsigned int ui)
Converts unsigned int 'ui' to a string.
int dy() const
Returns the image height.
bool viewing() const
Returns true if startViewer() has been called.
static bool enabled()
Returns true if test features are enabled.
ImageOutput()
Constructor.
Path dirname() const
Returns the path without the rightmost part, ignoring "." parts.
void pingViewerCheck()
Checks that the viewer is running if it should be (see pingViewer()), and throws an exeception if not...
A variant class holding a string, an item map keyed by name, or an ordered list of items...
An overload discriminator class for File methods.
A broadcast communication channel between unrelated processes using shared memory.
int dx() const
Returns the image width.
void startPublisher(const std::string &channel)
Starts the publisher channel.
bool pingViewer()
Returns true if the viewer seems to be running.
void add(const std::string &s)
Adds a string item to this list item.
A timer class template in which the timeout is delivered to the specified method. ...
A small-string class used for stringised Gr::ImageType instances.
bool has(const std::string &k) const
Returns true if this map item has the named key.
static std::string v0()
Returns a copy of argv[0] from the first call to the constructor that takes argc/argv.
A one-way, unreliable-datagram communication channel from a parent process to a child process...
A Path object represents a file system path.
static std::string meta()
Returns a list of shell meta-characters, typically used with escape().
void sendText(const char *data, size_t size, const std::string &type)
Emits a non-image message. Non-image messages are not saveTo()d the filesystem.