[modular][sessionctl] Add ability to list existing stories
This adds the command list_stories to sessionctl, which will immediately return the names of existing stories.
TEST=puppet_master_impl_unittest
MF-91 #comment [modular][sessionctl] Add ability to list existing stories
Change-Id: I8be5da0b3b34b2f81a7ffb31b83e47459677ac79
diff --git a/bin/sessionctl/logger.cc b/bin/sessionctl/logger.cc
index 1bda9ee..f8dfafa 100644
--- a/bin/sessionctl/logger.cc
+++ b/bin/sessionctl/logger.cc
@@ -10,6 +10,10 @@
const char kSuccessString[] = "success";
const char kCommandString[] = "command";
+// Key strings for JSON output.
+const char kParamsKeyString[] = "params";
+const char kStoriesKeyString[] = "stories";
+
Logger::Logger(bool json_out) : json_out_(json_out) {}
void Logger::LogError(const std::string& command,
@@ -29,6 +33,25 @@
}
void Logger::Log(const std::string& command,
+ const fidl::VectorPtr<fidl::StringPtr>& params) const {
+ std::stringstream output;
+
+ if (json_out_) {
+ std::cout << GenerateJsonLogString(command, params) << std::endl;
+ } else {
+ if (command == kListStoriesCommandString) {
+ output << "Stories in this session:" << std::endl;
+ }
+
+ for (auto& param : *params) {
+ output << param << std::endl;
+ }
+
+ std::cout << output.str() << std::endl;
+ }
+}
+
+void Logger::Log(const std::string& command,
const std::map<std::string, std::string>& params) const {
if (json_out_) {
std::cout << GenerateJsonLogString(command, params) << std::endl;
@@ -39,14 +62,36 @@
std::string Logger::GenerateJsonLogString(
const std::string& command,
- const std::map<std::string, std::string>& params) const {
- rapidjson::Document document;
- document.SetObject();
- document.AddMember(kSuccessString, true, document.GetAllocator());
- document.AddMember(kCommandString, command, document.GetAllocator());
+ const fidl::VectorPtr<fidl::StringPtr>& params) const {
+ rapidjson::Document document = GetDocument(command);
- // Generate params string. Ex. "mod_name": "mod1", "story_name": "story1"
- // std::string params_string;
+ // Generate array of |params| strings.
+ rapidjson::Document stories;
+ stories.SetArray();
+ for (auto& param : *params) {
+ rapidjson::Value story;
+ story.SetString(param.get().data(), param.get().size());
+ stories.PushBack(story, stories.GetAllocator());
+ }
+
+ // Determine what the strings in |params| represent.
+ rapidjson::Value key;
+ if (command == kListStoriesCommandString) {
+ key.SetString(kStoriesKeyString);
+ } else {
+ key.SetString(kParamsKeyString);
+ }
+
+ document.AddMember(key, stories, document.GetAllocator());
+ return JsonValueToPrettyString(document);
+}
+
+std::string Logger::GenerateJsonLogString(
+ const std::string& command,
+ const std::map<std::string, std::string>& params) const {
+ rapidjson::Document document = GetDocument(command);
+
+ // Generate a document containing |params| keys and values.
rapidjson::Document paramsJson;
paramsJson.SetObject();
for (const auto& p : params) {
@@ -58,10 +103,18 @@
paramsJson.AddMember(name, value, paramsJson.GetAllocator());
}
- document.AddMember("params", paramsJson, document.GetAllocator());
+ document.AddMember(kParamsKeyString, paramsJson, document.GetAllocator());
return JsonValueToPrettyString(document);
}
+rapidjson::Document Logger::GetDocument(const std::string& command) const {
+ rapidjson::Document document;
+ document.SetObject();
+ document.AddMember(kSuccessString, true, document.GetAllocator());
+ document.AddMember(kCommandString, command, document.GetAllocator());
+ return document;
+}
+
std::string Logger::GenerateLogString(
const std::string& command,
const std::map<std::string, std::string>& params) const {
diff --git a/bin/sessionctl/logger.h b/bin/sessionctl/logger.h
index c3820c5..09b9d47 100644
--- a/bin/sessionctl/logger.h
+++ b/bin/sessionctl/logger.h
@@ -26,6 +26,9 @@
void LogError(const std::string& command, const std::string& error) const;
void Log(const std::string& command,
+ const fidl::VectorPtr<fidl::StringPtr>& params) const;
+
+ void Log(const std::string& command,
const std::map<std::string, std::string>& params) const;
private:
@@ -33,8 +36,14 @@
// |params| to be logged.
std::string GenerateJsonLogString(
const std::string& command,
+ const fidl::VectorPtr<fidl::StringPtr>& params) const;
+
+ std::string GenerateJsonLogString(
+ const std::string& command,
const std::map<std::string, std::string>& params) const;
+ rapidjson::Document GetDocument(const std::string& command) const;
+
// Returns a string of the executed |command| with respective |params| to be
// logged.
std::string GenerateLogString(
diff --git a/bin/sessionctl/main.cc b/bin/sessionctl/main.cc
index ee49a9f..3e0b014 100644
--- a/bin/sessionctl/main.cc
+++ b/bin/sessionctl/main.cc
@@ -102,7 +102,10 @@
delete_story
Delete the story.
required: --story_name
- optional: --json_out)";
+ optional: --json_out
+
+ list_stories
+ List all the stories in the current session.)";
}
PuppetMasterPtr ConnectToPuppetMaster(const ActiveSession& session) {
diff --git a/bin/sessionctl/session_ctl_app.cc b/bin/sessionctl/session_ctl_app.cc
index 2dc71f7..c4504eb 100644
--- a/bin/sessionctl/session_ctl_app.cc
+++ b/bin/sessionctl/session_ctl_app.cc
@@ -24,6 +24,8 @@
return ExecuteRemoveModCommand(command_line);
} else if (cmd == kDeleteStoryCommandString) {
return ExecuteDeleteStoryCommand(command_line);
+ } else if (cmd == kListStoriesCommandString) {
+ return ExecuteListStoriesCommand();
} else {
return kGetUsageErrorString;
}
@@ -149,6 +151,18 @@
return parsing_error;
}
+std::string SessionCtlApp::ExecuteListStoriesCommand() {
+ async::PostTask(dispatcher_, [this]() mutable {
+ puppet_master_->GetStories(
+ [this](fidl::VectorPtr<fidl::StringPtr> story_names) {
+ logger_.Log(kListStoriesCommandString, std::move(story_names));
+ on_command_executed_();
+ });
+ });
+
+ return "";
+}
+
fuchsia::modular::StoryCommand SessionCtlApp::MakeFocusStoryCommand() {
fuchsia::modular::StoryCommand command;
fuchsia::modular::SetFocusState set_focus_state;
diff --git a/bin/sessionctl/session_ctl_app.h b/bin/sessionctl/session_ctl_app.h
index a24c1cf..58e39e0 100644
--- a/bin/sessionctl/session_ctl_app.h
+++ b/bin/sessionctl/session_ctl_app.h
@@ -46,6 +46,7 @@
std::string ExecuteAddModCommand(const fxl::CommandLine& command_line);
std::string ExecuteRemoveModCommand(const fxl::CommandLine& command_line);
std::string ExecuteDeleteStoryCommand(const fxl::CommandLine& command_line);
+ std::string ExecuteListStoriesCommand();
private:
// Focus the story to which the mod we are adding belongs.
diff --git a/bin/sessionctl/session_ctl_constants.h b/bin/sessionctl/session_ctl_constants.h
index a95d377..890a223 100644
--- a/bin/sessionctl/session_ctl_constants.h
+++ b/bin/sessionctl/session_ctl_constants.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef PERIDOT_BIN_SESSIONCTL_COMMAND_NAMES_H_
-#define PERIDOT_BIN_SESSIONCTL_COMMAND_NAMES_H_
+#ifndef PERIDOT_BIN_SESSIONCTL_SESSION_CTL_CONSTANTS_H_
+#define PERIDOT_BIN_SESSIONCTL_SESSION_CTL_CONSTANTS_H_
namespace modular {
@@ -11,6 +11,7 @@
constexpr char kAddModCommandString[] = "add_mod";
constexpr char kDeleteStoryCommandString[] = "delete_story";
constexpr char kRemoveModCommandString[] = "remove_mod";
+constexpr char kListStoriesCommandString[] = "list_stories";
// Flags to pass to SessionCtlApp.
constexpr char kJsonOutFlagString[] = "json_out";
@@ -26,4 +27,4 @@
constexpr char kGetUsageErrorString[] = "GetUsage";
} // namespace modular
-#endif // PERIDOT_BIN_SESSIONCTL_COMMAND_NAMES_H_
+#endif // PERIDOT_BIN_SESSIONCTL_SESSION_CTL_CONSTANTS_H_
diff --git a/bin/sessionmgr/puppet_master/puppet_master_impl.cc b/bin/sessionmgr/puppet_master/puppet_master_impl.cc
index f20a486..68c466c 100644
--- a/bin/sessionmgr/puppet_master/puppet_master_impl.cc
+++ b/bin/sessionmgr/puppet_master/puppet_master_impl.cc
@@ -4,6 +4,7 @@
#include "peridot/bin/sessionmgr/puppet_master/puppet_master_impl.h"
+#include <lib/fxl/functional/make_copyable.h>
#include <lib/fxl/logging.h>
#include "peridot/bin/sessionmgr/puppet_master/story_puppet_master_impl.h"
@@ -33,13 +34,6 @@
story_puppet_masters_.AddBinding(std::move(controller), std::move(request));
}
-void PuppetMasterImpl::WatchSession(
- fidl::InterfaceHandle<fuchsia::modular::SessionWatcher> session_watcher,
- fuchsia::modular::WatchSessionOptionsPtr options,
- WatchSessionCallback done) {
- FXL_NOTIMPLEMENTED();
-}
-
void PuppetMasterImpl::DeleteStory(fidl::StringPtr story_name,
DeleteStoryCallback done) {
session_storage_->DeleteStory(story_name)->Then([done = std::move(done)] {
@@ -47,4 +41,18 @@
});
}
+void PuppetMasterImpl::GetStories(GetStoriesCallback done) {
+ session_storage_->GetAllStoryData()->Then(
+ [done = std::move(done)](
+ fidl::VectorPtr<fuchsia::modular::internal::StoryData>
+ all_story_data) {
+ auto result = fidl::VectorPtr<fidl::StringPtr>::New(0);
+ for (auto& story : *all_story_data) {
+ result.push_back(std::move(story.story_info.id));
+ }
+
+ done(std::move(result));
+ });
+}
+
} // namespace modular
diff --git a/bin/sessionmgr/puppet_master/puppet_master_impl.h b/bin/sessionmgr/puppet_master/puppet_master_impl.h
index 178de42..6260956 100644
--- a/bin/sessionmgr/puppet_master/puppet_master_impl.h
+++ b/bin/sessionmgr/puppet_master/puppet_master_impl.h
@@ -35,15 +35,12 @@
request) override;
// |PuppetMaster|
- void WatchSession(
- fidl::InterfaceHandle<fuchsia::modular::SessionWatcher> session_watcher,
- fuchsia::modular::WatchSessionOptionsPtr options,
- WatchSessionCallback done) override;
-
- // |PuppetMaster|
void DeleteStory(fidl::StringPtr story_name,
DeleteStoryCallback done) override;
+ // |PuppetMaster|
+ void GetStories(GetStoriesCallback done) override;
+
SessionStorage* const session_storage_; // Not owned.
StoryCommandExecutor* const executor_; // Not owned.
diff --git a/bin/sessionmgr/puppet_master/puppet_master_impl_unittest.cc b/bin/sessionmgr/puppet_master/puppet_master_impl_unittest.cc
index 5b45b0d..24176e3 100644
--- a/bin/sessionmgr/puppet_master/puppet_master_impl_unittest.cc
+++ b/bin/sessionmgr/puppet_master/puppet_master_impl_unittest.cc
@@ -303,5 +303,27 @@
RunLoopUntil([&] { return done; });
}
+TEST_F(PuppetMasterTest, GetStories) {
+ // Zero stories to should exist.
+ bool done{};
+ ptr_->GetStories([&](fidl::VectorPtr<fidl::StringPtr> story_names) {
+ EXPECT_EQ(0u, story_names->size());
+ done = true;
+ });
+ RunLoopUntil([&] { return done; });
+
+ // Create a story.
+ storage_->CreateStory("foo", {} /* extra_info */, {} /* story_options */);
+
+ // "foo" should be listed.
+ done = false;
+ ptr_->GetStories([&](fidl::VectorPtr<fidl::StringPtr> story_names) {
+ ASSERT_EQ(1u, story_names->size());
+ EXPECT_EQ("foo", story_names->at(0));
+ done = true;
+ });
+ RunLoopUntil([&] { return done; });
+}
+
} // namespace
} // namespace modular
diff --git a/public/fidl/fuchsia.modular/story/puppet_master.fidl b/public/fidl/fuchsia.modular/story/puppet_master.fidl
index 0541a98..ed7bbb4 100644
--- a/public/fidl/fuchsia.modular/story/puppet_master.fidl
+++ b/public/fidl/fuchsia.modular/story/puppet_master.fidl
@@ -55,17 +55,13 @@
// |request| is closed if control cannot be granted.
//
// TODO(thatguy): We want story names to be scoped to the client's namespace.
- 1: ControlStory(string story_name, request<StoryPuppetMaster> request);
-
- // Events on the session will be sent to |watcher| as long as |watcher| is
- // alive. |options| specifies filters and policy about which events are sent
- // to |watcher|.
- //
- // NOTE: Not implemented yet, pending MF-85.
- 2: WatchSession(SessionWatcher watcher, WatchSessionOptions? options) -> ();
+ ControlStory(string story_name, request<StoryPuppetMaster> request);
// Deletes a story associated to |story_name|.
- 3: DeleteStory(string story_name) -> ();
+ DeleteStory(string story_name) -> ();
+
+ // Returns a list of all the names of stories in the session.
+ GetStories() -> (vector<string> story_names);
};
struct WatchSessionOptions {
@@ -74,40 +70,25 @@
int32 placeholder;
};
-interface SessionWatcher {
- // Some events, in particular those that represent changes to internal
- // modular framework state, or those that do not pertain to a single story,
- // are not represented as commands.
- 1: OnStoryRuntimeState(StoryState state);
-
- // Indicates the story record was permanently deleted from storage.
- 2: OnStoryDeleted(string story_name);
-
- // Notifies of StoryCommands. If |is_last| == false, more StoryCommands
- // were executed in a single batch than can be fit into one message and the
- // client should expect further calls to OnStoryCommands() immediately.
- 3: OnStoryCommands(string story_name, vector<StoryCommand> commands, bool is_last);
-};
-
interface StoryPuppetMaster {
// Enqueues the given |commands| in the order they are given.
// Can be called as many times as necessary to specify the full
// set of changes to the story.
//
// To execute all enqueued commands, call Execute().
- 1: Enqueue(vector<StoryCommand> commands);
+ Enqueue(vector<StoryCommand> commands);
// Executes the commands enqueued so far by Enqueue() in order and as
// a batch: no other commands from other clients will be interleaved.
//
// If an error occurs, execution is stopped and an error code
// and message are returned in |result|.
- 2: Execute() -> (ExecuteResult result);
+ Execute() -> (ExecuteResult result);
// If this story is new, sets the options for its creation. Must be called
// before the first call to Execute(). Any subsequent calls (either on the
// same channel or on a new StoryPuppetMaster for an existing story) are
// ignored. Some StoryOptions can be changed through specific story commands.
// See story_command.fidl for details.
- 3: SetCreateOptions(StoryOptions story_options);
+ SetCreateOptions(StoryOptions story_options);
};