diff --git a/CMakeLists.txt b/CMakeLists.txt index bd05abd..4588671 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,9 +85,6 @@ endif( FFTW_FOUND ) # Boost (1.48 required for container; scarab minimum is 1.46) #find_package( Boost 1.48.0 REQUIRED ) -# Sandfly -add_definitions( -DDRIPLINE_AUTH_FILE=~/.project8_authentications.json ) - # Included external dependencies # Including: tk_spline add_subdirectory( external ) diff --git a/Dockerfile b/Dockerfile index 9625c5a..5cb2708 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,7 +18,7 @@ ENV PSYLLID_TAG=${psyllid_tag} ENV PSYLLID_INSTALL_PREFIX=${P8_ROOT}/${psyllid_subdir}/${PSYLLID_TAG} ENV NARG=${narg} -ENV PATH="${PATH}:${PSYLLID_INSTALL_PREFIX}" +ENV PATH="${PATH}:${PSYLLID_INSTALL_PREFIX}/bin" # Build image with dev dependencies FROM base AS deps diff --git a/sandfly b/sandfly index 0ead4ce..bca32da 160000 --- a/sandfly +++ b/sandfly @@ -1 +1 @@ -Subproject commit 0ead4ce3b48fb5b5274b6c65d37b6fcee4e1fcd9 +Subproject commit bca32da76947e82ce104463dfef02d3f171a8eac diff --git a/source/applications/psyllid.cc b/source/applications/psyllid.cc index 6b14642..c74ce24 100644 --- a/source/applications/psyllid.cc +++ b/source/applications/psyllid.cc @@ -12,6 +12,7 @@ #include "conductor.hh" #include "sandfly_error.hh" #include "server_config.hh" +#include "slack_relayer.hh" #include "application.hh" #include "logger.hh" @@ -41,10 +42,11 @@ int main( int argc, char** argv ) // The application scarab::main_app the_main; conductor the_conductor; - the_conductor.set_rc_creator< daq_control >(); // Default configuration + // Same as sandfly, but change the name the_main.default_config() = server_config(); + the_main.default_config()["name"]() = "psyllid"; // The main execution callback the_main.callback( [&](){ @@ -52,7 +54,8 @@ int main( int argc, char** argv ) auto t_cwrap = scarab::wrap_cancelable( the_conductor ); t_sig_hand.add_cancelable( t_cwrap ); - the_conductor.execute( the_main.primary_config(), the_main.auth() ); + the_conductor.execute< daq_control >( the_main.primary_config(), the_main.auth(), + std::make_shared< slack_relayer >(the_main.primary_config(), the_main.auth()) ); } ); // Command line options diff --git a/source/control/daq_control.cc b/source/control/daq_control.cc index 6be2919..2c4c8c5 100644 --- a/source/control/daq_control.cc +++ b/source/control/daq_control.cc @@ -59,7 +59,7 @@ namespace psyllid catch( std::exception& e ) { LERROR( plog, "Unable to start files: " << e.what() ); - f_msg_relay->slack_error( std::string("Unable to start files: ") + e.what() ); + f_msg_relay->send_error( std::string("Unable to start files: ") + e.what() ); set_status( status::error ); LDEBUG( plog, "Canceling midge" ); if( f_midge_pkg.have_lock() ) f_midge_pkg->cancel(); @@ -81,7 +81,7 @@ namespace psyllid catch( std::exception& e ) { LERROR( plog, "Unable to finish files: " << e.what() ); - f_msg_relay->slack_error( std::string("Unable to finish files: ") + e.what() ); + f_msg_relay->send_error( std::string("Unable to finish files: ") + e.what() ); set_status( status::error ); LDEBUG( plog, "Canceling midge" ); if( f_midge_pkg.have_lock() ) f_midge_pkg->cancel(); diff --git a/source/daq/CMakeLists.txt b/source/daq/CMakeLists.txt index 4b8f896..20c1259 100644 --- a/source/daq/CMakeLists.txt +++ b/source/daq/CMakeLists.txt @@ -9,6 +9,7 @@ set( headers event_builder.hh #single_value_trigger.hh frequency_mask_trigger.hh + locust_egg_reader.hh packet_receiver_socket.hh roach_config.hh streaming_writer.hh @@ -25,6 +26,7 @@ set( sources event_builder.cc #single_value_trigger.cc frequency_mask_trigger.cc + locust_egg_reader.cc packet_receiver_socket.cc roach_config.cc streaming_writer.cc diff --git a/source/daq/frequency_mask_trigger.hh b/source/daq/frequency_mask_trigger.hh index 0335aaa..539759f 100644 --- a/source/daq/frequency_mask_trigger.hh +++ b/source/daq/frequency_mask_trigger.hh @@ -64,7 +64,7 @@ namespace psyllid - "threshold-power-snr": float -- The threshold SNR, given as a power SNR - "threshold-power-snr-high": float -- A second SNR threshold, given as power SNR - "threshold-dB": float -- The threshold SNR, given as a dB factor - - "trigger-mode": string -- The trigger mode, can be set to "single-level-trigger" or "two-level-trigger" + - "trigger-mode": string -- The trigger mode, can be set to "single-level" or "two-level" - "n-spline-points": uint -- The number of points to have in the spline fit for the trigger mask - "mask-configuration": string || node -- If a string, path to a yaml file with mask and mask-data arrays to populate the respective vectors; if a node, then contains those arrays of floats. diff --git a/source/daq/locust_egg_reader.cc b/source/daq/locust_egg_reader.cc new file mode 100644 index 0000000..d2c0b6f --- /dev/null +++ b/source/daq/locust_egg_reader.cc @@ -0,0 +1,389 @@ +/* + * locust_egg_reader.cc + * + * Created on: Dec. 13, 2024 + * Author: pkolbeck + */ + + +#include "locust_egg_reader.hh" + +#include "psyllid_error.hh" +#include "time_data.hh" + +#include "M3Monarch.hh" + +#include "run_control.hh" + +#include "logger.hh" +#include "param.hh" + +#include +#include + +using midge::stream; + +namespace psyllid +{ + REGISTER_NODE_AND_BUILDER( locust_egg_reader, "locust-egg-reader", locust_egg_reader_binding ); + + LOGGER( plog, "locust_egg_reader" ); + + // locust_egg_reader methods + locust_egg_reader::locust_egg_reader() : + f_egg( nullptr ), + f_egg_path( "/dev/null" ), + f_read_n_records( 0 ), + f_repeat_egg( false ), + f_length( 10 ), + f_start_paused( true ), + f_slice_length( PAYLOAD_SIZE ), + f_paused( true ), + f_record_length( 0 ), + f_sample_size( 0 ), + f_pkt_id_offset( 0 ), + f_uint_to_int( false ) + { + } + + locust_egg_reader::~locust_egg_reader() + { + cleanup_file(); + } + + void locust_egg_reader::initialize() + { + f_paused = f_start_paused; + + out_buffer< 0 >().initialize( f_length ); + + LDEBUG( plog, "opening egg file [" << f_egg_path << "]" ); + f_egg = monarch3::Monarch3::OpenForReading( f_egg_path ); + f_egg->ReadHeader(); + // do we want/need to do anything with the header? + const monarch3::M3Header *t_egg_header = f_egg->GetHeader(); + LDEBUG( plog, "egg header content:\n" ); + LDEBUG( plog, *t_egg_header ); + //TODO this should probably not assume single-channel mode... + f_record_length = t_egg_header->ChannelHeaders()[0].GetRecordSize(); + f_sample_size = t_egg_header->ChannelHeaders()[0].GetSampleSize(); + return; + + } + + void locust_egg_reader::execute( midge::diptera* a_midge ) + { + try + { + LDEBUG( plog, "Executing the locust_egg_reader" ); + LDEBUG( plog, "Uint to int conversion: [" << f_uint_to_int << "]") + //TODO use header to loop streams so we can send more than one? + //const monarch3::M3Header *t_egg_header = f_egg->GetHeader(); + const monarch3::M3Stream* t_stream = f_egg->GetStream( 0 ); + const monarch3::M3Record* t_record = t_stream->GetChannelRecord( 0 ); + + time_data* t_data = nullptr; + + // starting not in a paused state is not currently known to work + if ( !f_paused ) + { + if( ! out_stream< 0 >().set( stream::s_start ) ) return; + } + + uint64_t t_records_read = 0; + uint64_t t_slice_offset = 0; + + // starting execution loop + while (! is_canceled() ) + { + if( (out_stream< 0 >().get() == stream::s_stop) ) + { + LWARN( plog, "Output stream(s) have stop condition" ); + break; + } + if( have_instruction() ) + { + if( f_paused && use_instruction() == midge::instruction::resume ) + { + LDEBUG( plog, "egg reader resuming" ); + if( ! out_stream< 0 >().set( stream::s_start ) ) throw midge::node_nonfatal_error() << "Stream 0 error while starting"; + f_paused = false; + t_records_read = 0; + } + else if ( !f_paused && use_instruction() == midge::instruction::pause ) + { + LDEBUG( plog, "egg reader pausing" ); + if( ! out_stream< 0 >().set( stream::s_stop ) ) throw midge::node_nonfatal_error() << "Stream 0 error while stopping"; + f_paused = true; + } + } + // only read if not paused: + if ( ! f_paused ) + { + //if ( !read_slice(t_data, t_stream, t_record) ) break; + bool write_slice_ok = write_slice(t_data, t_stream, t_record, &t_slice_offset, &t_records_read); + if ( !write_slice_ok || (f_read_n_records > 0 && t_records_read >= f_read_n_records) ) + { + LINFO( plog, "breaking out of loop because record limit or end of file reached" ); + std::shared_ptr< sandfly::run_control > t_run_control = use_run_control(); + t_run_control->stop_run(); + } + // add some sleep to try and not lap downstream nodes + std::this_thread::sleep_for(std::chrono::microseconds(100)); + } + else + { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + } + } + catch( std::exception ) + { + LWARN( plog, "got an exception, throwing" ); + a_midge->throw_ex( std::current_exception() ); + } + LDEBUG( plog, "at the end of locust egg execute" ); + } + + void locust_egg_reader::finalize() + { + LDEBUG( plog, "finalize the locust_egg_reader" ); + out_buffer< 0 >().finalize(); + LDEBUG( plog, "buffer finalized" ); + cleanup_file(); + return; + } + + bool locust_egg_reader::read_slice(time_data* t_data, const monarch3::M3Stream* t_stream, const monarch3::M3Record* t_record) + { + LDEBUG( plog, "reading a slice" ); + // update t_data to point to the next slot in the output stream + t_data = out_stream< 0 >().data(); + // read next record in egg file, writing into the output_stream + if ( !t_stream->ReadRecord() ) + { + if ( !f_repeat_egg ) + { + LDEBUG( plog, "reached end of file, stopping" ); + return false; + } + else + { + LDEBUG( plog, "reached end of file, restarting" ); + t_stream->ReadRecord( -1 * int(t_stream->GetRecordCountInFile()) ); + // when we loop back, we want the record ID to increment and have a gap relative to the end of the file + f_pkt_id_offset += 1 + t_stream->GetNRecordsInFile(); + } + } + std::copy(&t_record->GetData()[0], &t_record->GetData()[f_record_length*2], &t_data->get_array()[0][0]); + + // packet ID logic + //TODO do this pkt ID logic reasonable? + t_data->set_pkt_in_batch( t_record->GetRecordId() + f_pkt_id_offset ); + t_data->set_pkt_in_session( t_record->GetRecordId() + f_pkt_id_offset ); + if ( !out_stream< 0 >().set( stream::s_run ) ) + { + LERROR( plog, "egg reader exiting due to stream error" ); + return false; + } + return true; + } + + bool locust_egg_reader::read_record( const monarch3::M3Stream* t_stream ) + { + LDEBUG( plog, "attempting to read a record") + if ( !t_stream->ReadRecord() ) + { + if ( !f_repeat_egg ) + { + LDEBUG( plog, "reached end of file, stopping" ); + return false; + } + else + { + LDEBUG( plog, "reached end of file, restarting" ); + t_stream->ReadRecord( -1 * int(t_stream->GetRecordCountInFile()) ); + // when we loop back, we want the record ID to increment and have a gap relative to the end of the file + f_pkt_id_offset += 1 + t_stream->GetNRecordsInFile(); + } + } + return true; + } + + void locust_egg_reader::packet_logic( time_data* t_data, const monarch3::M3Record* t_record ) + { + // packet ID logic + //TODO do this pkt ID logic reasonable? + t_data->set_pkt_in_batch( t_record->GetRecordId() + f_pkt_id_offset ); + t_data->set_pkt_in_session( t_record->GetRecordId() + f_pkt_id_offset ); + } + + bool locust_egg_reader::check_stream() + { + if ( !out_stream< 0 >().set( stream::s_run ) ) + { + LERROR( plog, "egg reader exiting due to stream error" ); + return false; + } + return true; + } + + void locust_egg_reader::convert_uiq_to_iq( const u_char* t_source, int8_t* t_target, int t_data_len, bool t_convert ) + { + uint8_t t_128 = 128; + if( t_convert ) + { + for(int i = 0; i < t_data_len; i++ ) + { + t_target[i] = t_source[i] ^ t_128; + } + } + else + { + std::copy(t_source, &t_source[t_data_len], t_target); + } + + } + + bool locust_egg_reader::write_slice( time_data* t_data, const monarch3::M3Stream* t_stream, const monarch3::M3Record* t_record, uint64_t* t_slice_offset, uint64_t* t_records_read ) + { + uint32_t t_num_samples = f_record_length * f_sample_size; + if ( f_slice_length > t_num_samples) + { + LERROR( plog, "slice length is longer than record length * sample size"); + return false; + } + + // update t_data to point to the next slot in the output stream. + t_data = out_stream< 0 >().data(); + + + + // starting + if( *t_records_read == 0 ) + { + LDEBUG( plog, "starting to read the first record" ); + // read record + if ( !read_record( t_stream ) ) + { + // end of file + LDEBUG( plog, "reached end of file" ); + return false; + } + // have started reading another record. + (*t_records_read)++; + + } + + LDEBUG( plog, "writing slice of length [" << f_slice_length << "] at offset [" << *t_slice_offset << "] in record with [" << t_num_samples << "] numbers"); + if( *t_slice_offset + f_slice_length <= t_num_samples ) + { + // don't have to read data from the next record yet. + // copy the part of the new record + convert_uiq_to_iq(&t_record->GetData()[*t_slice_offset], &t_data->get_array()[0][0], f_slice_length, f_uint_to_int); + // packet logic + packet_logic( t_data, t_record ); + // check stream + if ( !check_stream() ) + { + return false; + } + // increment t_slice_offset by f_slice_length + *t_slice_offset += f_slice_length; + } + else + { + // have to read data from the next record if want to continue + + if( *t_records_read >= f_read_n_records ) + { + // we've reached the specified max number of records to read + LDEBUG( plog, "reached max records" ); + return false; + } + + // keep pointer to current record + const monarch3::M3Record* t_old_record = t_record; + // read new record + if( !read_record( t_stream ) ) + { + // end of file + LDEBUG( plog, "reached end of file" ); + return false; + } + // have started reading another record + (*t_records_read)++; + + LDEBUG( plog, "switching to new record" ); + // get amount left in current record + uint64_t t_num_samples_left = t_num_samples - *t_slice_offset; + // copy rest of current data + convert_uiq_to_iq(&t_old_record->GetData()[*t_slice_offset], &t_data->get_array()[0][0], t_num_samples_left, f_uint_to_int); + // update slice offset + *t_slice_offset = f_slice_length - t_num_samples_left; + // copy new data + convert_uiq_to_iq(&t_record->GetData()[0], &t_data->get_array()[0][t_num_samples_left], *t_slice_offset, f_uint_to_int); + + // packet logic + packet_logic( t_data, t_record ); + // check stream + if ( !check_stream() ) + { + return false; + } + + } + + return true; + + } + + void locust_egg_reader::cleanup_file() + { + LDEBUG( plog, "cleaning up file" ); + if ( f_egg == NULL ) return; + LDEBUG( plog, "clean egg" ); + if ( f_egg->GetState() != monarch3::Monarch3::eClosed ) + { + LDEBUG( plog, "actually close egg" ); + f_egg->FinishReading(); + } + } + + // locust_egg_reader_binding methods + locust_egg_reader_binding::locust_egg_reader_binding() : + sandfly::_node_binding< locust_egg_reader, locust_egg_reader_binding >() + { + } + + locust_egg_reader_binding::~locust_egg_reader_binding() + { + } + + void locust_egg_reader_binding::do_apply_config( locust_egg_reader* a_node, const scarab::param_node& a_config ) const + { + LDEBUG( plog, "Configuring locust_egg_reader with:\n" << a_config ); + a_node->set_egg_path( a_config.get_value( "egg-path", a_node->get_egg_path() ) ); + a_node->set_read_n_records( a_config.get_value( "read-n-records", a_node->get_read_n_records() ) ); + a_node->set_repeat_egg( a_config.get_value( "repeat-egg", a_node->get_repeat_egg() ) ); + a_node->set_length( a_config.get_value( "length", a_node->get_length() ) ); + a_node->set_start_paused( a_config.get_value( "start-paused", a_node->get_start_paused() ) ); + // a_node->set_slice_length( a_config.get_value( "slice-length", a_node->get_slice_length() ) ); + a_node->set_uint_to_int( a_config.get_value( "uint-to-int", a_node->get_uint_to_int() ) ); + return; + } + + void locust_egg_reader_binding::do_dump_config( const locust_egg_reader* a_node, scarab::param_node& a_config ) const + { + LDEBUG( plog, "Dumping configuration for locust_egg_reader" ); + a_config.add( "egg-path", scarab::param_value( a_node->get_egg_path() ) ); + a_config.add( "read-n-records", scarab::param_value( a_node->get_read_n_records() ) ); + a_config.add( "repeat-egg", scarab::param_value( a_node->get_repeat_egg() ) ); + a_config.add( "length", scarab::param_value( a_node->get_length() ) ); + a_config.add( "start-paused", scarab::param_value( a_node->get_length() ) ); + // a_config.add( "slice-length", scarab::param_value( a_node->get_slice_length() ) ); + a_config.add( "uint-to-int", scarab::param_value( a_node->get_uint_to_int() ) ); + return; + } + +} /* namespace psyllid */ diff --git a/source/daq/locust_egg_reader.hh b/source/daq/locust_egg_reader.hh new file mode 100644 index 0000000..7327c5a --- /dev/null +++ b/source/daq/locust_egg_reader.hh @@ -0,0 +1,101 @@ +/* + * locust_egg_reader.hh + * + * Created on: Dec 13, 2024 + * Author: pkolbeck + */ + +#ifndef PSYLLID_LOCUST_EGG_READER_HH_ +#define PSYLLID_LOCUST_EGG_READER_HH_ + +#include "producer.hh" + +#include "control_access.hh" +#include "memory_block.hh" +#include "node_builder.hh" + +namespace monarch3 +{ + class Monarch3; + class M3Stream; + class M3Record; +} + +namespace psyllid +{ + /*! + @class locust_egg_reader + @author P. T. Kolbeck + + @brief A producer to read time-domain slices from a locust-style egg file and place them in time data buffers. + + @details + + Parameter setting is not thread-safe. Executing is thread-safe. + + Node type: "locust-egg-reader" TODO: CHANGE NODE NAME, NEED TO ADD TO OTHER FILES + + Available configuration values: TODO: CHANGE PARAMETERS. WHAT PARAMETERS ARE USEFUL? + - "egg-path": string -- resolvable path to the egg file from which to read data + - "read-n-records": int -- number of records to read from file when executing, 0 means until end of file + - "repeat-egg": bool -- indicates if reaching the end of input file should end the reading (false) or loop back to the start of the file (true); default is false + + Output Streams: + - 0: time_data + */ + + // forward declarations + class time_data; + + // locust_egg_reader + class locust_egg_reader : public midge::_producer< midge::type_list >, public sandfly::control_access + { + public: + locust_egg_reader(); + virtual ~locust_egg_reader(); + + public: + mv_accessible( const monarch3::Monarch3*, egg ); + mv_accessible( std::string, egg_path ); + mv_accessible( uint64_t, read_n_records ); + mv_accessible( bool, repeat_egg ); + mv_accessible( uint64_t, length ); + mv_accessible( bool, start_paused ); + mv_accessible( uint64_t, slice_length); + mv_accessible( bool, uint_to_int) + + private: + bool f_paused; + uint32_t f_record_length; + uint32_t f_sample_size; + uint64_t f_pkt_id_offset; + + public: + virtual void initialize(); + virtual void execute( midge::diptera* a_midge = nullptr ); + virtual void finalize(); + + private: + bool read_slice( time_data* t_data, const monarch3::M3Stream* t_stream, const monarch3::M3Record* t_record ); + bool read_record( const monarch3::M3Stream* t_stream ); + void packet_logic( time_data* t_data, const monarch3::M3Record* t_record ); + bool check_stream(); + bool write_slice( time_data* t_data, const monarch3::M3Stream* t_stream, const monarch3::M3Record* t_record, uint64_t* t_slice_offset, uint64_t* t_records_read ); + void cleanup_file(); + void convert_uiq_to_iq( const u_char* t_source, int8_t* t_target, int t_data_len, bool t_convert ); + + }; + + class locust_egg_reader_binding : public sandfly::_node_binding< locust_egg_reader, locust_egg_reader_binding > + { + public: + locust_egg_reader_binding(); + virtual ~locust_egg_reader_binding(); + private: + virtual void do_apply_config( locust_egg_reader* a_node, const scarab::param_node& a_config ) const; + virtual void do_dump_config( const locust_egg_reader* a_node, scarab::param_node& a_config ) const; + }; + +} /* namespace psyllid */ + +#endif /* PSYLLID_LOCUST_EGG_READER_HH_ */ diff --git a/source/utility/CMakeLists.txt b/source/utility/CMakeLists.txt index 18daa4f..b8b0886 100644 --- a/source/utility/CMakeLists.txt +++ b/source/utility/CMakeLists.txt @@ -6,9 +6,11 @@ set( headers byte_swap.hh psyllid_error.hh psyllid_version.hh + slack_relayer.hh ) set( sources psyllid_error.cc + slack_relayer.cc ) configure_file( psyllid_version.cc.in ${CMAKE_CURRENT_BINARY_DIR}/psyllid_version.cc ) diff --git a/source/utility/slack_relayer.cc b/source/utility/slack_relayer.cc new file mode 100644 index 0000000..b008cb6 --- /dev/null +++ b/source/utility/slack_relayer.cc @@ -0,0 +1,85 @@ +/* + * slack_relayer.cc + * + * Created on: Feb 18, 2025 + * Author: N.S. Oblath + */ + +#include "slack_relayer.hh" + +#include "param.hh" + +namespace psyllid +{ + + slack_relayer::slack_relayer( const scarab::param_node& a_config, const scarab::authentication& a_auth ) : + sandfly::message_relayer( a_config, a_auth ) + {} + + + void slack_relayer::send_notice( const std::string& a_msg_text ) const + { + send_to_slack( a_msg_text, "status_message.notice." ); + return; + } + + void slack_relayer::send_warn( const std::string& a_msg_text ) const + { + send_to_slack( a_msg_text, "status_message.warning." ); + return; + } + + void slack_relayer::send_error( const std::string& a_msg_text ) const + { + send_to_slack( a_msg_text, "status_message.error." ); + return; + } + + void slack_relayer::send_critical( const std::string& a_msg_text ) const + { + send_to_slack( a_msg_text, "status_message.critical." ); + return; + } + + void slack_relayer::send_notice( scarab::param_ptr_t&& a_payload ) const + { + send_to_slack( std::move(a_payload), "status_message.notice." ); + return; + } + + void slack_relayer::send_warn( scarab::param_ptr_t&& a_payload ) const + { + send_to_slack( std::move(a_payload), "status_message.warning." ); + return; + } + + void slack_relayer::send_error( scarab::param_ptr_t&& a_payload ) const + { + send_to_slack( std::move(a_payload), "status_message.error." ); + return; + } + + void slack_relayer::send_critical( scarab::param_ptr_t&& a_payload ) const + { + send_to_slack( std::move(a_payload), "status_message.critical." ); + return; + } + + void slack_relayer::send_to_slack( const std::string& a_msg_text, const std::string& a_rk_root ) const + { + if( ! f_use_relayer ) return; + scarab::param_ptr_t t_msg_ptr( new scarab::param_node() ); + scarab::param_node& t_msg = t_msg_ptr->as_node(); + t_msg.add( "message", scarab::param_value( a_msg_text ) ); + send_to_slack( std::move(t_msg_ptr), a_rk_root ); + return; + } + + void slack_relayer::send_to_slack( scarab::param_ptr_t&& a_payload, const std::string& a_rk_root ) const + { + if( ! f_use_relayer ) return; + send_async( dripline::msg_alert::create( std::move(a_payload), a_rk_root + f_queue_name ) ); + return; + } + +} /* namespace psyllid */ diff --git a/source/utility/slack_relayer.hh b/source/utility/slack_relayer.hh new file mode 100644 index 0000000..22b0b24 --- /dev/null +++ b/source/utility/slack_relayer.hh @@ -0,0 +1,47 @@ +/* + * slack_relayer.hh + * + * Created on: Feb 18, 2025 + * Author: N.S. Oblath + */ + +#ifndef PSYLLID_SLACK_RELAYER_HH_ +#define PSYLLID_SLACK_RELAYER_HH_ + +#include "message_relayer.hh" + +#include "param_fwd.hh" + +namespace psyllid +{ + + class slack_relayer : public sandfly::message_relayer + { + public: + slack_relayer( const scarab::param_node& a_config, const scarab::authentication& a_auth ); + slack_relayer( const slack_relayer& ) = delete; + slack_relayer( slack_relayer&& ) = default; + virtual ~slack_relayer() = default; + + slack_relayer& operator=( const slack_relayer& ) = delete; + slack_relayer& operator=( slack_relayer&& ) = default; + + public: + void send_notice( const std::string& a_msg_text ) const override; + void send_warn( const std::string& a_msg_text ) const override; + void send_error( const std::string& a_msg_text ) const override; + void send_critical( const std::string& a_msg_text ) const override; + + void send_notice( scarab::param_ptr_t&& a_payload ) const override; + void send_warn( scarab::param_ptr_t&& a_payload ) const override; + void send_error( scarab::param_ptr_t&& a_payload ) const override; + void send_critical( scarab::param_ptr_t&& a_payload ) const override; + + protected: + void send_to_slack( const std::string& a_msg_text, const std::string& a_rk_root ) const; + void send_to_slack( scarab::param_ptr_t&& a_payload, const std::string& a_rk_root ) const; + }; + +} /* namespace psyllid */ + +#endif /* PSYLLID_SLACK_RELAYER_HH_ */