Skip to content

Comments

Performance/networking optimizations#45

Open
MarioIvancik wants to merge 12 commits intomasterfrom
BAF-1122/optimizations
Open

Performance/networking optimizations#45
MarioIvancik wants to merge 12 commits intomasterfrom
BAF-1122/optimizations

Conversation

@MarioIvancik
Copy link
Member

@MarioIvancik MarioIvancik commented Jul 18, 2025

https://youtrack.bringauto.com/issue/BAF-1122/Module-Gateway-performance

Summary by CodeRabbit

  • New Features

    • Added DUMMY protocol support and a dummy communication channel for testing.
  • Improvements

    • New compile-time option to set minimum logger verbosity with compile-time filtering.
    • Improved remote endpoint logging and general const-correctness; several ordered maps changed to unordered maps for performance and iteration differences.
  • Documentation

    • README documents the new logger verbosity CMake option.
  • Tests

    • Tests expanded to cover DUMMY protocol and related logging behavior.
  • Chores

    • Bumped module version and updated dependency versions.

@MarioIvancik MarioIvancik self-assigned this Jul 18, 2025
@coderabbitai
Copy link

coderabbitai bot commented Jul 18, 2025

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds compile-time logger verbosity and LoggerWrapper; introduces ProtocolType::DUMMY with DummyCommunication; widens const-correctness and tightens many function signatures; replaces several ordered maps with unordered_map; updates protobuf/buffer signatures; bumps CMake/dependency versions; and updates tests and docs.

Changes

