diff --git a/doc/src/api/vpr/contexts.rst b/doc/src/api/vpr/contexts.rst index ec69aea8404..f29f48dd8b6 100644 --- a/doc/src/api/vpr/contexts.rst +++ b/doc/src/api/vpr/contexts.rst @@ -43,3 +43,7 @@ Structures .. doxygenstruct:: TimingContext :project: vpr :members: + +.. doxygenstruct:: ServerContext + :project: vpr + :members: \ No newline at end of file diff --git a/doc/src/api/vpr/index.rst b/doc/src/api/vpr/index.rst index 37410b72b9c..2ca57515464 100644 --- a/doc/src/api/vpr/index.rst +++ b/doc/src/api/vpr/index.rst @@ -11,3 +11,4 @@ VPR API netlist route_tree rr_graph + server diff --git a/doc/src/api/vpr/server.rst b/doc/src/api/vpr/server.rst new file mode 100644 index 00000000000..2bda680bbc1 --- /dev/null +++ b/doc/src/api/vpr/server.rst @@ -0,0 +1,83 @@ +======== +Server +======== + +server::update +-------------- + +.. doxygenfunction:: server::update + :project: vpr + +server::GateIO +-------------- + +.. doxygenclass:: server::GateIO + :project: vpr + :members: + +server::Task +------------ + +.. doxygenfile:: commcmd.h + :project: vpr + +.. doxygenclass:: server::Task + :project: vpr + :members: + +server::TaskResolver +-------------------- + +.. doxygenclass:: server::TaskResolver + :project: vpr + :members: + +.. doxygenstruct:: server::CritPathsResult + :project: vpr + :members: + +.. doxygenfunction:: server::calc_critical_path + :project: vpr + +.. doxygenenum:: e_timing_report_detail + :project: vpr + +comm::Telegram +-------------- + +.. doxygenclass:: comm::TelegramHeader + :project: vpr + :members: + +.. doxygenstruct:: comm::TelegramFrame + :project: vpr + :members: + +.. doxygenclass:: comm::TelegramBuffer + :project: vpr + :members: + +.. doxygenclass:: comm::ByteArray + :project: vpr + :members: + +Parsers +------- + +.. doxygenclass:: server::TelegramOptions + :project: vpr + :members: + +.. doxygenclass:: comm::TelegramParser + :project: vpr + :members: + + +Compression utils +----------------- + +.. doxygenfunction:: try_compress + :project: vpr + +.. doxygenfunction:: try_decompress + :project: vpr diff --git a/doc/src/vpr/command_line_usage.rst b/doc/src/vpr/command_line_usage.rst index af611dad5c4..3895d071ee5 100644 --- a/doc/src/vpr/command_line_usage.rst +++ b/doc/src/vpr/command_line_usage.rst @@ -1824,6 +1824,27 @@ The following options are used to enable power estimation in VPR. Instructions on generating this file are provided in :ref:`power_estimation`. +Server Mode Options +^^^^^^^^^^^^^^^^^^^^^^^^ + +If VPR is in server mode, it listens on a socket for commands from a client. Currently, this is used to enable interactive timing analysis and visualization of timing paths in the VPR UI under the control of a separate client. + +The following options are used to enable server mode in VPR. + +.. seealso:: :ref:`server_mode` for more details. + +.. option:: --server + + Run in server mode. Accept single client application connection and respond to client requests + + **Default:** ``off`` + +.. option:: --port PORT + + Server port number. + + **Default:** ``60555`` + Command-line Auto Completion ---------------------------- diff --git a/doc/src/vtr/index.rst b/doc/src/vtr/index.rst index 4978bc440bf..4b02b7fe432 100644 --- a/doc/src/vtr/index.rst +++ b/doc/src/vtr/index.rst @@ -43,6 +43,7 @@ VTR also includes a set of benchmark designs known to work with the design flow. running_vtr benchmarks power_estimation/index.rst + server_mode/index.rst tasks run_vtr_flow run_vtr_task diff --git a/doc/src/vtr/server_mode/comm_telegram_body_structure.odg b/doc/src/vtr/server_mode/comm_telegram_body_structure.odg new file mode 100755 index 00000000000..9f10c8e7b5b Binary files /dev/null and b/doc/src/vtr/server_mode/comm_telegram_body_structure.odg differ diff --git a/doc/src/vtr/server_mode/comm_telegram_body_structure.svg b/doc/src/vtr/server_mode/comm_telegram_body_structure.svg new file mode 100644 index 00000000000..7b2897b1088 --- /dev/null +++ b/doc/src/vtr/server_mode/comm_telegram_body_structure.svg @@ -0,0 +1,293 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + JOB_ID: int + + + + + + + + CMD: int + + + + + + + + OPTIONS: string + + + + + + + + STATUS: bool + + + + + + + + DATA: string + + + + + + + + {option_data_type} + + + + + + + + {option_name} + + + + + + + + {option_value} + + + + + + + + : + + + + + + + + {option_data_type} + + + + + + + + : + + + + + + + + {option_data_type} + + + + + + + + option_element2 + + + + + + + + ; + + + + + + + + option_element1 + + + + + + + + ; + + + + + + + + ... + + + + + + + + option_element_n + + + + + + + + OPTIONS + + + + + + + + n + + + + + + + + OPTION ELEMENT + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/src/vtr/server_mode/comm_telegram_structure.odg b/doc/src/vtr/server_mode/comm_telegram_structure.odg new file mode 100755 index 00000000000..68d2872aa12 Binary files /dev/null and b/doc/src/vtr/server_mode/comm_telegram_structure.odg differ diff --git a/doc/src/vtr/server_mode/comm_telegram_structure.svg b/doc/src/vtr/server_mode/comm_telegram_structure.svg new file mode 100755 index 00000000000..25e7602152d --- /dev/null +++ b/doc/src/vtr/server_mode/comm_telegram_structure.svg @@ -0,0 +1,584 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + I + + + + + + + + P + + + + + + + + A + + + + + + + + \0 + + + + + + + + + + + + + + + ? + + + + + + + + ? + + + + + + + + ? + + + + + + + + ? + + + + + + + + + + + + + + + ? + + + + + + + + ? + + + + + + + + ? + + + + + + + + ? + + + + + + + + + + + + + + + ? + + + + + + + + BODY LENGTH + + + + + + + + BODY CHECKSUM + + + + + + + + COMPRESSOR_ID + + + + + + + + 0 + + + + + + + + 1 + + + + + + + + 2 + + + + + + + + 3 + + + + + + + + 4 + + + + + + + + 5 + + + + + + + + 6 + + + + + + + + 7 + + + + + + + + 8 + + + + + + + + 9 + + + + + + + + 10 + + + + + + + + 11 + + + + + + + + 12 + + + + + + + + TELEGRAM HEADER + + + + + + + + + + + + + + + ? + + + + + + + + ? + + + + + + + + ? + + + + + + + + ? + + + + + + + + ? + + + + + + + + ? + + + + + + + + + + + + + + + + 13 + + + + + + + + 14 + + + + + + + + 15 + + + + + + + + 15+n + + + + + + + + 16+n + + + + + + + + 17+n + + + + + + + + n + + + + + + + + TELEGRAM BODY + + + + + + + + HEADER + + + + + + + + BODY + + + + + + + + TELEGRAM + + + + + + + + SIGNATURE + + + + + + + + + + + + + + + + + + + + + + + + + 4 bytes + + + + + + + + + + + 4 bytes + + + + + + + + + + + 4 bytes + + + + + + + + + + + 1 byte + + + + diff --git a/doc/src/vtr/server_mode/index.rst b/doc/src/vtr/server_mode/index.rst new file mode 100644 index 00000000000..66972681241 --- /dev/null +++ b/doc/src/vtr/server_mode/index.rst @@ -0,0 +1,208 @@ +.. _server_mode: + +Server Mode +================ + +If VPR is in server mode, it listens on a socket for commands from a client. Currently, this is used to enable interactive timing analysis and visualization of timing paths in the VPR UI under the control of a separate client. +VPR provides the ability to run in server mode using the following command-line arguments. + +.. code-block:: none + + --server --port_num 60555 + +Server mode may only accept a single client application connection and respond to two types of requests: **get critical path report** and **highlight selected critical path elements**. + +Communication telegram +------------------------- + +Telegram consists of two parts: a fixed-size **telegram header** and a variable-size **telegram body**. +The telegram header contains helper information required to properly extract the telegram body sequence from the data flow. + +.. _fig_comm_telegram_structure: + +.. figure:: comm_telegram_structure.* + + Communication telegram structure. + +.. note:: The telegram body itself could be compressed with zlib to minimize the amount of data transferred over the socket. + This compression is applied to the response of the 'get critical path report' request. The compressor ID byte in the telegram header signals whether the telegram body is compressed. + When the compressor ID is null, the telegram body is not compressed. If the compressor ID is 'z', it means the body is compressed with zlib. + +.. note:: The checksum field contains the telegram body checksum. This checksum is used to validate the consistency of the telegram body during the dispatching phase. + If checksums are mismatched, the telegram is considered invalid and is skipped in processing. + + +.. _fig_comm_telegram_body_structure: + +.. figure:: comm_telegram_body_structure.* + + Communication telegram body structure. + + **telegram body** is a flat **JSON** structure. + + **CMD** could have following integer values: + + - 0 - command id for **get critical path** + - 1 - command id for **highlight selected path elements** + + JOB_ID is a unique ID for a task. It is used to associate the request with the response by matching the same JOB_ID. Each new client request should increment the JOB_ID value; otherwise, it will not be clear which request the current response belongs to. + + +Get critical path timing report example +--------------------------------------- + + Let's take a look at an example of a request timing report telegram body with the following options: + + - path_num = 1 + - path_type = "setup" + - details_level = "netlist" + - is_flat_routing = false + + .. code-block:: json + :caption: telegram body **REQUEST** example + :linenos: + + { + "JOB_ID": "1", + "CMD": "0", + "OPTIONS": "int:path_num:1;string:path_type:setup;string:details_level:netlist;bool:is_flat_routing:0" + } + + **path_type** could have following string values: + + - "setup" + - "hold" + + **details_level** could have following string values: + + - "netlist" + - "aggregated" + - "detailed" + - "debug" + + Response will look like: + + .. code-block:: json + :caption: telegram body **RESPONSE** example + :linenos: + + { + "JOB_ID": "1", + "CMD": "0", + "OPTIONS": "int:path_num:1;string:path_type:setup;string:details_level:netlist;bool:is_flat_routing:0", + "DATA": " + #Timing report of worst 1 path(s) + # Unit scale: 1e-09 seconds + # Output precision: 3 + + #Path 1 + Startpoint: count[1].Q[0] (dffsre clocked by clk) + Endpoint : count[13].D[0] (dffsre clocked by clk) + Path Type : setup + + Point Incr Path + ------------------------------------------------------------------------------------------ + clock clk (rise edge) 0.000 0.000 + clock source latency 0.000 0.000 + clk.inpad[0] (.input) 0.000 0.000 + count[1].C[0] (dffsre) 0.715 0.715 + count[1].Q[0] (dffsre) [clock-to-output] 0.286 1.001 + count_adder_carry_p_cout[2].p[0] (adder_carry) 0.573 1.574 + count_adder_carry_p_cout[2].cout[0] (adder_carry) 0.068 1.642 + count_adder_carry_p_cout[3].cin[0] (adder_carry) 0.043 1.685 + count_adder_carry_p_cout[3].cout[0] (adder_carry) 0.070 1.755 + count_adder_carry_p_cout[4].cin[0] (adder_carry) 0.053 1.808 + count_adder_carry_p_cout[4].cout[0] (adder_carry) 0.070 1.877 + count_adder_carry_p_cout[5].cin[0] (adder_carry) 0.043 1.921 + count_adder_carry_p_cout[5].cout[0] (adder_carry) 0.070 1.990 + count_adder_carry_p_cout[6].cin[0] (adder_carry) 0.053 2.043 + count_adder_carry_p_cout[6].cout[0] (adder_carry) 0.070 2.113 + count_adder_carry_p_cout[7].cin[0] (adder_carry) 0.043 2.156 + count_adder_carry_p_cout[7].cout[0] (adder_carry) 0.070 2.226 + count_adder_carry_p_cout[8].cin[0] (adder_carry) 0.053 2.279 + count_adder_carry_p_cout[8].cout[0] (adder_carry) 0.070 2.348 + count_adder_carry_p_cout[9].cin[0] (adder_carry) 0.043 2.391 + count_adder_carry_p_cout[9].cout[0] (adder_carry) 0.070 2.461 + count_adder_carry_p_cout[10].cin[0] (adder_carry) 0.053 2.514 + count_adder_carry_p_cout[10].cout[0] (adder_carry) 0.070 2.584 + count_adder_carry_p_cout[11].cin[0] (adder_carry) 0.043 2.627 + count_adder_carry_p_cout[11].cout[0] (adder_carry) 0.070 2.696 + count_adder_carry_p_cout[12].cin[0] (adder_carry) 0.053 2.749 + count_adder_carry_p_cout[12].cout[0] (adder_carry) 0.070 2.819 + count_adder_carry_p_cout[13].cin[0] (adder_carry) 0.043 2.862 + count_adder_carry_p_cout[13].cout[0] (adder_carry) 0.070 2.932 + count_adder_carry_p_cout[14].cin[0] (adder_carry) 0.053 2.985 + count_adder_carry_p_cout[14].sumout[0] (adder_carry) 0.040 3.025 + count_dffsre_Q_D[13].in[0] (.names) 0.564 3.589 + count_dffsre_Q_D[13].out[0] (.names) 0.228 3.818 + count[13].D[0] (dffsre) 0.000 3.818 + data arrival time 3.818 + + clock clk (rise edge) 0.000 0.000 + clock source latency 0.000 0.000 + clk.inpad[0] (.input) 0.000 0.000 + count[13].C[0] (dffsre) 0.715 0.715 + clock uncertainty 0.000 0.715 + cell setup time -0.057 0.659 + data required time 0.659 + ------------------------------------------------------------------------------------------ + data required time 0.659 + data arrival time -3.818 + ------------------------------------------------------------------------------------------ + slack (VIOLATED) -3.159 + + + #End of timing report + #RPT METADATA: + path_index/clock_launch_path_elements_num/arrival_path_elements_num + 0/2/30 + ", + "STATUS": "1" + } + +Draw selected critical path elements example +-------------------------------------------- + + Let's take a look at an example of a request timing report telegram body with the following options: + + - path_elements = path 0 and it's sub-elements 10,11,12,13,14,15,20,21,22,23,24,25 + - high_light_mode = "crit path flylines delays" + - draw_path_contour = 1 + + .. code-block:: json + :caption: telegram body **REQUEST** example + :linenos: + + { + "JOB_ID": "2", + "CMD": "1", + "OPTIONS": "string:path_elements:0#10,11,12,13,14,15,20,21,22,23,24,25;string:high_light_mode:crit path flylines delays;bool:draw_path_contour:1" + } + + **high_light_mode** could have following string values: + + - "crit path flylines" + - "crit path flylines delays" + - "crit path routing" + - "crit path routing delays" + + Response will look like: + + .. code-block:: json + :caption: telegram body **RESPONSE** example + :linenos: + + { + "JOB_ID": "2", + "CMD": "1", + "OPTIONS": "string:path_elements:0#10,11,12,13,14,15,20,21,22,23,24,25;string:high_light_mode:crit path flylines delays;bool:draw_path_contour:1", + "DATA": "", + "STATUS": "1" + } + + .. note:: If status is not 1, the field ***DATA*** contains error string. + + + + + diff --git a/vpr/src/base/vpr_api.cpp b/vpr/src/base/vpr_api.cpp index e23e98083cf..e8656ef1dc8 100644 --- a/vpr/src/base/vpr_api.cpp +++ b/vpr/src/base/vpr_api.cpp @@ -828,9 +828,9 @@ RouteStatus vpr_route_flow(const Netlist<>& net_list, routing_delay_calc = std::make_shared(atom_ctx.nlist, atom_ctx.lookup, net_delay, is_flat); timing_info = make_setup_hold_timing_info(routing_delay_calc, router_opts.timing_update_type); #ifndef NO_SERVER - if (g_vpr_ctx.server().gateIO().is_running()) { - g_vpr_ctx.mutable_server().set_timing_info(timing_info); - g_vpr_ctx.mutable_server().set_routing_delay_calc(routing_delay_calc); + if (g_vpr_ctx.server().gate_io.is_running()) { + g_vpr_ctx.mutable_server().timing_info = timing_info; + g_vpr_ctx.mutable_server().routing_delay_calc = routing_delay_calc; } #endif /* NO_SERVER */ } else { @@ -1080,7 +1080,7 @@ void vpr_init_server(const t_vpr_setup& vpr_setup) { #ifndef NO_SERVER if (vpr_setup.ServerOpts.is_server_mode_enabled) { /* Set up a server and its callback to be triggered at 100ms intervals by the timer's timeout event. */ - server::GateIO& gate_io = g_vpr_ctx.mutable_server().mutable_gateIO(); + server::GateIO& gate_io = g_vpr_ctx.mutable_server().gate_io; if (!gate_io.is_running()) { gate_io.start(vpr_setup.ServerOpts.port_num); g_timeout_add(/*interval_ms*/ 100, server::update, &application); diff --git a/vpr/src/base/vpr_context.h b/vpr/src/base/vpr_context.h index 201157609fd..b6ccba2d4d9 100644 --- a/vpr/src/base/vpr_context.h +++ b/vpr/src/base/vpr_context.h @@ -568,35 +568,18 @@ struct NocContext : public Context { * @brief State relating to server mode * * This should contain only data structures that - * related to server state. + * relate to the vpr server state. */ -class ServerContext : public Context { - public: - const server::GateIO& gateIO() const { return gate_io_; } - server::GateIO& mutable_gateIO() { return gate_io_; } - - const server::TaskResolver& task_resolver() const { return task_resolver_; } - server::TaskResolver& mutable_task_resolver() { return task_resolver_; } - - void set_crit_paths(std::vector&& crit_paths) { crit_paths_ = std::move(crit_paths); } - const std::vector& crit_paths() const { return crit_paths_; } - - void clear_crit_path_elements() { crit_path_element_indexes_.clear(); } - void set_crit_path_elements(const std::map>& crit_path_element_indexes) { crit_path_element_indexes_ = crit_path_element_indexes; } - std::map> crit_path_element_indexes() const { return crit_path_element_indexes_; } - - void set_draw_crit_path_contour(bool draw_crit_path_contour) { draw_crit_path_contour_ = draw_crit_path_contour; } - bool draw_crit_path_contour() const { return draw_crit_path_contour_; } - - void set_timing_info(const std::shared_ptr& timing_info) { timing_info_ = timing_info; } - const std::shared_ptr& timing_info() const { return timing_info_; } - - void set_routing_delay_calc(const std::shared_ptr& routing_delay_calc) { routing_delay_calc_ = routing_delay_calc; } - const std::shared_ptr& routing_delay_calc() const { return routing_delay_calc_; } +struct ServerContext : public Context { + /** + * @brief \ref server::GateIO. + */ + server::GateIO gate_io; - private: - server::GateIO gate_io_; - server::TaskResolver task_resolver_; + /** + * @brief \ref server::TaskResolver. + */ + server::TaskResolver task_resolver; /** * @brief Stores the critical path items. @@ -605,7 +588,7 @@ class ServerContext : public Context { * Once calculated upon request, it provides the value for a specific critical path * to be rendered upon user request. */ - std::vector crit_paths_; + std::vector crit_paths; /** * @brief Stores the selected critical path elements. @@ -613,24 +596,25 @@ class ServerContext : public Context { * This value is used to render the selected critical path elements upon client request. * The std::map key plays role of path index, where the element indexes are stored as std::set. */ - std::map> crit_path_element_indexes_; + std::map> crit_path_element_indexes; /** * @brief Stores the flag indicating whether to draw the critical path contour. * - * If the flag is set to true, the non-selected critical path elements will be drawn as a contour, while selected elements will be drawn as usual. + * If True, the entire path will be rendered with some level of transparency, regardless of the selection of path elements. However, selected path elements will be drawn in full color. + * This feature is helpful in visual debugging, to see how the separate path elements are mapped into the whole path. */ - bool draw_crit_path_contour_ = false; + bool draw_crit_path_contour = false; /** * @brief Reference to the SetupHoldTimingInfo calculated during the routing stage. */ - std::shared_ptr timing_info_; + std::shared_ptr timing_info; /** * @brief Reference to the PostClusterDelayCalculator calculated during the routing stage. */ - std::shared_ptr routing_delay_calc_; + std::shared_ptr routing_delay_calc; }; #endif /* NO_SERVER */ diff --git a/vpr/src/draw/draw.cpp b/vpr/src/draw/draw.cpp index 6b774d53a7b..ec4f764868f 100644 --- a/vpr/src/draw/draw.cpp +++ b/vpr/src/draw/draw.cpp @@ -255,9 +255,9 @@ static void draw_main_canvas(ezgl::renderer* g) { draw_placement_macros(g); #ifndef NO_SERVER - if (g_vpr_ctx.server().gateIO().is_running()) { + if (g_vpr_ctx.server().gate_io.is_running()) { const ServerContext& server_ctx = g_vpr_ctx.server(); // shortcut - draw_crit_path_elements(server_ctx.crit_paths(), server_ctx.crit_path_element_indexes(), server_ctx.draw_crit_path_contour(), g); + draw_crit_path_elements(server_ctx.crit_paths, server_ctx.crit_path_element_indexes, server_ctx.draw_crit_path_contour, g); } else { draw_crit_path(g); } diff --git a/vpr/src/draw/draw_basic.h b/vpr/src/draw/draw_basic.h index 250f90802ef..d939b43b8ec 100644 --- a/vpr/src/draw/draw_basic.h +++ b/vpr/src/draw/draw_basic.h @@ -111,6 +111,10 @@ void draw_crit_path(ezgl::renderer* g); * * This function draws critical path elements based on the provided timing paths * and indexes map. It is primarily used in server mode, where items are drawn upon request. + * + * @param paths The vector of TimingPath objects representing the critical paths. + * @param indexes The map of sets, where the map keys are path indices in std::vector, and each set contains the indices of the data_arrival_path elements ( @ref tatum::TimingPath ) to draw. + * @param g Pointer to the ezgl::renderer object on which the elements will be drawn. */ void draw_crit_path_elements(const std::vector& paths, const std::map>& indexes, bool draw_crit_path_contour, ezgl::renderer* g); diff --git a/vpr/src/server/bytearray.h b/vpr/src/server/bytearray.h index d414ae0817c..154153be6f9 100644 --- a/vpr/src/server/bytearray.h +++ b/vpr/src/server/bytearray.h @@ -10,35 +10,99 @@ namespace comm { /** - * @brief ByteArray as a simple wrapper over std::vector + * @brief ByteArray is a simple wrapper over std::vector that provides a user-friendly interface for manipulating array data.. */ class ByteArray : public std::vector { public: static const std::size_t DEFAULT_SIZE_HINT = 1024; - ByteArray(const char* data) + /** + * @brief Constructs a ByteArray from a null-terminated C string. + * + * Constructs a ByteArray object from the specified null-terminated C string. + * The constructor interprets the input string as a sequence of bytes until the + * null terminator '\0' is encountered, and initializes the ByteArray with those bytes. + * + * @param data A pointer to the null-terminated C string from which to construct the ByteArray. + */ + explicit ByteArray(const char* data) : std::vector(data, data + std::strlen(data)) {} + /** + * @brief Constructs a ByteArray from a raw character array. + * + * Constructs a ByteArray object from the specified raw character array, + * with the given size. This constructor interprets the input data as a sequence + * of bytes and initializes the ByteArray with those bytes. + * + * @param data A pointer to the raw character array from which to construct the ByteArray. + * @param size The size of the raw character array, in bytes. + */ ByteArray(const char* data, std::size_t size) : std::vector(data, data + size) {} - ByteArray(std::size_t size_hint = DEFAULT_SIZE_HINT) { + /** + * @brief Constructs a byte array with the specified size hint. + * + * This constructor initializes the byte array with an initial capacity determined by the size hint. + * + * @param size_hint The initial capacity hint for the byte array. + */ + explicit ByteArray(std::size_t size_hint = DEFAULT_SIZE_HINT) { reserve(size_hint); } + /** + * @brief Constructs a byte array from the elements in the range [first, last). + * + * This constructor initializes the byte array with the elements in the range [first, last), + * where `first` and `last` are iterators defining the range. + * + * @tparam Iterator The type of iterator used to specify the range. + * @param first An iterator to the first element in the range. + * @param last An iterator to the last element in the range. + */ template ByteArray(Iterator first, Iterator last): std::vector(first, last) {} + /** + * @brief Appends the content of another byte array to the end of this byte array. + * + * This function adds all the bytes from the specified byte array `appendix` + * to the end of this byte array. + * + * @param appendix The byte array whose content is to be appended. + */ void append(const ByteArray& appendix) { insert(end(), appendix.begin(), appendix.end()); } + /** + * @brief Appends a byte to the end of the byte array. + * + * This function adds the specified byte to the end of the byte array. + * + * @param b The byte to append to the byte array. + */ void append(char b) { push_back(b); } + /** + * @brief Finds the position of the specified sequence in the byte array. + * + * This function searches for the specified sequence of characters within the byte array. + * If the sequence is found, it returns a pair containing `true` and the starting index of the sequence. + * If the sequence is not found, it returns a pair containing `false` and `0`. + * + * @param sequence A pointer to the sequence of characters to search for. + * @param sequence_size The size of the sequence to search for. + * @return A `std::pair` where the first element is a boolean indicating whether the sequence was + * found (`true`) or not (`false`), and the second element is the starting index of the sequence if + * found. + */ std::pair find_sequence(const char* sequence, std::size_t sequence_size) { const std::size_t ssize = size(); if (ssize >= sequence_size) { @@ -58,14 +122,41 @@ class ByteArray : public std::vector { return std::make_pair(false, 0); } + /** + * @brief Converts the container to a std::string_view. + * + * This operator allows the container to be implicitly converted to a `std::string_view`, + * providing a non-owning view into the container's data. + * + * @return A `std::string_view` representing the container's data. + */ operator std::string_view() const { return std::string_view(this->data(), this->size()); } + /** + * @brief Calculates the checksum of the elements in the container. + * + * This function iterates over each element in the container and adds their unsigned integer representations + * to the sum. The result is returned as a 32-bit unsigned integer. + * + * @return The checksum of the elements in the container. + */ uint32_t calc_check_sum() { return calc_check_sum(*this); } + /** + * @brief Calculates the checksum of the elements in the given iterable container. + * + * This function template calculates the checksum of the elements in the provided iterable container. + * It iterates over each element in the container and adds their unsigned integer representations to the sum. + * The result is returned as a 32-bit unsigned integer. + * + * @tparam T The type of the iterable container. + * @param iterable The iterable container whose elements checksum is to be calculated. + * @return The checksum of the elements in the iterable container. + */ template static uint32_t calc_check_sum(const T& iterable) { uint32_t sum = 0; diff --git a/vpr/src/server/commcmd.h b/vpr/src/server/commcmd.h new file mode 100644 index 00000000000..28f3f69f452 --- /dev/null +++ b/vpr/src/server/commcmd.h @@ -0,0 +1,18 @@ +#ifndef COMMCMD_H +#define COMMCMD_H + +#ifndef NO_SERVER + +namespace comm { + +enum class CMD : int { + NONE=-1, + GET_PATH_LIST_ID=0, + DRAW_PATH_ID=1 +}; + +} // namespace comm + +#endif /* NO_SERVER */ + +#endif /* COMMCMD_H */ diff --git a/vpr/src/server/commconstants.h b/vpr/src/server/commconstants.h index 545c00a977b..2eaeed60386 100644 --- a/vpr/src/server/commconstants.h +++ b/vpr/src/server/commconstants.h @@ -12,7 +12,7 @@ inline const std::string KEY_CMD{"CMD"}; inline const std::string KEY_OPTIONS{"OPTIONS"}; inline const std::string KEY_DATA{"DATA"}; inline const std::string KEY_STATUS{"STATUS"}; -inline const std::string ECHO_DATA{"ECHO"}; +inline const std::string ECHO_TELEGRAM_BODY{"ECHO"}; const unsigned char ZLIB_COMPRESSOR_ID = 'z'; const unsigned char NONE_COMPRESSOR_ID = '\x0'; @@ -28,11 +28,6 @@ inline const std::string OPTION_DRAW_PATH_CONTOUR{"draw_path_contour"}; inline const std::string KEY_SETUP_PATH_LIST{"setup"}; inline const std::string KEY_HOLD_PATH_LIST{"hold"}; -enum CMD { - CMD_GET_PATH_LIST_ID=0, - CMD_DRAW_PATH_ID -}; - } // namespace comm #endif /* NO_SERVER */ diff --git a/vpr/src/server/gateio.cpp b/vpr/src/server/gateio.cpp index 573797cb44e..d40431e7da9 100644 --- a/vpr/src/server/gateio.cpp +++ b/vpr/src/server/gateio.cpp @@ -134,10 +134,10 @@ GateIO::ActivityStatus GateIO::handle_telegrams(std::vectordata}; + std::string message{telegram_frame->body}; bool is_echo_telegram = false; - if ((message.size() == comm::ECHO_DATA.size()) && (message == comm::ECHO_DATA)) { - m_logger.queue(LogLevel::Detail, "received", comm::ECHO_DATA); + if ((message.size() == comm::ECHO_TELEGRAM_BODY.size()) && (message == comm::ECHO_TELEGRAM_BODY)) { + m_logger.queue(LogLevel::Detail, "received", comm::ECHO_TELEGRAM_BODY); is_echo_telegram = true; status = ActivityStatus::CLIENT_ACTIVITY; } @@ -148,7 +148,7 @@ GateIO::ActivityStatus GateIO::handle_telegrams(std::vector cmd_opt = comm::TelegramParser::try_extract_field_cmd(message); std::optional options_opt = comm::TelegramParser::try_extract_field_options(message); if (job_id_opt && cmd_opt && options_opt) { - TaskPtr task = std::make_unique(job_id_opt.value(), cmd_opt.value(), options_opt.value()); + TaskPtr task = std::make_unique(job_id_opt.value(), static_cast(cmd_opt.value()), options_opt.value()); const comm::TelegramHeader& header = telegram_frame->header; m_logger.queue(LogLevel::Info, "received:", header.info(), task->info(/*skipDuration*/true)); std::unique_lock lock(m_tasks_mutex); @@ -167,17 +167,17 @@ GateIO::ActivityStatus GateIO::handle_client_alive_tracker(sockpp::tcp6_socket& if (client_alive_tracker_ptr) { /// handle sending echo to client if (client_alive_tracker_ptr->is_time_to_sent_echo()) { - comm::TelegramHeader echo_header = comm::TelegramHeader::construct_from_data(comm::ECHO_DATA); + comm::TelegramHeader echo_header = comm::TelegramHeader::construct_from_body(comm::ECHO_TELEGRAM_BODY); std::string message{echo_header.buffer()}; - message.append(comm::ECHO_DATA); + message.append(comm::ECHO_TELEGRAM_BODY); try { std::size_t bytes_sent = client.write(message); if (bytes_sent == message.size()) { - m_logger.queue(LogLevel::Detail, "sent", comm::ECHO_DATA); + m_logger.queue(LogLevel::Detail, "sent", comm::ECHO_TELEGRAM_BODY); client_alive_tracker_ptr->on_echo_sent(); } } catch(...) { - m_logger.queue(LogLevel::Debug, "fail to sent", comm::ECHO_DATA); + m_logger.queue(LogLevel::Debug, "fail to sent", comm::ECHO_TELEGRAM_BODY); status = ActivityStatus::COMMUNICATION_PROBLEM; } } diff --git a/vpr/src/server/gateio.h b/vpr/src/server/gateio.h index 8dfb9ce686e..aa9036459c5 100644 --- a/vpr/src/server/gateio.h +++ b/vpr/src/server/gateio.h @@ -26,16 +26,16 @@ namespace server { * * Operable only with a single client. As soon as client connection is detected * it begins listening on the specified port number for incoming client requests, - * collects and encapsulates them into tasks. - * The incoming tasks are extracted and handled by the top-level logic (TaskResolver). - * Once the tasks are resolved by the TaskResolver, they are returned - * to be sent back to the client as a response. + * collects and encapsulates them into tasks (see @ref Task). + * The incoming tasks are extracted and handled by the top-level logic @ref TaskResolver in the main thread. + * Once the tasks are resolved by the @ref TaskResolver, they are returned to be sent back to the client app as a response. + * Moving @ref Task across threads happens in @ref server::update. * - * @note: + * @note * - The GateIO instance should be created and managed from the main thread, while its internal processing * and IO operations are performed asynchronously in a separate thread. This separation ensures smooth IO behavior * and responsiveness of the application. - * - Gateio is not started automatically upon creation, you have to use the 'start' method with the port number. + * - GateIO is not started automatically upon creation, you have to use the 'start' method with the port number. * - The socket is initialized in a non-blocking mode to function properly in a multithreaded environment. */ class GateIO @@ -141,6 +141,9 @@ class GateIO const int LOOP_INTERVAL_MS = 100; public: + /** + * @brief Default constructor for GateIO. + */ GateIO(); ~GateIO(); @@ -150,7 +153,11 @@ class GateIO GateIO(GateIO&&) = delete; GateIO& operator=(GateIO&&) = delete; - // Check if the port listening process is currently running + /** + * @brief Returns a bool indicating whether or not the port listening process is currently running. + * + * @return True if the port listening process is running, false otherwise. + */ bool is_running() const { return m_is_running.load(); } /** @@ -161,7 +168,7 @@ class GateIO * * @param tasks A reference to a vector where the received tasks will be moved. */ - void take_received_tasks(std::vector&); + void take_received_tasks(std::vector& tasks); /** * @brief Moves tasks to the send queue. @@ -172,12 +179,12 @@ class GateIO * * @param tasks A reference to a vector containing the tasks to be moved to the send queue. */ - void move_tasks_to_send_queue(std::vector&); + void move_tasks_to_send_queue(std::vector& tasks); /** * @brief Prints log messages for the GateIO. * - * @note Must be called from main thread since it's invoke std::cout. + * @note Must be called from the main thread since it's invoke std::cout. * Calling this method from other threads may result in unexpected behavior. */ void print_logs(); @@ -189,9 +196,9 @@ class GateIO * Once started,the server will continue running in a separate thread and will accept connection only from a single client * attempting to connect to the specified port. * - * @param portNum The port number on which the server will listen for incoming connection. + * @param port_num The port number on which the server will listen for incoming connection. */ - void start(int portNum); + void start(int port_num); /** * @brief Stops the server and terminates the listening thread. diff --git a/vpr/src/server/pathhelper.cpp b/vpr/src/server/pathhelper.cpp index fb0dfd621b9..c3bfca88e50 100644 --- a/vpr/src/server/pathhelper.cpp +++ b/vpr/src/server/pathhelper.cpp @@ -34,8 +34,8 @@ static void collect_crit_path_metadata(std::stringstream& ss, const std::vector< */ CritPathsResultPtr calc_critical_path(const std::string& report_type, int crit_path_num, e_timing_report_detail details_level, bool is_flat_routing) { // shortcuts - const std::shared_ptr& timing_info = g_vpr_ctx.server().timing_info(); - const std::shared_ptr& routing_delay_calc = g_vpr_ctx.server().routing_delay_calc(); + const std::shared_ptr& timing_info = g_vpr_ctx.server().timing_info; + const std::shared_ptr& routing_delay_calc = g_vpr_ctx.server().routing_delay_calc; auto& timing_ctx = g_vpr_ctx.timing(); auto& atom_ctx = g_vpr_ctx.atom(); diff --git a/vpr/src/server/pathhelper.h b/vpr/src/server/pathhelper.h index e79dc270f88..8d2244a885a 100644 --- a/vpr/src/server/pathhelper.h +++ b/vpr/src/server/pathhelper.h @@ -18,15 +18,34 @@ namespace server { * It contains the critical path list and the generated report as a string. */ struct CritPathsResult { + /** + * @brief Checks if the CritPathsResult contains report. + * @return True if contains report, false otherwise. + */ bool is_valid() const { return !report.empty(); } + + /** + * @brief Vector containing timing paths. + */ std::vector paths; + + /** + * @brief String containing the generated report. + */ std::string report; }; using CritPathsResultPtr = std::shared_ptr; -/** - * @brief Helper function to calculate critical path timing report with specified parameters. - */ +/** +* @brief Calculates the critical path. + +* This function calculates the critical path based on the provided parameters. +* @param type The type of the critical path. Must be either "setup" or "hold". +* @param crit_path_num The max number of critical paths to record. +* @param details_level The level of detail for the timing report. See @ref e_timing_report_detail. +* @param is_flat_routing Indicates whether flat routing should be used. +* @return A `CritPathsResultPtr` which is a pointer to the result of the critical path calculation (see @ref CritPathsResult). +*/ CritPathsResultPtr calc_critical_path(const std::string& type, int crit_path_num, e_timing_report_detail details_level, bool is_flat_routing); } // namespace server diff --git a/vpr/src/server/serverupdate.cpp b/vpr/src/server/serverupdate.cpp index caf06d5e890..de45c45936d 100644 --- a/vpr/src/server/serverupdate.cpp +++ b/vpr/src/server/serverupdate.cpp @@ -9,12 +9,12 @@ namespace server { gboolean update(gpointer data) { - const bool is_running = g_vpr_ctx.server().gateIO().is_running(); + const bool is_running = g_vpr_ctx.server().gate_io.is_running(); if (is_running) { // shortcuts ezgl::application* app = static_cast(data); - GateIO& gate_io = g_vpr_ctx.mutable_server().mutable_gateIO(); - TaskResolver& task_resolver = g_vpr_ctx.mutable_server().mutable_task_resolver(); + GateIO& gate_io = g_vpr_ctx.mutable_server().gate_io; + TaskResolver& task_resolver = g_vpr_ctx.mutable_server().task_resolver; std::vector tasks_buff; @@ -24,7 +24,7 @@ gboolean update(gpointer data) { } tasks_buff.clear(); - const bool is_server_context_initialized = g_vpr_ctx.server().timing_info() && g_vpr_ctx.server().routing_delay_calc(); + const bool is_server_context_initialized = g_vpr_ctx.server().timing_info && g_vpr_ctx.server().routing_delay_calc; if (is_server_context_initialized) { bool has_finished_tasks = task_resolver.update(app); diff --git a/vpr/src/server/task.cpp b/vpr/src/server/task.cpp index bf99164aafc..f05ada6d835 100644 --- a/vpr/src/server/task.cpp +++ b/vpr/src/server/task.cpp @@ -10,7 +10,7 @@ namespace server { -Task::Task(int jobId, int cmd, const std::string& options) +Task::Task(int jobId, comm::CMD cmd, const std::string& options) : m_job_id(jobId), m_cmd(cmd), m_options(options) { m_creation_time = std::chrono::high_resolution_clock::now(); } @@ -27,25 +27,25 @@ void Task::chop_num_sent_bytes_from_response_buffer(std::size_t bytes_sent_num) } } -bool Task::options_match(const class std::unique_ptr& other) { +bool Task::options_match(const std::unique_ptr& other) { if (other->options().size() != m_options.size()) { return false; } return other->options() == m_options; } -void Task::fail(const std::string& error) { +void Task::set_fail(const std::string& error) { m_is_finished = true; m_error = error; bake_response(); } -void Task::success() { +void Task::set_success() { m_is_finished = true; bake_response(); } -void Task::success(std::string&& result) { +void Task::set_success(std::string&& result) { m_result = std::move(result); m_is_finished = true; bake_response(); @@ -55,7 +55,7 @@ std::string Task::info(bool skip_duration) const { std::stringstream ss; ss << "task[" << "id=" << std::to_string(m_job_id) - << ",cmd=" << std::to_string(m_cmd); + << ",cmd=" << std::to_string(static_cast(m_cmd)); if (!skip_duration) { ss << ",exists=" << get_pretty_duration_str_from_ms(time_ms_elapsed()); } @@ -73,7 +73,7 @@ void Task::bake_response() { ss << "{"; ss << "\"" << comm::KEY_JOB_ID << "\":\"" << m_job_id << "\","; - ss << "\"" << comm::KEY_CMD << "\":\"" << m_cmd << "\","; + ss << "\"" << comm::KEY_CMD << "\":\"" << static_cast(m_cmd) << "\","; ss << "\"" << comm::KEY_OPTIONS << "\":\"" << m_options << "\","; if (has_error()) { ss << "\"" << comm::KEY_DATA << "\":\"" << m_error << "\","; @@ -100,7 +100,7 @@ void Task::bake_response() { } std::string body{std::move(body_opt.value())}; - m_telegram_header = comm::TelegramHeader::construct_from_data(body, compressor_id); + m_telegram_header = comm::TelegramHeader::construct_from_body(body, compressor_id); m_response_buffer.append(m_telegram_header.buffer().begin(), m_telegram_header.buffer().end()); m_response_buffer.append(body); diff --git a/vpr/src/server/task.h b/vpr/src/server/task.h index 0082c48f223..3d29e49373f 100644 --- a/vpr/src/server/task.h +++ b/vpr/src/server/task.h @@ -8,6 +8,7 @@ #include #include "telegramheader.h" +#include "commcmd.h" namespace server { @@ -19,41 +20,167 @@ namespace server { */ class Task { public: - Task(int job_id, int cmd, const std::string& options = ""); + /** + * @brief Constructs a new Task object. + * + * @param job_id The ID of the job associated with the task. + * @param cmd The command ID (see @ref comm::CMD) associated with the task. + * @param options Additional options for the task (default: empty string). + */ + Task(int job_id, comm::CMD cmd, const std::string& options = ""); Task(const Task&) = delete; Task& operator=(const Task&) = delete; + /** + * @brief Gets the job ID associated with the task. + * + * @return The job ID. + */ int job_id() const { return m_job_id; } - int cmd() const { return m_cmd; } - - void chop_num_sent_bytes_from_response_buffer(std::size_t bytesSentNum); - - bool options_match(const class std::unique_ptr& other); + /** + * @brief Gets the command ID associated with the task. + * + * @return The command ID (see @ref comm::CMD). + */ + comm::CMD cmd() const { return m_cmd; } + + /** + * @brief Removes the specified number of bytes from the response buffer. + * + * This method removes the specified number of bytes from the beginning of the response buffer. + * It is typically used after sending a response to discard the bytes that have been sent. + * + * @param bytes_sent_num The number of bytes to remove from the response buffer. + */ + void chop_num_sent_bytes_from_response_buffer(std::size_t bytes_sent_num); + + /** + * @brief Checks if the options of this task match the options of another task. + * + * This method compares the options of this task with the options of another task + * and returns true if they match, otherwise returns false. + * + * @param other The other task to compare options with. + * @return True if the options match, false otherwise. + */ + bool options_match(const std::unique_ptr& other); + + /** + * @brief Retrieves the response buffer. + * + * This method returns a constant reference to the response buffer, which contains the data after task execution. + * + * @return A constant reference to the response buffer. + */ const std::string& response_buffer() const { return m_response_buffer; } + /** + * @brief Checks if the task has finished execution. + * + * This method returns true if the task has finished execution; otherwise, it returns false. + * + * @return True if the task has finished execution, false otherwise. + */ bool is_finished() const { return m_is_finished; } + + /** + * @brief Checks if the task has encountered an error. + * + * This method returns true if the task has encountered an error; otherwise, it returns false. + * + * @return True if the task has encountered an error, false otherwise. + */ bool has_error() const { return !m_error.empty(); } + + /** + * @brief Retrieves the error message associated with the task. + * + * This method returns the error message associated with the task, if any. + * + * @return A constant reference to the error message string. + */ const std::string& error() const { return m_error; } + /** + * @brief Retrieves the original number of response bytes. + * + * This method returns the original number of response bytes before any chopping operation. + * + * @return The original number of response bytes. + */ std::size_t orig_reponse_bytes_num() const { return m_orig_reponse_bytes_num; } + /** + * @brief Checks if the response has been fully sent. + * + * This method returns true if the entire response has been successfully sent, + * otherwise it returns false. + * + * @return True if the response has been fully sent, false otherwise. + */ bool is_response_fully_sent() const { return m_is_response_fully_sent; } - void fail(const std::string& error); - void success(); - void success(std::string&& result); - + /** + * @brief Marks the task as failed with the specified error message. + * + * This method sets the task's error message to the provided error string, + * indicating that the task has failed. + * + * @param error The error message describing the reason for the task's failure. + */ + void set_fail(const std::string& error); + + /** + * @brief Marks the task as successfully completed. + */ + void set_success(); + + /** + * @brief Marks the task as successfully completed with the specified result. + * + * This method marks the task as successfully completed and stores the result. + * It takes an rvalue reference to a string, allowing for efficient move semantics. + * + * @param result An rvalue reference to a string describing the result of the task execution. + * The content of this string will be moved into the task's result storage. + */ + void set_success(std::string&& result); + + /** + * @brief Generates a string containing information about the task. + * + * This method generates a string containing information about the task, + * including its identifier, command, options, and optionally its duration. + * + * @param skip_duration If true, the duration information will be omitted from the string. + * + * @return A string containing information about the task. + */ std::string info(bool skip_duration = false) const; + /** + * @brief Retrieves the TelegramHeader associated with the task. + * + * This method returns a reference to the TelegramHeader associated with the task. + * + * @return A reference to the TelegramHeader associated with the task. + */ const comm::TelegramHeader& telegram_header() const { return m_telegram_header; } + /** + * @brief Retrieves the options associated with the task. + * + * This method returns a reference to the options string associated with the task. + * + * @return A reference to the options string associated with the task. + */ const std::string& options() const { return m_options; } private: int m_job_id = -1; - int m_cmd = -1; + comm::CMD m_cmd = comm::CMD::NONE; std::string m_options; std::string m_result; std::string m_error; diff --git a/vpr/src/server/taskresolver.cpp b/vpr/src/server/taskresolver.cpp index 0f90cb354ca..5298521ece0 100644 --- a/vpr/src/server/taskresolver.cpp +++ b/vpr/src/server/taskresolver.cpp @@ -18,12 +18,12 @@ void TaskResolver::own_task(TaskPtr&& new_task) { if (task->cmd() == new_task->cmd()) { if (task->options_match(new_task)) { std::string msg = "similar task is already in execution, reject new " + new_task->info() + " and waiting for old " + task->info() + " execution"; - new_task->fail(msg); + new_task->set_fail(msg); } else { // handle case when task has same cmd but different options if (new_task->job_id() > task->job_id()) { std::string msg = "old " + task->info() + " is overridden by a new " + new_task->info(); - task->fail(msg); + task->set_fail(msg); } } } @@ -64,12 +64,12 @@ bool TaskResolver::update(ezgl::application* app) { for (auto& task: m_tasks) { if (!task->is_finished()) { switch(task->cmd()) { - case comm::CMD_GET_PATH_LIST_ID: { + case comm::CMD::GET_PATH_LIST_ID: { process_get_path_list_task(app, task); has_processed_task = true; break; } - case comm::CMD_DRAW_PATH_ID: { + case comm::CMD::DRAW_PATH_ID: { process_draw_critical_path_task(app, task); has_processed_task = true; break; @@ -88,7 +88,7 @@ void TaskResolver::process_get_path_list_task(ezgl::application*, const TaskPtr& if (!options.has_errors()) { ServerContext& server_ctx = g_vpr_ctx.mutable_server(); // shortcut - server_ctx.clear_crit_path_elements(); // reset selection if path list options has changed + server_ctx.crit_path_element_indexes.clear(); // reset selection if path list options has changed // read options const int n_critical_path_num = options.get_int(comm::OPTION_PATH_NUM, 1); @@ -101,22 +101,22 @@ void TaskResolver::process_get_path_list_task(ezgl::application*, const TaskPtr& if (details_level_opt) { CritPathsResultPtr crit_paths_result = calc_critical_path(path_type, n_critical_path_num, details_level_opt.value(), is_flat); if (crit_paths_result->is_valid()) { - server_ctx.set_crit_paths(std::move(crit_paths_result->paths)); - task->success(std::move(crit_paths_result->report)); + server_ctx.crit_paths = std::move(crit_paths_result->paths); + task->set_success(std::move(crit_paths_result->report)); } else { std::string msg{"Critical paths report is empty"}; VTR_LOG_ERROR(msg.c_str()); - task->fail(msg); + task->set_fail(msg); } } else { std::string msg{"unsupported report details level " + details_level_str}; VTR_LOG_ERROR(msg.c_str()); - task->fail(msg); + task->set_fail(msg); } } else { std::string msg{"options errors in get crit path list telegram: " + options.errors_str()}; VTR_LOG_ERROR(msg.c_str()); - task->fail(msg); + task->set_fail(msg); } } @@ -130,24 +130,24 @@ void TaskResolver::process_draw_critical_path_task(ezgl::application* app, const const bool draw_path_contour = options.get_bool(comm::OPTION_DRAW_PATH_CONTOUR, false); // set critical path elements to render - server_ctx.set_crit_path_elements(path_elements); - server_ctx.set_draw_crit_path_contour(draw_path_contour); + server_ctx.crit_path_element_indexes = std::move(path_elements); + server_ctx.draw_crit_path_contour = draw_path_contour; // update gtk UI GtkComboBox* toggle_crit_path = GTK_COMBO_BOX(app->get_object("ToggleCritPath")); gint high_light_mode_index = get_item_index_by_text(toggle_crit_path, high_light_mode.c_str()); if (high_light_mode_index != -1) { gtk_combo_box_set_active(toggle_crit_path, high_light_mode_index); - task->success(); + task->set_success(); } else { std::string msg{"cannot find ToggleCritPath qcombobox index for item " + high_light_mode}; VTR_LOG_ERROR(msg.c_str()); - task->fail(msg); + task->set_fail(msg); } } else { std::string msg{"options errors in highlight crit path telegram: " + options.errors_str()}; VTR_LOG_ERROR(msg.c_str()); - task->fail(msg); + task->set_fail(msg); } } diff --git a/vpr/src/server/taskresolver.h b/vpr/src/server/taskresolver.h index 9ae91f5e64a..eca06bc1b74 100644 --- a/vpr/src/server/taskresolver.h +++ b/vpr/src/server/taskresolver.h @@ -20,23 +20,47 @@ namespace server { * * Process and resolve server task, store result and status for processed task. */ - class TaskResolver { public: + /** + * @brief Default constructor for TaskResolver. + */ TaskResolver()=default; + ~TaskResolver()=default; int tasks_num() const { return m_tasks.size(); } - /* own task to process */ - void own_task(TaskPtr&&); - - /* process tasks */ - bool update(ezgl::application*); - - /* extract finished tasks */ - void take_finished_tasks(std::vector&); - + /** + * @brief Takes ownership of a task. + * + * This method takes ownership of a task by moving it into the TaskResolver's internal task queue. + * After calling this method, the task will be owned and managed by the TaskResolver. + * + * @param task The task to take ownership of. After calling this method, the task object will be in a valid but unspecified state. + * + * @note After calling this method, the caller should avoid accessing or modifying the task object. + */ + void own_task(TaskPtr&& task); + + /** + * @brief Resolve queued tasks. + * + * @param app A pointer to the ezgl::application object representing the application instance. + */ + bool update(ezgl::application* app); + + /** + * @brief Extracts finished tasks from the internal task queue. + * + * This function removes finished tasks from the internal task queue and appends them to the provided vector. + * After this operation, the internal task queue will no longer hold the extracted tasks. + * + * @param tasks A reference to a vector where the finished tasks will be appended. + */ + void take_finished_tasks(std::vector& tasks); + + // helper method used in tests const std::vector& tasks() const { return m_tasks; } private: diff --git a/vpr/src/server/telegrambuffer.cpp b/vpr/src/server/telegrambuffer.cpp index 27a4e80cf3b..0aab6af8be1 100644 --- a/vpr/src/server/telegrambuffer.cpp +++ b/vpr/src/server/telegrambuffer.cpp @@ -44,14 +44,14 @@ void TelegramBuffer::take_telegram_frames(std::vector& r std::size_t expected_telegram_size = TelegramHeader::size() + header.body_bytes_num(); if (m_raw_buffer.size() >= expected_telegram_size) { // checksum validation - ByteArray data(m_raw_buffer.begin() + TelegramHeader::size(), m_raw_buffer.begin() + expected_telegram_size); - uint32_t actual_check_sum = data.calc_check_sum(); + ByteArray body(m_raw_buffer.begin() + TelegramHeader::size(), m_raw_buffer.begin() + expected_telegram_size); + uint32_t actual_check_sum = body.calc_check_sum(); if (actual_check_sum == header.body_check_sum()) { // construct telegram frame if checksum matches TelegramFramePtr telegram_frame_ptr = std::make_shared(); telegram_frame_ptr->header = header; - telegram_frame_ptr->data = std::move(data); - data.clear(); // post std::move safety step + telegram_frame_ptr->body = std::move(body); + body.clear(); // post std::move safety step result.push_back(telegram_frame_ptr); } else { @@ -65,12 +65,6 @@ void TelegramBuffer::take_telegram_frames(std::vector& r } } -std::vector TelegramBuffer::take_telegram_frames() { - std::vector result; - take_telegram_frames(result); - return result; -} - void TelegramBuffer::take_errors(std::vector& errors) { errors.reserve(errors.size() + m_errors.size()); std::move(std::begin(m_errors), std::end(m_errors), std::back_inserter(errors)); diff --git a/vpr/src/server/telegrambuffer.h b/vpr/src/server/telegrambuffer.h index c781ab6dccd..b5822e9a5c6 100644 --- a/vpr/src/server/telegrambuffer.h +++ b/vpr/src/server/telegrambuffer.h @@ -16,15 +16,20 @@ namespace comm { /** * @brief Implements Telegram Buffer as a wrapper over BytesArray * - * It aggregates received bytes and return only well filled frames. + * It aggregates received bytes and assists in extracting telegram frames ( @ref TelegramFrame ) from the raw byte buffer. */ class TelegramBuffer { - static const std::size_t DEFAULT_SIZE_HINT = 1024; + inline static const std::size_t DEFAULT_SIZE_HINT = 1024; public: - TelegramBuffer(): m_raw_buffer(DEFAULT_SIZE_HINT) {} - explicit TelegramBuffer(std::size_t sizeHint): m_raw_buffer(sizeHint) {} + /** + * @brief Constructs a TelegramBuffer object with a specified size hint. + * + * This constructor initializes a TelegramBuffer object with a specified size hint for the raw buffer. + */ + explicit TelegramBuffer(std::size_t size_hint = DEFAULT_SIZE_HINT): m_raw_buffer(size_hint) {} + ~TelegramBuffer()=default; /** @@ -44,21 +49,14 @@ class TelegramBuffer * * @param data The byte array whose contents will be appended to internal byte buffer. */ - void append(const ByteArray&); + void append(const ByteArray& data); /** * @brief Extracts well-formed telegram frames from the internal byte buffer. * * @param frames A reference to a vector where the extracted telegram frames will be stored. */ - void take_telegram_frames(std::vector&); - - /** - * @brief Extracts well-formed telegram frames from the internal byte buffer. - * - * @return std::vector A vector containing pointers to the extracted telegram frames. - */ - std::vector take_telegram_frames(); + void take_telegram_frames(std::vector& frames); /** * @brief Takes errors from the internal storage. @@ -70,7 +68,7 @@ class TelegramBuffer * * @note After calling this function, the internal error storage will be cleared. */ - void take_errors(std::vector&); + void take_errors(std::vector& errors); /** * @brief Retrieves a constant reference to the internal byte buffer. @@ -84,6 +82,15 @@ class TelegramBuffer std::vector m_errors; std::optional m_header_opt; + /** + * @brief Checks for the presence of the telegram header in the buffer. + * + * This function searches for the telegram header signature in the raw buffer. + * If the signature is found, any bytes preceding the header start position + * are discarded from the buffer. + * + * @return true if the telegram header signature is found, false otherwise. + */ bool check_telegram_header_presence(); }; diff --git a/vpr/src/server/telegramframe.h b/vpr/src/server/telegramframe.h index c542d41d1ee..e2237de3e36 100644 --- a/vpr/src/server/telegramframe.h +++ b/vpr/src/server/telegramframe.h @@ -10,18 +10,21 @@ namespace comm { - /** * @brief Structure representing a TelegramFrame. * * A TelegramFrame consists of a TelegramHeader followed by data. -* -* @var header The TelegramHeader containing metadata about the telegram message. @see TelegramHeader -* @var data The actual data of the telegram message. */ struct TelegramFrame { + /** + * @brief header The TelegramHeader containing metadata about the telegram message. + */ TelegramHeader header; - ByteArray data; + + /** + * @brief body The actual data of the telegram message. + */ + ByteArray body; }; using TelegramFramePtr = std::shared_ptr; diff --git a/vpr/src/server/telegramheader.cpp b/vpr/src/server/telegramheader.cpp index 344e8fe7422..f1f05a4864e 100644 --- a/vpr/src/server/telegramheader.cpp +++ b/vpr/src/server/telegramheader.cpp @@ -73,7 +73,7 @@ std::string TelegramHeader::info() const { return ss.str(); } -comm::TelegramHeader TelegramHeader::construct_from_data(const std::string_view& body, uint8_t compressor_id) { +comm::TelegramHeader TelegramHeader::construct_from_body(const std::string_view& body, uint8_t compressor_id) { uint32_t body_check_sum = ByteArray::calc_check_sum(body); return comm::TelegramHeader{static_cast(body.size()), body_check_sum, compressor_id}; } diff --git a/vpr/src/server/telegramheader.h b/vpr/src/server/telegramheader.h index 1a3f990ddb1..5190a3ac7e7 100644 --- a/vpr/src/server/telegramheader.h +++ b/vpr/src/server/telegramheader.h @@ -11,19 +11,17 @@ namespace comm { /** - * @brief The fixed size bytes sequence where the metadata of a telegram message is stored. + * @brief The fixed size byte sequence where the metadata of a telegram message is stored. * * This structure is used to describe the message frame sequence in order to successfully extract it. * The TelegramHeader structure follows this format: - * ------------------------------------------------------ - * [ 4 bytes ][ 4 bytes ][ 4 bytes ][ 1 byte ] - * [SIGNATURE][DATA_LENGTH][DATA_CHECKSUM][COMPRESSOR_ID] - * ------------------------------------------------------ + * - [ 4 bytes ]: SIGNATURE - A 4-byte constant sequence "I", "P", "A", "\0" which indicates the valid start of a TelegramHeader. + * - [ 4 bytes ]: DATA_LENGTH - A 4-byte field where the data length is stored, allowing for proper identification of the start and end of the TelegramFrame sequence. + * - [ 4 bytes ]: DATA_CHECKSUM - A 4-byte field where the data checksum is stored to validate the attached data. + * - [ 1 byte ]: COMPRESSOR_ID - A 1-byte field where the compressor ID is stored. If it's null, it means the telegram body is not compressed (in text/json format). + * Otherwise, the telegram body is compressed. Currently, only zlib compression for the telegram body is supported, which is specified with COMPRESSOR_ID='z'. * - * The SIGNATURE is a 4-byte constant sequence "I", "P", "A", "\0" which indicates the valid start of a TelegramHeader. - * The DATA_LENGTH is a 4-byte field where the data length is stored, allowing for proper identification of the start and end of the TelegramFrame sequence. - * The DATA_CHECKSUM is a 4-byte field where the data checksum is stored to validate the attached data. - * The COMPRESSOR_ID is a 1-byte field where the compressor id is stored. If it's NULL, it means the data is not compressed (in text/json format). + * @note: The DATA_CHECKSUM field can be used to check the integrity of the telegram body on the client app side. */ class TelegramHeader { public: @@ -38,26 +36,96 @@ class TelegramHeader { static constexpr size_t COMPRESSORID_OFFSET = CHECKSUM_OFFSET + CHECKSUM_SIZE; TelegramHeader()=default; - explicit TelegramHeader(uint32_t length, uint32_t checkSum, uint8_t compressorId = 0); - explicit TelegramHeader(const ByteArray& body); - ~TelegramHeader()=default; - static comm::TelegramHeader construct_from_data(const std::string_view& body, uint8_t compressor_id = 0); + /** + * @brief Constructs a TelegramHeader object with the specified length, checksum, and optional compressor ID. + * + * @param length The length of the telegram body. + * @param check_sum The checksum of the telegram body. + * @param compressor_id The compressor ID used for compressing the telegram body (default is 0). + */ + explicit TelegramHeader(uint32_t length, uint32_t check_sum, uint8_t compressor_id = 0); + + /** + * @brief Constructs a TelegramHeader object from the provided byte buffer. + * + * This constructor initializes a TelegramHeader object using the length and checksum information taken from the provided byte buffer. + * + * @param buffer The ByteArray containing the header data of the telegram. + */ + explicit TelegramHeader(const ByteArray& buffer); + + ~TelegramHeader()=default; + /** + * @brief Constructs a TelegramHeader based on the provided body data. + * + * @param body The body data used to calculate the size and checksum. + * @param compressor_id The ID of the compressor used for compression (default is 0, means no compressor is used). + * @return A TelegramHeader object constructed from the provided body data. + */ + static comm::TelegramHeader construct_from_body(const std::string_view& body, uint8_t compressor_id = 0); + + /** + * @brief Returns the total size of the TelegramHeader. + * + * This static constexpr method returns the total size of the TelegramHeader, including all its components. + * + * @return The total size of the TelegramHeader. + */ static constexpr size_t size() { return SIGNATURE_SIZE + LENGTH_SIZE + CHECKSUM_SIZE + COMPRESSORID_SIZE; } + /** + * @brief To checks if the TelegramHeader is valid. + * + * @return True if the TelegramHeader is valid, false otherwise. + */ bool is_valid() const { return m_is_valid; } + /** + * @brief Retrieves the buffer associated with the TelegramHeader. + * + * This method returns a constant reference to the buffer associated with the TelegramHeader. + * + * @return A constant reference to the buffer. + */ const ByteArray& buffer() const { return m_buffer; } + /** + * @brief Retrieves the number of bytes in the telegram body. + * + * @return The number of bytes in the telegram body. + */ uint32_t body_bytes_num() const { return m_body_bytes_num; } + + /** + * @brief Retrieves the checksum of telegram body. + * + * @return The checksum of telegram body. + */ uint32_t body_check_sum() const { return m_body_check_sum; } + + /** + * @brief Retrieves the compressor ID used for compressing telegram body. + * + * @return The compressor ID of the telegram body. 0 if the telegram body is not compressed. + */ uint8_t compressor_id() const { return m_compressor_id; } + /** + * @brief Checks if the telegram body is compressed. + * + * @return True if the telegram body is compressed; otherwise, false. + */ bool is_body_compressed() const { return m_compressor_id != 0; } + /** + * @brief Retrieves information about the telegram header. + * + * @return A string containing information about the telegram header. + */ std::string info() const; private: diff --git a/vpr/src/server/telegramoptions.h b/vpr/src/server/telegramoptions.h index 2d3a00b8952..41237cdde2e 100644 --- a/vpr/src/server/telegramoptions.h +++ b/vpr/src/server/telegramoptions.h @@ -13,7 +13,7 @@ namespace server { /** * @brief Option class Parser - * + * * Parse the string of options in the format "TYPE:KEY1:VALUE1;TYPE:KEY2:VALUE2", * for example "int:path_num:11;string:path_type:debug;int:details_level:3;bool:is_flat_routing:0". * It provides a simple interface to check value presence and access them. @@ -34,19 +34,85 @@ class TelegramOptions { }; public: + /** + * @brief Constructs a TelegramOptions object with the provided data and expected keys. + * + * This constructor initializes a TelegramOptions object with the given data string + * and a vector of expected keys. It parses the data string and validates that such data has all required keys. + * If some keys are absent, it collects the errors. + * + * @param data The data string containing the options. + * @param expected_keys A vector of strings representing the expected keys in the options. + */ TelegramOptions(const std::string& data, const std::vector& expected_keys); ~TelegramOptions()=default; + /** + * @brief Checks if there are any errors present. + * + * This function returns true if there are errors present in the error container, + * otherwise it returns false. + * + * @return True if there are errors present, false otherwise. + */ bool has_errors() const { return !m_errors.empty(); } - std::map> get_map_of_sets(const std::string& name); - - std::string get_string(const std::string& name); - - int get_int(const std::string& name, int fail_value); - - bool get_bool(const std::string& name, bool fail_value); - + /** + * @brief Retrieves a map of sets associated with the specified key. + * + * This function retrieves a map of sets associated with the specified key. + * + * @note The map of sets is used to store the critical path index (map key) and the associated set of selected sub-path element indexes (map value). + * + * @param key The key of the map of sets to retrieve. + * @return The map of sets associated with the specified key. + */ + std::map> get_map_of_sets(const std::string& key); + + /** + * @brief Retrieves the string associated with the specified key. + * + * This function retrieves the string associated with the specified key. + * The key is used to identify the desired string value. + * + * @param key The key of the string to retrieve. + * @return The string associated with the specified key. + */ + std::string get_string(const std::string& key); + + /** + * @brief Retrieves the integer value associated with the specified key. + * + * This function retrieves the integer value associated with the specified key. + * If the key is found, its corresponding integer value is returned. + * If the key is not found, the specified fail_value is returned instead. + * + * @param key The key whose associated integer value is to be retrieved. + * @param fail_value The value to return if the key is not found. + * @return The integer value associated with the specified key, or fail_value if the key is not found. + */ + int get_int(const std::string& key, int fail_value); + + /** + * @brief Retrieves the boolean value associated with the specified key. + * + * This function retrieves the boolean value associated with the specified key. + * + * @param key The key whose associated boolean value is to be retrieved. + * @param fail_value The value to return if the key is not found. + * @return The boolean value associated with the specified key, or fail_value if the key is not found. + */ + bool get_bool(const std::string& key, bool fail_value); + + /** + * @brief Retrieves a concatenated string of all errors stored in the container. + * + * This function retrieves a concatenated string of all errors stored in the container. + * It concatenates all error strings stored in the container and returns the result. + * If there are no errors stored in the container, an empty string is returned. + * + * @return A concatenated string of all errors stored in the container. + */ std::string errors_str() const; private: diff --git a/vpr/src/server/telegramparser.h b/vpr/src/server/telegramparser.h index 8ebb49955f2..23e942f1d9d 100644 --- a/vpr/src/server/telegramparser.h +++ b/vpr/src/server/telegramparser.h @@ -9,17 +9,71 @@ namespace comm { /** - * @brief Dummy JSON parser using regular expressions. + * @brief Dummy JSON parser. * - * This module provides helper methods to extract values for a keys as "JOB_ID", "CMD", or "OPTIONS" - * from a JSON schema structured as follows: {JOB_ID:num, CMD:enum, OPTIONS:string}. + * This class provides helper methods to extract values for a keys as "JOB_ID", "CMD", "OPTIONS", "DATA", or "STATUS + * from a JSON schema structured as follows: {JOB_ID:num, CMD:enum, OPTIONS:string, DATA:string, STATUS:num}. */ class TelegramParser { public: + /** + * @brief Attempts to extract the JOB_ID field from a given message. + * + * This function parses the provided message and attempts to extract the JOB_ID field from it. + * If the JOB_ID field is found and successfully extracted, it is returned as an optional integer. + * If the JOB_ID field is not found or cannot be parsed as an integer, an empty optional is returned. + * + * @param message The message from which to extract the JOB_ID field. + * @return An optional integer containing the extracted JOB_ID if successful, otherwise an empty optional. + */ static std::optional try_extract_field_job_id(const std::string& message); + + /** + * @brief Attempts to extract the CMD field from a given message. + * + * This function parses the provided message and attempts to extract the CMD field from it. + * If the CMD field is found and successfully extracted, it is returned as an optional integer. + * If the CMD field is not found or cannot be parsed as an integer, an empty optional is returned. + * + * @param message The message from which to extract the CMD field. + * @return An optional integer containing the extracted CMD if successful, otherwise an empty optional. + */ static std::optional try_extract_field_cmd(const std::string& message); + + /** + * @brief Attempts to extract the OPTIONS field from a given message. + * + * This function parses the provided message and attempts to extract the OPTIONS field from it. + * If the OPTIONS field is found and successfully extracted, it is returned as an optional string. + * If the OPTIONS field is not found an empty optional is returned. + * + * @param message The message from which to extract the OPTIONS field. + * @return An optional string containing the extracted OPTIONS if successful, otherwise an empty optional. + */ static std::optional try_extract_field_options(const std::string& message); + + /** + * @brief Attempts to extract the DATA field from a given message. + * + * This function parses the provided message and attempts to extract the DATA field from it. + * If the DATA field is found and successfully extracted, it is returned as an optional string. + * If the DATA field is not found an empty optional is returned. + * + * @param message The message from which to extract the DATA field. + * @return An optional string containing the extracted DATA if successful, otherwise an empty optional. + */ static std::optional try_extract_field_data(const std::string& message); + + /** + * @brief Attempts to extract the STATUS field from a given message. + * + * This function parses the provided message and attempts to extract the STATUS field from it. + * If the STATUS field is found and successfully extracted, it is returned as an optional integer. + * If the STATUS field is not found or cannot be parsed as an integer, an empty optional is returned. + * + * @param message The message from which to extract the STATUS field. + * @return An optional integer containing the extracted STATUS if successful, otherwise an empty optional. + */ static std::optional try_extract_field_status(const std::string& message); private: diff --git a/vpr/test/test_server_taskresolver.cpp b/vpr/test/test_server_taskresolver.cpp index 4e9ff388341..eda8d5ae82f 100644 --- a/vpr/test/test_server_taskresolver.cpp +++ b/vpr/test/test_server_taskresolver.cpp @@ -8,7 +8,7 @@ TEST_CASE("test_server_taskresolver_cmdSpamFilter", "[vpr]") { server::TaskResolver resolver; - const int cmd = 10; + const comm::CMD cmd = comm::CMD::GET_PATH_LIST_ID; { server::TaskPtr task0 = std::make_unique(1, cmd); @@ -43,7 +43,7 @@ TEST_CASE("test_server_taskresolver_cmdSpamFilter", "[vpr]") { TEST_CASE("test_server_taskresolver_cmdOverrideFilter", "[vpr]") { server::TaskResolver resolver; - const int cmd = 10; + const comm::CMD cmd = comm::CMD::GET_PATH_LIST_ID; { server::TaskPtr task0 = std::make_unique(1, cmd, "1"); @@ -75,14 +75,17 @@ TEST_CASE("test_server_taskresolver_cmdOverrideFilter", "[vpr]") { TEST_CASE("test_server_taskresolver_cmdSpamAndOverrideOptions", "[vpr]") { server::TaskResolver resolver; + const comm::CMD cmd1 = comm::CMD::GET_PATH_LIST_ID; + const comm::CMD cmd2 = comm::CMD::DRAW_PATH_ID; + { - server::TaskPtr task0 = std::make_unique(1, 2, "1"); - server::TaskPtr task1 = std::make_unique(2, 2, "11"); - server::TaskPtr task2 = std::make_unique(3, 2, "222"); - server::TaskPtr task3 = std::make_unique(4, 2, "222"); - server::TaskPtr task4 = std::make_unique(5, 1); - server::TaskPtr task5 = std::make_unique(6, 1); - server::TaskPtr task6 = std::make_unique(7, 1); + server::TaskPtr task0 = std::make_unique(1, cmd2, "1"); + server::TaskPtr task1 = std::make_unique(2, cmd2, "11"); + server::TaskPtr task2 = std::make_unique(3, cmd2, "222"); + server::TaskPtr task3 = std::make_unique(4, cmd2, "222"); + server::TaskPtr task4 = std::make_unique(5, cmd1); + server::TaskPtr task5 = std::make_unique(6, cmd1); + server::TaskPtr task6 = std::make_unique(7, cmd1); resolver.own_task(std::move(task0)); resolver.own_task(std::move(task1)); @@ -101,11 +104,11 @@ TEST_CASE("test_server_taskresolver_cmdSpamAndOverrideOptions", "[vpr]") { const server::TaskPtr& task1 = resolver.tasks().at(1); REQUIRE(task0->job_id() == 3); - REQUIRE(task0->cmd() == 2); + REQUIRE(task0->cmd() == cmd2); REQUIRE(task0->options() == "222"); REQUIRE(task1->job_id() == 5); - REQUIRE(task1->cmd() == 1); + REQUIRE(task1->cmd() == cmd1); REQUIRE(task1->options() == ""); } diff --git a/vpr/test/test_server_telegrambuffer.cpp b/vpr/test/test_server_telegrambuffer.cpp index 767b4892030..6c5c793c3d2 100644 --- a/vpr/test/test_server_telegrambuffer.cpp +++ b/vpr/test/test_server_telegrambuffer.cpp @@ -40,7 +40,8 @@ TEST_CASE("test_server_telegrambuffer_oneOpened", "[vpr]") { buff.append(comm::ByteArray{"111"}); buff.append(comm::ByteArray{"222"}); - auto frames = buff.take_telegram_frames(); + std::vector frames; + buff.take_telegram_frames(frames); REQUIRE(frames.size() == 0); REQUIRE(std::string_view{buff.data()} == "111222"); @@ -52,12 +53,13 @@ TEST_CASE("test_server_telegrambuffer_notFilledTelegramButWithPrependedRubish", const comm::ByteArray rubbish{"#@!"}; const comm::ByteArray msgBody{"some message"}; - const comm::TelegramHeader msgHeader{comm::TelegramHeader::construct_from_data(msgBody)}; + const comm::TelegramHeader msgHeader{comm::TelegramHeader::construct_from_body(msgBody)}; tBuff.append(rubbish); tBuff.append(msgHeader.buffer()); - auto frames = tBuff.take_telegram_frames(); + std::vector frames; + tBuff.take_telegram_frames(frames); REQUIRE(0 == frames.size()); REQUIRE(msgHeader.buffer() == tBuff.data()); // the rubbish prefix fragment will be absent here @@ -70,8 +72,8 @@ TEST_CASE("test_server_telegrambuffer__oneFinishedOneOpened", "[vpr]") const comm::ByteArray msgBody1{"message1"}; const comm::ByteArray msgBody2{"message2"}; - const comm::TelegramHeader msgHeader1{comm::TelegramHeader::construct_from_data(msgBody1)}; - const comm::TelegramHeader msgHeader2{comm::TelegramHeader::construct_from_data(msgBody2)}; + const comm::TelegramHeader msgHeader1{comm::TelegramHeader::construct_from_body(msgBody1)}; + const comm::TelegramHeader msgHeader2{comm::TelegramHeader::construct_from_body(msgBody2)}; comm::ByteArray t1(msgHeader1.buffer()); t1.append(msgBody1); @@ -83,10 +85,11 @@ TEST_CASE("test_server_telegrambuffer__oneFinishedOneOpened", "[vpr]") tBuff.append(t1); tBuff.append(t2); - auto frames = tBuff.take_telegram_frames(); + std::vector frames; + tBuff.take_telegram_frames(frames); REQUIRE(1 == frames.size()); - REQUIRE(msgBody1 == frames[0]->data); + REQUIRE(msgBody1 == frames[0]->body); REQUIRE(t2 == tBuff.data()); } @@ -98,8 +101,8 @@ TEST_CASE("test_server_telegrambuffer_twoFinished", "[vpr]") const comm::ByteArray msgBody1{"message1"}; const comm::ByteArray msgBody2{"message2"}; - const comm::TelegramHeader msgHeader1{comm::TelegramHeader::construct_from_data(msgBody1)}; - const comm::TelegramHeader msgHeader2{comm::TelegramHeader::construct_from_data(msgBody2)}; + const comm::TelegramHeader msgHeader1{comm::TelegramHeader::construct_from_body(msgBody1)}; + const comm::TelegramHeader msgHeader2{comm::TelegramHeader::construct_from_body(msgBody2)}; comm::ByteArray t1(msgHeader1.buffer()); t1.append(msgBody1); @@ -110,11 +113,12 @@ TEST_CASE("test_server_telegrambuffer_twoFinished", "[vpr]") tBuff.append(t1); tBuff.append(t2); - auto frames = tBuff.take_telegram_frames(); + std::vector frames; + tBuff.take_telegram_frames(frames); REQUIRE(2 == frames.size()); - REQUIRE(msgBody1 == frames[0]->data); - REQUIRE(msgBody2 == frames[1]->data); + REQUIRE(msgBody1 == frames[0]->body); + REQUIRE(msgBody2 == frames[1]->body); REQUIRE(comm::ByteArray{} == tBuff.data()); } @@ -126,8 +130,8 @@ TEST_CASE("test_server_telegrambuffer_clear", "[vpr]") const comm::ByteArray msgBody1{"message1"}; const comm::ByteArray msgBody2{"message2"}; - const comm::TelegramHeader msgHeader1{comm::TelegramHeader::construct_from_data(msgBody1)}; - const comm::TelegramHeader msgHeader2{comm::TelegramHeader::construct_from_data(msgBody2)}; + const comm::TelegramHeader msgHeader1{comm::TelegramHeader::construct_from_body(msgBody1)}; + const comm::TelegramHeader msgHeader2{comm::TelegramHeader::construct_from_body(msgBody2)}; comm::ByteArray t1(msgHeader1.buffer()); t1.append(msgBody1); @@ -137,7 +141,8 @@ TEST_CASE("test_server_telegrambuffer_clear", "[vpr]") tBuff.clear(); - auto frames = tBuff.take_telegram_frames(); + std::vector frames; + tBuff.take_telegram_frames(frames); REQUIRE(0 == frames.size()); REQUIRE(comm::ByteArray{} == tBuff.data());