2020-03-04 18:05:57 +03:00
/* -------------------------------------------------------------------------- */
2023-01-09 14:23:19 +03:00
/* Copyright 2002-2023, OpenNebula Project, OpenNebula Systems */
2020-03-04 18:05:57 +03:00
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
/* not use this file except in compliance with the License. You may obtain */
/* a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and */
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
# ifndef STREAM_MANAGER_H
# define STREAM_MANAGER_H
# include <stdlib.h>
# include <string.h>
# include <unistd.h>
# include <sys/ioctl.h>
# include <string.h>
# include <map>
# include <thread>
# include <memory>
# include <string>
# include <functional>
# include <mutex>
# include <condition_variable>
# include "Message.h"
2020-03-07 01:52:47 +03:00
# include "StringBuffer.h"
2020-03-04 18:05:57 +03:00
/**
* This class manages a stream to process Messages . The StreamManager
* thread reads from the stream for input messages and executed the associated
* action in a separated ( detached ) thread .
*/
2020-06-29 13:14:00 +03:00
template < typename MSG >
2020-03-04 18:05:57 +03:00
class StreamManager
{
public :
2020-06-29 13:14:00 +03:00
using callback_t = std : : function < void ( std : : unique_ptr < MSG > ) > ;
2020-03-04 18:05:57 +03:00
/* ---------------------------------------------------------------------- */
/* ---------------------------------------------------------------------- */
/**
* @ param fd file descriptor for the stream
* @ param error_cbk function to execute on error ( parse error or UNDEFINED )
*/
StreamManager ( int __fd , callback_t error_cbk ) : _fd ( __fd )
{
2020-06-29 13:14:00 +03:00
register_action ( MSG : : msg_enum : : UNDEFINED , error_cbk ) ;
2020-03-04 18:05:57 +03:00
} ;
StreamManager ( callback_t error_cbk ) : StreamManager ( - 1 , error_cbk ) { } ;
2020-06-29 13:14:00 +03:00
StreamManager ( ) : StreamManager ( - 1 , [ ] ( std : : unique_ptr < MSG > m ) { } ) { } ;
2020-03-04 18:05:57 +03:00
2020-07-05 23:01:32 +03:00
virtual ~ StreamManager ( )
2020-03-04 18:05:57 +03:00
{
close ( _fd ) ;
} ;
/**
* Associate a function to be executed when a message of the given type is
* read
* @ param t the message type
* @ param a callback function to be executed
*/
2020-06-29 13:14:00 +03:00
void register_action ( typename MSG : : msg_enum t , callback_t a ) ;
2020-03-04 18:05:57 +03:00
/**
* Reads messages from the stream and execute callbacks . This method should
* be run in a separated thread .
* @ param concurrency number of concurrent actions , use 0 to run all the
* actions sequetianlly in this thread .
*/
virtual int action_loop ( int concurrency ) ;
/**
* Sets the file descriptor for the stream
* @ param fd file descriptor
*/
void fd ( int __fd )
{
_fd = __fd ;
}
/**
* Look for the associated callback for the message and execute it
* @ param msg read from the stream
*/
2020-06-29 13:14:00 +03:00
void do_action ( std : : unique_ptr < MSG > & msg , bool threaded ) ;
2020-03-04 18:05:57 +03:00
protected :
/**
* Read a line from the stream
* @ return - 1 in case of error or EOL
*/
2020-03-07 01:52:47 +03:00
virtual int read_line ( std : : string & line )
{
return buffer . read_line ( _fd , line ) ;
}
2020-03-04 18:05:57 +03:00
private :
int _fd ;
std : : mutex _mutex ;
std : : condition_variable _cond ;
2023-02-02 14:48:43 +03:00
int _concurrency = 0 ;
2020-03-04 18:05:57 +03:00
2020-06-29 13:14:00 +03:00
std : : map < typename MSG : : msg_enum , callback_t > actions ;
2020-03-04 18:05:57 +03:00
2020-03-07 01:52:47 +03:00
StringBuffer buffer ;
2020-03-04 18:05:57 +03:00
} ;
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* Stream Manager Implementation */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
2020-06-29 13:14:00 +03:00
template < typename MSG >
void StreamManager < MSG >
: : register_action ( typename MSG : : msg_enum t , callback_t a )
2020-03-04 18:05:57 +03:00
{
auto ret = actions . insert ( { t , a } ) ;
if ( ! ret . second )
{
ret . first - > second = a ;
}
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
2020-06-29 13:14:00 +03:00
template < typename MSG >
void StreamManager < MSG >
: : do_action ( std : : unique_ptr < MSG > & msg , bool thr )
2020-03-04 18:05:57 +03:00
{
const auto it = actions . find ( msg - > type ( ) ) ;
if ( it = = actions . end ( ) )
{
return ;
}
const auto action = it - > second ;
2020-06-29 13:14:00 +03:00
MSG * mptr = msg . release ( ) ;
2020-03-04 18:05:57 +03:00
if ( thr )
{
std : : unique_lock < std : : mutex > lock ( _mutex ) ;
while ( _concurrency < = 0 )
{
_cond . wait ( lock ) ;
}
- - _concurrency ;
lock . unlock ( ) ;
std : : thread action_thread ( [ this , action , mptr ] {
2020-06-29 13:14:00 +03:00
action ( std : : unique_ptr < MSG > { mptr } ) ;
2020-03-04 18:05:57 +03:00
std : : unique_lock < std : : mutex > lock ( _mutex ) ;
_concurrency + + ;
lock . unlock ( ) ;
_cond . notify_one ( ) ;
} ) ;
action_thread . detach ( ) ;
}
else
{
2020-06-29 13:14:00 +03:00
action ( std : : unique_ptr < MSG > { mptr } ) ;
2020-03-04 18:05:57 +03:00
}
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
2020-06-29 13:14:00 +03:00
template < typename MSG >
int StreamManager < MSG >
: : action_loop ( int concurrency )
2020-03-04 18:05:57 +03:00
{
bool threaded = concurrency > 0 ;
_concurrency = concurrency ;
while ( true )
{
std : : string line ;
if ( read_line ( line ) ! = 0 )
{
return - 1 ;
}
if ( line . empty ( ) )
{
continue ;
}
2020-06-29 13:14:00 +03:00
std : : unique_ptr < MSG > msg { new MSG } ;
2020-03-04 18:05:57 +03:00
2020-06-29 13:14:00 +03:00
msg - > parse_from ( line ) ;
2020-03-04 18:05:57 +03:00
do_action ( msg , threaded ) ; //Errors are handled by the UNDEFINED action
}
return 0 ;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
# endif /*STREAM_MANAGER_H*/