Cohort / File(s) Summary
Build & docs
CMakeLists.txt, cmake/Dependencies.cmake, CMLibStorage.cmake, README.md, Dockerfile
Bumps module version to 1.3.5, adds BRINGAUTO_MODULE_GATEWAY_MINIMUM_LOGGER_VERBOSITY CACHE STRING (DEBUG/INFO/WARNING/ERROR/CRITICAL), upgrades cxxopts/nlohmann_json, adds STORAGE_LIST_DEP_REVISION, and updates README/Dockerfile.
Logger core & validation
include/bringauto/settings/LoggerWrapper.hpp, include/bringauto/settings/LoggerId.hpp, source/bringauto/settings/LoggerId.cpp
Adds header-only LoggerWrapper template (compile-time filtering + runtime delegation), compile-time validation of verbosity macro, and LoggerId changes.
Logger usage & init
main.cpp, test/include/*Tests.hpp, test/include/InternalServerTests.hpp, test/include/ErrorAggregatorTests.hpp, test/include/ExternalConnectionTests.hpp, test/include/StatusAggregatorTests.hpp
Replaces previous LoggerSettings-based init with simplified Logger::init("...") across app and tests.
New protocol & channel
include/bringauto/external_client/connection/communication/DummyCommunication.hpp, source/bringauto/external_client/connection/communication/DummyCommunication.cpp, include/bringauto/settings/Constants.hpp
Adds ProtocolType::DUMMY, Constants::DUMMY, and DummyCommunication test/non-connecting channel (initialize/send/receive/close).
Enum & utils changes
include/bringauto/common_utils/EnumUtils.hpp, source/bringauto/common_utils/EnumUtils.cpp, test/source/EnumUtilsTests.cpp
Makes to-string utilities constexpr returning std::string_view in header, adds DUMMY mapping string→enum, removes duplicate to-string implementations in one TU, and updates tests (MQTT uppercase, DUMMY).
External client & connections
include/bringauto/external_client/ExternalClient.hpp, source/bringauto/external_client/ExternalClient.cpp, include/bringauto/external_client/connection/ExternalConnection.hpp, source/bringauto/external_client/connection/ExternalConnection.cpp
Adds DUMMY handling, changes constructors to accept const shared_ptr&, replaces several std::mapstd::unordered_map, switches lookups to iterator-based access, and marks multiple methods const.
ICommunication & MQTT
include/bringauto/external_client/connection/communication/ICommunicationChannel.hpp, include/bringauto/external_client/connection/communication/MqttCommunication.hpp, source/bringauto/external_client/connection/communication/MqttCommunication.cpp
ICommunicationChannel now takes settings by value and moves them; include reorder; MQTT reconnect logic changed to always close existing client then connect (behavioral change).
Protobuf & buffer handling
include/bringauto/common_utils/ProtobufUtils.hpp, source/bringauto/common_utils/ProtobufUtils.cpp, include/bringauto/modules/Buffer.hpp
Changes copyStatusToBuffer/copyCommandToBuffer to accept const modules::Buffer&, uses local size vars for memcpy, and removes unused includes; minor Buffer header cleanup.
Const-correctness & API tweaks
many include/bringauto/**, source/bringauto/** (e.g., ModuleHandler, ModuleManagerLibraryHandler, StatusAggregator, InternalServer, ThreadTimer, etc.)
Widespread addition of const qualifiers to methods/parameters, small parameter renames, new Connection::remoteEndpointAddress(), removal of unused includes, and many locals made const — review headers for ABI/signature changes.
Container type changes
include/bringauto/settings/Settings.hpp, include/bringauto/structures/ExternalConnectionSettings.hpp, include/bringauto/structures/ModuleLibrary.hpp, source/bringauto/structures/ModuleLibrary.cpp, test/include/testing_utils/ConfigMock.hpp
Replaces multiple std::map usages with std::unordered_map (module paths, protocol settings, module registries, mocks) and updates related APIs/tests.
Tests & test utils
test/source/*, test/include/*, test/include/testing_utils/ConfigMock.hpp
Updates tests for DUMMY protocol and logger changes, adapts mocks to unordered_map, re-enables/adjusts tests, and removes a timeout-based test helper.
Misc struct/type changes
include/bringauto/structures/*, include/bringauto/modules/*
Small struct/type tweaks: ExternalConnectionSettings.portstd::uint16_t, protocolSettingsunordered_map, removed redundant public: in a struct, and signature adjustments across modules.

Sequence Diagram(s)

sequenceDiagram
    participant Build as Build (CMake)
    participant Main as main
    participant Logger as LoggerWrapper
    participant Settings as SettingsParser

    Build->>Main: compile with BRINGAUTO_MODULE_GATEWAY_MINIMUM_LOGGER_VERBOSITY
    Main->>Logger: Logger::init("ModuleGateway")
    Settings->>Main: parse runtime settings
    Main->>Logger: log call (compile-time filter -> delegate to BaseLogger)
Loading
sequenceDiagram
    participant Settings as SettingsParser
    participant External as ExternalClient
    participant Comm as DummyCommunication
    participant Log as LoggerWrapper

    Settings->>External: provide ExternalConnectionSettings (ProtocolType::DUMMY)
    External->>Comm: construct DummyCommunication(settings)
    Comm->>Log: log initialize (initializeConnection)
    Comm->>Comm: initializeConnection() sets isConnected_ = true
    External->>Comm: sendMessage(...)
    Comm-->>External: returns true
    External->>Comm: receiveMessage()
    Comm-->>External: returns nullptr
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • koudis
🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 21.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Performance/networking optimizations' is vague and overly broad. While the PR does include performance and networking improvements, the title lacks specificity about the main changes, such as the const-correctness improvements, logger initialization refactoring, or protocol type additions. Consider a more specific title that highlights the primary change, such as 'Add const-correctness improvements and logger verbosity configuration' or 'Refactor logging system and add DUMMY protocol support'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch BAF-1122/optimizations

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (3)
include/bringauto/structures/AtomicQueue.hpp (1)

33-36: Clarify return-value semantics in the fresh comment while you’re here

Nice typo fix. Since you’re touching the docblock anyway, consider spelling out that the function returns true only when the timeout expired and the queue is still empty:

- * @return true if the queue is empty
+ * @return true if the queue is still empty after the timeout has elapsed,
+ *         false if a value became available before the timeout.
README.md (1)

80-88: LGTM! Clear documentation of new logger verbosity option.

The documentation clearly explains the new MINIMUM_LOGGER_VERBOSITY CMake option and its performance benefits through compile-time log filtering. This aligns well with the PR's performance optimization objectives.

Consider fixing the minor formatting inconsistency flagged by markdownlint - the list uses asterisks while other lists in the file use dashes.

-* MINIMUM_LOGGER_VERBOSITY=0/1/2/3/4
+- MINIMUM_LOGGER_VERBOSITY=0/1/2/3/4
source/bringauto/common_utils/EnumUtils.cpp (1)

13-15: DUMMY protocol support added correctly.

The logic for handling the DUMMY protocol type is consistent with the existing MQTT protocol handling. However, there's an indentation inconsistency - the new code uses spaces while the existing code appears to use tabs.

Consider fixing the indentation to match the existing style:

-	} else if(toEnum == settings::Constants::DUMMY) {
-        return structures::ProtocolType::DUMMY;
-    }
+	} else if(toEnum == settings::Constants::DUMMY) {
+		return structures::ProtocolType::DUMMY;
+	}

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
README.md (2)

80-82: Markdown-lint MD004 violation – switch to dash bullets for consistency

markdownlint flags the new bullet because the project’s doc style-guide prefers - over *.
Since the surrounding list items (61-78) already use *, you can either:

  1. Adopt dashes here and everywhere else (preferred ‑ silences the linter globally), or
  2. Add an explicit rule override to keep asterisks.

Example fix for the new item:

-* MODULE_GATEWAY_MINIMUM_LOGGER_VERBOSITY=0/1/2/3/4
+- MODULE_GATEWAY_MINIMUM_LOGGER_VERBOSITY=0/1/2/3/4

83-88: Spell out the enum names to avoid “magic numbers”

Readers unfamiliar with ba-logger may not know which numeric level maps to which macro/enum.
Consider appending the symbolic names once to improve clarity:

-  - 0: DEBUG
-  - 1: INFO
-  - 2: WARNING
-  - 3: ERROR
-  - 4: CRITICAL
+  - 0 (`BA_LOGGER_VERBOSITY_DEBUG`): DEBUG  
+  - 1 (`BA_LOGGER_VERBOSITY_INFO`): INFO  
+  - 2 (`BA_LOGGER_VERBOSITY_WARNING`): WARNING  
+  - 3 (`BA_LOGGER_VERBOSITY_ERROR`): ERROR  
+  - 4 (`BA_LOGGER_VERBOSITY_CRITICAL`): CRITICAL

This keeps the README self-contained and reduces the mental jump to the codebase/macros.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0cf2f5e and b4bd01a.

📒 Files selected for processing (9)
  • CMakeLists.txt (1 hunks)
  • Dockerfile (1 hunks)
  • README.md (1 hunks)
  • include/bringauto/settings/LoggerId.hpp (1 hunks)
  • include/bringauto/settings/LoggerWrapper.hpp (1 hunks)
  • include/bringauto/structures/Connection.hpp (1 hunks)
  • main.cpp (3 hunks)
  • source/bringauto/common_utils/ProtobufUtils.cpp (5 hunks)
  • source/bringauto/internal_server/InternalServer.cpp (18 hunks)
🧠 Learnings (1)
README.md (6)

Learnt from: koudis
PR: #43
File: CMakeLists.txt:11-14
Timestamp: 2025-06-29T18:12:34.666Z
Learning: In the ModuleGateway project's CMakeLists.txt, compile definitions for version strings are intentionally set with escaped quotes using CMDEF_COMPILE_DEFINITIONS to produce compiler flags like -DMODULE_GATEWAY_VERSION="1.3.3", ensuring the macro expands to a proper string literal in C++ code.

Learnt from: MarioIvancik
PR: #38
File: include/bringauto/structures/LoggingSettings.hpp:10-15
Timestamp: 2024-10-31T10:45:48.494Z
Learning: In the ModuleGateway project, values in the structures defined in include/bringauto/structures/LoggingSettings.hpp are validated in SettingsParser.cpp, so additional validation within the structures is unnecessary.

Learnt from: Mayt34
PR: bringauto/transparent-module#1
File: CMakeLists.txt:15-20
Timestamp: 2024-10-03T17:41:56.410Z
Learning: In the transparent_module project, all modules should be built by default; FLEET_PROTOCOL_BUILD_MODULE_GATEWAY and FLEET_PROTOCOL_BUILD_EXTERNAL_SERVER should be set to ON by default.

Learnt from: Mayt34
PR: bringauto/transparent-module#1
File: CMakeLists.txt:15-20
Timestamp: 2024-10-09T05:03:50.249Z
Learning: In the transparent_module project, all modules should be built by default; FLEET_PROTOCOL_BUILD_MODULE_GATEWAY and FLEET_PROTOCOL_BUILD_EXTERNAL_SERVER should be set to ON by default.

Learnt from: mikusaq
PR: bacpack-system/packager#24
File: modules/bringauto_log/Handler.go:40-54
Timestamp: 2024-10-09T05:03:50.249Z
Learning: The bringauto_log module does not currently use the debug log level.

Learnt from: mikusaq
PR: bacpack-system/packager#24
File: modules/bringauto_log/Handler.go:40-54
Timestamp: 2024-09-30T11:00:40.818Z
Learning: The bringauto_log module does not currently use the debug log level.

🪛 markdownlint-cli2 (0.17.2)
README.md

80-80: Unordered list style
Expected: dash; Actual: asterisk

(MD004, ul-style)

✅ Files skipped from review due to trivial changes (1)
  • Dockerfile
🚧 Files skipped from review as they are similar to previous changes (7)
  • include/bringauto/structures/Connection.hpp
  • main.cpp
  • source/bringauto/common_utils/ProtobufUtils.cpp
  • CMakeLists.txt
  • include/bringauto/settings/LoggerWrapper.hpp
  • include/bringauto/settings/LoggerId.hpp
  • source/bringauto/internal_server/InternalServer.cpp
🧰 Additional context used
🧠 Learnings (1)
README.md (6)

Learnt from: koudis
PR: #43
File: CMakeLists.txt:11-14
Timestamp: 2025-06-29T18:12:34.666Z
Learning: In the ModuleGateway project's CMakeLists.txt, compile definitions for version strings are intentionally set with escaped quotes using CMDEF_COMPILE_DEFINITIONS to produce compiler flags like -DMODULE_GATEWAY_VERSION="1.3.3", ensuring the macro expands to a proper string literal in C++ code.

Learnt from: MarioIvancik
PR: #38
File: include/bringauto/structures/LoggingSettings.hpp:10-15
Timestamp: 2024-10-31T10:45:48.494Z
Learning: In the ModuleGateway project, values in the structures defined in include/bringauto/structures/LoggingSettings.hpp are validated in SettingsParser.cpp, so additional validation within the structures is unnecessary.

Learnt from: Mayt34
PR: bringauto/transparent-module#1
File: CMakeLists.txt:15-20
Timestamp: 2024-10-03T17:41:56.410Z
Learning: In the transparent_module project, all modules should be built by default; FLEET_PROTOCOL_BUILD_MODULE_GATEWAY and FLEET_PROTOCOL_BUILD_EXTERNAL_SERVER should be set to ON by default.

Learnt from: Mayt34
PR: bringauto/transparent-module#1
File: CMakeLists.txt:15-20
Timestamp: 2024-10-09T05:03:50.249Z
Learning: In the transparent_module project, all modules should be built by default; FLEET_PROTOCOL_BUILD_MODULE_GATEWAY and FLEET_PROTOCOL_BUILD_EXTERNAL_SERVER should be set to ON by default.

Learnt from: mikusaq
PR: bacpack-system/packager#24
File: modules/bringauto_log/Handler.go:40-54
Timestamp: 2024-10-09T05:03:50.249Z
Learning: The bringauto_log module does not currently use the debug log level.

Learnt from: mikusaq
PR: bacpack-system/packager#24
File: modules/bringauto_log/Handler.go:40-54
Timestamp: 2024-09-30T11:00:40.818Z
Learning: The bringauto_log module does not currently use the debug log level.

🪛 markdownlint-cli2 (0.17.2)
README.md

80-80: Unordered list style
Expected: dash; Actual: asterisk

(MD004, ul-style)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
include/bringauto/settings/LoggerId.hpp (1)

34-45: Consider making the DEBUG case explicit.

The function correctly converts string verbosity levels to enum values. However, the "DEBUG" case is handled implicitly by the default return. Consider making it explicit for clarity:

 constexpr logging::LoggerVerbosity toLoggerVerbosity(std::string_view verbosityString) {
-	if (verbosityString == "INFO") {
+	if (verbosityString == "DEBUG") {
+		return logging::LoggerVerbosity::Debug;
+	} else if (verbosityString == "INFO") {
 		return logging::LoggerVerbosity::Info;
 	} else if (verbosityString == "WARNING") {
 		return logging::LoggerVerbosity::Warning;
 	} else if (verbosityString == "ERROR") {
 		return logging::LoggerVerbosity::Error;
 	} else if (verbosityString == "CRITICAL") {
 		return logging::LoggerVerbosity::Critical;
 	}
-	return logging::LoggerVerbosity::Debug;
+	// This should never be reached due to static_assert validation
+	return logging::LoggerVerbosity::Debug;
 }
README.md (1)

80-83: Good documentation of the new compile-time logging feature.

The documentation accurately describes the new MODULE_GATEWAY_MINIMUM_LOGGER_VERBOSITY CMake argument and its performance benefits. The listed verbosity levels match the implementation.

Fix the list style for consistency with the rest of the document:

-* MODULE_GATEWAY_MINIMUM_LOGGER_VERBOSITY=DEBUG/INFO/WARNING/ERROR/CRITICAL
+- MODULE_GATEWAY_MINIMUM_LOGGER_VERBOSITY=DEBUG/INFO/WARNING/ERROR/CRITICAL
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b4bd01a and 4a84ce1.

📒 Files selected for processing (4)
  • CMakeLists.txt (1 hunks)
  • README.md (1 hunks)
  • include/bringauto/external_client/connection/communication/DummyCommunication.hpp (1 hunks)
  • include/bringauto/settings/LoggerId.hpp (1 hunks)
🧠 Learnings (2)
include/bringauto/settings/LoggerId.hpp (5)

Learnt from: MarioIvancik
PR: #38
File: include/bringauto/structures/LoggingSettings.hpp:10-15
Timestamp: 2024-10-31T10:45:48.494Z
Learning: In the ModuleGateway project, values in the structures defined in include/bringauto/structures/LoggingSettings.hpp are validated in SettingsParser.cpp, so additional validation within the structures is unnecessary.

Learnt from: MarioIvancik
PR: #38
File: include/bringauto/structures/LoggingSettings.hpp:26-31
Timestamp: 2024-10-31T10:44:39.657Z
Learning: In the ModuleGateway project, logging settings are validated in SettingsParser, so additional validation in the LoggingSettings structure is not necessary.

Learnt from: koudis
PR: #43
File: CMakeLists.txt:11-14
Timestamp: 2025-06-29T18:12:34.666Z
Learning: In the ModuleGateway project's CMakeLists.txt, compile definitions for version strings are intentionally set with escaped quotes using CMDEF_COMPILE_DEFINITIONS to produce compiler flags like -DMODULE_GATEWAY_VERSION="1.3.3", ensuring the macro expands to a proper string literal in C++ code.

Learnt from: Melky-Phoe
PR: bringauto/fleet-management-http-api#17
File: fleet_management_api/main.py:42-42
Timestamp: 2024-09-18T06:54:20.565Z
Learning: The team prefers using constants for configuration values like the logging configuration file path instead of making them configurable via command-line arguments or configuration parameters unless necessary.

Learnt from: Melky-Phoe
PR: bringauto/fleet-management-http-api#17
File: fleet_management_api/main.py:42-42
Timestamp: 2024-10-09T05:03:50.249Z
Learning: The team prefers using constants for configuration values like the logging configuration file path instead of making them configurable via command-line arguments or configuration parameters unless necessary.

README.md (6)

Learnt from: koudis
PR: #43
File: CMakeLists.txt:11-14
Timestamp: 2025-06-29T18:12:34.666Z
Learning: In the ModuleGateway project's CMakeLists.txt, compile definitions for version strings are intentionally set with escaped quotes using CMDEF_COMPILE_DEFINITIONS to produce compiler flags like -DMODULE_GATEWAY_VERSION="1.3.3", ensuring the macro expands to a proper string literal in C++ code.

Learnt from: MarioIvancik
PR: #38
File: include/bringauto/structures/LoggingSettings.hpp:10-15
Timestamp: 2024-10-31T10:45:48.494Z
Learning: In the ModuleGateway project, values in the structures defined in include/bringauto/structures/LoggingSettings.hpp are validated in SettingsParser.cpp, so additional validation within the structures is unnecessary.

Learnt from: mikusaq
PR: bacpack-system/packager#24
File: modules/bringauto_log/Handler.go:40-54
Timestamp: 2024-10-09T05:03:50.249Z
Learning: The bringauto_log module does not currently use the debug log level.

Learnt from: mikusaq
PR: bacpack-system/packager#24
File: modules/bringauto_log/Handler.go:40-54
Timestamp: 2024-09-30T11:00:40.818Z
Learning: The bringauto_log module does not currently use the debug log level.

Learnt from: Mayt34
PR: bringauto/transparent-module#1
File: CMakeLists.txt:15-20
Timestamp: 2024-10-03T17:41:56.410Z
Learning: In the transparent_module project, all modules should be built by default; FLEET_PROTOCOL_BUILD_MODULE_GATEWAY and FLEET_PROTOCOL_BUILD_EXTERNAL_SERVER should be set to ON by default.

Learnt from: Mayt34
PR: bringauto/transparent-module#1
File: CMakeLists.txt:15-20
Timestamp: 2024-10-09T05:03:50.249Z
Learning: In the transparent_module project, all modules should be built by default; FLEET_PROTOCOL_BUILD_MODULE_GATEWAY and FLEET_PROTOCOL_BUILD_EXTERNAL_SERVER should be set to ON by default.

🪛 markdownlint-cli2 (0.17.2)
README.md

80-80: Unordered list style
Expected: dash; Actual: asterisk

(MD004, ul-style)

🚧 Files skipped from review as they are similar to previous changes (2)
  • CMakeLists.txt
  • include/bringauto/external_client/connection/communication/DummyCommunication.hpp
🧰 Additional context used
🧠 Learnings (2)
include/bringauto/settings/LoggerId.hpp (5)

Learnt from: MarioIvancik
PR: #38
File: include/bringauto/structures/LoggingSettings.hpp:10-15
Timestamp: 2024-10-31T10:45:48.494Z
Learning: In the ModuleGateway project, values in the structures defined in include/bringauto/structures/LoggingSettings.hpp are validated in SettingsParser.cpp, so additional validation within the structures is unnecessary.

Learnt from: MarioIvancik
PR: #38
File: include/bringauto/structures/LoggingSettings.hpp:26-31
Timestamp: 2024-10-31T10:44:39.657Z
Learning: In the ModuleGateway project, logging settings are validated in SettingsParser, so additional validation in the LoggingSettings structure is not necessary.

Learnt from: koudis
PR: #43
File: CMakeLists.txt:11-14
Timestamp: 2025-06-29T18:12:34.666Z
Learning: In the ModuleGateway project's CMakeLists.txt, compile definitions for version strings are intentionally set with escaped quotes using CMDEF_COMPILE_DEFINITIONS to produce compiler flags like -DMODULE_GATEWAY_VERSION="1.3.3", ensuring the macro expands to a proper string literal in C++ code.

Learnt from: Melky-Phoe
PR: bringauto/fleet-management-http-api#17
File: fleet_management_api/main.py:42-42
Timestamp: 2024-09-18T06:54:20.565Z
Learning: The team prefers using constants for configuration values like the logging configuration file path instead of making them configurable via command-line arguments or configuration parameters unless necessary.

Learnt from: Melky-Phoe
PR: bringauto/fleet-management-http-api#17
File: fleet_management_api/main.py:42-42
Timestamp: 2024-10-09T05:03:50.249Z
Learning: The team prefers using constants for configuration values like the logging configuration file path instead of making them configurable via command-line arguments or configuration parameters unless necessary.

README.md (6)

Learnt from: koudis
PR: #43
File: CMakeLists.txt:11-14
Timestamp: 2025-06-29T18:12:34.666Z
Learning: In the ModuleGateway project's CMakeLists.txt, compile definitions for version strings are intentionally set with escaped quotes using CMDEF_COMPILE_DEFINITIONS to produce compiler flags like -DMODULE_GATEWAY_VERSION="1.3.3", ensuring the macro expands to a proper string literal in C++ code.

Learnt from: MarioIvancik
PR: #38
File: include/bringauto/structures/LoggingSettings.hpp:10-15
Timestamp: 2024-10-31T10:45:48.494Z
Learning: In the ModuleGateway project, values in the structures defined in include/bringauto/structures/LoggingSettings.hpp are validated in SettingsParser.cpp, so additional validation within the structures is unnecessary.

Learnt from: mikusaq
PR: bacpack-system/packager#24
File: modules/bringauto_log/Handler.go:40-54
Timestamp: 2024-10-09T05:03:50.249Z
Learning: The bringauto_log module does not currently use the debug log level.

Learnt from: mikusaq
PR: bacpack-system/packager#24
File: modules/bringauto_log/Handler.go:40-54
Timestamp: 2024-09-30T11:00:40.818Z
Learning: The bringauto_log module does not currently use the debug log level.

Learnt from: Mayt34
PR: bringauto/transparent-module#1
File: CMakeLists.txt:15-20
Timestamp: 2024-10-03T17:41:56.410Z
Learning: In the transparent_module project, all modules should be built by default; FLEET_PROTOCOL_BUILD_MODULE_GATEWAY and FLEET_PROTOCOL_BUILD_EXTERNAL_SERVER should be set to ON by default.

Learnt from: Mayt34
PR: bringauto/transparent-module#1
File: CMakeLists.txt:15-20
Timestamp: 2024-10-09T05:03:50.249Z
Learning: In the transparent_module project, all modules should be built by default; FLEET_PROTOCOL_BUILD_MODULE_GATEWAY and FLEET_PROTOCOL_BUILD_EXTERNAL_SERVER should be set to ON by default.

🪛 markdownlint-cli2 (0.17.2)
README.md

80-80: Unordered list style
Expected: dash; Actual: asterisk

(MD004, ul-style)

🔇 Additional comments (4)
include/bringauto/settings/LoggerId.hpp (4)

3-7: LGTM: Clean macro definition with proper default.

The include and macro definition are well-structured. The conditional definition allows CMake to override the default while providing a sensible fallback.


19-21: Well-implemented constexpr string comparison.

The use of std::string_view for compile-time string comparison is efficient and appropriate. This enables the static_assert validation at compile time.


23-28: Excellent compile-time validation.

The static_assert provides robust validation of the verbosity level macro at compile time, preventing invalid configurations from compiling. This addresses potential runtime errors early in the build process.


47-50: Excellent design for compile-time logging optimization.

The type aliases create a clean abstraction that enables compile-time log filtering. The Logger alias uses LoggerWrapper with compile-time verbosity evaluation, which should provide the performance benefits mentioned in the PR objectives.

@sonarqubecloud
Copy link

@jiriskuta jiriskuta force-pushed the BAF-1122/optimizations branch from bb7ca23 to 115f620 Compare February 18, 2026 19:36
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 11

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
source/bringauto/modules/StatusAggregator.cpp (1)

30-35: ⚠️ Potential issue | 🟠 Major

aggregateStatus returns an empty Buffer {} on failure, contradicting the log message and likely corrupting device state.

Line 33 warns "returning current status buffer" but the function unconditionally returns aggregatedStatusBuff, which remains default-initialized to Buffer {} when module_->aggregateStatus fails. Both callers propagate this empty buffer:

  • aggregateSetStatusdeviceState.setStatus({}) — overwrites the device's current status with an empty buffer.
  • aggregateSetSendStatusdeviceState.setStatusAndResetTimer({}) + pushes {} to the aggregated message queue.

Either currStatus should be returned on the error path to preserve existing state (matching the log intent), or the error path must be handled more deliberately.

🐛 Proposed fix
 Buffer
 StatusAggregator::aggregateStatus(const structures::StatusAggregatorDeviceState &deviceState, const Buffer &status,
 								  const unsigned int &device_type) const {
-	auto &currStatus = deviceState.getStatus();
+	const auto &currStatus = deviceState.getStatus();
 	Buffer aggregatedStatusBuff {};
 	if (module_->aggregateStatus(aggregatedStatusBuff, currStatus, status, device_type) != OK) {
 		log::logWarning("Error occurred while aggregating status, returning current status buffer");
+		return currStatus;
 	}
 	return aggregatedStatusBuff;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@source/bringauto/modules/StatusAggregator.cpp` around lines 30 - 35, The
current error path in StatusAggregator::aggregateStatus returns a
default-initialized aggregatedStatusBuff (Buffer {}) which contradicts the log
and overwrites device state; change the failure branch so that when
module_->aggregateStatus(aggregatedStatusBuff, currStatus, status, device_type)
!= OK you assign or return currStatus (the existing deviceState.getStatus())
instead of the empty aggregatedStatusBuff to preserve state — update the error
branch in aggregateStatus to set aggregatedStatusBuff = currStatus (or return
currStatus) so callers like aggregateSetStatus and aggregateSetSendStatus do not
receive and propagate an empty Buffer.
source/bringauto/modules/ModuleHandler.cpp (1)

15-21: ⚠️ Potential issue | 🟡 Minor

Unused variable deviceId in destroy() — dead code block.

The if(message.disconnected()) block creates deviceId but never uses it. The block is a no-op and will likely generate a compiler warning for the unused variable.

🧹 Proposed fix
 		auto &message = fromInternalQueue_->front();
-		if(message.disconnected()) {
-			auto deviceId = message.getDeviceId();
-		}
 		fromInternalQueue_->pop();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@source/bringauto/modules/ModuleHandler.cpp` around lines 15 - 21, In
destroy(), the if(message.disconnected()) block declares deviceId via
message.getDeviceId() but never uses it, causing dead code and compiler
warnings; remove the unused variable and the empty if block (or replace it with
the intended cleanup call if you meant to act on deviceId), i.e., in the loop
over fromInternalQueue_ eliminate the no-op if(message.disconnected()) { auto
deviceId = message.getDeviceId(); } so only fromInternalQueue_->pop() remains
(or add the actual disconnect handling using message.getDeviceId()).
🧹 Nitpick comments (13)
include/bringauto/external_client/connection/messages/SentMessagesHandler.hpp (1)

68-68: isDeviceConnected is missing const and [[nodiscard]] — inconsistent with sibling predicates.

isAnyDeviceConnected (line 75) is both const and [[nodiscard]]. If isDeviceConnected does not mutate state (which is implied by its query semantics), it should follow the same pattern.

♻️ Proposed fix
-	bool isDeviceConnected(const structures::DeviceIdentification &device);
+	[[nodiscard]] bool isDeviceConnected(const structures::DeviceIdentification &device) const;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@include/bringauto/external_client/connection/messages/SentMessagesHandler.hpp`
at line 68, The method declaration for isDeviceConnected should match the const
and [[nodiscard]] qualifiers used by its sibling predicate isAnyDeviceConnected:
update the declaration of isDeviceConnected(const
structures::DeviceIdentification &device) to [[nodiscard]] bool
isDeviceConnected(const structures::DeviceIdentification &device) const; so the
method is marked as a non-mutating, nodiscard query (and update any
corresponding definition/implementation of
SentMessagesHandler::isDeviceConnected to include the trailing const).
source/bringauto/external_client/connection/communication/MqttCommunication.cpp (1)

63-71: else ifif is a functional no-op; AI summary mischaracterises the change.

The early-return guard on lines 64–66 is still present in the new code:

if (client_ != nullptr && client_->is_connected()) {
    return;                    // ← still here, unchanged
}

Because the first branch always returns when true, execution only reaches line 67 when the first condition was false. In that case, both else if (client_ != nullptr) (old) and if (client_ != nullptr) (new) evaluate identically — all three cases produce the same outcome:

State Old New
client_ == nullptr connect() connect()
exists + connected return return
exists + disconnected closeConnection()connect() closeConnection()connect()

The AI summary's claim that "now it closes (if present) and then reconnects" (implying the early return was removed) is incorrect — no behavioral change has occurred.

The else if phrasing was marginally clearer since it made the mutual exclusion between the two branches explicit. Keeping else if (or adding a comment) would preserve that intent.

♻️ Optional: restore the more expressive `else if`
-	if (client_ != nullptr) {
+	else if (client_ != nullptr) {
 		closeConnection();
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@source/bringauto/external_client/connection/communication/MqttCommunication.cpp`
around lines 63 - 71, The change to MqttCommunication::initializeConnection
altered the branch from "else if (client_ != nullptr)" to a standalone "if
(client_ != nullptr)" which is functionally equivalent but less explicitly
signaling mutual exclusivity with the earlier early-return; restore the original
"else if (client_ != nullptr)" (or add a brief clarifying comment above the
early-return) so the intent that the connected case is mutually exclusive with
the disconnected-but-existing case is clear when reading the code; ensure
references to client_, client_->is_connected(), closeConnection(), and connect()
remain unchanged.
source/bringauto/modules/StatusAggregator.cpp (1)

16-18: Redundant devices.contains check is unreachable dead code.

is_device_valid (line 164) already verifies both is_device_type_supported and devices.contains(device). If it returns OK, the device is guaranteed to be in the map — lines 16-18 can never execute.

♻️ Proposed cleanup
 int StatusAggregator::clear_device(const structures::DeviceIdentification &device) {
 	if(is_device_valid(device) == NOT_OK) {
 		return DEVICE_NOT_REGISTERED;
 	}
-	if (not devices.contains(device)) {
-		return NOT_OK;
-	}
 	auto &deviceState = devices.at(device);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@source/bringauto/modules/StatusAggregator.cpp` around lines 16 - 18, The
early devices.contains(device) guard that returns NOT_OK (the block at lines
checking devices.contains before proceeding) is redundant because
is_device_valid(...) already ensures both is_device_type_supported(...) and
devices.contains(device); remove the unreachable contains check and its return,
and ensure callers rely on is_device_valid (referenced by is_device_valid and
devices.contains) so the function proceeds assuming the device is present; keep
any necessary null/lookup code that actually uses devices but delete the
redundant conditional and return NOT_OK.
include/bringauto/common_utils/EnumUtils.hpp (1)

31-41: Consider removing default to get compiler warnings on unhandled enum values.

With default: present, adding a new ProtocolType enumerator won't produce a -Wswitch warning. Removing default and keeping only the explicit INVALID case lets the compiler catch missing cases at compile time. Same applies to loggerVerbosityToString below.

Proposed change for protocolTypeToString
 	static constexpr std::string_view protocolTypeToString(structures::ProtocolType toString) {
 		switch(toString) {
 			case structures::ProtocolType::MQTT:
 				return settings::Constants::MQTT;
 			case structures::ProtocolType::DUMMY:
 				return settings::Constants::DUMMY;
 			case structures::ProtocolType::INVALID:
-			default:
 				return "";
 		}
+		return "";
 	};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/bringauto/common_utils/EnumUtils.hpp` around lines 31 - 41, Remove
the `default:` branch in protocolTypeToString so the switch only handles the
explicit ProtocolType enumerators (MQTT, DUMMY, INVALID) which enables compiler
-Wswitch warnings for new enum values; keep the INVALID case to return the empty
string and ensure the function remains constexpr and returns std::string_view
for all handled cases. Apply the same change to loggerVerbosityToString:
eliminate its `default:` branch and list all Verbosity enum cases explicitly so
the compiler will warn when a new verbosity value is added.
include/bringauto/modules/StatusAggregator.hpp (2)

163-185: Pass device_type by value, not by const unsigned int &, for small integral types.

const unsigned int & for device_type adds indirection without benefit — unsigned int is a register-sized type that is more efficiently passed by value. This applies to all three private helpers.

♻️ Proposed fix
-	Buffer aggregateStatus(const structures::StatusAggregatorDeviceState &deviceState,
-						   const Buffer &status,
-						   const unsigned int &device_type) const;
+	Buffer aggregateStatus(const structures::StatusAggregatorDeviceState &deviceState,
+						   const Buffer &status,
+						   unsigned int device_type) const;

-	void aggregateSetStatus(structures::StatusAggregatorDeviceState &deviceState, const Buffer &status,
-							const unsigned int &device_type) const;
+	void aggregateSetStatus(structures::StatusAggregatorDeviceState &deviceState, const Buffer &status,
+							unsigned int device_type) const;

-	void aggregateSetSendStatus(structures::StatusAggregatorDeviceState &deviceState, const Buffer &status,
-								const unsigned int &device_type) const;
+	void aggregateSetSendStatus(structures::StatusAggregatorDeviceState &deviceState, const Buffer &status,
+								unsigned int device_type) const;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/bringauto/modules/StatusAggregator.hpp` around lines 163 - 185,
Change the parameter type for device_type from const unsigned int & to unsigned
int (pass by value) in the three methods aggregateStatus, aggregateSetStatus,
and aggregateSetSendStatus so small integral types are passed efficiently;
update their declarations (and any corresponding definitions/implementations) to
use unsigned int device_type instead of const unsigned int &device_type and
ensure any callers still compile with the new signature.

148-151: getDeviceTimeoutCount should be const — it's a pure accessor.

This method only reads the timeout count for a device and does not modify StatusAggregator state. Marking it const would be correct and allow it to be called on const StatusAggregator instances.

♻️ Proposed fix
-	int getDeviceTimeoutCount(const structures::DeviceIdentification& device);
+	int getDeviceTimeoutCount(const structures::DeviceIdentification& device) const;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/bringauto/modules/StatusAggregator.hpp` around lines 148 - 151, The
method getDeviceTimeoutCount is an accessor and should be marked const: update
the declaration in StatusAggregator.hpp to int getDeviceTimeoutCount(const
structures::DeviceIdentification& device) const; and also update the
corresponding implementation/definition (e.g.,
StatusAggregator::getDeviceTimeoutCount) to be const so the signatures match;
ensure any callers expecting a non-const method still work and that you rebuild
to catch mismatches.
source/bringauto/modules/ModuleHandler.cpp (1)

172-176: Prefer .at() over operator[] for safer map access.

Line 176 uses statusAggregators[moduleNumber], which would insert a default-constructed shared_ptr<StatusAggregator> if the key were absent. The contains guard at line 172 makes an actual insertion unreachable, but .at() would be more defensive and makes the intent explicit.

♻️ Proposed fix
-	const auto statusAggregator = statusAggregators[moduleNumber];
+	const auto statusAggregator = statusAggregators.at(moduleNumber);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@source/bringauto/modules/ModuleHandler.cpp` around lines 172 - 176, Replace
the use of operator[] with a bounds-checked lookup: when retrieving the
aggregator for moduleNumber from statusAggregators (in ModuleHandler.cpp around
the usage of statusAggregators and moduleNumber), use
statusAggregators.at(moduleNumber) and assign it to a const reference (e.g.,
const auto& statusAggregator) to avoid unintended insertion and extra copies;
keep the existing contains check unchanged.
source/bringauto/settings/SettingsParser.cpp (1)

130-156: const-qualified methods that mutate state through the shared_ptr — consider removing const or documenting the intent.

fillLoggingSettings, fillInternalServerSettings, fillModulePathsSettings, and fillExternalConnectionSettings are all marked const, but each of them mutates *settings_ (the Settings object pointed to by settings_). In a const member function, the shared_ptr member itself (i.e., which Settings object it points to) cannot change, but nothing prevents mutation of the underlying object. The const qualifier therefore gives a false impression that these methods are non-modifying. Since fillSettings() (line 117, non-const) is the only caller, no API break occurs, but readers may be misled into thinking callers with const SettingsParser & can invoke these methods safely.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@source/bringauto/settings/SettingsParser.cpp` around lines 130 - 156, These
helper methods (fillLoggingSettings, fillInternalServerSettings,
fillModulePathsSettings, fillExternalConnectionSettings) are declared const but
mutate the Settings object via the shared_ptr settings_; remove the misleading
const qualifier from those member functions (or if you prefer to keep them, add
clear comments/docs stating they mutate *settings_) so callers understand they
modify state; update the declarations and definitions to be non-const (or add
documentation above each method) and run a build to fix any const-call sites
(fillSettings is already non-const so it should remain unchanged).
include/bringauto/external_client/connection/communication/DummyCommunication.hpp (1)

17-17: Constructor takes const& while the base now takes by value — move optimization is lost.

ICommunicationChannel's constructor was updated this PR to take ExternalConnectionSettings by value precisely to allow callers to move into it. DummyCommunication still takes a const&, so the base always copy-constructs the settings. For consistency with the optimization intent:

♻️ Proposed fix
-    explicit DummyCommunication(const structures::ExternalConnectionSettings &settings);
+    explicit DummyCommunication(structures::ExternalConnectionSettings settings);

And in DummyCommunication.cpp:

-DummyCommunication::DummyCommunication(const structures::ExternalConnectionSettings &settings)
-    : ICommunicationChannel(settings)
+DummyCommunication::DummyCommunication(structures::ExternalConnectionSettings settings)
+    : ICommunicationChannel(std::move(settings))
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@include/bringauto/external_client/connection/communication/DummyCommunication.hpp`
at line 17, DummyCommunication's constructor currently accepts const
ExternalConnectionSettings& which prevents taking advantage of the move-friendly
ICommunicationChannel(ExternalConnectionSettings) change; update
DummyCommunication(const structures::ExternalConnectionSettings &settings) to
take the parameter by value (structures::ExternalConnectionSettings settings)
and in the implementation forward/move that parameter into the base
ICommunicationChannel constructor and any members (use std::move(settings) when
calling ICommunicationChannel(...) and assigning to members) so callers can move
settings into DummyCommunication and avoid unnecessary copies.
include/bringauto/settings/LoggerId.hpp (1)

17-28: "DEBUG" is not an explicit case — falls through silently to the default.

Since MODULE_GATEWAY_MINIMUM_LOGGER_VERBOSITY defaults to "DEBUG", the most common input is handled via the else-fallthrough rather than an explicit branch. While correct, it contradicts the doc comment's statement that the fallback is for unknown inputs, and hides intent.

♻️ Suggested explicit case
 constexpr bringauto::logging::LoggerVerbosity toLoggerVerbosity(std::string_view verbosityString) {
+    if (verbosityString == "DEBUG") {
+        return bringauto::logging::LoggerVerbosity::Debug;
+    } else if (verbosityString == "INFO") {
-    if (verbosityString == "INFO") {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/bringauto/settings/LoggerId.hpp` around lines 17 - 28, The
toLoggerVerbosity(std::string_view verbosityString) function currently relies on
fall-through to return LoggerVerbosity::Debug for "DEBUG" and unknown values;
add an explicit branch that checks for "DEBUG" and returns
bringauto::logging::LoggerVerbosity::Debug so the intent is clear and matches
the doc comment, keeping the existing final return as the unknown-input
fallback; update the function to include the explicit "DEBUG" case (referencing
toLoggerVerbosity and bringauto::logging::LoggerVerbosity) and leave the default
return behavior unchanged.
include/bringauto/structures/ModuleLibrary.hpp (1)

24-35: Explicit #include <unordered_map> recommended for clarity.

std::unordered_map is used at lines 24, 33, and 35. While the code compiles due to the transitive include from StatusAggregator.hpp (which includes <unordered_map>), explicitly including it in this header improves code clarity and avoids fragile implicit dependencies.

Suggested addition
 `#include` <bringauto/modules/ModuleManagerLibraryHandler.hpp>
 `#include` <bringauto/modules/StatusAggregator.hpp>

+#include <unordered_map>
 `#include` <memory>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/bringauto/structures/ModuleLibrary.hpp` around lines 24 - 35, Add an
explicit include for <unordered_map> in ModuleLibrary.hpp to avoid relying on
transitive includes; update the header that declares loadLibraries,
initStatusAggregators and the member maps moduleLibraryHandlers and
statusAggregators so it directly includes <unordered_map> at the top of the file
(keeping existing includes intact).
source/bringauto/external_client/connection/ExternalConnection.cpp (1)

177-197: Inconsistent map access: operator[] still used here while find() is used elsewhere.

Lines 183 and 191 still use errorAggregators_[deviceModule] directly, which default-constructs an entry if the key is absent (and invalidates iterators on unordered_map). The rest of this file was migrated to find()/end() checks. Consider applying the same pattern here for consistency and safety.

Suggested approach
+	const auto aggIt = errorAggregators_.find(deviceModule);
+	if (aggIt == errorAggregators_.end()) {
+		log::logError("Module {} not found in error aggregators", deviceModule);
+		return DEVICE_NOT_REGISTERED;
+	}
+	auto &errorAggregator = aggIt->second;
+
-	const auto &lastErrorStatusRc = errorAggregators_[deviceModule].get_error(errorBuffer, deviceIdentification);
+	const auto &lastErrorStatusRc = errorAggregator.get_error(errorBuffer, deviceIdentification);
 	...
-	const int lastStatusRc = errorAggregators_[deviceModule].get_last_status(statusBuffer, deviceIdentification);
+	const int lastStatusRc = errorAggregator.get_last_status(statusBuffer, deviceIdentification);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@source/bringauto/external_client/connection/ExternalConnection.cpp` around
lines 177 - 197, In ExternalConnection::statusMessageHandle the code uses
errorAggregators_[deviceModule] which can create a new map entry and invalidate
iterators; change to lookup via errorAggregators_.find(deviceModule), check
against end() and if missing log and return DEVICE_NOT_REGISTERED (or
appropriate error), then call get_error and get_last_status on the found
iterator's mapped value; ensure you use the iterator (e.g., it->second) for both
get_error and get_last_status to match the rest of the file's find()/end()
pattern and avoid accidental insertions.
include/bringauto/settings/LoggerWrapper.hpp (1)

34-72: if constexpr pattern doesn't fully elide the log call at compile time.

When the if constexpr branch is taken (returns early), the BaseLogger::log(...) call on the next line is still instantiated (though unreachable). An else branch or inverted condition would make the intent clearer and is more idiomatic for compile-time filtering:

if constexpr (verbosity <= logging::LoggerVerbosity::Debug) {
    BaseLogger::log(logging::LoggerVerbosity::Debug, std::forward<LogArgs>(args)...);
}

In practice, compilers optimize away the unreachable code, so this is a clarity improvement rather than a functional fix.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/bringauto/settings/LoggerWrapper.hpp` around lines 34 - 72, The
compile-time filtering pattern in LoggerWrapper's methods (e.g., logDebug,
logInfo, logWarning, logError, logCritical) should invert the constexpr
condition so the BaseLogger::log call is only instantiated inside the taken
branch; replace the existing "if constexpr (verbosity >
logging::LoggerVerbosity::<Level>) { return; } BaseLogger::log(...)" with "if
constexpr (verbosity <= logging::LoggerVerbosity::<Level>) {
BaseLogger::log(...); }" for each method to make intent explicit and avoid
instantiating the log call when excluded.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@include/bringauto/external_client/ExternalClient.hpp`:
- Line 82: Add a direct header include for unordered_map in ExternalClient.hpp
so the declaration of externalConnectionMap_ (std::unordered_map<unsigned int,
std::reference_wrapper<connection::ExternalConnection>>) does not rely on
transitive includes; open include list in ExternalClient.hpp and add `#include`
<unordered_map> near the other standard headers to make the dependency explicit
and prevent brittle compilation when upstream headers change.

In `@include/bringauto/internal_server/InternalServer.hpp`:
- Line 23: Fix the grammar in the comment inside InternalServer.hpp: change
"Messaged is send through queue to ModuleHandler, and when answer is given
resends it to Internal client." to a correct phrasing such as "Message is sent
through queue to ModuleHandler, and when an answer is given it is resent to the
internal client." Update the comment near the InternalServer
declaration/definition so it uses "Message" and "is sent" (and optionally add
"an" before "answer" and normalize "internal client" casing).

In `@include/bringauto/settings/LoggerWrapper.hpp`:
- Around line 33-72: Update the misleading comments and the copy-paste label in
LoggerWrapper.hpp: for each wrapper (logDebug, logInfo, logWarning, logError,
logCritical) change the comment to state that the call is skipped when the
wrapper's configured verbosity is higher than the message level (i.e., "Skip
logging if configured verbosity is higher than <Level>"), and in the dynamic
log(...) method replace the incorrect "Critical" reference with the correct
level/name used there so the comment matches the implemented check.

In `@include/bringauto/structures/Connection.hpp`:
- Around line 28-33: The remoteEndpointAddress() method currently calls
socket.is_open() and then socket.remote_endpoint(), which has a TOCTOU and can
throw boost::system::system_error; change remoteEndpointAddress() to call the
non-throwing overload remote_endpoint(error_code&) on the same socket object
(e.g., socket.remote_endpoint(ec)), check the resulting
boost::system::error_code (or empty/failed) and return the address string only
on success, otherwise return a safe "(N/A, socket is not open)" or a clear error
placeholder; keep references to remoteEndpointAddress(), socket,
remote_endpoint(), and is_open() to locate and update the method.

In `@source/bringauto/common_utils/EnumUtils.cpp`:
- Around line 13-15: The DUMMY branch in EnumUtils::toEnum (the if/else branch
checking toEnum == settings::Constants::DUMMY and returning
structures::ProtocolType::DUMMY) is indented with spaces while surrounding
branches (e.g., the MQTT branch) use tabs; replace the leading spaces with tabs
to match the file's indentation style so the DUMMY branch aligns with the other
else-if branches.

In `@source/bringauto/external_client/connection/ExternalConnection.cpp`:
- Around line 382-400: The iterator `it` returned in
ExternalConnection::fillErrorAggregator is potentially invalidated by
fillErrorAggregatorWithNotAckedStatuses because that method may use
errorAggregators_ operator[]; to fix, avoid using the possibly-invalidated
iterator: save the key (moduleNum) and after calling
fillErrorAggregatorWithNotAckedStatuses re-find the entry in errorAggregators_
(e.g., auto it = errorAggregators_.find(moduleNum) again) before accessing
it->second and calling add_status_to_error_aggregator, or alternatively replace
the operator[] usage in fillErrorAggregatorWithNotAckedStatuses with
errorAggregators_.at(...) so missing modules throw instead of inserting and
invalidating iterators; ensure you update references to it, moduleNum,
fillErrorAggregatorWithNotAckedStatuses, errorAggregators_, and
add_status_to_error_aggregator accordingly.

In `@source/bringauto/internal_server/InternalServer.cpp`:
- Around line 37-40: The code currently calls the throwing overload
connection->socket.set_option(keepAliveOption) and
connection->socket.set_option(noDelayOption) inside the async accept handler;
change these to the error_code overloads (e.g.,
connection->socket.set_option(option, boost::system::error_code ec)) and check
ec for errors, logging the failure and cleanly closing or abandoning connection
instead of allowing an exception to escape the accept lambda/run loop; update
the code paths around keepAliveOption, noDelayOption and the async accept
handler to handle and recover from non‑fatal set_option failures.

In `@source/bringauto/modules/StatusAggregator.cpp`:
- Around line 227-228: The getDeviceTimeoutCount implementation currently uses
deviceTimeouts_[device] which silently inserts missing keys; change
StatusAggregator::getDeviceTimeoutCount to use deviceTimeouts_.find(device) and
return 0 if not found (no insertion), and update the declaration/signature of
getDeviceTimeoutCount in the header to be const so the implementation can be
const-correct and compiled as a const method; ensure the header/signature
matches the new const implementation.

In `@source/bringauto/settings/SettingsParser.cpp`:
- Around line 228-230: The assignment to settingsName for ProtocolType::DUMMY is
dead because fillExternalConnectionSettings leaves protocolSettings empty and
the serialization loop that would use settingsName never runs; update the code
so settingsName is only set when protocolSettings is non-empty (e.g., check
protocolSettings or the vector used in the serialization loop before assigning
settingsName), or explicitly skip/annotate the DUMMY case in the switch for
ProtocolType::DUMMY (referencing ProtocolType::DUMMY, Constants::DUMMY,
settingsName, and fillExternalConnectionSettings) to make the intent clear and
remove the unreachable assignment.

In `@test/source/InternalServerTests.cpp`:
- Around line 532-533: Fix the typos in the comment block that begins "@brief
tests if server correctly disconnects if it does not receive response to connect
from module hanlder in itme" by changing "itme" to "time" and "hanlder" to
"handler" so the line reads "...response to connect from module handler in
time".

In `@test/source/testing_utils/TestHandler.cpp`:
- Line 305: Remove the now-unused method
insteadOfMessageExpectTimeoutThenError(): delete its declaration in
InternalClientForTesting.hpp and its implementation in
InternalClientForTesting.cpp (symbol: insteadOfMessageExpectTimeoutThenError) to
clean up dead code, and update any references if present; additionally, rename
runTestsWithModuleHandlerTimeout and its helpers runConnects and runStatuses to
names that reflect immediate error behavior (e.g.,
runTestsWithModuleHandlerError, runConnectsWithErrors, runStatusesWithErrors) so
their intent matches the client expecting an immediate error rather than a
timeout.

---

Outside diff comments:
In `@source/bringauto/modules/ModuleHandler.cpp`:
- Around line 15-21: In destroy(), the if(message.disconnected()) block declares
deviceId via message.getDeviceId() but never uses it, causing dead code and
compiler warnings; remove the unused variable and the empty if block (or replace
it with the intended cleanup call if you meant to act on deviceId), i.e., in the
loop over fromInternalQueue_ eliminate the no-op if(message.disconnected()) {
auto deviceId = message.getDeviceId(); } so only fromInternalQueue_->pop()
remains (or add the actual disconnect handling using message.getDeviceId()).

In `@source/bringauto/modules/StatusAggregator.cpp`:
- Around line 30-35: The current error path in StatusAggregator::aggregateStatus
returns a default-initialized aggregatedStatusBuff (Buffer {}) which contradicts
the log and overwrites device state; change the failure branch so that when
module_->aggregateStatus(aggregatedStatusBuff, currStatus, status, device_type)
!= OK you assign or return currStatus (the existing deviceState.getStatus())
instead of the empty aggregatedStatusBuff to preserve state — update the error
branch in aggregateStatus to set aggregatedStatusBuff = currStatus (or return
currStatus) so callers like aggregateSetStatus and aggregateSetSendStatus do not
receive and propagate an empty Buffer.

---

Duplicate comments:
In `@include/bringauto/modules/ModuleHandler.hpp`:
- Around line 34-97: Several methods in ModuleHandler.hpp are marked const but
visibly mutate shared state (e.g., dereferencing shared_ptrs/references); remove
the const qualifier from any method that performs observable mutations: run(),
destroy(), handleMessages(), checkTimeoutedMessages(), handleDisconnect(),
sendAggregatedStatus(), handleConnect(), sendConnectResponse(), handleStatus(),
and checkExternalQueueSize(). Update the method declarations in the header and
the corresponding definitions in the implementation file to drop the trailing
const, and adjust any callers or tests if they relied on the const signature;
alternatively, if you truly need a const method, make the mutated member(s)
mutable and document the narrower "logical const" guarantee—choose one approach
and apply it consistently for the listed methods.

---

Nitpick comments:
In `@include/bringauto/common_utils/EnumUtils.hpp`:
- Around line 31-41: Remove the `default:` branch in protocolTypeToString so the
switch only handles the explicit ProtocolType enumerators (MQTT, DUMMY, INVALID)
which enables compiler -Wswitch warnings for new enum values; keep the INVALID
case to return the empty string and ensure the function remains constexpr and
returns std::string_view for all handled cases. Apply the same change to
loggerVerbosityToString: eliminate its `default:` branch and list all Verbosity
enum cases explicitly so the compiler will warn when a new verbosity value is
added.

In
`@include/bringauto/external_client/connection/communication/DummyCommunication.hpp`:
- Line 17: DummyCommunication's constructor currently accepts const
ExternalConnectionSettings& which prevents taking advantage of the move-friendly
ICommunicationChannel(ExternalConnectionSettings) change; update
DummyCommunication(const structures::ExternalConnectionSettings &settings) to
take the parameter by value (structures::ExternalConnectionSettings settings)
and in the implementation forward/move that parameter into the base
ICommunicationChannel constructor and any members (use std::move(settings) when
calling ICommunicationChannel(...) and assigning to members) so callers can move
settings into DummyCommunication and avoid unnecessary copies.

In
`@include/bringauto/external_client/connection/messages/SentMessagesHandler.hpp`:
- Line 68: The method declaration for isDeviceConnected should match the const
and [[nodiscard]] qualifiers used by its sibling predicate isAnyDeviceConnected:
update the declaration of isDeviceConnected(const
structures::DeviceIdentification &device) to [[nodiscard]] bool
isDeviceConnected(const structures::DeviceIdentification &device) const; so the
method is marked as a non-mutating, nodiscard query (and update any
corresponding definition/implementation of
SentMessagesHandler::isDeviceConnected to include the trailing const).

In `@include/bringauto/modules/StatusAggregator.hpp`:
- Around line 163-185: Change the parameter type for device_type from const
unsigned int & to unsigned int (pass by value) in the three methods
aggregateStatus, aggregateSetStatus, and aggregateSetSendStatus so small
integral types are passed efficiently; update their declarations (and any
corresponding definitions/implementations) to use unsigned int device_type
instead of const unsigned int &device_type and ensure any callers still compile
with the new signature.
- Around line 148-151: The method getDeviceTimeoutCount is an accessor and
should be marked const: update the declaration in StatusAggregator.hpp to int
getDeviceTimeoutCount(const structures::DeviceIdentification& device) const; and
also update the corresponding implementation/definition (e.g.,
StatusAggregator::getDeviceTimeoutCount) to be const so the signatures match;
ensure any callers expecting a non-const method still work and that you rebuild
to catch mismatches.

In `@include/bringauto/settings/LoggerId.hpp`:
- Around line 17-28: The toLoggerVerbosity(std::string_view verbosityString)
function currently relies on fall-through to return LoggerVerbosity::Debug for
"DEBUG" and unknown values; add an explicit branch that checks for "DEBUG" and
returns bringauto::logging::LoggerVerbosity::Debug so the intent is clear and
matches the doc comment, keeping the existing final return as the unknown-input
fallback; update the function to include the explicit "DEBUG" case (referencing
toLoggerVerbosity and bringauto::logging::LoggerVerbosity) and leave the default
return behavior unchanged.

In `@include/bringauto/settings/LoggerWrapper.hpp`:
- Around line 34-72: The compile-time filtering pattern in LoggerWrapper's
methods (e.g., logDebug, logInfo, logWarning, logError, logCritical) should
invert the constexpr condition so the BaseLogger::log call is only instantiated
inside the taken branch; replace the existing "if constexpr (verbosity >
logging::LoggerVerbosity::<Level>) { return; } BaseLogger::log(...)" with "if
constexpr (verbosity <= logging::LoggerVerbosity::<Level>) {
BaseLogger::log(...); }" for each method to make intent explicit and avoid
instantiating the log call when excluded.

In `@include/bringauto/structures/ModuleLibrary.hpp`:
- Around line 24-35: Add an explicit include for <unordered_map> in
ModuleLibrary.hpp to avoid relying on transitive includes; update the header
that declares loadLibraries, initStatusAggregators and the member maps
moduleLibraryHandlers and statusAggregators so it directly includes
<unordered_map> at the top of the file (keeping existing includes intact).

In
`@source/bringauto/external_client/connection/communication/MqttCommunication.cpp`:
- Around line 63-71: The change to MqttCommunication::initializeConnection
altered the branch from "else if (client_ != nullptr)" to a standalone "if
(client_ != nullptr)" which is functionally equivalent but less explicitly
signaling mutual exclusivity with the earlier early-return; restore the original
"else if (client_ != nullptr)" (or add a brief clarifying comment above the
early-return) so the intent that the connected case is mutually exclusive with
the disconnected-but-existing case is clear when reading the code; ensure
references to client_, client_->is_connected(), closeConnection(), and connect()
remain unchanged.

In `@source/bringauto/external_client/connection/ExternalConnection.cpp`:
- Around line 177-197: In ExternalConnection::statusMessageHandle the code uses
errorAggregators_[deviceModule] which can create a new map entry and invalidate
iterators; change to lookup via errorAggregators_.find(deviceModule), check
against end() and if missing log and return DEVICE_NOT_REGISTERED (or
appropriate error), then call get_error and get_last_status on the found
iterator's mapped value; ensure you use the iterator (e.g., it->second) for both
get_error and get_last_status to match the rest of the file's find()/end()
pattern and avoid accidental insertions.

In `@source/bringauto/modules/ModuleHandler.cpp`:
- Around line 172-176: Replace the use of operator[] with a bounds-checked
lookup: when retrieving the aggregator for moduleNumber from statusAggregators
(in ModuleHandler.cpp around the usage of statusAggregators and moduleNumber),
use statusAggregators.at(moduleNumber) and assign it to a const reference (e.g.,
const auto& statusAggregator) to avoid unintended insertion and extra copies;
keep the existing contains check unchanged.

In `@source/bringauto/modules/StatusAggregator.cpp`:
- Around line 16-18: The early devices.contains(device) guard that returns
NOT_OK (the block at lines checking devices.contains before proceeding) is
redundant because is_device_valid(...) already ensures both
is_device_type_supported(...) and devices.contains(device); remove the
unreachable contains check and its return, and ensure callers rely on
is_device_valid (referenced by is_device_valid and devices.contains) so the
function proceeds assuming the device is present; keep any necessary null/lookup
code that actually uses devices but delete the redundant conditional and return
NOT_OK.

In `@source/bringauto/settings/SettingsParser.cpp`:
- Around line 130-156: These helper methods (fillLoggingSettings,
fillInternalServerSettings, fillModulePathsSettings,
fillExternalConnectionSettings) are declared const but mutate the Settings
object via the shared_ptr settings_; remove the misleading const qualifier from
those member functions (or if you prefer to keep them, add clear comments/docs
stating they mutate *settings_) so callers understand they modify state; update
the declarations and definitions to be non-const (or add documentation above
each method) and run a build to fix any const-call sites (fillSettings is
already non-const so it should remain unchanged).

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
source/bringauto/modules/ModuleHandler.cpp (1)

114-124: ⚠️ Potential issue | 🟠 Major

get_aggregated_status return value silently discarded — potential silent bad-data push.

Line 118 ignores the return code from get_aggregated_status, while the identical call in checkTimeoutedMessages() (line 61) explicitly checks for < 0 and bails. If the call fails, aggregatedStatusBuffer may be empty or invalid, yet the message is unconditionally pushed to toExternalQueue_ on line 120.

The PR description says "Fixed StatusAggregator::aggregateStatus returning empty buffer on error" — this addresses the producer side but doesn't remove the need for defensive handling at the consumer call site.

🛡️ Proposed fix
 	Buffer aggregatedStatusBuffer {};
-	statusAggregator->get_aggregated_status(aggregatedStatusBuffer, deviceId);
-	const auto statusMessage = common_utils::ProtobufUtils::createInternalClientStatusMessage(device, aggregatedStatusBuffer);
-	toExternalQueue_->pushAndNotify(structures::InternalClientMessage(disconnected, statusMessage));
+	const int rc = statusAggregator->get_aggregated_status(aggregatedStatusBuffer, deviceId);
+	if(rc < 0) {
+		settings::Logger::logWarning("get_aggregated_status failed with return code: {} for device {}", rc, deviceId.convertToString());
+		return;
+	}
+	const auto statusMessage = common_utils::ProtobufUtils::createInternalClientStatusMessage(device, aggregatedStatusBuffer);
+	toExternalQueue_->pushAndNotify(structures::InternalClientMessage(disconnected, statusMessage));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@source/bringauto/modules/ModuleHandler.cpp` around lines 114 - 124,
ModuleHandler::sendAggregatedStatus currently ignores the return value of
statusAggregator->get_aggregated_status which can produce an empty/invalid
aggregatedStatusBuffer and cause a bad message to be pushed to toExternalQueue_;
update sendAggregatedStatus to capture and check the return code from
get_aggregated_status (same pattern used in checkTimeoutedMessages()), and if
the return indicates failure (<0) bail out (do not create/push the
statusMessage) and optionally log an error via settings::Logger before
returning; reference statusAggregator, get_aggregated_status,
aggregatedStatusBuffer, toExternalQueue_, and
ModuleHandler::sendAggregatedStatus when implementing the change.
source/bringauto/settings/SettingsParser.cpp (1)

185-189: ⚠️ Potential issue | 🟡 Minor

Silent skip of MQTT settings on missing key masks misconfiguration.

When protocolType == MQTT, if endpoint["mqtt_settings"] is absent from the JSON, the guard at line 185 causes protocolSettings to remain empty and the endpoint is still pushed to externalConnectionSettingsList. Any downstream consumer that dereferences MQTT-specific settings (broker, port, etc.) will observe an empty map rather than a configuration error, making malformed config files difficult to diagnose.

Consider at minimum emitting a std::cerr warning (consistent with the INVALID-type warning at line 177) when !settingsName.empty() but the key is absent:

🛡️ Proposed fix
-		if(!settingsName.empty() && endpoint.find(settingsName) != endpoint.end()) {
+		if(!settingsName.empty()) {
+			if(endpoint.find(settingsName) == endpoint.end()) {
+				std::cerr << "[WARNING] Expected settings key '" << settingsName
+				          << "' not found in endpoint configuration." << std::endl;
+			} else {
 			for(auto &[key, val]: endpoint[settingsName].items()) {
 				externalConnectionSettings.protocolSettings[key] = to_string(val);
 			}
+			}
 		}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@source/bringauto/settings/SettingsParser.cpp` around lines 185 - 189, When
protocolType == MQTT and settingsName is non-empty but
endpoint.find(settingsName) == endpoint.end(), currently protocolSettings stays
empty and the endpoint is still pushed; instead emit a std::cerr warning
(matching the INVALID-type warning style around the INVALID warning near line
177) that includes settingsName and the endpoint identifier, and do not push
this malformed endpoint into externalConnectionSettingsList (or mark it invalid)
so malformed configs are surfaced; update the block around
endpoint[settingsName] handling that populates
externalConnectionSettings.protocolSettings to log the warning and skip adding
to externalConnectionSettingsList when the key is missing.
source/bringauto/internal_server/InternalServer.cpp (1)

349-365: ⚠️ Potential issue | 🟠 Major

catch(const boost::exception &) won't catch what write_some actually throws — uncaught exception will crash the caller.

boost::asio::ip::tcp::socket::write_some (when called without an error_code parameter) throws boost::system::system_error on error. boost::system::system_error derives from std::runtime_error, not boost::exception. The catch handler at line 361 therefore provides no protection: a write failure on line 353 propagates uncaught out of sendResponse.

Additionally, the write_some call at line 341 (writing the header) is outside the try/catch entirely, so it has no protection either. If it fails, the exception propagates immediately.

sendResponse is invoked from both the io_context thread (via connection handlers) and the listener thread (via validateResponse). An unhandled boost::system::system_error from either call site would propagate into io_context::run() or terminate the listener thread.

🛡️ Proposed fix — match the pattern used for set_option
-	auto data = message.SerializeAsString();
-	const uint32_t header = data.size();
-	const auto headerWSize = connection->socket.write_some(boost::asio::buffer(&header, sizeof(uint32_t)));
-	if(headerWSize != sizeof(uint32_t)) {
-		log::logError("Error in sendResponse(...): "
-					  "Cannot write message header to Internal Client, "
-					  "connection's ip address is {}",
-					  connection->remoteEndpointAddress());
-		return false;
-	}
-	try {
-		log::logDebug("Sending response to Internal Client, "
-					  "connection's ip address is {}",
-					  connection->remoteEndpointAddress());
-		const auto dataWSize = connection->socket.write_some(boost::asio::buffer(data));
-		if(dataWSize != header) {
-			log::logError("Error in sendResponse(...): "
-						  "Cannot write data to Internal Client, "
-						  "connection's ip address is {}",
-						  connection->remoteEndpointAddress());
-			return false;
-		}
-	} catch(const boost::exception &) {
-		log::logError("Error in sendResponse(...): "
-					  "Cannot write data to Internal Client");
-		return false;
-	}
+	auto data = message.SerializeAsString();
+	const uint32_t header = data.size();
+	boost::system::error_code writeEc;
+	const auto headerWSize = connection->socket.write_some(
+			boost::asio::buffer(&header, sizeof(uint32_t)), writeEc);
+	if(writeEc || headerWSize != sizeof(uint32_t)) {
+		log::logError("Error in sendResponse(...): "
+					  "Cannot write message header to Internal Client, "
+					  "connection's ip address is {}: {}",
+					  connection->remoteEndpointAddress(), writeEc.message());
+		return false;
+	}
+	log::logDebug("Sending response to Internal Client, "
+				  "connection's ip address is {}",
+				  connection->remoteEndpointAddress());
+	const auto dataWSize = connection->socket.write_some(
+			boost::asio::buffer(data), writeEc);
+	if(writeEc || dataWSize != header) {
+		log::logError("Error in sendResponse(...): "
+					  "Cannot write data to Internal Client, "
+					  "connection's ip address is {}: {}",
+					  connection->remoteEndpointAddress(), writeEc.message());
+		return false;
+	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@source/bringauto/internal_server/InternalServer.cpp` around lines 349 - 365,
The try/catch in sendResponse currently catches boost::exception but write_some
throws boost::system::system_error (so failures escape) and the initial header
write is outside the try block; fix by wrapping both header write and payload
write in the same try block and catch the correct exception type (catch const
boost::system::system_error& or catch const std::exception& to match the pattern
used in set_option), logging the error with connection->remoteEndpointAddress()
and returning false; update the try/catch around connection->socket.write_some
calls in sendResponse so both writes are protected and errors are handled
gracefully.
🧹 Nitpick comments (6)
include/bringauto/structures/Connection.hpp (1)

30-30: Explicitly include <string> for direct usage in this header.

While std::string is available transitively through DeviceIdentification.hpp, the return type on line 30 and string concatenation on line 37 directly depend on this header. Explicit inclusion improves maintainability and avoids fragility if upstream headers change.

Proposed fix
 `#include` <condition_variable>
+#include <string>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/bringauto/structures/Connection.hpp` at line 30, The header uses
std::string directly in the Connection class (notably the
remoteEndpointAddress() method and the string concatenation later) but relies on
transitive inclusion; explicitly add an include for <string> at the top of
include/bringauto/structures/Connection.hpp so std::string is directly available
for remoteEndpointAddress() and any string ops in this header (e.g., the
concatenation around line 37).
include/bringauto/settings/LoggerWrapper.hpp (1)

69-75: logCritical guard is always false but harmless.

verbosity > logging::LoggerVerbosity::Critical can never be true if Critical is the highest enum value, making the if constexpr a dead branch. This is fine for consistency across all log-level wrappers — just noting it's a no-op guard.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/bringauto/settings/LoggerWrapper.hpp` around lines 69 - 75, The
compile-time guard in logCritical is dead because
logging::LoggerVerbosity::Critical is the top value; remove the redundant if
constexpr block in the template function logCritical and simply call
BaseLogger::log(logging::LoggerVerbosity::Critical,
std::forward<LogArgs>(args)...); so the function contains a single direct call
to BaseLogger::log and no unreachable branch.
source/bringauto/modules/ModuleHandler.cpp (2)

105-107: Redundant intermediate device copy — deviceId.convertToIPDevice() suffices.

device on line 105 is a copy of deviceId created solely to call .convertToIPDevice() on line 106. Since deviceId is the same DeviceIdentification, the copy is unnecessary.

♻️ Proposed fix
-	const auto device = structures::DeviceIdentification(deviceId);
-	const auto internalProtocolDevice = device.convertToIPDevice();
+	const auto internalProtocolDevice = deviceId.convertToIPDevice();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@source/bringauto/modules/ModuleHandler.cpp` around lines 105 - 107, The local
copy named device is redundant; replace creation of device with a direct call on
deviceId: call deviceId.convertToIPDevice() and pass the result to
sendAggregatedStatus instead of using the temporary device variable (update the
call sites in ModuleHandler.cpp that reference device and ensure the converted
type from convertToIPDevice() is used directly in sendAggregatedStatus).

165-172: operator[] on statusAggregators contradicts the PR's stated goal of "avoiding operator[] silent insert" and forces non-const binding.

Line 165 uses auto & (non-const) — unlike the matching patterns in handleDisconnect (line 87) and handleConnect (line 130) which both use const auto &. The non-constness propagates to line 172 where operator[] is used. Although the contains guard on line 168 prevents an actual default-insertion at runtime, the PR commit log explicitly calls out "avoided operator[] silent insert" — this instance was missed. Switching to .at() restores consistency, makes the intent explicit, and allows the binding to be const auto &.

♻️ Proposed fix
-	auto &statusAggregators = moduleLibrary_.statusAggregators;
+	const auto &statusAggregators = moduleLibrary_.statusAggregators;
 	// ...
-	const auto statusAggregator = statusAggregators[moduleNumber];
+	const auto statusAggregator = statusAggregators.at(moduleNumber);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@source/bringauto/modules/ModuleHandler.cpp` around lines 165 - 172, The code
binds statusAggregators with a non-const reference and then uses operator[]
(statusAggregators[moduleNumber]), which contradicts the PR goal to avoid silent
inserts; change the binding to const auto& (match
handleDisconnect/handleConnect) and replace operator[] with .at() to access the
entry safely: use const auto& statusAggregators =
moduleLibrary_.statusAggregators (or keep existing name) and const auto&
statusAggregator = statusAggregators.at(moduleNumber) so you rely on the
contains check and avoid potential silent insertion from operator[].
source/bringauto/settings/SettingsParser.cpp (2)

130-193: const on fill methods is technically valid but semantically misleading.*

fillLoggingSettings, fillInternalServerSettings, fillModulePathsSettings, and fillExternalConnectionSettings are all marked const yet mutate settings_->... through the shared pointer. In C++ a const method contract guarantees the pointer itself won't be reseated, not that the pointed-to object is immutable. This compiles and runs correctly, but callers reading the header will reasonably infer these are non-mutating.

The clear intent distinction is already present: fillSettings() (non-const) reseats the pointer; the fill* helpers write through it. Consider whether dropping const from the four fill helpers would better express their mutating nature. Given this is a deliberate, widespread pattern in the PR, no change is strictly required.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@source/bringauto/settings/SettingsParser.cpp` around lines 130 - 193, These
four helper methods are marked const but they mutate the pointed-to settings
object; remove the const qualifier from SettingsParser::fillLoggingSettings,
SettingsParser::fillInternalServerSettings,
SettingsParser::fillModulePathsSettings, and
SettingsParser::fillExternalConnectionSettings to reflect their mutating
behavior. Update both the declarations (header) and the definitions (cpp) to
drop the trailing const, and run a build to fix any callsites or overrides that
assumed a const signature.

231-237: Two minor consistency issues in the serialization loop.

  1. INVALID case is dead code (lines 231–233). fillExternalConnectionSettings issues continue for INVALID/default (line 178), so no INVALID-typed endpoint ever enters externalConnectionSettingsList. The settingsName = "INVALID" branch in serializeToJson can never be reached.

  2. Loop has no guard on settingsName (lines 235–237). fillExternalConnectionSettings guards the equivalent loop with if(!settingsName.empty() ...) (line 185). Without the same guard here, a DUMMY endpoint that somehow carries a non-empty protocolSettings (e.g., constructed externally) would serialize under the key "", creating a malformed JSON entry. Adding the same guard would make the two code paths symmetric and is a low-cost defensive improvement.

♻️ Proposed fix
-		case structures::ProtocolType::INVALID:
-			settingsName = "INVALID";
-			break;
+		case structures::ProtocolType::INVALID:
+			break; // unreachable: INVALID endpoints are excluded in fillExternalConnectionSettings
 		}
-		for(const auto &[key, val]: endpoint.protocolSettings) {
-			endpointAsJson[settingsName][key] = nlohmann::json::parse(val);
+		if(!settingsName.empty()) {
+			for(const auto &[key, val]: endpoint.protocolSettings) {
+				endpointAsJson[settingsName][key] = nlohmann::json::parse(val);
+			}
 		}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@source/bringauto/settings/SettingsParser.cpp` around lines 231 - 237, The
serializeToJson code contains an unreachable INVALID branch and lacks the same
defensive guard used in fillExternalConnectionSettings; remove the dead "case
structures::ProtocolType::INVALID" branch (or leave but note it's unreachable)
and wrap the protocolSettings serialization loop with the same check used
elsewhere—i.e., only iterate when settingsName is non-empty—so in
serializeToJson around the for(const auto& [key,val] :
endpoint.protocolSettings) ensure you first verify if(!settingsName.empty())
before writing into endpointAsJson; reference symbols: serializeToJson,
fillExternalConnectionSettings, settingsName, endpoint.protocolSettings,
endpointAsJson.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@source/bringauto/modules/ModuleHandler.cpp`:
- Line 49: In checkTimeoutedMessages(), remove the unused local variable
assignment "auto moduleLibraryHandler =
moduleLibrary_.moduleLibraryHandlers.at(key);" — either delete the line entirely
or, if you still want to validate the key exists, replace it with a bare call
"moduleLibrary_.moduleLibraryHandlers.at(key);" (or use a contains/find check)
so you don't create an unused variable; refer to checkTimeoutedMessages(),
moduleLibrary_.moduleLibraryHandlers and key to locate the code.

---

Outside diff comments:
In `@source/bringauto/internal_server/InternalServer.cpp`:
- Around line 349-365: The try/catch in sendResponse currently catches
boost::exception but write_some throws boost::system::system_error (so failures
escape) and the initial header write is outside the try block; fix by wrapping
both header write and payload write in the same try block and catch the correct
exception type (catch const boost::system::system_error& or catch const
std::exception& to match the pattern used in set_option), logging the error with
connection->remoteEndpointAddress() and returning false; update the try/catch
around connection->socket.write_some calls in sendResponse so both writes are
protected and errors are handled gracefully.

In `@source/bringauto/modules/ModuleHandler.cpp`:
- Around line 114-124: ModuleHandler::sendAggregatedStatus currently ignores the
return value of statusAggregator->get_aggregated_status which can produce an
empty/invalid aggregatedStatusBuffer and cause a bad message to be pushed to
toExternalQueue_; update sendAggregatedStatus to capture and check the return
code from get_aggregated_status (same pattern used in checkTimeoutedMessages()),
and if the return indicates failure (<0) bail out (do not create/push the
statusMessage) and optionally log an error via settings::Logger before
returning; reference statusAggregator, get_aggregated_status,
aggregatedStatusBuffer, toExternalQueue_, and
ModuleHandler::sendAggregatedStatus when implementing the change.

In `@source/bringauto/settings/SettingsParser.cpp`:
- Around line 185-189: When protocolType == MQTT and settingsName is non-empty
but endpoint.find(settingsName) == endpoint.end(), currently protocolSettings
stays empty and the endpoint is still pushed; instead emit a std::cerr warning
(matching the INVALID-type warning style around the INVALID warning near line
177) that includes settingsName and the endpoint identifier, and do not push
this malformed endpoint into externalConnectionSettingsList (or mark it invalid)
so malformed configs are surfaced; update the block around
endpoint[settingsName] handling that populates
externalConnectionSettings.protocolSettings to log the warning and skip adding
to externalConnectionSettingsList when the key is missing.

---

Duplicate comments:
In `@include/bringauto/structures/Connection.hpp`:
- Around line 23-40: No change required: the remoteEndpointAddress()
implementation correctly uses socket.is_open() and the non-throwing
socket.remote_endpoint(ec) to distinguish failure modes; leave the function
(remoteEndpointAddress) and its use of socket.remote_endpoint(ec) and
ec.message() as-is so both informative diagnostics remain.

In `@source/bringauto/internal_server/InternalServer.cpp`:
- Around line 37-45: The socket option calls in InternalServer.cpp now correctly
use the non-throwing overload of connection->socket.set_option with a
boost::system::error_code (optEc) and log warnings on failure; keep the
implementation in the set_option calls for boost::asio::socket_base::keep_alive
and boost::asio::ip::tcp::no_delay as shown (retain the optEc usage and the
log::logWarning(...) calls) so the non-throwing behavior and diagnostic logging
for connection->socket are preserved.

In `@source/bringauto/modules/StatusAggregator.cpp`:
- Around line 225-230: getDeviceTimeoutCount should avoid mutating the
deviceTimeouts_ map and be callable on const objects; replace any use of
operator[] with a lookup using deviceTimeouts_.find(...) and return the found
value or 0 if not present, and mark the method const (as in
StatusAggregator::getDeviceTimeoutCount(const structures::DeviceIdentification&
device) const) so it doesn't modify state and doesn't silently insert keys into
deviceTimeouts_.

In `@source/bringauto/settings/SettingsParser.cpp`:
- Around line 228-230: Ensure the DUMMY branch in the switch handling
structures::ProtocolType::DUMMY remains a no-op: remove any leftover
settingsName = std::string(Constants::DUMMY) assignment and keep the explicit
empty case with a clarifying comment so settingsName stays empty; locate this
change where the switch on ProtocolType is implemented in SettingsParser (the
case for structures::ProtocolType::DUMMY) and preserve the current no-op
behavior.

---

Nitpick comments:
In `@include/bringauto/settings/LoggerWrapper.hpp`:
- Around line 69-75: The compile-time guard in logCritical is dead because
logging::LoggerVerbosity::Critical is the top value; remove the redundant if
constexpr block in the template function logCritical and simply call
BaseLogger::log(logging::LoggerVerbosity::Critical,
std::forward<LogArgs>(args)...); so the function contains a single direct call
to BaseLogger::log and no unreachable branch.

In `@include/bringauto/structures/Connection.hpp`:
- Line 30: The header uses std::string directly in the Connection class (notably
the remoteEndpointAddress() method and the string concatenation later) but
relies on transitive inclusion; explicitly add an include for <string> at the
top of include/bringauto/structures/Connection.hpp so std::string is directly
available for remoteEndpointAddress() and any string ops in this header (e.g.,
the concatenation around line 37).

In `@source/bringauto/modules/ModuleHandler.cpp`:
- Around line 105-107: The local copy named device is redundant; replace
creation of device with a direct call on deviceId: call
deviceId.convertToIPDevice() and pass the result to sendAggregatedStatus instead
of using the temporary device variable (update the call sites in
ModuleHandler.cpp that reference device and ensure the converted type from
convertToIPDevice() is used directly in sendAggregatedStatus).
- Around line 165-172: The code binds statusAggregators with a non-const
reference and then uses operator[] (statusAggregators[moduleNumber]), which
contradicts the PR goal to avoid silent inserts; change the binding to const
auto& (match handleDisconnect/handleConnect) and replace operator[] with .at()
to access the entry safely: use const auto& statusAggregators =
moduleLibrary_.statusAggregators (or keep existing name) and const auto&
statusAggregator = statusAggregators.at(moduleNumber) so you rely on the
contains check and avoid potential silent insertion from operator[].

In `@source/bringauto/settings/SettingsParser.cpp`:
- Around line 130-193: These four helper methods are marked const but they
mutate the pointed-to settings object; remove the const qualifier from
SettingsParser::fillLoggingSettings, SettingsParser::fillInternalServerSettings,
SettingsParser::fillModulePathsSettings, and
SettingsParser::fillExternalConnectionSettings to reflect their mutating
behavior. Update both the declarations (header) and the definitions (cpp) to
drop the trailing const, and run a build to fix any callsites or overrides that
assumed a const signature.
- Around line 231-237: The serializeToJson code contains an unreachable INVALID
branch and lacks the same defensive guard used in
fillExternalConnectionSettings; remove the dead "case
structures::ProtocolType::INVALID" branch (or leave but note it's unreachable)
and wrap the protocolSettings serialization loop with the same check used
elsewhere—i.e., only iterate when settingsName is non-empty—so in
serializeToJson around the for(const auto& [key,val] :
endpoint.protocolSettings) ensure you first verify if(!settingsName.empty())
before writing into endpointAsJson; reference symbols: serializeToJson,
fillExternalConnectionSettings, settingsName, endpoint.protocolSettings,
endpointAsJson.

@jiriskuta jiriskuta force-pushed the BAF-1122/optimizations branch from ecef0e9 to aca4baa Compare February 19, 2026 12:41
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
source/bringauto/modules/ModuleHandler.cpp (1)

113-123: ⚠️ Potential issue | 🟠 Major

get_aggregated_status return value silently discarded — may push empty/invalid buffer to external queue.

Every other call site that calls get_aggregated_status guards against negative return codes (e.g., checkTimeoutedMessages line 60-63 breaks on < 0). Here the return value is not captured at all, so an error from the aggregator results in an empty aggregatedStatusBuffer being wrapped into a status message and pushed to toExternalQueue_.

🐛 Proposed fix
 void ModuleHandler::sendAggregatedStatus(const structures::DeviceIdentification &deviceId, const ip::Device &device,
                                          bool disconnected) const {
     const auto &statusAggregator = moduleLibrary_.statusAggregators.at(deviceId.getModule());
     Buffer aggregatedStatusBuffer {};
-    statusAggregator->get_aggregated_status(aggregatedStatusBuffer, deviceId);
+    const int remainingMessages = statusAggregator->get_aggregated_status(aggregatedStatusBuffer, deviceId);
+    if(remainingMessages < 0) {
+        settings::Logger::logError("get_aggregated_status failed in sendAggregatedStatus with code: {}", remainingMessages);
+        return;
+    }
     const auto statusMessage = common_utils::ProtobufUtils::createInternalClientStatusMessage(device, aggregatedStatusBuffer);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@source/bringauto/modules/ModuleHandler.cpp` around lines 113 - 123,
ModuleHandler::sendAggregatedStatus currently ignores the return value of
statusAggregator->get_aggregated_status and may push an empty/invalid
aggregatedStatusBuffer to toExternalQueue_; capture the return value (e.g., int
rc = statusAggregator->get_aggregated_status(...)), check for rc < 0, and on
error log a descriptive message (using settings::Logger) and return/skip pushing
toExternalQueue_ instead of wrapping and pushing an invalid status; keep the
existing behavior for rc >= 0 (createInternalClientStatusMessage and push), and
reference ModuleHandler::sendAggregatedStatus,
statusAggregator->get_aggregated_status, aggregatedStatusBuffer and
toExternalQueue_ when making the change.
include/bringauto/structures/ExternalConnectionSettings.hpp (1)

34-34: ⚠️ Potential issue | 🟡 Minor

port is missing its default member initializer and uses a non-standard POSIX type.

Two issues on this line:

  1. Every other field uses {} in-class initialization (protocolType {}, serverIp {}, modules {}), but port does not. When the struct is created via non-value-initialization, port will hold an indeterminate value.
  2. u_int16_t is a POSIX extension (declared in <sys/types.h>). The portable standard-library equivalent is uint16_t from <cstdint>, which is already guaranteed by C++20.
🛡️ Proposed fix
+#include <cstdint>
 `#include` <string>
 `#include` <unordered_map>
 `#include` <vector>

 ...

-	u_int16_t port;
+	uint16_t port {};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/bringauto/structures/ExternalConnectionSettings.hpp` at line 34,
ExternalConnectionSettings::port currently uses non-portable u_int16_t and lacks
an in-class initializer; change the member declaration for port to use the
standard uint16_t type and give it an in-class default (e.g., port {}), and if
<cstdint> isn't already included in the header, add it so uint16_t is available;
update only the member declaration in the struct ExternalConnectionSettings.
🧹 Nitpick comments (7)
source/bringauto/common_utils/EnumUtils.cpp (1)

1-1: Consider adding a direct #include <bringauto/settings/Constants.hpp> include.

settings::Constants is accessible through EnumUtils.hpp's transitive include, but making the dependency explicit will improve code clarity. While the current transitive chain is stable, an explicit direct include documents the actual dependencies used in this file.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@source/bringauto/common_utils/EnumUtils.cpp` at line 1, Add an explicit
include for the settings::Constants header in EnumUtils.cpp to document the
dependency instead of relying on a transitive include; update
source/bringauto/common_utils/EnumUtils.cpp to add `#include`
<bringauto/settings/Constants.hpp> alongside the existing `#include`
<bringauto/common_utils/EnumUtils.hpp> so references to settings::Constants in
this translation unit are directly satisfied and the dependency is clear.
source/bringauto/modules/ModuleHandler.cpp (2)

160-171: operator[] remains in handleStatus — inconsistent with PR goal and rest of code.

The PR commit message explicitly states "avoided operator[] silent insert", and both handleDisconnect and handleConnect use .at() after a contains guard. handleStatus still uses operator[] (line 171). Additionally, line 164 declares statusAggregators as a non-const auto &, while the equivalent declarations in handleDisconnect (line 86) and handleConnect (line 129) are both const auto &.

Making statusAggregators const on line 164 and switching to .at() on line 171 aligns this method with the rest of the codebase.

♻️ Proposed fix
-	auto &statusAggregators = moduleLibrary_.statusAggregators;
+	const auto &statusAggregators = moduleLibrary_.statusAggregators;
 	settings::Logger::logDebug("Module handler received status from device: {}", deviceName);

 	if(not statusAggregators.contains(moduleNumber)) {
 		settings::Logger::logWarning("Module number: {} is not supported", static_cast<int>(moduleNumber));
 		return;
 	}
-	const auto statusAggregator = statusAggregators[moduleNumber];
+	const auto &statusAggregator = statusAggregators.at(moduleNumber);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@source/bringauto/modules/ModuleHandler.cpp` around lines 160 - 171, In
handleStatus, make the local reference to moduleLibrary_.statusAggregators a
const auto& (matching handleConnect/handleDisconnect) and replace the operator[]
access with .at() after the contains guard: keep the existing
contains(moduleNumber) check, change statusAggregators to const auto&
statusAggregators, and fetch the aggregator with
statusAggregators.at(moduleNumber) to avoid silent insertion; the relevant
symbols are handleStatus, statusAggregators, moduleLibrary_, contains, and at().

104-106: Eliminate redundant DeviceIdentification copy in handleDisconnect.

The device variable (line 104) is created solely to call convertToIPDevice() on line 105. Since deviceId is already a DeviceIdentification const reference and convertToIPDevice() is const-qualified, the copy is unnecessary.

♻️ Proposed fix
-	const auto device = structures::DeviceIdentification(deviceId);
-	const auto internalProtocolDevice = device.convertToIPDevice();
+	const auto internalProtocolDevice = deviceId.convertToIPDevice();
 	sendAggregatedStatus(deviceId, internalProtocolDevice, true);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@source/bringauto/modules/ModuleHandler.cpp` around lines 104 - 106, Remove
the redundant copy of DeviceIdentification in handleDisconnect: instead of
constructing a local "device" from deviceId just to call convertToIPDevice(),
call deviceId.convertToIPDevice() directly and pass its result into
sendAggregatedStatus(deviceId, ..., true); update the code using the existing
const reference deviceId and remove the unused local variable to avoid the
needless copy while preserving sendAggregatedStatus and convertToIPDevice()
usage.
include/bringauto/modules/StatusAggregator.hpp (1)

174-175: aggregateSetStatus/aggregateSetSendStatus: const qualifier is misleading alongside a non-const deviceState reference.

Both methods mutate deviceState (non-const ref) but are declared const (promising not to modify *this). This combination means:

  • They cannot be called from any other const member function (a const this yields a const map-element reference, which can't bind to StatusAggregatorDeviceState &).
  • The const label gives a false "no side effects" signal — these methods do have observable side effects through the aggregator's devices map.

aggregateStatus (line 163) takes a const ref and is const — a self-consistent pure query. For consistency and clarity, remove const from the two mutating helpers.

♻️ Proposed fix
-	void aggregateSetStatus(structures::StatusAggregatorDeviceState &deviceState, const Buffer &status,
-							const unsigned int &device_type) const;
+	void aggregateSetStatus(structures::StatusAggregatorDeviceState &deviceState, const Buffer &status,
+							const unsigned int &device_type);

-	void aggregateSetSendStatus(structures::StatusAggregatorDeviceState &deviceState, const Buffer &status,
-								const unsigned int &device_type) const;
+	void aggregateSetSendStatus(structures::StatusAggregatorDeviceState &deviceState, const Buffer &status,
+								const unsigned int &device_type);

Also applies to: 184-185

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/bringauto/modules/StatusAggregator.hpp` around lines 174 - 175, The
header declares aggregateSetStatus and aggregateSetSendStatus as const but they
take a non-const StatusAggregatorDeviceState& and mutate state; remove the
trailing const on both declarations in StatusAggregator.hpp and update their
corresponding definitions (and any forward declarations) to non-const in the
.cpp so the methods can legally modify deviceState and be called from non-const
contexts; also update any callers or member functions that assumed the
const-qualified signatures to use the updated non-const methods.
source/bringauto/settings/SettingsParser.cpp (1)

224-237: serializeToJson switch is missing a default: case, unlike its counterpart in fillExternalConnectionSettings.

The parallel switch in fillExternalConnectionSettings (line 175) uses case ProtocolType::INVALID: default: to catch unrecognized values. The serializeToJson switch handles only the three known enumerators; if a new ProtocolType is added later, settingsName will silently remain empty and the loop at line 235 will write protocol settings under endpointAsJson[""], producing malformed JSON that is hard to diagnose.

♻️ Proposed fix
 		case structures::ProtocolType::INVALID:
 			settingsName = "INVALID";
 			break;
+		default:
+			// Unknown protocol type — skip settings serialization
+			break;
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@source/bringauto/settings/SettingsParser.cpp` around lines 224 - 237, The
switch on endpoint.protocolType in serializeToJson leaves settingsName empty for
unhandled enums which can cause protocol settings to be written under an empty
key; update the switch in serializeToJson (the one handling
structures::ProtocolType values and setting settingsName) to include a default:
case that mirrors fillExternalConnectionSettings (e.g., set settingsName =
"INVALID" or otherwise handle unknown values), and/or explicitly skip writing
protocolSettings when protocolType == structures::ProtocolType::DUMMY to avoid
endpointAsJson[""] — reference the switch over endpoint.protocolType, the
settingsName variable, the endpoint.protocolSettings loop, and endpointAsJson to
locate and fix the logic.
test/source/InternalServerTests.cpp (1)

558-582: Minor doc wording: "command to status" is ambiguous.

Line 559: "does not receive command to status from module handler" reads oddly. Consider "does not receive a command in response to status from module handler in time".

📝 Proposed fix
- * `@brief` tests if server correctly disconnects if it does not receive command to status from module handler in time
+ * `@brief` tests if server correctly disconnects if it does not receive a command in response to status from module handler in time
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/source/InternalServerTests.cpp` around lines 558 - 582, The test comment
in TEST_F
InternalServerTests::TestForBehaviorWhereModuleHandlerDoesntRespondToStatus uses
ambiguous wording "command to status"; update the comment above the test to read
something clearer such as "tests if server correctly disconnects if it does not
receive a command in response to status from module handler in time" so the
intent is explicit and matches the test behavior in
runTestsWithModuleHandlerTimeout.
include/bringauto/external_client/connection/communication/DummyCommunication.hpp (1)

1-4: Consider adding direct #include for ExternalConnectionSettings.hpp to improve header self-containment.

structures::ExternalConnectionSettings is used in the constructor declaration (line 25) and is available transitively through ICommunicationChannel.hpp, which directly includes it. However, adding an explicit include makes this header more resilient to changes in the ICommunicationChannel include chain.

📝 Proposed addition
 `#include` <bringauto/external_client/connection/communication/ICommunicationChannel.hpp>
+#include <bringauto/structures/ExternalConnectionSettings.hpp>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@include/bringauto/external_client/connection/communication/DummyCommunication.hpp`
around lines 1 - 4, Add a direct include for ExternalConnectionSettings.hpp in
DummyCommunication.hpp to make the header self-contained: currently
DummyCommunication.hpp references structures::ExternalConnectionSettings in its
constructor declaration but relies on the transitive include from
ICommunicationChannel.hpp, so add an explicit `#include` for
ExternalConnectionSettings.hpp and keep the existing include of
ICommunicationChannel.hpp unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@include/bringauto/settings/LoggerWrapper.hpp`:
- Around line 28-30: LoggerWrapper::init signature changed to accept only
std::string_view (bringauto::settings::Logger::init / LoggerWrapper::init) so
tests that construct a bringauto::logging::LoggerSettings and call
Logger::init(params) must be updated: remove the LoggerSettings construction and
call Logger::init with the logger name string literal (e.g.,
"InternalServerTests"). Also fix the macro name mismatch by replacing
MODULE_GATEWAY_MINIMUM_LOGGER_VERBOSITY with the correctly defined
BRINGAUTO_MODULE_GATEWAY_MINIMUM_LOGGER_VERBOSITY (or the proper BRINGAUTO_
prefixed macro) in the listed test files (InternalServerTests.hpp,
ErrorAggregatorTests.hpp, StatusAggregatorTests.hpp,
ExternalConnectionTests.hpp) and remove any use of toLoggerVerbosity there since
the new API no longer needs it.

---

Outside diff comments:
In `@include/bringauto/structures/ExternalConnectionSettings.hpp`:
- Line 34: ExternalConnectionSettings::port currently uses non-portable
u_int16_t and lacks an in-class initializer; change the member declaration for
port to use the standard uint16_t type and give it an in-class default (e.g.,
port {}), and if <cstdint> isn't already included in the header, add it so
uint16_t is available; update only the member declaration in the struct
ExternalConnectionSettings.

In `@source/bringauto/modules/ModuleHandler.cpp`:
- Around line 113-123: ModuleHandler::sendAggregatedStatus currently ignores the
return value of statusAggregator->get_aggregated_status and may push an
empty/invalid aggregatedStatusBuffer to toExternalQueue_; capture the return
value (e.g., int rc = statusAggregator->get_aggregated_status(...)), check for
rc < 0, and on error log a descriptive message (using settings::Logger) and
return/skip pushing toExternalQueue_ instead of wrapping and pushing an invalid
status; keep the existing behavior for rc >= 0
(createInternalClientStatusMessage and push), and reference
ModuleHandler::sendAggregatedStatus, statusAggregator->get_aggregated_status,
aggregatedStatusBuffer and toExternalQueue_ when making the change.

---

Duplicate comments:
In `@source/bringauto/common_utils/EnumUtils.cpp`:
- Around line 13-14: The added else if branch checking toEnum against
settings::Constants::DUMMY and returning structures::ProtocolType::DUMMY is
correct; ensure the line uses the same tab-style indentation as the surrounding
code and keep the return value as ProtocolType::DUMMY (check identifiers:
toEnum, settings::Constants::DUMMY, structures::ProtocolType::DUMMY) so no
further changes are required.

In `@source/bringauto/modules/StatusAggregator.cpp`:
- Around line 225-230: getDeviceTimeoutCount previously risked silently
inserting a key by using operator[], so update
StatusAggregator::getDeviceTimeoutCount to perform a const lookup with
deviceTimeouts_.find(device) and return it->second if found or 0 otherwise;
ensure the method remains const and uses the member deviceTimeouts_ to avoid
side effects.

---

Nitpick comments:
In
`@include/bringauto/external_client/connection/communication/DummyCommunication.hpp`:
- Around line 1-4: Add a direct include for ExternalConnectionSettings.hpp in
DummyCommunication.hpp to make the header self-contained: currently
DummyCommunication.hpp references structures::ExternalConnectionSettings in its
constructor declaration but relies on the transitive include from
ICommunicationChannel.hpp, so add an explicit `#include` for
ExternalConnectionSettings.hpp and keep the existing include of
ICommunicationChannel.hpp unchanged.

In `@include/bringauto/modules/StatusAggregator.hpp`:
- Around line 174-175: The header declares aggregateSetStatus and
aggregateSetSendStatus as const but they take a non-const
StatusAggregatorDeviceState& and mutate state; remove the trailing const on both
declarations in StatusAggregator.hpp and update their corresponding definitions
(and any forward declarations) to non-const in the .cpp so the methods can
legally modify deviceState and be called from non-const contexts; also update
any callers or member functions that assumed the const-qualified signatures to
use the updated non-const methods.

In `@source/bringauto/common_utils/EnumUtils.cpp`:
- Line 1: Add an explicit include for the settings::Constants header in
EnumUtils.cpp to document the dependency instead of relying on a transitive
include; update source/bringauto/common_utils/EnumUtils.cpp to add `#include`
<bringauto/settings/Constants.hpp> alongside the existing `#include`
<bringauto/common_utils/EnumUtils.hpp> so references to settings::Constants in
this translation unit are directly satisfied and the dependency is clear.

In `@source/bringauto/modules/ModuleHandler.cpp`:
- Around line 160-171: In handleStatus, make the local reference to
moduleLibrary_.statusAggregators a const auto& (matching
handleConnect/handleDisconnect) and replace the operator[] access with .at()
after the contains guard: keep the existing contains(moduleNumber) check, change
statusAggregators to const auto& statusAggregators, and fetch the aggregator
with statusAggregators.at(moduleNumber) to avoid silent insertion; the relevant
symbols are handleStatus, statusAggregators, moduleLibrary_, contains, and at().
- Around line 104-106: Remove the redundant copy of DeviceIdentification in
handleDisconnect: instead of constructing a local "device" from deviceId just to
call convertToIPDevice(), call deviceId.convertToIPDevice() directly and pass
its result into sendAggregatedStatus(deviceId, ..., true); update the code using
the existing const reference deviceId and remove the unused local variable to
avoid the needless copy while preserving sendAggregatedStatus and
convertToIPDevice() usage.

In `@source/bringauto/settings/SettingsParser.cpp`:
- Around line 224-237: The switch on endpoint.protocolType in serializeToJson
leaves settingsName empty for unhandled enums which can cause protocol settings
to be written under an empty key; update the switch in serializeToJson (the one
handling structures::ProtocolType values and setting settingsName) to include a
default: case that mirrors fillExternalConnectionSettings (e.g., set
settingsName = "INVALID" or otherwise handle unknown values), and/or explicitly
skip writing protocolSettings when protocolType ==
structures::ProtocolType::DUMMY to avoid endpointAsJson[""] — reference the
switch over endpoint.protocolType, the settingsName variable, the
endpoint.protocolSettings loop, and endpointAsJson to locate and fix the logic.

In `@test/source/InternalServerTests.cpp`:
- Around line 558-582: The test comment in TEST_F
InternalServerTests::TestForBehaviorWhereModuleHandlerDoesntRespondToStatus uses
ambiguous wording "command to status"; update the comment above the test to read
something clearer such as "tests if server correctly disconnects if it does not
receive a command in response to status from module handler in time" so the
intent is explicit and matches the test behavior in
runTestsWithModuleHandlerTimeout.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@CMLibStorage.cmake`:
- Line 4: The variable STORAGE_LIST_DEP_REVISION is defined but never used;
either consume it where the storage dependency is fetched or remove it. Locate
the FetchContent/ExternalProject block that pulls in the storage/package-tracker
dependency (search for FetchContent_Declare, FetchContent_MakeAvailable,
ExternalProject_Add or the package-tracker URL) and wire
STORAGE_LIST_DEP_REVISION into the checkout by passing it as the
GIT_TAG/URL/REVISION argument (or equivalent) so the fetch uses that tag, or
delete the STORAGE_LIST_DEP_REVISION declaration from CMLibStorage.cmake if
version pinning is enforced elsewhere.

@jiriskuta jiriskuta force-pushed the BAF-1122/optimizations branch 2 times, most recently from 1211ac6 to 8e3fdbc Compare February 19, 2026 13:55
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
source/bringauto/modules/ModuleHandler.cpp (1)

164-172: ⚠️ Potential issue | 🟡 Minor

Add const qualifier and use .at() for consistency and safety.

Line 164 omits const (unlike handleDisconnect line 86 and handleConnect line 129), and line 171 uses operator[] while every other map access in this file (lines 93, 138, and the guards using contains()) follows the safer pattern with .at(). std::unordered_map::operator[] silently inserts missing keys; .at() throws instead, which is safer and more consistent with the rest of the codebase.

♻️ Proposed fix
-	auto &statusAggregators = moduleLibrary_.statusAggregators;
+	const auto &statusAggregators = moduleLibrary_.statusAggregators;
 	...
-	const auto statusAggregator = statusAggregators[moduleNumber];
+	const auto &statusAggregator = statusAggregators.at(moduleNumber);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@source/bringauto/modules/ModuleHandler.cpp` around lines 164 - 172, The
statusAggregators and moduleLibrary access here should be const and use .at()
for safety: make statusAggregators a const reference (matching
handleDisconnect/handleConnect) and replace the use of operator[] when
retrieving moduleHandler with
moduleLibrary_.moduleLibraryHandlers.at(moduleNumber) (and similarly ensure
statusAggregator is obtained via .at() if applicable) so look for the symbols
statusAggregators, moduleLibrary_.moduleLibraryHandlers, statusAggregator and
moduleHandler and change to const refs and .at() access consistent with
contains().
source/bringauto/internal_server/InternalServer.cpp (2)

104-111: ⚠️ Potential issue | 🟡 Minor

Format string mismatch: 4 {} placeholders but only 3 arguments.

The string "bufferOffset: {} is greater than bytesTransferred: {}, Invalid bufferOffset: {} received ... connection's ip address is {}" has 4 placeholders, but only bufferOffset, bytesTransferred, and connection->remoteEndpointAddress() are passed (3 args). The third {} ("Invalid bufferOffset: {}") has no corresponding argument — the bufferOffset value should be repeated. With fmt/spdlog, this will throw or produce malformed output in this error path.

🐛 Proposed fix
-        log::logError(
-                "Error in processBufferData(...): bufferOffset: {} is greater than bytesTransferred: {}, "
-                "Invalid bufferOffset: {} received from Internal Client, "
-                "connection's ip address is {}", bufferOffset, bytesTransferred, 
-                connection->remoteEndpointAddress());
+        log::logError(
+                "Error in processBufferData(...): bufferOffset: {} is greater than bytesTransferred: {}, "
+                "Invalid bufferOffset: {} received from Internal Client, "
+                "connection's ip address is {}", bufferOffset, bytesTransferred, bufferOffset,
+                connection->remoteEndpointAddress());
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@source/bringauto/internal_server/InternalServer.cpp` around lines 104 - 111,
The log call in processBufferData(...) has 4 "{}" placeholders but only 3
arguments, causing a format mismatch; update the processBufferData error log
(the log::logError call that mentions bufferOffset, bytesTransferred and
connection->remoteEndpointAddress) to pass the missing value (repeat
bufferOffset as the third argument) so the four placeholders map to
bufferOffset, bytesTransferred, bufferOffset, and
connection->remoteEndpointAddress() respectively.

340-366: ⚠️ Potential issue | 🟠 Major

Fix exception handling: use std::exception instead of boost::exception, and wrap the header write.

When Boost.Asio's write_some() throws, it throws boost::system::system_error, which inherits from std::runtime_errorstd::exception. Catching boost::exception only works if Boost is compiled with BOOST_ASIO_HAS_BOOST_THROW_EXCEPTION defined and BOOST_EXCEPTION_DISABLE disabled; otherwise the exception is thrown directly as boost::system::system_error and the catch silently fails, allowing the exception to escape and crash the server.

Additionally, the first write_some() call on line 342 (the header write) lies completely outside the try block, leaving it unprotected.

Fix:

  1. Change catch(const boost::exception &) to catch(const std::exception &) — this always works since boost::system::system_error always derives from std::exception.
  2. Move the try block to start before line 342 to protect both writes.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@source/bringauto/internal_server/InternalServer.cpp` around lines 340 - 366,
In sendResponse, the initial header write (connection->socket.write_some) is
outside the try block and the code catches boost::exception which can miss
boost::system::system_error; move the try to start before the first write_some
so both header and data writes are protected, and replace catch(const
boost::exception &) with catch(const std::exception &) so
boost::system::system_error is caught; keep the existing error logging paths
(optionally include ex.what() in logs) and ensure the return false behavior
remains unchanged.
🧹 Nitpick comments (6)
include/bringauto/modules/StatusAggregator.hpp (2)

163-165: const unsigned int &device_type — prefer pass-by-value for primitive types.

Passing unsigned int by const reference adds indirection without benefit for a trivially-copyable 4-byte type and may prevent register-based optimizations. This applies to all three helpers (aggregateStatus, aggregateSetStatus, aggregateSetSendStatus).

♻️ Proposed change (all three helpers)
-  Buffer aggregateStatus(const structures::StatusAggregatorDeviceState &deviceState,
-                         const Buffer &status,
-                         const unsigned int &device_type) const;
+  Buffer aggregateStatus(const structures::StatusAggregatorDeviceState &deviceState,
+                         const Buffer &status,
+                         unsigned int device_type) const;

-  void aggregateSetStatus(structures::StatusAggregatorDeviceState &deviceState, const Buffer &status,
-                          const unsigned int &device_type) const;
+  void aggregateSetStatus(structures::StatusAggregatorDeviceState &deviceState, const Buffer &status,
+                          unsigned int device_type) const;

-  void aggregateSetSendStatus(structures::StatusAggregatorDeviceState &deviceState, const Buffer &status,
-                              const unsigned int &device_type) const;
+  void aggregateSetSendStatus(structures::StatusAggregatorDeviceState &deviceState, const Buffer &status,
+                              unsigned int device_type) const;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/bringauto/modules/StatusAggregator.hpp` around lines 163 - 165,
Change the three helper signatures to pass the primitive device_type by value
instead of by const reference: update aggregateStatus, aggregateSetStatus, and
aggregateSetSendStatus to take unsigned int device_type (not const unsigned int&
device_type); adjust any corresponding declarations/definitions and call sites
if needed to match the new signature so callers continue to compile.

174-185: const on aggregateSetStatus / aggregateSetSendStatus is technically valid but semantically a no-op.

Both methods take deviceState as a non-const reference and mutate it. Because devices (line 194) becomes const in any const StatusAggregator context, its elements cannot bind to a non-const deviceState& parameter — these helpers can never legitimately be called on a const StatusAggregator instance regardless of the trailing const. The qualifier therefore provides no new call-site flexibility and may mislead readers into thinking the methods are side-effect free.

If the intent is only to prevent accidental writes to other members of *this inside these helpers, a doc comment to that effect (or removing the const) would be clearer.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/bringauto/modules/StatusAggregator.hpp` around lines 174 - 185, The
trailing const on aggregateSetStatus and aggregateSetSendStatus is misleading
because both accept a non-const reference to
structures::StatusAggregatorDeviceState and mutate it, which prevents these
methods from being callable on a const StatusAggregator; remove the trailing
const from the declarations of aggregateSetStatus and aggregateSetSendStatus
(and their definitions/implementations) so their signatures correctly reflect
that they mutate state (or alternatively add a clarifying doc comment if you
intentionally want to keep the methods non-mutating of *this while modifying
deviceState), and ensure consistency with the member devices usage that cannot
bind to a non-const deviceState when StatusAggregator is const.
source/bringauto/settings/SettingsParser.cpp (2)

130-130: fill* methods are misleadingly const — they mutate state through shared_ptr indirection.

In C++, const on a member function makes this a pointer-to-const, so settings_ becomes const std::shared_ptr<Settings>. However, std::shared_ptr<T>::operator->() const returns T* (not const T*), meaning all writes through settings_->… still compile and execute. These four methods genuinely modify the Settings object; the const qualifier only prevents rebinding settings_ itself (a trivially weak guarantee here).

The three truly non-mutating methods — areCmdArgumentsCorrect(), areSettingsCorrect(), and serializeToJson() — are correctly const. For the fill* methods, consider dropping the const qualifier to accurately reflect their mutating semantics:

♻️ Proposed fix
-void SettingsParser::fillLoggingSettings(const nlohmann::json &file) const {
+void SettingsParser::fillLoggingSettings(const nlohmann::json &file) {
-void SettingsParser::fillInternalServerSettings(const nlohmann::json &file) const {
+void SettingsParser::fillInternalServerSettings(const nlohmann::json &file) {
-void SettingsParser::fillModulePathsSettings(const nlohmann::json &file) const {
+void SettingsParser::fillModulePathsSettings(const nlohmann::json &file) {
-void SettingsParser::fillExternalConnectionSettings(const nlohmann::json &file) const {
+void SettingsParser::fillExternalConnectionSettings(const nlohmann::json &file) {

The corresponding header declarations in include/bringauto/settings/SettingsParser.hpp (snippets 1–4, lines 52, 54, 56, 58) would need matching updates.

Also applies to: 144-144, 152-152, 158-158

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@source/bringauto/settings/SettingsParser.cpp` at line 130, The four mutating
"fill" methods (e.g., SettingsParser::fillLoggingSettings,
SettingsParser::fillSerialSettings, SettingsParser::fillJoystickSettings,
SettingsParser::fillGamepadSettings) are incorrectly declared/defined as const;
remove the trailing const from each method definition and update the matching
declarations in SettingsParser.hpp so they are non-const, ensuring the methods
accurately reflect that they mutate the Settings object via settings_.hpp/impl
updates must be consistent between header and source.

235-237: Serialization loop lacks the !settingsName.empty() guard present on the fill side.

Line 185 guards protocol-settings access with !settingsName.empty(). The corresponding serialization loop at lines 235–237 has no such guard. Currently safe — the fill guard ensures DUMMY endpoints always have an empty protocolSettings map, so the loop body never executes for them. But if that invariant ever breaks (e.g., a future code path populates protocolSettings for a DUMMY endpoint), endpointAsJson[""] would be silently written into the JSON output.

Adding a matching guard brings the serialization side into defensive parity with the fill side:

♻️ Proposed fix
-        for(const auto &[key, val]: endpoint.protocolSettings) {
-            endpointAsJson[settingsName][key] = nlohmann::json::parse(val);
-        }
+        if(!settingsName.empty()) {
+            for(const auto &[key, val]: endpoint.protocolSettings) {
+                endpointAsJson[settingsName][key] = nlohmann::json::parse(val);
+            }
+        }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@source/bringauto/settings/SettingsParser.cpp` around lines 235 - 237, The
serialization loop writes endpointAsJson[settingsName][key] =
nlohmann::json::parse(val) without checking settingsName; add the same defensive
guard used during fill so we only iterate protocolSettings when settingsName is
non-empty. Concretely, wrap the loop that visits endpoint.protocolSettings with
if (!settingsName.empty()) { ... } (referencing variables/settingsName,
endpoint.protocolSettings, endpointAsJson) so DUMMY or empty-named endpoints
cannot create endpointAsJson[""] entries.
source/bringauto/modules/ModuleHandler.cpp (1)

104-106: Unnecessary intermediate copy of DeviceIdentification.

device (line 104) is a copy of deviceId used solely to call convertToIPDevice() on line 105. The copy serves no purpose; call it directly on deviceId.

♻️ Proposed fix
-	const auto device = structures::DeviceIdentification(deviceId);
-	const auto internalProtocolDevice = device.convertToIPDevice();
+	const auto internalProtocolDevice = deviceId.convertToIPDevice();
 	sendAggregatedStatus(deviceId, internalProtocolDevice, true);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@source/bringauto/modules/ModuleHandler.cpp` around lines 104 - 106, Remove
the unnecessary copy of DeviceIdentification: instead of creating the temporary
variable device from structures::DeviceIdentification(deviceId) solely to call
convertToIPDevice(), call convertToIPDevice() directly from the deviceId-derived
DeviceIdentification expression and pass the resulting internalProtocolDevice to
sendAggregatedStatus. Update the code around DeviceIdentification,
convertToIPDevice, and sendAggregatedStatus so there is no unused intermediate
variable named device and internalProtocolDevice is produced directly from the
expression using deviceId.
include/bringauto/settings/LoggerId.hpp (1)

17-28: toLoggerVerbosity silently falls back to Debug for any unrecognized string.

An invalid macro value (e.g., a typo like "DEBUGG" in CMake) would silently produce the Debug level with no compile-time diagnostic. Since the values are constrained by CMake's STRINGS property this is low-risk in practice, but a static_assert would make bad values immediately visible at build time.

♻️ Suggested improvement
 constexpr bringauto::logging::LoggerVerbosity toLoggerVerbosity(std::string_view verbosityString) {
-    if (verbosityString == "INFO") {
+    if (verbosityString == "DEBUG") {
+        return bringauto::logging::LoggerVerbosity::Debug;
+    } else if (verbosityString == "INFO") {
         return bringauto::logging::LoggerVerbosity::Info;
     } else if (verbosityString == "WARNING") {
         return bringauto::logging::LoggerVerbosity::Warning;
     } else if (verbosityString == "ERROR") {
         return bringauto::logging::LoggerVerbosity::Error;
     } else if (verbosityString == "CRITICAL") {
         return bringauto::logging::LoggerVerbosity::Critical;
     }
-    return bringauto::logging::LoggerVerbosity::Debug;
+    // unreachable for valid CMake-defined values; static_assert catches typos at compile time
+    return bringauto::logging::LoggerVerbosity::Debug; // satisfies constexpr return requirement
 }

Then add a guard at the usage site:

static_assert(
    toLoggerVerbosity(BRINGAUTO_MODULE_GATEWAY_MINIMUM_LOGGER_VERBOSITY) != 
    toLoggerVerbosity("__invalid__"),
    "BRINGAUTO_MODULE_GATEWAY_MINIMUM_LOGGER_VERBOSITY must be one of: DEBUG, INFO, WARNING, ERROR, CRITICAL"
);

(A cleaner approach requires a sentinel/invalid enum value, but the principle stands.)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/bringauto/settings/LoggerId.hpp` around lines 17 - 28,
toLoggerVerbosity currently returns Debug for unknown strings causing silent
acceptance of bad macro values; change this so invalid input is detected at
compile-time by adding a sentinel enum value (e.g., LoggerVerbosity::Invalid) to
bringauto::logging::LoggerVerbosity, update toLoggerVerbosity to return
LoggerVerbosity::Invalid for unrecognized strings, and then add a static_assert
at each usage site (e.g., comparing
toLoggerVerbosity(BRINGAUTO_MODULE_GATEWAY_MINIMUM_LOGGER_VERBOSITY) !=
LoggerVerbosity::Invalid) so mis-typed CMake STRINGS produce a build error;
reference symbols: LoggerVerbosity, toLoggerVerbosity,
BRINGAUTO_MODULE_GATEWAY_MINIMUM_LOGGER_VERBOSITY.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@source/bringauto/internal_server/InternalServer.cpp`:
- Around line 104-111: The log call in processBufferData(...) has 4 "{}"
placeholders but only 3 arguments, causing a format mismatch; update the
processBufferData error log (the log::logError call that mentions bufferOffset,
bytesTransferred and connection->remoteEndpointAddress) to pass the missing
value (repeat bufferOffset as the third argument) so the four placeholders map
to bufferOffset, bytesTransferred, bufferOffset, and
connection->remoteEndpointAddress() respectively.
- Around line 340-366: In sendResponse, the initial header write
(connection->socket.write_some) is outside the try block and the code catches
boost::exception which can miss boost::system::system_error; move the try to
start before the first write_some so both header and data writes are protected,
and replace catch(const boost::exception &) with catch(const std::exception &)
so boost::system::system_error is caught; keep the existing error logging paths
(optionally include ex.what() in logs) and ensure the return false behavior
remains unchanged.

In `@source/bringauto/modules/ModuleHandler.cpp`:
- Around line 164-172: The statusAggregators and moduleLibrary access here
should be const and use .at() for safety: make statusAggregators a const
reference (matching handleDisconnect/handleConnect) and replace the use of
operator[] when retrieving moduleHandler with
moduleLibrary_.moduleLibraryHandlers.at(moduleNumber) (and similarly ensure
statusAggregator is obtained via .at() if applicable) so look for the symbols
statusAggregators, moduleLibrary_.moduleLibraryHandlers, statusAggregator and
moduleHandler and change to const refs and .at() access consistent with
contains().

---

Nitpick comments:
In `@include/bringauto/modules/StatusAggregator.hpp`:
- Around line 163-165: Change the three helper signatures to pass the primitive
device_type by value instead of by const reference: update aggregateStatus,
aggregateSetStatus, and aggregateSetSendStatus to take unsigned int device_type
(not const unsigned int& device_type); adjust any corresponding
declarations/definitions and call sites if needed to match the new signature so
callers continue to compile.
- Around line 174-185: The trailing const on aggregateSetStatus and
aggregateSetSendStatus is misleading because both accept a non-const reference
to structures::StatusAggregatorDeviceState and mutate it, which prevents these
methods from being callable on a const StatusAggregator; remove the trailing
const from the declarations of aggregateSetStatus and aggregateSetSendStatus
(and their definitions/implementations) so their signatures correctly reflect
that they mutate state (or alternatively add a clarifying doc comment if you
intentionally want to keep the methods non-mutating of *this while modifying
deviceState), and ensure consistency with the member devices usage that cannot
bind to a non-const deviceState when StatusAggregator is const.

In `@include/bringauto/settings/LoggerId.hpp`:
- Around line 17-28: toLoggerVerbosity currently returns Debug for unknown
strings causing silent acceptance of bad macro values; change this so invalid
input is detected at compile-time by adding a sentinel enum value (e.g.,
LoggerVerbosity::Invalid) to bringauto::logging::LoggerVerbosity, update
toLoggerVerbosity to return LoggerVerbosity::Invalid for unrecognized strings,
and then add a static_assert at each usage site (e.g., comparing
toLoggerVerbosity(BRINGAUTO_MODULE_GATEWAY_MINIMUM_LOGGER_VERBOSITY) !=
LoggerVerbosity::Invalid) so mis-typed CMake STRINGS produce a build error;
reference symbols: LoggerVerbosity, toLoggerVerbosity,
BRINGAUTO_MODULE_GATEWAY_MINIMUM_LOGGER_VERBOSITY.

In `@source/bringauto/modules/ModuleHandler.cpp`:
- Around line 104-106: Remove the unnecessary copy of DeviceIdentification:
instead of creating the temporary variable device from
structures::DeviceIdentification(deviceId) solely to call convertToIPDevice(),
call convertToIPDevice() directly from the deviceId-derived DeviceIdentification
expression and pass the resulting internalProtocolDevice to
sendAggregatedStatus. Update the code around DeviceIdentification,
convertToIPDevice, and sendAggregatedStatus so there is no unused intermediate
variable named device and internalProtocolDevice is produced directly from the
expression using deviceId.

In `@source/bringauto/settings/SettingsParser.cpp`:
- Line 130: The four mutating "fill" methods (e.g.,
SettingsParser::fillLoggingSettings, SettingsParser::fillSerialSettings,
SettingsParser::fillJoystickSettings, SettingsParser::fillGamepadSettings) are
incorrectly declared/defined as const; remove the trailing const from each
method definition and update the matching declarations in SettingsParser.hpp so
they are non-const, ensuring the methods accurately reflect that they mutate the
Settings object via settings_.hpp/impl updates must be consistent between header
and source.
- Around line 235-237: The serialization loop writes
endpointAsJson[settingsName][key] = nlohmann::json::parse(val) without checking
settingsName; add the same defensive guard used during fill so we only iterate
protocolSettings when settingsName is non-empty. Concretely, wrap the loop that
visits endpoint.protocolSettings with if (!settingsName.empty()) { ... }
(referencing variables/settingsName, endpoint.protocolSettings, endpointAsJson)
so DUMMY or empty-named endpoints cannot create endpointAsJson[""] entries.

@jiriskuta jiriskuta force-pushed the BAF-1122/optimizations branch 3 times, most recently from 4e9399e to 5086af0 Compare February 20, 2026 11:49
@jiriskuta jiriskuta force-pushed the BAF-1122/optimizations branch from 5086af0 to 4682161 Compare February 20, 2026 12:00
jiriskuta and others added 2 commits February 20, 2026 13:16
- Fixed StatusAggregator::aggregateStatus returning empty buffer on error
- Removed unreachable contains() check in clear_device
- Fixed getDeviceTimeoutCount using operator[] (silent insert); marked const
- Fixed Connection::remoteEndpointAddress using throwing remote_endpoint
- Fixed InternalServer set_option using throwing overload in async handler
- Removed dead code (unused deviceId) in ModuleHandler::destroy
- Fixed LoggerWrapper::init to take only logger name; verbosity is always
  the compile-time template parameter
- Renamed MODULE_GATEWAY_MINIMUM_LOGGER_VERBOSITY to
  BRINGAUTO_MODULE_GATEWAY_MINIMUM_LOGGER_VERBOSITY; added STRINGS validation
- Fixed misleading comments in LoggerWrapper
- Fixed mixed indentation in EnumUtils.cpp DUMMY branch
- Added per-value docs to ProtocolType enum with DUMMY reconnect-loop warning
- Removed dead settingsName assignment for DUMMY in serializeToJson
- Removed pointless sync_with_stdio/cin.tie and unused include from main.cpp

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Increased version of cxxopts from v3.0.5 to v3.1.1
Increased version of nlohmann_json from v3.2.0 to v3.10.5
@jiriskuta jiriskuta force-pushed the BAF-1122/optimizations branch from 4682161 to d0e9cc8 Compare February 20, 2026 12:16
@jiriskuta jiriskuta assigned jiriskuta and unassigned MarioIvancik Feb 20, 2026
@jiriskuta jiriskuta requested a review from koudis February 20, 2026 12:37
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (3)
source/bringauto/modules/ModuleHandler.cpp (1)

57-64: Consider consistent const-correctness in this loop.

For consistency with the PR's const-correctness theme, device in the loop and internalProtocolDevice could both be const-qualified since neither is modified:

♻️ Suggested improvement
-		for (auto &device: unique_devices) {
+		for (const auto &device: unique_devices) {
 			while(true) {
 				Buffer aggregatedStatusBuffer {};
 				const int remainingMessages = statusAggregator->get_aggregated_status(aggregatedStatusBuffer, device);
 				if(remainingMessages < 0) {
 					break;
 				}
-				auto internalProtocolDevice = device.convertToIPDevice();
+				const auto internalProtocolDevice = device.convertToIPDevice();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@source/bringauto/modules/ModuleHandler.cpp` around lines 57 - 64, The loop
should use const-correctness: change the range-loop variable over unique_devices
to a const reference (e.g., "const auto &device") and also make the result of
device.convertToIPDevice() a const-qualified local (e.g., "const auto
internalProtocolDevice") in the block where Buffer aggregatedStatusBuffer is
created and statusAggregator->get_aggregated_status(...) is called; this
preserves immutability for device and internalProtocolDevice in
ModuleHandler.cpp without changing behavior.
include/bringauto/structures/Connection.hpp (1)

23-40: Good safety improvement using the non-throwing remote_endpoint() overload.

The implementation correctly addresses the TOCTOU race condition by using the error_code overload. One minor observation: the socket.is_open() check on line 31 is now redundant since remote_endpoint(ec) will set ec if the socket isn't open. You could simplify by removing the preliminary check:

Optional simplification
 [[nodiscard]]
 std::string remoteEndpointAddress() const {
-    if (!socket.is_open()) {
-        return "(N/A, socket is not open)";
-    }
     boost::system::error_code ec;
     const auto ep = socket.remote_endpoint(ec);
     if (ec) {
-        return "(N/A, no remote endpoint: " + ec.message() + ")";
+        return "(N/A, " + ec.message() + ")";
     }
     return ep.address().to_string();
 }

,

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/bringauto/structures/Connection.hpp` around lines 23 - 40, The
socket.is_open() pre-check in remoteEndpointAddress() is redundant because
socket.remote_endpoint(ec) will set ec when the socket isn't open; remove the if
(!socket.is_open()) branch and rely solely on boost::system::error_code ec from
socket.remote_endpoint(ec) to detect and return the diagnostic string, keeping
the existing ec.message() handling and final ep.address().to_string() return
path.
source/bringauto/modules/StatusAggregator.cpp (1)

95-102: Inconsistent use of device and deviceId in lambda.

The lambda captures device by value but also receives deviceId as a parameter. These should be identical at runtime, but using both creates confusion. Line 98 uses the captured device while line 99 uses the parameter deviceId.

Consider using the parameter deviceId consistently to avoid confusion and eliminate the unnecessary capture.

♻️ Proposed fix
-		const std::function<int(const structures::DeviceIdentification&)> timeouted_force_aggregation = [device, this](
+		const std::function<int(const structures::DeviceIdentification&)> timeouted_force_aggregation = [this](
 				const structures::DeviceIdentification& deviceId) {
 					timeoutedMessageReady_.store(true);
-					deviceTimeouts_[device]++;
+					deviceTimeouts_[deviceId]++;
 					return force_aggregation_on_device(deviceId);
 		};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@source/bringauto/modules/StatusAggregator.cpp` around lines 95 - 102, The
lambda timeouted_force_aggregation inconsistently uses the captured variable
device and the parameter deviceId; remove the unnecessary capture of device and
use the parameter deviceId everywhere inside the lambda (e.g., increment
deviceTimeouts_[deviceId] and call force_aggregation_on_device(deviceId)),
keeping the capture of this only. Update the lambda capture list and body
accordingly so it consistently references deviceId and avoids mixing captured
and parameter names.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@include/bringauto/modules/StatusAggregator.hpp`:
- Around line 146-151: The doc for getDeviceTimeoutCount still refers to a
“unique key from getId” but the parameter is now a
structures::DeviceIdentification; update the parameter description to state that
it accepts a DeviceIdentification object (from Protobuf/device identity
structures) and describe which fields are used (e.g., device id/namespace or the
exact identification fields returned by ProtobufUtils::getId) and what callers
should supply; also update the brief to clarify it returns the timeout count for
that DeviceIdentification rather than for a string key.
- Around line 174-175: The method declarations aggregateSetStatus and
aggregateSetSendStatus wrongly have a trailing const despite mutating the
deviceState via setStatus()/setStatusAndResetTimer(); remove the const qualifier
from both method signatures in StatusAggregator.hpp so the declarations match
their mutating behavior and implementation, updating the signatures for
aggregateSetStatus(structures::StatusAggregatorDeviceState &deviceState, const
Buffer &status, const unsigned int &device_type) and
aggregateSetSendStatus(structures::StatusAggregatorDeviceState &deviceState,
const Buffer &status, const unsigned int &device_type) accordingly.

In `@include/bringauto/structures/ExternalConnectionSettings.hpp`:
- Around line 3-5: Replace the non-standard, uninitialized u_int16_t port in the
ExternalConnectionSettings struct with a standard, default-initialized type: add
`#include` <cstdint> to the includes and change the member to std::uint16_t
port{0}; so it matches the other {}-initialized members (e.g., host, username)
and avoids using the platform-specific u_int16_t.

---

Nitpick comments:
In `@include/bringauto/structures/Connection.hpp`:
- Around line 23-40: The socket.is_open() pre-check in remoteEndpointAddress()
is redundant because socket.remote_endpoint(ec) will set ec when the socket
isn't open; remove the if (!socket.is_open()) branch and rely solely on
boost::system::error_code ec from socket.remote_endpoint(ec) to detect and
return the diagnostic string, keeping the existing ec.message() handling and
final ep.address().to_string() return path.

In `@source/bringauto/modules/ModuleHandler.cpp`:
- Around line 57-64: The loop should use const-correctness: change the
range-loop variable over unique_devices to a const reference (e.g., "const auto
&device") and also make the result of device.convertToIPDevice() a
const-qualified local (e.g., "const auto internalProtocolDevice") in the block
where Buffer aggregatedStatusBuffer is created and
statusAggregator->get_aggregated_status(...) is called; this preserves
immutability for device and internalProtocolDevice in ModuleHandler.cpp without
changing behavior.

In `@source/bringauto/modules/StatusAggregator.cpp`:
- Around line 95-102: The lambda timeouted_force_aggregation inconsistently uses
the captured variable device and the parameter deviceId; remove the unnecessary
capture of device and use the parameter deviceId everywhere inside the lambda
(e.g., increment deviceTimeouts_[deviceId] and call
force_aggregation_on_device(deviceId)), keeping the capture of this only. Update
the lambda capture list and body accordingly so it consistently references
deviceId and avoids mixing captured and parameter names.

@jiriskuta jiriskuta force-pushed the BAF-1122/optimizations branch from 1a24844 to 967b413 Compare February 20, 2026 13:15
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
source/bringauto/settings/SettingsParser.cpp (1)

235-237: ⚠️ Potential issue | 🟡 Minor

serializeToJson() loop missing guard for empty settingsName.

The parse side at line 185 correctly guards if(!settingsName.empty() && ...) before accessing endpoint[settingsName]. The serialize side has no equivalent guard: if settingsName is empty and protocolSettings is non-empty for any reason, endpointAsJson[""][key] produces malformed JSON. Currently safe only because DUMMY endpoints always arrive with empty protocolSettings, but this asymmetry is a latent bug.

🔧 Proposed fix — add guard before the loop
-		for(const auto &[key, val]: endpoint.protocolSettings) {
-			endpointAsJson[settingsName][key] = nlohmann::json::parse(val);
-		}
+		if(!settingsName.empty()) {
+			for(const auto &[key, val]: endpoint.protocolSettings) {
+				endpointAsJson[settingsName][key] = nlohmann::json::parse(val);
+			}
+		}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@source/bringauto/settings/SettingsParser.cpp` around lines 235 - 237,
serializeToJson() writes protocolSettings into endpointAsJson using settingsName
without checking for an empty settingsName; add a guard equivalent to the parse
side: only iterate and assign endpoint.protocolSettings into
endpointAsJson[settingsName] when !settingsName.empty() and
endpoint.protocolSettings is non-empty. Wrap the for(const auto& [key,val]:
endpoint.protocolSettings) loop in that conditional (using the existing
settingsName variable and endpoint.protocolSettings) to avoid producing
endpointAsJson[""] entries.
🧹 Nitpick comments (3)
source/bringauto/modules/ModuleHandler.cpp (1)

174-177: const on statusBuffer is shallow — contents are mutated by copyStatusToBuffer.

constructBuffer allocates a writable buffer whose contents are then filled by copyStatusToBuffer on line 176. Marking it const is technically valid (the wrapper's pointer member isn't reassigned), but it is misleading to readers since the buffer's payload is mutated. Consider dropping const here to signal intent, or at minimum add a brief comment.

♻️ Suggested diff
-	const auto statusBuffer = moduleHandler->constructBuffer(statusData.size());
+	auto statusBuffer = moduleHandler->constructBuffer(statusData.size());
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@source/bringauto/modules/ModuleHandler.cpp` around lines 174 - 177, The
variable statusBuffer (returned from
moduleHandler->constructBuffer(statusData.size())) is marked const but its
contents are mutated by common_utils::ProtobufUtils::copyStatusToBuffer(status,
statusBuffer); remove the const qualifier from the statusBuffer declaration in
ModuleHandler.cpp so the mutability of the buffer's payload is clear (or if you
must keep const, add a concise comment above the declaration explaining that the
wrapper is immutable while its internal payload is mutated by
copyStatusToBuffer).
include/bringauto/structures/Connection.hpp (1)

30-30: Re-add #include <string> after removing it from the header.

remoteEndpointAddress() returns std::string, but the explicit #include <string> was removed. It currently compiles only via transitive inclusion through DeviceIdentification.hpp or Boost, which is fragile and may break with future header changes.

🔧 Proposed fix
 `#include` <bringauto/structures/DeviceIdentification.hpp>
 `#include` <bringauto/settings/Constants.hpp>
 `#include` <boost/asio.hpp>
+#include <string>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/bringauto/structures/Connection.hpp` at line 30, The header defines
remoteEndpointAddress() which returns std::string but no longer includes
<string>; restore a direct include by adding `#include` <string> at the top of
Connection.hpp so the declaration of remoteEndpointAddress() doesn't rely on
transitive includes (modify Connection.hpp to include <string> and leave the
remoteEndpointAddress() declaration unchanged).
source/bringauto/internal_server/InternalServer.cpp (1)

335-368: write_some may silently drop large messages — prefer boost::asio::write.

write_some is a single non-looping call that may return fewer bytes than requested on a large payload. The new check at lines 344 and 355 correctly detects this and returns false, but that causes the connection to be torn down for what may be a transient, benign partial write. boost::asio::write loops internally until the full buffer is transferred (or throws/errors), which is the semantically correct primitive for a synchronous "send the complete message" operation.

♻️ Proposed refactor
-		const auto headerWSize = connection->socket.write_some(boost::asio::buffer(&header, sizeof(uint32_t)));
-		if(headerWSize != sizeof(uint32_t)) {
-			log::logError("Error in sendResponse(...): "
-						  "Cannot write message header to Internal Client, "
-						  "connection's ip address is {}",
-						  connection->remoteEndpointAddress());
-			return false;
-		}
+		boost::system::error_code writeEc;
+		boost::asio::write(connection->socket, boost::asio::buffer(&header, sizeof(uint32_t)), writeEc);
+		if(writeEc) {
+			log::logError("Error in sendResponse(...): "
+						  "Cannot write message header to Internal Client: {}, "
+						  "connection's ip address is {}",
+						  writeEc.message(), connection->remoteEndpointAddress());
+			return false;
+		}
 		log::logDebug("Sending response to Internal Client, "
 					  "connection's ip address is {}",
 					  connection->remoteEndpointAddress());
-		const auto dataWSize = connection->socket.write_some(boost::asio::buffer(data));
-		if(dataWSize != header) {
-			log::logError("Error in sendResponse(...): "
-						  "Cannot write data to Internal Client, "
-						  "connection's ip address is {}",
-						  connection->remoteEndpointAddress());
-			return false;
-		}
-	} catch(const std::exception &ex) {
+		boost::asio::write(connection->socket, boost::asio::buffer(data), writeEc);
+		if(writeEc) {
+			log::logError("Error in sendResponse(...): "
+						  "Cannot write data to Internal Client: {}, "
+						  "connection's ip address is {}",
+						  writeEc.message(), connection->remoteEndpointAddress());
+			return false;
+		}
+	} catch(const std::exception &ex) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@source/bringauto/internal_server/InternalServer.cpp` around lines 335 - 368,
The current InternalServer::sendResponse uses connection->socket.write_some for
both the header and payload which can perform partial writes; replace these
calls with boost::asio::write to ensure the full header
(boost::asio::buffer(&header, sizeof(uint32_t))) and the full payload
(boost::asio::buffer(data)) are written atomically by looping internally, remove
the manual size checks against headerWSize/dataWSize (since boost::asio::write
throws on failure), and keep the existing try/catch around the write calls so
exceptions (ex.what()) are logged and the function returns false on error.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@include/bringauto/settings/LoggerWrapper.hpp`:
- Around line 9-11: The doc comment for the LoggerWrapper class contains a typo:
change "bellow" to "below" in the class comment in LoggerWrapper.hpp (the
comment above the LoggerWrapper class declaration) so it reads "below the set
verbosity level" instead of "bellow the set verbosity level."

In `@include/bringauto/structures/ExternalConnectionSettings.hpp`:
- Around line 15-25: The ProtocolType enum's INVALID sentinel is -1 but a
value-initialized member protocolType {} ends up as MQTT (0); update the
ExternalConnectionSettings member default to explicitly initialize protocolType
to ProtocolType::INVALID so a default-constructed ExternalConnectionSettings
yields the error sentinel (replace the current protocolType {} default with
ProtocolType::INVALID).

In `@source/bringauto/internal_server/InternalServer.cpp`:
- Around line 269-272: handleDisconnect currently calls findConnection and
removeConnFromMap which access connectedDevices_ without locking serverMutex_,
causing a data race with other handlers (asyncReceiveHandler, handleConnection,
validateResponse) run by io_context threads; fix by acquiring serverMutex_
(std::scoped_lock or std::lock_guard on serverMutex_) at the start of
InternalServer::handleDisconnect (or modify findConnection/removeConnFromMap to
require/accept a locked mutex) so all accesses to connectedDevices_ from
handleDisconnect are protected, then release the lock after removeConnFromMap
completes.

In `@source/bringauto/modules/ModuleHandler.cpp`:
- Around line 170-171: The two local variables statusAggregator and
moduleHandler are currently copying shared_ptrs from the maps
(statusAggregators.at(...) and moduleLibrary_.moduleLibraryHandlers.at(...)),
causing unnecessary atomic refcount operations on every status message; change
those local declarations to hold references to the stored shared_ptrs (use const
auto& for statusAggregator and const auto& for moduleHandler) so you avoid
incrementing/decrementing the shared_ptr refcount in the hot path that processes
incoming device status messages in ModuleHandler.cpp.

In `@test/include/ErrorAggregatorTests.hpp`:
- Line 24: The test now calls Logger::init(std::string_view) which falls back to
the compile-time BRINGAUTO_MODULE_GATEWAY_MINIMUM_LOGGER_VERBOSITY (default
DEBUG) and increases test verbosity; change the test to call the explicit
settings overload to restore Critical-only output by invoking Logger::init with
a LoggerSettings (e.g.,
Logger::init(LoggerSettings{.verbosity=Logger::Verbosity::Critical}) or the
equivalent constructor used elsewhere), or alternatively ensure the test build
overrides BRINGAUTO_MODULE_GATEWAY_MINIMUM_LOGGER_VERBOSITY to a less verbose
level (CRITICAL/ERROR) in CMake; update the call in the file that currently uses
Logger::init("ErrorAggregatorTests") to use the LoggerSettings API (or adjust
the build macro) so tests keep Critical verbosity.

---

Outside diff comments:
In `@source/bringauto/settings/SettingsParser.cpp`:
- Around line 235-237: serializeToJson() writes protocolSettings into
endpointAsJson using settingsName without checking for an empty settingsName;
add a guard equivalent to the parse side: only iterate and assign
endpoint.protocolSettings into endpointAsJson[settingsName] when
!settingsName.empty() and endpoint.protocolSettings is non-empty. Wrap the
for(const auto& [key,val]: endpoint.protocolSettings) loop in that conditional
(using the existing settingsName variable and endpoint.protocolSettings) to
avoid producing endpointAsJson[""] entries.

---

Duplicate comments:
In `@include/bringauto/modules/StatusAggregator.hpp`:
- Around line 174-175: The const qualifier on aggregateSetStatus and
aggregateSetSendStatus is correct; leave the methods declared as const (they
only constrain *this and do not mutate member variables) and ensure consistency
with aggregateStatus which already uses const StatusAggregatorDeviceState&; to
make intent explicit, add a brief comment near the declarations of
aggregateSetStatus, aggregateSetSendStatus, and aggregateStatus noting that
these methods may modify the passed-in deviceState parameter but do not mutate
StatusAggregator's members (i.e., logical vs bitwise const).

In `@include/bringauto/structures/ExternalConnectionSettings.hpp`:
- Around line 3-6: The review notes the previous fix (adding `#include` <cstdint>
and using std::uint16_t port {} in the ExternalConnectionSettings structure) is
already applied; no code changes needed—just verify ExternalConnectionSettings
has std::uint16_t port {} and `#include` <cstdint> present and remove this
duplicate review comment to avoid clutter.

In `@source/bringauto/common_utils/EnumUtils.cpp`:
- Around line 13-14: The DUMMY branch in EnumUtils.cpp is correct and follows
the same pattern/indentation as the MQTT branch, so no code changes are
required; leave the else if (toEnum == settings::Constants::DUMMY) { return
structures::ProtocolType::DUMMY; } branch as-is in the function handling enum
conversion.

---

Nitpick comments:
In `@include/bringauto/structures/Connection.hpp`:
- Line 30: The header defines remoteEndpointAddress() which returns std::string
but no longer includes <string>; restore a direct include by adding `#include`
<string> at the top of Connection.hpp so the declaration of
remoteEndpointAddress() doesn't rely on transitive includes (modify
Connection.hpp to include <string> and leave the remoteEndpointAddress()
declaration unchanged).

In `@source/bringauto/internal_server/InternalServer.cpp`:
- Around line 335-368: The current InternalServer::sendResponse uses
connection->socket.write_some for both the header and payload which can perform
partial writes; replace these calls with boost::asio::write to ensure the full
header (boost::asio::buffer(&header, sizeof(uint32_t))) and the full payload
(boost::asio::buffer(data)) are written atomically by looping internally, remove
the manual size checks against headerWSize/dataWSize (since boost::asio::write
throws on failure), and keep the existing try/catch around the write calls so
exceptions (ex.what()) are logged and the function returns false on error.

In `@source/bringauto/modules/ModuleHandler.cpp`:
- Around line 174-177: The variable statusBuffer (returned from
moduleHandler->constructBuffer(statusData.size())) is marked const but its
contents are mutated by common_utils::ProtobufUtils::copyStatusToBuffer(status,
statusBuffer); remove the const qualifier from the statusBuffer declaration in
ModuleHandler.cpp so the mutability of the buffer's payload is clear (or if you
must keep const, add a concise comment above the declaration explaining that the
wrapper is immutable while its internal payload is mutated by
copyStatusToBuffer).

@jiriskuta jiriskuta force-pushed the BAF-1122/optimizations branch from 967b413 to f6b0974 Compare February 20, 2026 13:46
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
include/bringauto/modules/StatusAggregator.hpp (1)

196-199: ⚠️ Potential issue | 🟡 Minor

Stale comment: key is no longer a string.

The deviceTimeouts_ map comment still reads "key is device identification converted to string" but the key type is now structures::DeviceIdentification directly.

✏️ Proposed fix
 	/**
-	 * `@brief` Map of devices timeouts, key is device identification converted to string
+	 * `@brief` Map of devices timeouts, key is device identification
 	 */
 	std::unordered_map<structures::DeviceIdentification, int> deviceTimeouts_ {};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/bringauto/modules/StatusAggregator.hpp` around lines 196 - 199, The
comment for deviceTimeouts_ is stale—update the doc above the member
std::unordered_map<structures::DeviceIdentification, int> deviceTimeouts_ to
reflect that the key is a structures::DeviceIdentification (not a string);
modify the brief description in StatusAggregator.hpp to say "key is
DeviceIdentification" or "key is structures::DeviceIdentification" and remove
the "converted to string" wording so the comment matches the actual type.
🧹 Nitpick comments (1)
include/bringauto/settings/LoggerWrapper.hpp (1)

28-30: Missing explicit <string_view> (and <string>) includes.

init's parameter and body rely on std::string_view and std::string respectively, but neither header is included directly. The implementation currently depends entirely on transitive inclusion through <libbringauto_logger/bringauto/logging/Logger.hpp>. If that library ever drops those transitive includes, this header breaks.

📎 Proposed fix
 `#include` <libbringauto_logger/bringauto/logging/Logger.hpp>
