summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax Kellermann <max@musicpd.org>2020-01-20 09:10:02 +0100
committerMax Kellermann <max@musicpd.org>2020-01-20 14:56:31 +0100
commitcc7f66822ed4e4f673255f3094bdc123831d8c56 (patch)
tree41dde0044002890840204898c21db53c364669b7
parent9cbfa66886257d0df4c677c01e37be05bbf6f266 (diff)
command/partition: add command "delpartition"
-rw-r--r--NEWS1
-rw-r--r--doc/protocol.rst4
-rw-r--r--src/Instance.cxx14
-rw-r--r--src/Instance.hxx2
-rw-r--r--src/command/AllCommands.cxx1
-rw-r--r--src/command/PartitionCommands.cxx42
-rw-r--r--src/command/PartitionCommands.hxx3
-rw-r--r--src/output/MultipleOutputs.hxx12
8 files changed, 79 insertions, 0 deletions
diff --git a/NEWS b/NEWS
index 0ddd59453..8e9f1bfdd 100644
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,7 @@ ver 0.22 (not yet released)
"window" parameters
- add command "readpicture" to download embedded pictures
- command "moveoutput" moves an output between partitions
+ - command "delpartition" deletes a partition
- show partition name in "status" response
* tags
- new tags "Grouping" (for ID3 "TIT1"), "Work" and "Conductor"
diff --git a/doc/protocol.rst b/doc/protocol.rst
index 88742f9d2..a51a3b6b5 100644
--- a/doc/protocol.rst
+++ b/doc/protocol.rst
@@ -1262,6 +1262,10 @@ client is assigned to one partition at a time.
:command:`newpartition {NAME}`
Create a new partition.
+:command:`delpartition {NAME}`
+ Delete a partition. The partition must be empty (no connected
+ clients and no outputs).
+
:command:`moveoutput {OUTPUTNAME}`
Move an output to the current partition.
diff --git a/src/Instance.cxx b/src/Instance.cxx
index bcb8502f9..2d8003f42 100644
--- a/src/Instance.cxx
+++ b/src/Instance.cxx
@@ -87,6 +87,20 @@ Instance::FindPartition(const char *name) noexcept
return nullptr;
}
+void
+Instance::DeletePartition(Partition &partition) noexcept
+{
+ // TODO: use boost::intrusive::list to avoid this loop
+ for (auto i = partitions.begin();; ++i) {
+ assert(i != partitions.end());
+
+ if (&*i == &partition) {
+ partitions.erase(i);
+ break;
+ }
+ }
+}
+
#ifdef ENABLE_DATABASE
const Database &
diff --git a/src/Instance.hxx b/src/Instance.hxx
index 2b72c4521..0baebcc26 100644
--- a/src/Instance.hxx
+++ b/src/Instance.hxx
@@ -171,6 +171,8 @@ struct Instance final
gcc_pure
Partition *FindPartition(const char *name) noexcept;
+ void DeletePartition(Partition &partition) noexcept;
+
void BeginShutdownPartitions() noexcept;
#ifdef ENABLE_DATABASE
diff --git a/src/command/AllCommands.cxx b/src/command/AllCommands.cxx
index 73ae9b4e7..8943f44e0 100644
--- a/src/command/AllCommands.cxx
+++ b/src/command/AllCommands.cxx
@@ -103,6 +103,7 @@ static constexpr struct command commands[] = {
{ "decoders", PERMISSION_READ, 0, 0, handle_decoders },
{ "delete", PERMISSION_CONTROL, 1, 1, handle_delete },
{ "deleteid", PERMISSION_CONTROL, 1, 1, handle_deleteid },
+ { "delpartition", PERMISSION_ADMIN, 1, 1, handle_delpartition },
{ "disableoutput", PERMISSION_ADMIN, 1, 1, handle_disableoutput },
{ "enableoutput", PERMISSION_ADMIN, 1, 1, handle_enableoutput },
#ifdef ENABLE_DATABASE
diff --git a/src/command/PartitionCommands.cxx b/src/command/PartitionCommands.cxx
index bbb0e0143..fbcb8a754 100644
--- a/src/command/PartitionCommands.cxx
+++ b/src/command/PartitionCommands.cxx
@@ -113,6 +113,48 @@ handle_newpartition(Client &client, Request request, Response &response)
}
CommandResult
+handle_delpartition(Client &client, Request request, Response &response)
+{
+ const char *name = request.front();
+ if (!IsValidPartitionName(name)) {
+ response.Error(ACK_ERROR_ARG, "bad name");
+ return CommandResult::ERROR;
+ }
+
+ auto &instance = client.GetInstance();
+ auto *partition = instance.FindPartition(name);
+ if (partition == nullptr) {
+ response.Error(ACK_ERROR_NO_EXIST, "no such partition");
+ return CommandResult::ERROR;
+ }
+
+ if (partition == &instance.partitions.front()) {
+ response.Error(ACK_ERROR_UNKNOWN,
+ "cannot delete the default partition");
+ return CommandResult::ERROR;
+ }
+
+ if (!partition->clients.empty()) {
+ response.Error(ACK_ERROR_UNKNOWN,
+ "partition still has clients");
+ return CommandResult::ERROR;
+ }
+
+ if (!partition->outputs.IsDummy()) {
+ response.Error(ACK_ERROR_UNKNOWN,
+ "partition still has outputs");
+ return CommandResult::ERROR;
+ }
+
+ partition->BeginShutdown();
+ instance.DeletePartition(*partition);
+
+ instance.EmitIdle(IDLE_PARTITION);
+
+ return CommandResult::OK;
+}
+
+CommandResult
handle_moveoutput(Client &client, Request request, Response &response)
{
const char *output_name = request[0];
diff --git a/src/command/PartitionCommands.hxx b/src/command/PartitionCommands.hxx
index c840c0a82..22ce5df8c 100644
--- a/src/command/PartitionCommands.hxx
+++ b/src/command/PartitionCommands.hxx
@@ -36,6 +36,9 @@ CommandResult
handle_newpartition(Client &client, Request request, Response &response);
CommandResult
+handle_delpartition(Client &client, Request request, Response &response);
+
+CommandResult
handle_moveoutput(Client &client, Request request, Response &response);
#endif
diff --git a/src/output/MultipleOutputs.hxx b/src/output/MultipleOutputs.hxx
index fc65e8460..885f5f522 100644
--- a/src/output/MultipleOutputs.hxx
+++ b/src/output/MultipleOutputs.hxx
@@ -103,6 +103,18 @@ public:
}
/**
+ * Are all outputs dummy?
+ */
+ gcc_pure
+ bool IsDummy() const noexcept {
+ for (const auto &i : outputs)
+ if (!i->IsDummy())
+ return false;
+
+ return true;
+ }
+
+ /**
* Returns the audio output device with the specified name.
* Returns nullptr if the name does not exist.
*/