Make chip-tool subscription shutdown commands easier to use. (#21750)
* Removes redundant "subscription" from the command names, since it's part of
the "cluster" already.
* Removes the need to specify fabric-index (which was ambiguous anyway, in terms
of whether it was the fabric-index on the server or the client), deriving
fabric information from the command's identity (--commissioner-name) instead.
* Adds a shutdown-all command.
* Adds various documentation bits.
Fixes https://github.com/project-chip/connectedhomeip/issues/21724
diff --git a/examples/chip-tool/commands/clusters/SubscriptionsCommands.h b/examples/chip-tool/commands/clusters/SubscriptionsCommands.h
index c5c5b46..9626070 100644
--- a/examples/chip-tool/commands/clusters/SubscriptionsCommands.h
+++ b/examples/chip-tool/commands/clusters/SubscriptionsCommands.h
@@ -26,7 +26,8 @@
class ShutdownSubscription : public CHIPCommand
{
public:
- ShutdownSubscription(CredentialIssuerCommands * credsIssuerConfig) : CHIPCommand("shutdown-subscription", credsIssuerConfig)
+ ShutdownSubscription(CredentialIssuerCommands * credsIssuerConfig) :
+ CHIPCommand("shutdown-one", credsIssuerConfig, "Shut down a single subscription, identified by its subscription id.")
{
AddArgument("subscription-id", 0, UINT64_MAX, &mSubscriptionId);
}
@@ -44,39 +45,58 @@
chip::SubscriptionId mSubscriptionId;
};
-class ShutdownSubscriptions : public CHIPCommand
+class ShutdownSubscriptionsForNode : public CHIPCommand
{
public:
- ShutdownSubscriptions(CredentialIssuerCommands * credsIssuerConfig) : CHIPCommand("shutdown-subscriptions", credsIssuerConfig)
+ ShutdownSubscriptionsForNode(CredentialIssuerCommands * credsIssuerConfig) :
+ CHIPCommand("shutdown-all-for-node", credsIssuerConfig, "Shut down all subscriptions targeting a given node.")
{
- AddArgument("fabric-index", 0, UINT64_MAX, &mFabricIndex);
- AddArgument("node-id", 0, UINT64_MAX, &mNodeId);
+ AddArgument("node-id", 0, UINT64_MAX, &mNodeId,
+ "The node id, scoped to the commissioner name the command is running under.");
}
/////////// CHIPCommand Interface /////////
CHIP_ERROR RunCommand() override
{
- CHIP_ERROR err = CHIP_NO_ERROR;
+ chip::app::InteractionModelEngine::GetInstance()->ShutdownSubscriptions(CurrentCommissioner().GetFabricIndex(), mNodeId);
- chip::app::InteractionModelEngine::GetInstance()->ShutdownSubscriptions(mFabricIndex, mNodeId);
-
- SetCommandExitStatus(err);
+ SetCommandExitStatus(CHIP_NO_ERROR);
return CHIP_NO_ERROR;
}
chip::System::Clock::Timeout GetWaitDuration() const override { return chip::System::Clock::Seconds16(10); }
private:
- chip::FabricIndex mFabricIndex;
chip::NodeId mNodeId;
};
+class ShutdownAllSubscriptions : public CHIPCommand
+{
+public:
+ ShutdownAllSubscriptions(CredentialIssuerCommands * credsIssuerConfig) :
+ CHIPCommand("shutdown-all", credsIssuerConfig, "Shut down all subscriptions to all nodes.")
+ {}
+
+ /////////// CHIPCommand Interface /////////
+ CHIP_ERROR RunCommand() override
+ {
+ chip::app::InteractionModelEngine::GetInstance()->ShutdownAllSubscriptions();
+
+ SetCommandExitStatus(CHIP_NO_ERROR);
+ return CHIP_NO_ERROR;
+ }
+ chip::System::Clock::Timeout GetWaitDuration() const override { return chip::System::Clock::Seconds16(10); }
+
+private:
+};
+
void registerClusterSubscriptions(Commands & commands, CredentialIssuerCommands * credsIssuerConfig)
{
const char * clusterName = "Subscriptions";
commands_list clusterCommands = {
- make_unique<ShutdownSubscription>(credsIssuerConfig), //
- make_unique<ShutdownSubscriptions>(credsIssuerConfig), //
+ make_unique<ShutdownSubscription>(credsIssuerConfig), //
+ make_unique<ShutdownSubscriptionsForNode>(credsIssuerConfig), //
+ make_unique<ShutdownAllSubscriptions>(credsIssuerConfig), //
};
commands.Register(clusterName, clusterCommands);
diff --git a/examples/chip-tool/commands/common/CHIPCommand.h b/examples/chip-tool/commands/common/CHIPCommand.h
index 02a30eb..47bcc78 100644
--- a/examples/chip-tool/commands/common/CHIPCommand.h
+++ b/examples/chip-tool/commands/common/CHIPCommand.h
@@ -59,15 +59,15 @@
static constexpr uint16_t kMaxGroupsPerFabric = 5;
static constexpr uint16_t kMaxGroupKeysPerFabric = 8;
- CHIPCommand(const char * commandName, CredentialIssuerCommands * credIssuerCmds) :
- Command(commandName), mCredIssuerCmds(credIssuerCmds)
+ CHIPCommand(const char * commandName, CredentialIssuerCommands * credIssuerCmds, const char * helpText = nullptr) :
+ Command(commandName, helpText), mCredIssuerCmds(credIssuerCmds)
{
AddArgument("paa-trust-store-path", &mPaaTrustStorePath,
"Path to directory holding PAA certificate information. Can be absolute or relative to the current working "
"directory.");
- AddArgument(
- "commissioner-name", &mCommissionerName,
- "Name of fabric to use. Valid values are \"alpha\", \"beta\", \"gamma\", and integers greater than or equal to 4.");
+ AddArgument("commissioner-name", &mCommissionerName,
+ "Name of fabric to use. Valid values are \"alpha\", \"beta\", \"gamma\", and integers greater than or equal to "
+ "4. The default if not specified is \"alpha\".");
AddArgument("commissioner-nodeid", 0, UINT64_MAX, &mCommissionerNodeId,
"The node id to use for chip-tool. If not provided, kTestControllerNodeId (112233, 0x1B669) will be used.");
#if CHIP_CONFIG_TRANSPORT_TRACE_ENABLED
diff --git a/examples/chip-tool/commands/common/Command.h b/examples/chip-tool/commands/common/Command.h
index 2a7411c..96de494 100644
--- a/examples/chip-tool/commands/common/Command.h
+++ b/examples/chip-tool/commands/common/Command.h
@@ -105,10 +105,11 @@
::chip::Inet::InterfaceId interfaceId;
};
- Command(const char * commandName) : mName(commandName) {}
+ Command(const char * commandName, const char * helpText = nullptr) : mName(commandName), mHelpText(helpText) {}
virtual ~Command() {}
const char * GetName(void) const { return mName; }
+ const char * GetHelpText() const { return mHelpText; }
const char * GetAttribute(void) const;
const char * GetEvent(void) const;
const char * GetArgumentName(size_t index) const;
@@ -271,7 +272,8 @@
*/
size_t AddArgumentToList(Argument && argument);
- const char * mName = nullptr;
- bool mIsInteractive = false;
+ const char * mName = nullptr;
+ const char * mHelpText = nullptr;
+ bool mIsInteractive = false;
std::vector<Argument> mArgs;
};
diff --git a/examples/chip-tool/commands/common/Commands.cpp b/examples/chip-tool/commands/common/Commands.cpp
index 16e188c..333138b 100644
--- a/examples/chip-tool/commands/common/Commands.cpp
+++ b/examples/chip-tool/commands/common/Commands.cpp
@@ -350,6 +350,11 @@
}
fprintf(stderr, " %s %s %s\n", executable.c_str(), clusterName.c_str(), arguments.c_str());
+ if (command->GetHelpText())
+ {
+ fprintf(stderr, "\n%s\n", command->GetHelpText());
+ }
+
if (description.size() > 0)
{
fprintf(stderr, "%s\n", description.c_str());
diff --git a/examples/tv-casting-app/tv-casting-common/commands/common/CHIPCommand.cpp b/examples/tv-casting-app/tv-casting-common/commands/common/CHIPCommand.cpp
index 3a39954..c992736 100644
--- a/examples/tv-casting-app/tv-casting-common/commands/common/CHIPCommand.cpp
+++ b/examples/tv-casting-app/tv-casting-common/commands/common/CHIPCommand.cpp
@@ -83,3 +83,39 @@
{
Shutdown();
}
+
+chip::Controller::DeviceCommissioner & CHIPCommand::CurrentCommissioner()
+{
+ auto item = mCommissioners.find(GetIdentity());
+ return *item->second;
+}
+
+constexpr chip::FabricId kIdentityOtherFabricId = 4;
+std::map<std::string, std::unique_ptr<chip::Controller::DeviceCommissioner>> CHIPCommand::mCommissioners;
+
+std::string CHIPCommand::GetIdentity()
+{
+ std::string name = mCommissionerName.HasValue() ? mCommissionerName.Value() : kIdentityAlpha;
+ if (name.compare(kIdentityAlpha) != 0 && name.compare(kIdentityBeta) != 0 && name.compare(kIdentityGamma) != 0 &&
+ name.compare(kIdentityNull) != 0)
+ {
+ chip::FabricId fabricId = strtoull(name.c_str(), nullptr, 0);
+ if (fabricId >= kIdentityOtherFabricId)
+ {
+ // normalize name since it is used in persistent storage
+
+ char s[24];
+ sprintf(s, "%" PRIu64, fabricId);
+
+ name = s;
+ }
+ else
+ {
+ ChipLogError(chipTool, "Unknown commissioner name: %s. Supported names are [%s, %s, %s, 4, 5...]", name.c_str(),
+ kIdentityAlpha, kIdentityBeta, kIdentityGamma);
+ chipDie();
+ }
+ }
+
+ return name;
+}
diff --git a/src/app/InteractionModelEngine.cpp b/src/app/InteractionModelEngine.cpp
index 4232601..745d992 100644
--- a/src/app/InteractionModelEngine.cpp
+++ b/src/app/InteractionModelEngine.cpp
@@ -279,6 +279,17 @@
}
}
+void InteractionModelEngine::ShutdownAllSubscriptions()
+{
+ for (auto * readClient = mpActiveReadClientList; readClient != nullptr; readClient = readClient->GetNextClient())
+ {
+ if (readClient->IsSubscriptionType())
+ {
+ readClient->Close(CHIP_NO_ERROR);
+ }
+ }
+}
+
void InteractionModelEngine::OnDone(CommandHandler & apCommandObj)
{
mCommandHandlerObjs.ReleaseObject(&apCommandObj);
diff --git a/src/app/InteractionModelEngine.h b/src/app/InteractionModelEngine.h
index 9f21baf..6dffea8 100644
--- a/src/app/InteractionModelEngine.h
+++ b/src/app/InteractionModelEngine.h
@@ -139,6 +139,11 @@
void ShutdownSubscriptions(FabricIndex aFabricIndex, NodeId aPeerNodeId);
/**
+ * Tears down all active subscriptions.
+ */
+ void ShutdownAllSubscriptions();
+
+ /**
* Expire active transactions and release related objects for the given fabric index.
* This is used for releasing transactions that won't be closed when a fabric is removed.
*/