+
+#include <string>
+#include <string_view>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/bringauto/settings/LoggerWrapper.hpp` around lines 28 - 30, The
header is missing direct includes for std::string_view and std::string which
LoggerWrapper::init depends on (parameter type std::string_view and constructing
std::string for logging::LoggerSettings passed to BaseLogger::init); add the
appropriate headers (<string_view> and <string>) to this file so
LoggerWrapper::init no longer relies on transitive includes from
bringauto/logging/Logger.hpp and will compile if those transitive includes are
removed.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@include/bringauto/modules/StatusAggregator.hpp`:
- Around line 196-199: The comment for deviceTimeouts_ is stale—update the doc
above the member std::unordered_map<structures::DeviceIdentification, int>
deviceTimeouts_ to reflect that the key is a structures::DeviceIdentification
(not a string); modify the brief description in StatusAggregator.hpp to say "key
is DeviceIdentification" or "key is structures::DeviceIdentification" and remove
the "converted to string" wording so the comment matches the actual type.

---

Duplicate comments:
In `@include/bringauto/modules/StatusAggregator.hpp`:
- Around line 174-175: The member functions aggregateSetStatus and
aggregateSetSendStatus are incorrectly declared as const despite mutating the
passed-in devices (structures::StatusAggregatorDeviceState &deviceState); remove
the trailing const from their declarations and corresponding definitions in
StatusAggregator (so StatusAggregator::aggregateSetStatus(...) and
StatusAggregator::aggregateSetSendStatus(...) are non-const member functions) so
callers (including when invoked on non-const devices[key]) can pass the
non-const reference and the methods can call
setStatus()/setStatusAndResetTimer() without const-qualification errors; update
both the header (StatusAggregator.hpp) and any implementation file to match.

In `@source/bringauto/internal_server/InternalServer.cpp`:
- Around line 269-273: The data race in handleDisconnect has been fixed by
acquiring serverMutex_ before accessing shared state; ensure you continue to
hold serverMutex_ while calling findConnection and removeConnFromMap and also
defensively handle a null/invalid connection return from findConnection before
calling removeConnFromMap (e.g., check connection != nullptr), keeping the lock
scoped via std::lock_guard<std::mutex> on serverMutex_ inside
InternalServer::handleDisconnect.
- Around line 38-46: The socket option handling is already fixed: the async
accept lambda uses the non-throwing overload of socket::set_option with a
boost::system::error_code (optEc) and logs failures, preventing
boost::system::system_error from escaping io_context::run(); no further changes
required to connection->socket.set_option for keep_alive or tcp::no_delay, just
ensure the same pattern (optEc + log::logWarning) is used anywhere else you set
socket options in the async accept code path.

In `@source/bringauto/modules/ModuleHandler.cpp`:
- Around line 170-171: Change the temporary shared_ptr lookups to bind by
reference to avoid atomic ref-count increments on the hot path: use const auto&
when retrieving entries from statusAggregators and
moduleLibrary_.moduleLibraryHandlers (i.e., statusAggregator and moduleHandler
that are indexed by moduleNumber) so you hold references instead of copying
shared_ptrs; ensure any subsequent usage expects a reference and does not
attempt to move or rebind those variables.

In `@source/bringauto/modules/StatusAggregator.cpp`:
- Around line 225-230: Replace use of operator[] that could insert phantom
entries by performing a const lookup with deviceTimeouts_.find in
getDeviceTimeoutCount(const structures::DeviceIdentification &device) and return
it->second when found otherwise return 0; ensure the method remains const and
uses the local iterator variable (it) as in the diff so no modification to
deviceTimeouts_ occurs during lookup.

---

Nitpick comments:
In `@include/bringauto/settings/LoggerWrapper.hpp`:
- Around line 28-30: The header is missing direct includes for std::string_view
and std::string which LoggerWrapper::init depends on (parameter type
std::string_view and constructing std::string for logging::LoggerSettings passed
to BaseLogger::init); add the appropriate headers (<string_view> and <string>)
to this file so LoggerWrapper::init no longer relies on transitive includes from
bringauto/logging/Logger.hpp and will compile if those transitive includes are
removed.

@jiriskuta jiriskuta force-pushed the BAF-1122/optimizations branch from f6b0974 to 040b7f7 Compare February 20, 2026 14:14
@jiriskuta
Copy link

@coderabbitai resolve

Addressing repeated false positives for future reviews:

StatusAggregator.hpp — trailing const on aggregateSetStatus / aggregateSetSendStatus
These are correctly marked const. The const qualifier applies to *this (the StatusAggregator instance), which neither
method modifies. Taking a non-const StatusAggregatorDeviceState &deviceState parameter and mutating it through that reference
is standard C++ and does not conflict with the method-level const.

SettingsParser.cpp — serialization guard for empty settingsName
DUMMY endpoints always have an empty protocolSettings map by design, so the loop body never executes. The guard would be
dead code.

ErrorAggregatorTests.hpp — Logger verbosity
LoggerWrapper::init(std::string_view) passes the compile-time template parameter verbosity to BaseLogger::init, which is
identical to what the previous LoggerSettings construction passed. No verbosity regression occurred. There is also no
LoggerSettings overload on LoggerWrapper::init.

StatusAggregator.cppgetDeviceTimeoutCount uses operator[]
The method already uses deviceTimeouts_.find() with an iterator check, not operator[]. No change needed.

@coderabbitai
Copy link

coderabbitai bot commented Feb 20, 2026

Tip

For best results, initiate chat on the files or code changes.

@jiriskuta, thank you for these detailed clarifications! I've recorded all four points to avoid flagging these patterns in future reviews:

  1. StatusAggregator.hpp const methods — Understood. The const qualifier on aggregateSetStatus and aggregateSetSendStatus correctly applies to *this (the StatusAggregator instance), not to the deviceState parameter. Mutating a non-const reference parameter is perfectly valid in a const member function.

  2. SettingsParser.cpp DUMMY serialization — Noted. Since DUMMY endpoints have an empty protocolSettings map by design, an explicit guard would indeed be dead code as the loop naturally skips empty maps.

  3. ErrorAggregatorTests.hpp Logger initialization — Clear. The LoggerWrapper::init(std::string_view) already passes the compile-time template parameter verbosity to BaseLogger::init, maintaining the same behavior as the previous LoggerSettings approach.

  4. StatusAggregator.cpp safe map access — Confirmed. The getDeviceTimeoutCount method already uses find() with proper iterator validation, not direct operator[] access.

I've stored these as learnings to improve accuracy in future reviews.


✏️ Learnings added
Learnt from: jiriskuta
URL: https://github.com/bringauto/module-gateway/pull/45

Timestamp: 2026-02-20T14:16:22.121Z
Learning: In `StatusAggregator.hpp` (module-gateway), the methods `aggregateSetStatus` and `aggregateSetSendStatus` are correctly marked `const`. The `const` qualifier applies to `*this` (the `StatusAggregator` instance), not to the `StatusAggregatorDeviceState &deviceState` parameter. Mutating the `deviceState` parameter through a non-const reference in a const member function is valid C++ practice.

Learnt from: jiriskuta
URL: https://github.com/bringauto/module-gateway/pull/45

Timestamp: 2026-02-20T14:16:22.121Z
Learning: In `SettingsParser.cpp` (module-gateway), `DUMMY` protocol endpoints always have an empty `protocolSettings` map by design. When serializing, no explicit guard is needed before iterating over `protocolSettings` because the loop body naturally never executes for empty maps, so such a guard would be dead code.

Learnt from: jiriskuta
URL: https://github.com/bringauto/module-gateway/pull/45

Timestamp: 2026-02-20T14:16:22.121Z
Learning: In test files like `ErrorAggregatorTests.hpp` (module-gateway), when `LoggerWrapper::init(std::string_view)` is called, it internally passes the compile-time template parameter `verbosity` to `BaseLogger::init`. This maintains the same verbosity behavior as the previous `LoggerSettings` construction pattern, so there is no verbosity regression when migrating to the simpler `init(string_view)` call.

Learnt from: jiriskuta
URL: https://github.com/bringauto/module-gateway/pull/45

Timestamp: 2026-02-20T14:16:22.121Z
Learning: In `StatusAggregator.cpp` (module-gateway), the `getDeviceTimeoutCount` method already uses `deviceTimeouts_.find()` with proper iterator checking (comparing against `end()`), not unsafe `operator[]` access. The implementation is already correct and safe.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: Mayt34
Repo: bringauto/transparent-module PR: 1
File: source/bringauto/modules/devices/testing_device/testing_module_manager.cpp:25-34
Timestamp: 2024-10-03T11:24:43.894Z
Learning: In the `testing_device_aggregate_status` function for the testing device, status aggregation of current and new status is not necessary due to the module's simple logic, similar to the io-module which works without aggregation.

Learnt from: Mayt34
Repo: bringauto/transparent-module PR: 1
File: source/bringauto/modules/devices/testing_device/testing_module_manager.cpp:25-34
Timestamp: 2024-10-09T05:03:50.249Z
Learning: In the `testing_device_aggregate_status` function for the testing device, status aggregation of current and new status is not necessary due to the module's simple logic, similar to the io-module which works without aggregation.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
source/bringauto/modules/ModuleHandler.cpp (1)

93-93: auto & is implicitly const here, but const auto & would be more explicit and consistent.

Both statusAggregators references (lines 86, 128) are const auto &, so .at() returns a const T& — the binding is already const. Lines 114, 170, and 171 use explicit const auto & for the same pattern. Using const auto & here too removes any reader ambiguity.

♻️ Proposed fix
-	auto &statusAggregator = statusAggregators.at(moduleNumber);   // line 93
+	const auto &statusAggregator = statusAggregators.at(moduleNumber);

-	auto &statusAggregator = statusAggregators.at(moduleNumber);   // line 137
+	const auto &statusAggregator = statusAggregators.at(moduleNumber);

Also applies to: 137-137

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@source/bringauto/modules/ModuleHandler.cpp` at line 93, The binding for
statusAggregators.at(moduleNumber) uses "auto &statusAggregator" which is
implicitly const due to statusAggregators being a const reference; change this
to "const auto &statusAggregator" in ModuleHandler.cpp to make const-ness
explicit and consistent with the other usages (the .at(moduleNumber) calls at
the other locations such as the second occurrence around the 137 area). Update
both occurrences so the symbol statusAggregator is declared as const auto & to
match the surrounding code.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@include/bringauto/structures/ExternalConnectionSettings.hpp`:
- Around line 15-35: No code changes required — the review confirms
ProtocolType::INVALID is set and ExternalConnectionSettings now initializes
protocolType and port correctly (see ProtocolType enum and
ExternalConnectionSettings struct), so proceed to approve/merge the change
as-is.

In `@source/bringauto/modules/ModuleHandler.cpp`:
- Around line 170-171: The review approves using const auto& for
statusAggregator and moduleHandler to avoid redundant shared_ptr refcount ops;
no code change required—keep the lines using statusAggregators.at(moduleNumber)
and moduleLibrary_.moduleLibraryHandlers.at(moduleNumber) with const auto& and
leave moduleNumber usage as-is.

In `@source/bringauto/modules/StatusAggregator.cpp`:
- Around line 225-230: The previous silent-insertion bug in
getDeviceTimeoutCount is fixed: replace any use of operator[] on deviceTimeouts_
with a const-safe lookup; in StatusAggregator::getDeviceTimeoutCount use
deviceTimeouts_.find(device) to check existence and return it->second or 0,
preserving the const qualifier on the method and avoiding modification of
deviceTimeouts_.

---

Nitpick comments:
In `@source/bringauto/modules/ModuleHandler.cpp`:
- Line 93: The binding for statusAggregators.at(moduleNumber) uses "auto
&statusAggregator" which is implicitly const due to statusAggregators being a
const reference; change this to "const auto &statusAggregator" in
ModuleHandler.cpp to make const-ness explicit and consistent with the other
usages (the .at(moduleNumber) calls at the other locations such as the second
occurrence around the 137 area). Update both occurrences so the symbol
statusAggregator is declared as const auto & to match the surrounding code.

@jiriskuta jiriskuta force-pushed the BAF-1122/optimizations branch 3 times, most recently from ed1553e to 7644429 Compare February 20, 2026 16:41
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (6)
include/bringauto/external_client/ExternalClient.hpp (1)

57-60: Minor doc typo: "commands messages" → "command messages".

📝 Proposed fix
-	 * `@brief` Handle commands messages from an external server
+	 * `@brief` Handle command messages from an external server
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/bringauto/external_client/ExternalClient.hpp` around lines 57 - 60,
Update the doc comment for the ExternalClient::handleCommands() declaration to
fix the typo: change "Handle commands messages from an external server" to
"Handle command messages from an external server" in
include/bringauto/external_client/ExternalClient.hpp so the comment correctly
reads and matches the function purpose.
source/bringauto/modules/ModuleHandler.cpp (1)

