44namespace csp ::adapters::websocket {
55
66WebsocketEndpointManager::WebsocketEndpointManager ( ClientAdapterManager* mgr, const Dictionary & properties, Engine* engine )
7- : m_ioc(),
7+ : m_num_threads( static_cast <size_t >(properties.get<int64_t >(" num_threads" )) ),
8+ m_ioc ( m_num_threads ),
89 m_engine( engine ),
10+ m_strand( boost::asio::make_strand(m_ioc) ),
911 m_mgr( mgr ),
1012 m_active( false ),
1113 m_shouldRun( false ),
@@ -22,8 +24,7 @@ WebsocketEndpointManager::WebsocketEndpointManager( ClientAdapterManager* mgr, c
2224 // m_work_guard(properties.get<bool>("dynamic") ?
2325 // std::make_optional(boost::asio::make_work_guard(m_ioc)) :
2426 // std::nullopt),
25- m_dynamic( properties.get<bool >(" dynamic" ) )
26- {
27+ m_dynamic( properties.get<bool >(" dynamic" ) ){
2728 // Total number of subscribe and send function calls, set on the adapter manager
2829 // when is it created. Note, that some of the input adapters might have been
2930 // pruned from the graph and won't get created.
@@ -49,21 +50,29 @@ WebsocketEndpointManager::WebsocketEndpointManager( ClientAdapterManager* mgr, c
4950void WebsocketEndpointManager::start (DateTime starttime, DateTime endtime) {
5051 // maybe restart here?
5152 m_shouldRun = true ;
52- m_thread = std::make_unique<std::thread>([this ]() {
53- m_ioc.reset ();
54- if ( !m_dynamic ){
55- boost::asio::post (m_ioc, [this ]() {
56- // We subscribe for both the subscribe and send calls
57- // But we probably should check here.
58- if ( m_outputAdapters.size () == 1 )
59- handleConnectionRequest (Dictionary (m_properties), 0 , false );
60- // // If we have an input adapter call AND it's not pruned.
61- if ( m_inputAdapters.size () == 1 && !adapterPruned (0 ))
62- handleConnectionRequest (Dictionary (m_properties), 0 , true );
63- });
64- }
65- m_ioc.run ();
66- });
53+ // std::vector<std::thread> threads;
54+
55+ m_ioc.reset ();
56+ if ( !m_dynamic ){
57+ boost::asio::post (m_strand, [this ]() {
58+ // We subscribe for both the subscribe and send calls
59+ // But we probably should check here.
60+ if ( m_outputAdapters.size () == 1 )
61+ handleConnectionRequest (Dictionary (m_properties), 0 , false );
62+ // // If we have an input adapter call AND it's not pruned.
63+ if ( m_inputAdapters.size () == 1 && !adapterPruned (0 ))
64+ handleConnectionRequest (Dictionary (m_properties), 0 , true );
65+ });
66+ }
67+ for (auto i = 0 ; i < m_num_threads; ++i) {
68+ m_threads.emplace_back (std::make_unique<std::thread>([this ]() {
69+ m_ioc.run ();
70+ }));
71+ }
72+ // m_thread = std::make_unique<std::thread>([this]() {
73+ // // m_ioc.reset();
74+ // m_ioc.run();
75+ // });
6776};
6877
6978bool WebsocketEndpointManager::adapterPruned ( size_t caller_id ){
@@ -403,7 +412,7 @@ void WebsocketEndpointManager::stop() {
403412 // Stop all endpoints
404413 // Endpoints running on m_ioc thread,
405414 // So we call stop there
406- boost::asio::post (m_ioc , [this ]() {
415+ boost::asio::post (m_strand , [this ]() {
407416 for (auto & [endpoint_id, _] : m_endpoints) {
408417 // TODO ponder
409418 // Since this is called from the main thread,
@@ -422,6 +431,16 @@ void WebsocketEndpointManager::stop() {
422431 m_ioc.stop ();
423432 m_cv.notify_one ();
424433 if ( m_thread ) m_thread->join ();
434+
435+ // Wait for all threads to finish
436+ for (auto & thread : m_threads) {
437+ if (thread && thread->joinable ()) {
438+ thread->join ();
439+ }
440+ }
441+
442+ // Clear threads before other members are destroyed
443+ m_threads.clear ();
425444};
426445
427446PushInputAdapter* WebsocketEndpointManager::getInputAdapter (CspTypePtr & type, PushMode pushMode, const Dictionary & properties)
@@ -445,15 +464,15 @@ OutputAdapter* WebsocketEndpointManager::getOutputAdapter( const Dictionary & pr
445464 assert (!properties.get <bool >(" is_subscribe" ));
446465 assert (m_outputAdapters.size () == validated_id);
447466
448- auto output_adapter = m_engine -> createOwnedObject<ClientOutputAdapter>( this , validated_id, m_ioc );
467+ auto output_adapter = m_engine -> createOwnedObject<ClientOutputAdapter>( this , validated_id, m_ioc, m_strand );
449468 m_outputAdapters[validated_id] = output_adapter;
450469 return m_outputAdapters[validated_id];
451470};
452471
453472OutputAdapter * WebsocketEndpointManager::getHeaderUpdateAdapter ()
454473{
455474 if (m_updateAdapter == nullptr )
456- m_updateAdapter = m_engine -> createOwnedObject<ClientHeaderUpdateOutputAdapter>( m_endpoint -> getProperties (), this );
475+ m_updateAdapter = m_engine -> createOwnedObject<ClientHeaderUpdateOutputAdapter>( m_endpoint -> getProperties (), this , m_strand );
457476
458477 return m_updateAdapter;
459478};
@@ -465,7 +484,7 @@ OutputAdapter * WebsocketEndpointManager::getConnectionRequestAdapter( const Dic
465484 auto is_subscribe = properties.get <bool >(" is_subscribe" );
466485
467486 auto * adapter = m_engine->createOwnedObject <ClientConnectionRequestAdapter>(
468- this , m_ioc, is_subscribe, caller_id
487+ this , m_ioc, is_subscribe, caller_id, m_strand
469488 );
470489 m_connectionRequestAdapters.push_back (adapter);
471490
0 commit comments