From bfd07412bb96d0bfc2fee92b28cb84c4b7ec5bb8 Mon Sep 17 00:00:00 2001 From: Khushboo Mehta Date: Fri, 17 Apr 2026 10:48:39 +0200 Subject: [PATCH] feat: allow long module names --- cpp/logos_instance.h | 58 ++++++++++++++++++++++++++++- tests/sdk/test_logos_instance.cpp | 62 +++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+), 1 deletion(-) diff --git a/cpp/logos_instance.h b/cpp/logos_instance.h index 1579add..e4627ed 100644 --- a/cpp/logos_instance.h +++ b/cpp/logos_instance.h @@ -1,6 +1,7 @@ #ifndef LOGOS_INSTANCE_H #define LOGOS_INSTANCE_H +#include #include #include #include @@ -15,6 +16,34 @@ * ID. Used by both provider and consumer to build matching registry URLs. */ namespace LogosInstance { + inline QString shortSha1Hex(const QString& value, int length) + { + return QString::fromLatin1( + QCryptographicHash::hash(value.toUtf8(), QCryptographicHash::Sha1) + .toHex() + .left(length)); + } + + inline QString leftUtf8Bytes(const QString& value, int maxBytes) + { + if (maxBytes <= 0) + return QString(); + + const QByteArray utf8 = value.toUtf8(); + if (utf8.size() <= maxBytes) + return value; + + QByteArray truncated = utf8.left(maxBytes); + while (!truncated.isEmpty()) { + const QString decoded = + QString::fromUtf8(truncated.constData(), truncated.size()); + if (decoded.toUtf8().size() == truncated.size()) + return decoded; + truncated.chop(1); + } + return QString(); + } + inline const QString id() { const QByteArray inherited = qgetenv("LOGOS_INSTANCE_ID"); if (!inherited.isEmpty()) @@ -25,7 +54,34 @@ namespace LogosInstance { } inline QString id(const QString& moduleName) { - return QString("local:logos_%1_%2").arg(moduleName).arg(id()); + constexpr int kMaxSocketFilenameBytes = 40; + constexpr int kModuleHashHexLen = 16; + constexpr int kMaxInstanceIdBytes = 12; + + const QString instanceId = id(); + const QString baseName = + QStringLiteral("logos_%1_%2").arg(moduleName, instanceId); + + if (baseName.toUtf8().size() <= kMaxSocketFilenameBytes) + return QStringLiteral("local:") + baseName; + + const QString instanceIdForSocket = + (instanceId.toUtf8().size() <= kMaxInstanceIdBytes) + ? instanceId + : shortSha1Hex(instanceId, kMaxInstanceIdBytes); + const QString moduleHash = shortSha1Hex(moduleName, kModuleHashHexLen); + + // Reserve bytes for "logos_" + "_" + moduleHash + "_" + instance ID. + const int fixedBytes = + 8 + kModuleHashHexLen + instanceIdForSocket.toUtf8().size(); + const int modulePrefixBytes = + qMax(0, kMaxSocketFilenameBytes - fixedBytes); + const QString modulePrefix = leftUtf8Bytes(moduleName, modulePrefixBytes); + + const QString socketName = + QStringLiteral("logos_%1_%2_%3") + .arg(modulePrefix, moduleHash, instanceIdForSocket); + return QStringLiteral("local:") + socketName; } } diff --git a/tests/sdk/test_logos_instance.cpp b/tests/sdk/test_logos_instance.cpp index d7ad132..16d73b5 100644 --- a/tests/sdk/test_logos_instance.cpp +++ b/tests/sdk/test_logos_instance.cpp @@ -53,3 +53,65 @@ TEST_F(LogosInstanceTest, RegistryUrlFormat) QString url = LogosInstance::id("my_module"); EXPECT_EQ(url, "local:logos_my_module_abc123def456"); } + +TEST_F(LogosInstanceTest, RegistryUrlTruncatesLongModuleNames) +{ + qputenv("LOGOS_INSTANCE_ID", "abc123def456"); + const QString longName = + "liblogos_execution_zone_wallet_module_with_extra_suffix"; + QString url = LogosInstance::id(longName); + + ASSERT_TRUE(url.startsWith("local:")); + const QString socketName = url.mid(QString("local:").size()); + + EXPECT_LE(socketName.toUtf8().size(), 40); + EXPECT_EQ(url, LogosInstance::id(longName)); + + EXPECT_NE(url, LogosInstance::id(longName + "_different")); +} + +// Golden test: pin the exact derived name so refactors don't silently change +// the socket naming scheme. +TEST_F(LogosInstanceTest, RegistryUrlGoldenLongName) +{ + qputenv("LOGOS_INSTANCE_ID", "abc123def456"); + const QString longName = + "liblogos_execution_zone_wallet_module_with_extra_suffix"; + EXPECT_EQ(LogosInstance::id(longName), + QStringLiteral("local:logos_libl_dc0d0a2280b70b17_abc123def456")); +} + +TEST_F(LogosInstanceTest, RegistryUrlTruncatesLongInstanceId) +{ + const QByteArray longInstanceId = + "instance_id_with_extra_suffix_that_is_deliberately_long_for_socket_names"; + const QString longName = + "liblogos_execution_zone_wallet_module_with_extra_suffix"; + + qputenv("LOGOS_INSTANCE_ID", longInstanceId); + const QString url = LogosInstance::id(longName); + + ASSERT_TRUE(url.startsWith("local:")); + const QString socketName = url.mid(QString("local:").size()); + EXPECT_LE(socketName.toUtf8().size(), 40); + EXPECT_EQ(url, LogosInstance::id(longName)); + + qputenv( + "LOGOS_INSTANCE_ID", + "instance_id_with_extra_suffix_that_is_deliberately_long_for_socket_names_changed"); + EXPECT_NE(url, LogosInstance::id(longName)); +} + +TEST_F(LogosInstanceTest, RegistryUrlTruncatesByUtf8Bytes) +{ + qputenv("LOGOS_INSTANCE_ID", "abc123def456"); + const QString unicodeLongName = QString::fromUtf8( + "模块_пример_モジュール_الوحدة_가나다라마바사아자차카타파하"); + + const QString url = LogosInstance::id(unicodeLongName); + ASSERT_TRUE(url.startsWith("local:")); + const QString socketName = url.mid(QString("local:").size()); + + EXPECT_LE(socketName.toUtf8().size(), 40); + EXPECT_EQ(url, LogosInstance::id(unicodeLongName)); +}