99-99: Nit: ret and getCommandRc could be const int for consistency.

Lines 51 and 60 use const int for similar never-modified return values. These two were missed.

Proposed fix
-	int ret = statusAggregator->force_aggregation_on_device(deviceId);
+	const int ret = statusAggregator->force_aggregation_on_device(deviceId);
-	int getCommandRc = statusAggregator->get_command(statusBuffer, deviceId, commandBuffer);
+	const int getCommandRc = statusAggregator->get_command(statusBuffer, deviceId, commandBuffer);

Also applies to: 193-193

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@source/bringauto/modules/ModuleHandler.cpp` at line 99, Make the return-value
locals that are never modified use const: change the local int named ret
assigned from statusAggregator->force_aggregation_on_device(deviceId) to const
int ret, and likewise change the int getCommandRc variable (the one assigned
from getCommandRc(...)) to const int getCommandRc; update their declarations in
ModuleHandler.cpp where they occur (including the other occurrence around line
193) so they match the existing const-int pattern used elsewhere.
include/bringauto/settings/LoggerWrapper.hpp (2)

42-45: Optional: "eliminated by optimizer" → "eliminated at compile time".

if constexpr discards the branch during template instantiation (compiler frontend), before any optimizer pass runs. The phrasing "call eliminated by optimizer" is slightly imprecise. The same comment appears in logInfo, logWarning, logError, and logCritical.

✏️ Proposed wording fix (representative, apply to all five wrappers)
-		return; // compile-time minimum exceeds Debug; call eliminated by optimizer
+		return; // compile-time minimum exceeds Debug; branch discarded at compile time
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/bringauto/settings/LoggerWrapper.hpp` around lines 42 - 45, Update
the explanatory comment in the LoggerWrapper.hpp template logging methods (
e.g., logDebug, logInfo, logWarning, logError, logCritical ) to replace
"eliminated by optimizer" with "eliminated at compile time" (or similar wording)
to accurately reflect that if constexpr removes the branch during template
instantiation rather than during optimizer passes; apply the same wording change
to the matching comment in each of the five wrapper methods.

