3636#include < exception>
3737#include < memory>
3838#include < mutex>
39+ #include < set>
3940#include < string>
4041#include < sstream>
4142#include < vector>
4243
44+ #include < boost/algorithm/string/join.hpp>
4345#include < boost/algorithm/string/predicate.hpp>
4446#include < boost/bind/bind.hpp>
4547#include < boost/bind/placeholders.hpp>
@@ -263,21 +265,19 @@ bool WebVideoServer::handle_list_streams(
263265 async_web_server_cpp::HttpConnectionPtr connection, const char * /* begin */ ,
264266 const char * /* end */ )
265267{
266- std::vector<std::string> image_topics;
267- std::vector<std::string> camera_info_topics;
268- auto tnat = get_topic_names_and_types ();
269- for (auto topic_and_types : tnat) {
270- if (topic_and_types.second .size () > 1 ) {
271- // skip over topics with more than one type
272- continue ;
273- }
274- auto & topic_name = topic_and_types.first ;
275- auto & topic_type = topic_and_types.second [0 ]; // explicitly take the first
276-
277- if (topic_type == " sensor_msgs/msg/Image" ) {
278- image_topics.push_back (topic_name);
279- } else if (topic_type == " sensor_msgs/msg/CameraInfo" ) {
280- camera_info_topics.push_back (topic_name);
268+ std::map<std::string, std::vector<std::string>> topics_by_type;
269+ std::set<std::string> all_topics;
270+
271+ for (const auto & factory_pair : image_streamer_factories_) {
272+ RCLCPP_DEBUG (get_logger (), " Getting topics from factory: %s" , factory_pair.first .c_str ());
273+ std::vector<std::string> factory_topics =
274+ factory_pair.second ->get_available_topics (shared_from_this ());
275+ RCLCPP_DEBUG (get_logger (), " Factory %s returned %zu topics" ,
276+ factory_pair.first .c_str (), factory_topics.size ());
277+ for (const auto & topic : factory_topics) {
278+ RCLCPP_DEBUG (get_logger (), " Topic: %s" , topic.c_str ());
279+ topics_by_type[factory_pair.first ].push_back (topic);
280+ all_topics.insert (topic);
281281 }
282282 }
283283
@@ -291,61 +291,44 @@ bool WebVideoServer::handle_list_streams(
291291
292292 connection->write (
293293 " <html>"
294- " <head><title>ROS Image Topic List</title></head>"
295- " <body><h1>Available ROS Image Topics:</h1>" );
294+ " <head><title>ROS Streamable Topic List</title></head>"
295+ " <body><h1>Available ROS Topics for streaming :</h1>" );
296296 connection->write (" <ul>" );
297- for (std::string & camera_info_topic : camera_info_topics) {
298- if (boost::algorithm::ends_with (camera_info_topic, " /camera_info" )) {
299- std::string base_topic = camera_info_topic.substr (
300- 0 ,
301- camera_info_topic.size () - strlen (" camera_info" ));
302- connection->write (" <li>" );
303- connection->write (base_topic);
304- connection->write (" <ul>" );
305- std::vector<std::string>::iterator image_topic_itr = image_topics.begin ();
306- for (; image_topic_itr != image_topics.end (); ) {
307- if (boost::starts_with (*image_topic_itr, base_topic)) {
308- connection->write (" <li><a href=\" /stream_viewer?topic=" );
309- connection->write (*image_topic_itr);
310- connection->write (" \" >" );
311- connection->write (image_topic_itr->substr (base_topic.size ()));
312- connection->write (" </a> (" );
313- connection->write (" <a href=\" /stream?topic=" );
314- connection->write (*image_topic_itr);
315- connection->write (" \" >Stream</a>) (" );
316- connection->write (" <a href=\" /snapshot?topic=" );
317- connection->write (*image_topic_itr);
318- connection->write (" \" >Snapshot</a>)" );
319- connection->write (" </li>" );
320-
321- image_topic_itr = image_topics.erase (image_topic_itr);
322- } else {
323- ++image_topic_itr;
324- }
297+ for (const std::string & topic : all_topics) {
298+ std::vector<std::string> available_stream_viewers;
299+ std::vector<std::string> available_streams;
300+
301+ for (const auto & factory_pair : topics_by_type) {
302+ const auto & type = factory_pair.first ;
303+ const auto & topics = factory_pair.second ;
304+ if (std::find (topics.begin (), topics.end (), topic) != topics.end ()) {
305+ available_stream_viewers.push_back (
306+ " <a href=\" /stream_viewer?topic=" + topic +
307+ " &type=" + type + " \" >" + type + " </a>" );
308+ available_streams.push_back (
309+ " <a href=\" /stream?topic=" + topic +
310+ " &type=" + type + " \" >" + type + " </a>" );
325311 }
326- connection->write (" </ul>" );
327312 }
313+
314+ connection->write (" <li>" );
315+ connection->write (topic);
316+ connection->write (" <ul>" );
317+ connection->write (" <li>" );
318+ connection->write (" <a href=\" /stream_viewer?topic=" + topic + " \" >" );
319+ connection->write (" Stream Viewer</a> (" );
320+ connection->write (boost::algorithm::join (available_stream_viewers, " , " ));
321+ connection->write (" )" );
328322 connection->write (" </li>" );
329- }
330- connection->write (" </ul>" );
331- // Add the rest of the image topics that don't have camera_info.
332- connection->write (" <ul>" );
333- std::vector<std::string>::iterator image_topic_itr = image_topics.begin ();
334- for (; image_topic_itr != image_topics.end (); ) {
335- connection->write (" <li><a href=\" /stream_viewer?topic=" );
336- connection->write (*image_topic_itr);
337- connection->write (" \" >" );
338- connection->write (*image_topic_itr);
339- connection->write (" </a> (" );
340- connection->write (" <a href=\" /stream?topic=" );
341- connection->write (*image_topic_itr);
342- connection->write (" \" >Stream</a>) (" );
343- connection->write (" <a href=\" /snapshot?topic=" );
344- connection->write (*image_topic_itr);
345- connection->write (" \" >Snapshot</a>)" );
323+ connection->write (" <li>" );
324+ connection->write (" <a href=\" /stream?topic=" + topic + " \" >" );
325+ connection->write (" Stream</a> (" );
326+ connection->write (boost::algorithm::join (available_streams, " , " ));
327+ connection->write (" )" );
328+ connection->write (" </li>" );
329+ connection->write (" </ul>" );
346330 connection->write (" </li>" );
347331
348- image_topic_itr = image_topics.erase (image_topic_itr);
349332 }
350333 connection->write (" </ul></body></html>" );
351334 return true ;
0 commit comments