34 GNet::BufferedServerPeer(peer_info,
"\r\n") ,
37 m_resources(resources) ,
38 m_config_default(config) ,
56 void Gv::HttpServerPeer::onSecure(
const std::string & )
60 void Gv::HttpServerPeer::selectSource(
const std::string & url_path )
62 if( m_sources.valid(url_path) )
64 bool new_source = m_sources.select( url_path , m_source ) ;
70 m_data_timer.cancelTimer() ;
71 G_DEBUG(
"Gv::HttpServerPeer::selectSource: new source: source-name=[" << m_source.name() <<
"]" ) ;
76 bool Gv::HttpServerPeer::onReceive(
const std::string & line )
78 if( m_config.moreVerbose() )
79 G_LOG(
"Gv::HttpServerPeer::onReceive: rx<<: \"" <<
G::Str::printable(line) <<
"\"" ) ;
81 if( m_config.idleTimeout() != 0U )
82 m_idle_timer.startTimer( m_config.idleTimeout() ) ;
84 if( ( m_state == s_init || m_state == s_idle ) && line.find(
"GET") == 0U )
88 part.push_back( std::string() ) ;
89 if( m_config.moreVerbose() )
90 G_LOG(
"Gv::HttpServerPeer::onReceive: http request: [" <<
G::Str::printable(line) <<
"]" ) ;
93 m_config = m_config_default ;
94 m_config.init( m_url ) ;
97 m_content_length = 0U ;
98 selectSource( m_url.path() ) ;
99 G_DEBUG(
"Gv::HttpServerPeer::onReceive: got get" ) ;
101 else if( ( m_state == s_init || m_state == s_idle ) && line.find(
"POST") == 0U )
105 part.push_back( std::string() ) ;
106 m_url =
G::Url(part[1U]) ;
107 if( m_config.moreVerbose() )
108 G_LOG(
"Gv::HttpServerPeer::onReceive: http request: [" <<
G::Str::printable(line) <<
"]" ) ;
110 m_state = s_got_post ;
111 m_content_length = 0U ;
112 selectSource( m_url.path() ) ;
114 else if( m_state == s_got_post && !line.empty() )
118 m_content_length = headerValue( line ) ;
120 else if( m_state == s_got_post && m_content_length )
122 m_state = s_got_post_headers ;
123 expect( m_content_length ) ;
124 m_content_length = 0U ;
126 else if( m_state == s_got_post || m_state == s_got_post_headers )
129 if( !line.empty() && m_config.moreVerbose() )
130 G_LOG(
"Gv::HttpServerPeer::onReceive: got post request body: [" <<
G::Str::printable(line) <<
"]" ) ;
133 else if( m_state == s_got_get && !line.empty() )
137 m_content_length = headerValue( line ) ;
139 else if( m_state == s_got_get && m_content_length )
141 m_state = s_got_get_headers ;
142 expect( m_content_length ) ;
143 m_content_length = 0U ;
145 else if( ( m_state == s_got_get || m_state == s_got_get_headers ) )
147 if( !line.empty() && m_config.moreVerbose() )
148 G_LOG(
"Gv::HttpServerPeer::onReceive: got get request body: [" <<
G::Str::printable(line) <<
"]" ) ;
150 if( m_url.has(
"send") )
151 doGatewayMessage( m_url.parameter(
"send") ) ;
153 if( fileRequest() || specialRequest() )
156 m_data_timer.startTimer( 0 ) ;
158 else if( m_source.get() == nullptr )
161 G_DEBUG(
"Gv::HttpServerPeer::onReceive: http request for invalid channel" ) ;
162 doSendResponse( 404 ,
"No such channel" ) ;
167 G_WARNING(
"Gv::HttpServerPeer::onReceive: http request for jpeg but no libjpeg built in" ) ;
168 doSendResponse( 415 ,
"Unsupported media type" ) ;
170 else if( m_image.empty() )
172 m_state = s_waiting ;
173 G_DEBUG(
"Gv::HttpServerPeer::onReceive: image not yet available: "
174 <<
"waiting up to " << m_config.firstImageTimeout() <<
"s" ) ;
175 if( m_config.quick() ) m_source.resend() ;
176 m_data_timer.startTimer( m_config.firstImageTimeout() ) ;
178 else if( m_config.streaming() )
180 m_state = s_streaming_first_idle ;
181 if( m_config.quick() ) m_source.resend() ;
182 m_data_timer.startTimer( 0 ) ;
186 m_state = s_single_idle ;
187 if( m_config.quick() ) m_source.resend() ;
188 m_data_timer.startTimer( 0 ) ;
193 G_DEBUG(
"Gv::HttpServerPeer::onReceive: ignoring unexpected data in state " << m_state ) ;
198 void Gv::HttpServerPeer::buildPduFirst()
200 G_ASSERT( !m_image.empty() ) ;
202 m_pdu.append( streamingHeader(m_image_size,m_image.type(),m_image_type_str) ) ;
203 m_pdu.append( streamingSubHeader(m_image_size,m_image.type(),m_image_type_str) ) ;
204 m_pdu.assignBody( m_image.ptr() , m_image_size ) ;
207 void Gv::HttpServerPeer::buildPdu()
209 G_ASSERT( !m_image.empty() ) ;
211 m_pdu.append( streamingSubHeader(m_image_size,m_image.type(),m_image_type_str) ) ;
212 m_pdu.assignBody( m_image.ptr() , m_image_size ) ;
215 void Gv::HttpServerPeer::buildPduSingle()
217 G_ASSERT( !m_image.empty() ) ;
219 m_pdu.append( simpleHeader(m_image_size,m_image.type(),m_image_type_str,m_source.name(),m_source.info()) ) ;
220 m_pdu.assignBody( m_image.ptr() , m_image_size ) ;
223 bool Gv::HttpServerPeer::sendPdu()
226 if( m_config.moreVerbose() )
227 G_LOG(
"Gv::HttpServerPeer::sendPdu: sending image: " << m_pdu.size() <<
" bytes" ) ;
228 bool sent = doSend( m_pdu ) ;
229 if( !sent && m_config.moreVerbose() )
230 G_LOG(
"Gv::HttpServerPeer::sendPdu: flow control asserted for image " << m_image_number ) ;
234 bool Gv::HttpServerPeer::doSend(
const Pdu & pdu )
236 doSendLogging( pdu ) ;
237 bool all_sent = send( pdu.segments() ) ;
243 bool Gv::HttpServerPeer::doSend(
const std::string & s )
245 doSendLogging( Pdu(s) ) ;
249 void Gv::HttpServerPeer::doSendLogging(
const Pdu & pdu )
const
251 if(
G::Log::at(G::Log::s_LogVerbose) && m_config.moreVerbose() )
253 typedef std::string::const_iterator Ptr ;
254 std::string s = pdu.head() ;
255 Ptr old = s.begin() ;
256 Ptr
const end = s.end() ;
257 for( Ptr pos = std::find(old,end,
'\n') ; pos != end ; old=pos+1 , pos = std::find(pos+1,end,
'\n') )
259 std::string line = pos != s.begin() ? std::string(old,pos) : std::string() ;
261 G_LOG(
"Gv::HttpServerPeer::doSend: tx>>: \"" <<
G::Str::printable(line) <<
"\"" ) ;
266 void Gv::HttpServerPeer::doPost()
268 std::string reason = doGatewayMessageImp( m_url.parameter(
"send") ) ;
270 doSendResponse( 200 ,
"OK" ) ;
272 doSendResponse( 500 , reason ) ;
275 void Gv::HttpServerPeer::doGatewayMessage(
const std::string & send_param )
277 std::string reason = doGatewayMessageImp( send_param ) ;
278 if( !reason.empty() )
279 G_WARNING(
"Gv::HttpServerPeer::doGatewayMessage: gateway message failed: " << reason ) ;
282 std::string Gv::HttpServerPeer::doGatewayMessageImp(
const std::string & send_param )
284 G_LOG(
"Gv::HttpServerPeer::doGatewayMessage: send=[" << send_param <<
"]" ) ;
286 if( send_param.empty() )
287 return "no 'send' parameter: nothing to do" ;
290 return "no gateway address configured" ;
295 return "incorrect 'send' parameter: no port value" ;
297 std::string payload =
G::Str::tail( send_param ,
" " ) ;
298 if( payload.empty() )
299 return "incorrect 'send' parameter: no message part" ;
307 ssize_t n = socket.writeto( payload.data() , payload.size() , address ) ;
308 G_LOG(
"Gv::HttpServerPeer::doGatewayMessage: gateway: "
309 <<
"host=[" << m_config.gateway().hostPartString() <<
"] "
310 <<
"port=[" << port <<
"] "
312 <<
"sent=" << n <<
"/" << payload.size() ) ;
313 if( n != static_cast<ssize_t>(payload.size()) )
314 return "udp send failed" ;
316 return std::string() ;
319 bool Gv::HttpServerPeer::fileRequest()
321 return m_resources.fileResource( m_url.path() ) ;
324 bool Gv::HttpServerPeer::specialRequest()
326 return m_resources.specialResource( m_url.path() ) ;
329 void Gv::HttpServerPeer::buildPduFromFile()
331 std::pair<std::string,std::string> pair = m_resources.fileResourcePair( m_url.path() ) ;
332 std::string path = pair.first ;
333 std::string type = pair.second ;
339 G_DEBUG(
"Gv::HttpServerPeer::buildPduFromFile: url-path=[" << m_url.path() <<
"] file-path=[" << path <<
"] type=[" << type <<
"]" ) ;
342 file.open( path.c_str() ) ;
348 file >> *image_buffer_ptr ;
351 G_WARNING(
"Gv::HttpServerPeer::buildPduFromFile: cannot read file [" <<
G::Str::printable(path) <<
"]" ) ;
355 size_t file_size = Gr::imagebuffer::size_of( *image_buffer_ptr ) ;
356 m_pdu.append( fileHeader(file_size,type) ) ;
357 m_pdu.assignBody( image_buffer_ptr , file_size ) ;
358 if( m_config.moreVerbose() )
359 G_LOG(
"Gv::HttpServerPeer::buildPduFromFile: serving file: path=[" << path <<
"] type=[" << type <<
"] size=" << file_size ) ;
364 G_WARNING(
"Gv::HttpServerPeer::buildPduFromFile: cannot open file [" <<
G::Str::printable(path) <<
"]" ) ;
369 const std::string & reason = pair.second ;
370 G_LOG(
"Gv::HttpServerPeer::buildPduFromFile: url-path=[" << m_url.path() <<
"]: resource not available: " << reason ) ;
375 m_pdu = errorResponse( 404 ,
"Not Found" ) ;
379 void Gv::HttpServerPeer::buildPduFromStatus()
383 for( G::StringArray::iterator p = list.begin() ; p != list.end() ; ++p )
387 std::ostringstream ss ;
389 size_t ss_size =
static_cast<size_t>(std::max(std::streampos(0),ss.tellp())) ;
391 m_pdu.append( fileHeader(ss_size,
"application/json") ) ;
392 m_pdu.append( ss.str() ) ;
395 void Gv::HttpServerPeer::onDataTimeout()
401 G_DEBUG(
"Gv::HttpServerPeer::onDataTimeout: image timeout: state " << m_state ) ;
402 if( m_state == s_file )
407 buildPduFromStatus() ;
409 bool all_sent = doSend( m_pdu ) ;
413 m_state = s_file_busy ;
415 else if( m_state == s_waiting )
417 if( m_image.empty() )
420 G_DEBUG(
"Gv::HttpServerPeer::onDataTimeout: no image available for http get request [" + m_url.str() +
"]" ) ;
421 doSendResponse( 503 ,
"Image unavailable" ,
"Retry-After: 1" ) ;
423 else if( m_config.streaming() )
425 m_state = s_streaming_first_idle ;
426 m_data_timer.startTimer( 0 ) ;
430 m_state = s_single_idle ;
431 m_data_timer.startTimer( 0 ) ;
434 else if( m_state == s_streaming_first_idle )
436 m_idle_timer.cancelTimer() ;
438 bool all_sent = sendPdu() ;
441 m_state = s_streaming_idle ;
442 m_data_timer.startTimer( m_config.imageRepeatTimeout() ) ;
446 m_state = s_streaming_first_busy ;
447 m_sending = m_image_number ;
450 else if( m_state == s_streaming_idle )
452 m_idle_timer.cancelTimer() ;
454 bool all_sent = sendPdu() ;
457 m_state = s_streaming_idle ;
458 m_data_timer.startTimer( m_config.imageRepeatTimeout() ) ;
462 m_state = s_streaming_busy ;
463 m_sending = m_image_number ;
466 else if( m_state == s_single_idle )
469 bool all_sent = sendPdu() ;
476 m_state = s_single_busy ;
477 m_sending = m_image_number ;
482 void Gv::HttpServerPeer::onSendComplete()
484 G_DEBUG(
"Gv::HttpServerPeer::onSendComplete: image " << m_sending <<
" sent" ) ;
485 if( m_config.moreVerbose() )
486 G_LOG(
"Gv::HttpServerPeer::onSendComplete: flow control released for image " << m_sending ) ;
488 if( m_state == s_idle )
491 else if( m_state == s_streaming_first_busy )
493 m_state = s_streaming_idle ;
494 startStreamingTimer() ;
497 else if( m_state == s_streaming_busy )
499 m_state = s_streaming_idle ;
500 startStreamingTimer() ;
503 else if( m_state == s_single_busy )
507 else if( m_state == s_file_busy )
513 void Gv::HttpServerPeer::startStreamingTimer()
515 G_ASSERT( m_sending != 0U ) ;
516 bool sent_image_is_latest = m_sending == m_image_number ;
517 if( sent_image_is_latest )
518 m_data_timer.startTimer( m_config.imageRepeatTimeout() ) ;
520 m_data_timer.startTimer( 0 ) ;
527 image_data.fill( 0 , 0 , 0 ) ;
530 Gr::ImageDataWriter writer( image_data , 0 , 0 ,
Gr::Colour(255U,255U,255U) ,
Gr::Colour(0,0,0) ,
true ,
false ) ;
531 writer.write( iterator_t(text_buffer) , iterator_t() ) ;
533 m_sources.converter().toJpeg( m_text_raw_image , m_text_jpeg_image ) ;
535 return m_text_jpeg_image ;
538 void Gv::HttpServerPeer::onNonImageInput( ImageInputSource & ,
Gr::Image image ,
const std::string & type_str )
540 G_ASSERT( !image.
empty() && !image.
valid() ) ;
541 G_DEBUG(
"Gv::HttpServerPeer::onNonImageInput: non-image [" << type_str <<
"]" ) ;
543 if( m_config.type() ==
"any" )
545 doInput( image , type_str ) ;
549 image = textToJpeg( image.
data() ) ;
550 doInput( image , image.
type().
str() ) ;
554 G_DEBUG(
"Gv::HttpServerPeer::onNonImageInput: not serving non-image" ) ;
558 void Gv::HttpServerPeer::onImageInput( ImageInputSource & ,
Gr::Image image )
560 G_DEBUG(
"Gv::HttpServerPeer::onImageInput: type=[" << image.
type() <<
"](" << image.
type() <<
") seqno=[" << m_image_number <<
"]" ) ;
561 doInput( image , image.
type().
str() ) ;
564 void Gv::HttpServerPeer::doInput(
Gr::Image image ,
const std::string & type_str )
567 if( m_image_number == 0U )
568 m_image_number = 1U ;
570 if( m_state == s_init || m_state == s_idle )
579 m_image_size = Gr::imagebuffer::size_of(image.
data()) ;
580 m_image_type_str = type_str ;
581 if( m_state == s_waiting || m_state == s_streaming_idle )
582 m_data_timer.startTimer( 0 ) ;
588 ImageInputConversion conversion ;
589 conversion.scale = m_config.scale() ;
590 conversion.monochrome = m_config.monochrome() ;
592 if( m_config.type() ==
"raw" || m_config.type() ==
"pnm" )
593 conversion.type = ImageInputConversion::to_raw ;
595 conversion.type = ImageInputConversion::none ;
597 conversion.type = ImageInputConversion::to_jpeg ;
601 void Gv::HttpServerPeer::onDelete(
const std::string & reason )
603 if( !reason.empty() && reason.find(
"peer disconnected") != 0U )
604 G_ERROR(
"Gv::HttpServerPeer::onException: exception: " << reason ) ;
605 G_LOG(
"Gv::HttpServerPeer::onDelete: disconnection of " << peerAddress().second.displayString() ) ;
608 void Gv::HttpServerPeer::onIdleTimeout()
610 G_LOG(
"Gv::HttpServerPeer::onIdleTimeout: timeout" ) ;
614 void Gv::HttpServerPeer::doSendResponse(
int e ,
const std::string & s ,
const std::string & header )
616 doSend( errorResponse(e,s,header) ) ;
619 std::string Gv::HttpServerPeer::errorResponse(
int e ,
const std::string & s ,
const std::string & header )
const
623 std::ostringstream ss ;
624 ss <<
"<!DOCTYPE html>\r\n<html><body><p>" << e <<
" " << s <<
"</p></body></html>\r\n" ;
628 std::ostringstream ss ;
630 <<
"HTTP/1.1 " << e <<
" " << s <<
"\r\n"
631 <<
"Content-Length: " << body.size() <<
"\r\n"
632 <<
"Content-Type: text/html\r\n" ;
633 if( !header.empty() )
634 ss << header <<
"\r\n" ;
636 <<
"Connection: keep-alive\r\n"
643 std::string Gv::HttpServerPeer::fileHeader(
size_t content_length ,
const std::string & content_type )
const
645 std::ostringstream ss ;
647 <<
"HTTP/1.1 200 OK\r\n" ;
648 if( !content_type.empty() )
649 ss <<
"Content-Type: " << content_type <<
"\r\n" ;
651 <<
"Content-Length: " << content_length <<
"\r\n"
652 <<
"Connection: keep-alive\r\n"
657 std::string Gv::HttpServerPeer::pnmHeader(
Gr::ImageType type )
const
659 std::ostringstream ss ;
664 ss << type.
dx() <<
" " << type.
dy() <<
"\n255\n" ;
668 std::string Gv::HttpServerPeer::pnmType(
Gr::ImageType type )
const
670 return "image/x-portable-anymap" ;
673 std::string Gv::HttpServerPeer::simpleHeader(
size_t content_length ,
Gr::ImageType type ,
674 const std::string & type_str ,
const std::string & source_name ,
const std::string & source_info )
const
676 std::string content_type = type.
valid() ? ( type.
isRaw() ? type.
str() : type.
simple() ) : type_str ;
678 std::string pnm_header ;
679 if( type.
isRaw() && m_config.type() ==
"pnm" )
681 pnm_header = pnmHeader( type ) ;
682 content_type = pnmType( type ) ;
683 content_length += pnm_header.size() ;
686 std::ostringstream ss ;
687 ss <<
"HTTP/1.1 200 OK\r\n" ;
688 if( m_config.refresh() )
689 ss <<
"Refresh: " << m_config.refresh() <<
"\r\n" ;
691 <<
"Content-Type: " << content_type <<
"\r\n"
692 <<
"Content-Length: " << content_length <<
"\r\n"
693 <<
"Cache-Control: no-cache\r\n"
694 <<
"Connection: keep-alive\r\n" ;
696 std::string appid(
"VT-" ) ;
697 if( appid.find(
"__") == 0U )
700 if( type.
valid() && type.
dx() != 0 )
701 ss <<
"X-" << appid <<
"Width: " << type.
dx() <<
"\r\n" ;
702 if( type.
valid() && type.
dy() != 0 )
703 ss <<
"X-" << appid <<
"Height: " << type.
dy() <<
"\r\n" ;
704 if( !source_name.empty() )
705 ss <<
"X-" << appid <<
"Source: " <<
G::Url::encode(source_name) <<
"\r\n" ;
706 if( !source_info.empty() )
707 ss <<
"X-" << appid <<
"Source-Info: " <<
G::Url::encode(source_info,
false) <<
"\r\n" ;
709 ss <<
"\r\n" << pnm_header ;
715 const char * boundary =
"29872987349876236436234298656398659642596" ;
718 std::string Gv::HttpServerPeer::streamingHeader(
size_t ,
Gr::ImageType type ,
const std::string & )
const
720 std::ostringstream ss ;
722 <<
"HTTP/1.1 200 OK\r\n"
723 <<
"Connection: keep-alive\r\n" ;
724 if( m_config.refresh() )
725 ss <<
"Refresh: " << m_config.refresh() <<
"\r\n" ;
727 <<
"Content-Type: multipart/x-mixed-replace;boundary=" << boundary <<
"\r\n" ;
729 std::string appid(
"VT-" ) ;
730 if( appid.find(
"__") == 0U )
733 if( type.
valid() && type.
dx() != 0 )
734 ss <<
"X-" << appid <<
"Width: " << type.
dx() <<
"\r\n" ;
735 if( type.
valid() && type.
dy() != 0 )
736 ss <<
"X-" << appid <<
"Height: " << type.
dy() <<
"\r\n" ;
743 std::string Gv::HttpServerPeer::streamingSubHeader(
size_t content_length ,
Gr::ImageType type ,
const std::string & type_str )
const
745 std::string content_type = type.
valid() ? ( type.
isRaw() ? type.
str() : type.
simple() ) : type_str ;
747 std::string pnm_header ;
748 if( type.
isRaw() && m_config.type() ==
"pnm" )
750 pnm_header = pnmHeader( type ) ;
751 content_type = pnmType( type ) ;
752 content_length += pnm_header.size() ;
755 std::ostringstream ss ;
757 <<
"\r\n--" << boundary <<
"\r\n"
758 <<
"Content-Type: " << content_type <<
"\r\n"
759 <<
"Content-Length: " << content_length <<
"\r\n"
760 <<
"\r\n" << pnm_header ;
764 unsigned int Gv::HttpServerPeer::headerValue(
const std::string & line )
768 G_DEBUG(
"Gv::HttpServerPeer::headerValue: not a number: [" << line <<
"]" ) ;
774 Gv::HttpServerPeer::Pdu::Pdu() :
775 m_body_ptr_size(0U) ,
778 m_segments.reserve( 3U ) ;
781 Gv::HttpServerPeer::Pdu::Pdu(
const std::string & s ) :
783 m_body_ptr_size(0U) ,
788 void Gv::HttpServerPeer::Pdu::clear()
790 G_ASSERT( m_body_ptr.get() ==
nullptr || !m_locked ) ;
792 m_body_ptr_size = 0U ;
796 bool Gv::HttpServerPeer::Pdu::empty()
const
798 return m_head.empty() && m_body_ptr_size == 0U ;
801 void Gv::HttpServerPeer::Pdu::append(
const std::string & s )
803 G_ASSERT( m_body_ptr.get() == nullptr ) ;
807 void Gv::HttpServerPeer::Pdu::assignBody( shared_ptr<const Gr::ImageBuffer> data_ptr ,
size_t n )
809 G_ASSERT( m_body_ptr.get() ==
nullptr || !m_locked ) ;
810 m_body_ptr = data_ptr ;
811 m_body_ptr_size = n ;
814 size_t Gv::HttpServerPeer::Pdu::size()
const
816 return m_head.size() + m_body_ptr_size ;
819 std::string Gv::HttpServerPeer::Pdu::head()
const
824 void Gv::HttpServerPeer::Pdu::operator=(
const std::string & s )
827 m_body_ptr_size = 0U ;
831 void Gv::HttpServerPeer::Pdu::lock()
const
833 G_ASSERT( !m_locked ) ;
837 void Gv::HttpServerPeer::Pdu::release()
839 G_ASSERT( m_locked ) ;
842 m_body_ptr_size = 0U ;
845 const std::vector<std::pair<const char *,size_t> > & Gv::HttpServerPeer::Pdu::segments()
const
848 if( !m_head.empty() ) m_segments.push_back( Segment(m_head.data(),m_head.size()) ) ;
849 if( m_body_ptr_size != 0U )
854 for( row_iterator part_p = Gr::imagebuffer::row_begin(image_buffer) ; part_p != Gr::imagebuffer::row_end(image_buffer) ; ++part_p )
856 const char * segment_p = Gr::imagebuffer::row_ptr(part_p) ;
857 size_t segment_n = Gr::imagebuffer::row_size(part_p) ;
858 m_segments.push_back( Segment(segment_p,segment_n) ) ;
bool isRaw() const
Returns true if a raw image type.
A configuration structure for Gv::HttpServerPeer holding default settings from the command-line which...
static std::string printable(const std::string &in, char escape= '\\')
Returns a printable represention of the given input string.
A traits class that can be specialised for Gr::ImageBuffer candidates.
A holder for image data, having eight bits per sample and one or three channels.
void out(std::ostream &s, int indent=-1) const
Does output streaming, using a json-like format.
static bool at(Severity)
Returns true if G::LogOutput::output() would log at the given level.
HttpServerPeer(GNet::Server::PeerInfo, Sources &, const Resources &, const Config &)
Constructor.
int channels() const
Returns the number of channels.
static Item map()
Factory function for a map item.
The GNet::Address class encapsulates a TCP/UDP transport address.
static std::vector< std::string > list(std::vector< std::string > *others=nullptr)
Returns a list of channel names.
std::vector< std::string > StringArray
A std::vector of std::strings.
A derivation of GNet::Socket for a datagram socket.
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...
static void splitIntoTokens(const std::string &in, StringArray &out, const std::string &ws)
Splits the string into 'ws'-delimited tokens.
A simple rgb colour structure.
Vectors ImageBuffer
An ImageBuffer is used to hold raw image data, typically in more than one chunk.
A simple parser for URLs.
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 ImageType raw(int dx, int dy, int channels)
Factory function for a raw image type.
bool empty() const
Returns true if constructed with no image data.
std::string str() const
Returns the image type string (including the size parameter).
A class holding shared read-only image data (Gr::ImageBuffer) and its associated image type (Gr::Imag...
bool valid() const
Returns true if valid.
unsigned int idleTimeout() const
Returns the connection idle timeout.
static bool available()
Returns true if a jpeg library is available.
static unsigned int toUInt(const std::string &s)
Converts string 's' to an unsigned int.
static ImageBuffer * blank(Image &, ImageType raw_type, bool contiguous=false)
Factory function for a not-really-blank raw image that is temporarily writable via the returned image...
static Address defaultAddress()
Returns a default address, being the IPv4 wildcard address with a zero port number.
int dy() const
Returns the image height.
static std::string head(const std::string &in, std::string::size_type pos, const std::string &default_=std::string())
Returns the first part of the string up to just before the given position.
static void trimRight(std::string &s, const std::string &ws, size_type limit=0U)
Trims the rhs of s, taking off up to 'limit' of the 'ws' characters.
bool valid() const
Returns !empty() && type().valid().
ImageType type() const
Returns the image type.
static std::string trimmed(const std::string &s, const std::string &ws)
Returns a trim()med version of s.
const ImageBuffer & data() const
Returns the image data.
A variant class holding a string, an item map keyed by name, or an ordered list of items...
int dx() const
Returns the image width.
A GNet::ServerPeer class for HTTP servers that serves up image streams.
void add(const std::string &s)
Adds a string item to this list item.
static Item info(const std::string &channel_name, bool all_slots=true)
Returns a variant containing information about the state of the channel.
std::string simple() const
Returns the basic image type string, excluding the size parameter.
virtual ~HttpServerPeer()
Destructor.
A container for ImageInputSource pointers, used by Gv::HttpServerPeer.
A configuration structure for resources that Gv::HttpServerPeer makes available.
static bool isUInt(const std::string &s)
Returns true if the string can be converted into an unsigned integer without throwing an exception...
static std::string::size_type ifind(const std::string &s, const std::string &key, std::string::size_type pos=0U)
Does a case-insensitive std::string::find().
void setPort(unsigned int port)
Sets the port number.
static std::string encode(const std::string &, bool plus_for_space=true)
Does url-encoding.
A structure used in GNet::Server::newPeer().
static std::string ws()
A convenience function returning standard whitespace characters.