72-78: The logCritical guard at lines 72-78 is dead code.

if constexpr (verbosity > logging::LoggerVerbosity::Critical) can never be true—Critical is the maximum enum value. The codebase defines exactly five verbosity levels (Debug, Info, Warning, Error, Critical), and all instantiations pass only these values to LoggerWrapper. The guard is harmless but serves no purpose and should either be removed or documented as a future-proof placeholder (e.g., if an Off level is planned).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/bringauto/settings/LoggerWrapper.hpp` around lines 72 - 78, The
compile-time guard in LoggerWrapper::logCritical is dead because verbosity can
never exceed logging::LoggerVerbosity::Critical; remove the useless if constexpr
block around the early return and call
BaseLogger::log(logging::LoggerVerbosity::Critical,
std::forward<LogArgs>(args)...) directly, or if you prefer to keep a
placeholder, replace the guard with an explicit comment referencing
LoggerWrapper::verbosity and logging::LoggerVerbosity::Critical explaining it’s
intentionally present for future-proofing (no behavior change to
BaseLogger::log).
source/bringauto/modules/StatusAggregator.cpp (1)

68-77: deviceTimeouts_ entries are not cleaned up on device removal.

remove_device erases from devices but leaves the corresponding entry in deviceTimeouts_ indefinitely. Over time this can accumulate stale entries for removed devices.

🧹 Proposed cleanup
 int StatusAggregator::remove_device(const structures::DeviceIdentification& device) {
 	if(is_device_valid(device) == NOT_OK) {
 		return DEVICE_NOT_REGISTERED;
 	}
 	clear_device(device);
+	deviceTimeouts_.erase(device);
 	boost::asio::post(context_->ioContext, [this, device]() { devices.erase(device); });
 	return OK;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@source/bringauto/modules/StatusAggregator.cpp` around lines 68 - 77,
remove_device currently erases the device from devices but leaves its entry in
deviceTimeouts_ causing stale growth; update StatusAggregator::remove_device to
also remove the deviceTimeouts_ entry (deviceTimeouts_.erase(device)) and
perform that cleanup inside the same boost::asio::post lambda (or otherwise
synchronized with context_->ioContext) alongside devices.erase(device) so both
structures are updated on the same execution context and avoid race conditions;
reference the existing clear_device call if additional teardown is needed before
erasure.
source/bringauto/internal_server/InternalServer.cpp (1)

117-117: Optional: prefer std::size_t (or auto) over uint8_t for headerSize.

uint8_t is an unusual type for a byte-count variable. It is implicitly promoted to std::size_t on every comparison (bytesTransferred < headerSize, bytesLeft -= headerSize) and in the std::memcpy count argument, which adds unnecessary implicit conversions throughout the function. Using std::size_t (or auto) matches the types of bytesTransferred and bytesLeft and makes the arithmetic more readable.

♻️ Proposed change
-	constexpr uint8_t headerSize = settings::header;
+	constexpr std::size_t headerSize = settings::header;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@source/bringauto/internal_server/InternalServer.cpp` at line 117, The
variable headerSize declared as constexpr uint8_t headerSize = settings::header;
should use a size type matching bytesTransferred/bytesLeft to avoid implicit
promotions; change it to constexpr std::size_t (or auto) headerSize =
settings::header; in InternalServer.cpp so comparisons and memcpy length
arguments use the same type (refer to headerSize in the function handling
bytesTransferred/bytesLeft to update this single declaration).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@source/bringauto/internal_server/InternalServer.cpp`:
- Around line 269-275: Ensure handleDisconnect acquires serverMutex_ and guards
against a null connection: inside InternalServer::handleDisconnect, take
std::lock_guard<std::mutex> lock(serverMutex_), call findConnection(deviceId),
then only call removeConnFromMap(connection) if connection is non-null
(if(connection)). This prevents races with
asyncReceiveHandler/handleConnection/validateResponse and avoids null deref in
removeConnFromMap::socket.shutdown.
- Around line 38-46: The updated code correctly uses the non-throwing overloads
of boost::asio::basic_stream_socket::set_option to avoid exceptions during async
accept; no functional change is required—keep the calls to
connection->socket.set_option(boost::asio::socket_base::keep_alive(true), optEc)
and connection->socket.set_option(boost::asio::ip::tcp::no_delay(true), optEc)
and the subsequent log::logWarning(...) checks as written to preserve graceful
error handling inside the accept lambda.

---

Nitpick comments:
In `@include/bringauto/external_client/ExternalClient.hpp`:
- Around line 57-60: Update the doc comment for the
ExternalClient::handleCommands() declaration to fix the typo: change "Handle
commands messages from an external server" to "Handle command messages from an
external server" in include/bringauto/external_client/ExternalClient.hpp so the
comment correctly reads and matches the function purpose.

In `@include/bringauto/settings/LoggerWrapper.hpp`:
- Around line 42-45: Update the explanatory comment in the LoggerWrapper.hpp
template logging methods ( e.g., logDebug, logInfo, logWarning, logError,
logCritical ) to replace "eliminated by optimizer" with "eliminated at compile
time" (or similar wording) to accurately reflect that if constexpr removes the
branch during template instantiation rather than during optimizer passes; apply
the same wording change to the matching comment in each of the five wrapper
methods.
- Around line 72-78: The compile-time guard in LoggerWrapper::logCritical is
dead because verbosity can never exceed logging::LoggerVerbosity::Critical;
remove the useless if constexpr block around the early return and call
BaseLogger::log(logging::LoggerVerbosity::Critical,
std::forward<LogArgs>(args)...) directly, or if you prefer to keep a
placeholder, replace the guard with an explicit comment referencing
LoggerWrapper::verbosity and logging::LoggerVerbosity::Critical explaining it’s
intentionally present for future-proofing (no behavior change to
BaseLogger::log).

In `@source/bringauto/internal_server/InternalServer.cpp`:
- Line 117: The variable headerSize declared as constexpr uint8_t headerSize =
settings::header; should use a size type matching bytesTransferred/bytesLeft to
avoid implicit promotions; change it to constexpr std::size_t (or auto)
headerSize = settings::header; in InternalServer.cpp so comparisons and memcpy
length arguments use the same type (refer to headerSize in the function handling
bytesTransferred/bytesLeft to update this single declaration).

In `@source/bringauto/modules/ModuleHandler.cpp`:
- Line 99: Make the return-value locals that are never modified use const:
change the local int named ret assigned from
statusAggregator->force_aggregation_on_device(deviceId) to const int ret, and
likewise change the int getCommandRc variable (the one assigned from
getCommandRc(...)) to const int getCommandRc; update their declarations in
ModuleHandler.cpp where they occur (including the other occurrence around line
193) so they match the existing const-int pattern used elsewhere.

In `@source/bringauto/modules/StatusAggregator.cpp`:
- Around line 68-77: remove_device currently erases the device from devices but
leaves its entry in deviceTimeouts_ causing stale growth; update
StatusAggregator::remove_device to also remove the deviceTimeouts_ entry
(deviceTimeouts_.erase(device)) and perform that cleanup inside the same
boost::asio::post lambda (or otherwise synchronized with context_->ioContext)
alongside devices.erase(device) so both structures are updated on the same
execution context and avoid race conditions; reference the existing clear_device
call if additional teardown is needed before erasure.

@jiriskuta jiriskuta force-pushed the BAF-1122/optimizations branch from 7644429 to e80d2ea Compare February 20, 2026 17:07
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@jiriskuta jiriskuta force-pushed the BAF-1122/optimizations branch from e80d2ea to 78e660f Compare February 20, 2026 17:11
@sonarqubecloud
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants