blob: 9e1211a7df600dcce0fea53454c6b84e620de00b [file] [log] [blame]
Alex Vakulenkoaa3a5592014-08-07 07:24:06 -07001// Copyright 2014 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "buffet/commands/command_instance.h"
6
Alex Vakulenko8dc69af2014-08-07 10:29:42 -07007#include <base/values.h>
Alex Vakulenkoa8b95bc2014-08-27 11:00:57 -07008#include <chromeos/errors/error.h>
9#include <chromeos/errors/error_codes.h>
Alex Vakulenko8dc69af2014-08-07 10:29:42 -070010
11#include "buffet/commands/command_definition.h"
12#include "buffet/commands/command_dictionary.h"
Alex Vakulenkof6b38712014-09-03 16:23:38 -070013#include "buffet/commands/command_proxy_interface.h"
14#include "buffet/commands/command_queue.h"
Alex Vakulenko8dc69af2014-08-07 10:29:42 -070015#include "buffet/commands/schema_constants.h"
16#include "buffet/commands/schema_utils.h"
Alex Vakulenko8dc69af2014-08-07 10:29:42 -070017
Alex Vakulenkoaa3a5592014-08-07 07:24:06 -070018namespace buffet {
19
Alex Vakulenkof6b38712014-09-03 16:23:38 -070020const char CommandInstance::kStatusQueued[] = "queued";
21const char CommandInstance::kStatusInProgress[] = "inProgress";
22const char CommandInstance::kStatusPaused[] = "paused";
23const char CommandInstance::kStatusError[] = "error";
24const char CommandInstance::kStatusDone[] = "done";
25const char CommandInstance::kStatusCanceled[] = "canceled";
26const char CommandInstance::kStatusAborted[] = "aborted";
27const char CommandInstance::kStatusExpired[] = "expired";
28
Alex Vakulenkoaa3a5592014-08-07 07:24:06 -070029CommandInstance::CommandInstance(const std::string& name,
30 const std::string& category,
31 const native_types::Object& parameters)
32 : name_(name), category_(category), parameters_(parameters) {
33}
34
35std::shared_ptr<const PropValue> CommandInstance::FindParameter(
36 const std::string& name) const {
37 std::shared_ptr<const PropValue> value;
38 auto p = parameters_.find(name);
39 if (p != parameters_.end())
40 value = p->second;
41 return value;
42}
43
Alex Vakulenko8dc69af2014-08-07 10:29:42 -070044namespace {
45
46// Helper method to retrieve command parameters from the command definition
47// object passed in as |json| and corresponding command definition schema
48// specified in |command_def|.
49// On success, returns |true| and the validated parameters and values through
50// |parameters|. Otherwise returns |false| and additional error information in
51// |error|.
52bool GetCommandParameters(const base::DictionaryValue* json,
53 const CommandDefinition* command_def,
54 native_types::Object* parameters,
Alex Vakulenko5f472062014-08-14 17:54:04 -070055 chromeos::ErrorPtr* error) {
Alex Vakulenko8dc69af2014-08-07 10:29:42 -070056 // Get the command parameters from 'parameters' property.
57 base::DictionaryValue no_params; // Placeholder when no params are specified.
58 const base::DictionaryValue* params = nullptr;
59 const base::Value* params_value = nullptr;
60 if (json->GetWithoutPathExpansion(commands::attributes::kCommand_Parameters,
61 &params_value)) {
62 // Make sure the "parameters" property is actually an object.
63 if (!params_value->GetAsDictionary(&params)) {
Alex Vakulenko5f472062014-08-14 17:54:04 -070064 chromeos::Error::AddToPrintf(error, chromeos::errors::json::kDomain,
65 chromeos::errors::json::kObjectExpected,
66 "Property '%s' must be a JSON object",
67 commands::attributes::kCommand_Parameters);
Alex Vakulenko8dc69af2014-08-07 10:29:42 -070068 return false;
69 }
70 } else {
71 // "parameters" are not specified. Assume empty param list.
72 params = &no_params;
73 }
74
75 // Now read in the parameters and validate their values against the command
76 // definition schema.
77 if (!TypedValueFromJson(params, command_def->GetParameters().get(),
78 parameters, error)) {
79 return false;
80 }
81 return true;
82}
83
84} // anonymous namespace
85
Alex Vakulenkofedc4872014-08-20 12:38:43 -070086std::unique_ptr<CommandInstance> CommandInstance::FromJson(
Alex Vakulenko8dc69af2014-08-07 10:29:42 -070087 const base::Value* value,
88 const CommandDictionary& dictionary,
Alex Vakulenko5f472062014-08-14 17:54:04 -070089 chromeos::ErrorPtr* error) {
Alex Vakulenkofedc4872014-08-20 12:38:43 -070090 std::unique_ptr<CommandInstance> instance;
Alex Vakulenko8dc69af2014-08-07 10:29:42 -070091 // Get the command JSON object from the value.
92 const base::DictionaryValue* json = nullptr;
93 if (!value->GetAsDictionary(&json)) {
Alex Vakulenko5f472062014-08-14 17:54:04 -070094 chromeos::Error::AddTo(error, chromeos::errors::json::kDomain,
95 chromeos::errors::json::kObjectExpected,
96 "Command instance is not a JSON object");
Alex Vakulenko8dc69af2014-08-07 10:29:42 -070097 return instance;
98 }
99
100 // Get the command name from 'name' property.
101 std::string command_name;
102 if (!json->GetStringWithoutPathExpansion(commands::attributes::kCommand_Name,
103 &command_name)) {
Alex Vakulenko5f472062014-08-14 17:54:04 -0700104 chromeos::Error::AddTo(error, errors::commands::kDomain,
105 errors::commands::kPropertyMissing,
106 "Command name is missing");
Alex Vakulenko8dc69af2014-08-07 10:29:42 -0700107 return instance;
108 }
109 // Make sure we know how to handle the command with this name.
110 const CommandDefinition* command_def = dictionary.FindCommand(command_name);
111 if (!command_def) {
Alex Vakulenko5f472062014-08-14 17:54:04 -0700112 chromeos::Error::AddToPrintf(error, errors::commands::kDomain,
113 errors::commands::kInvalidCommandName,
114 "Unknown command received: %s",
115 command_name.c_str());
Alex Vakulenko8dc69af2014-08-07 10:29:42 -0700116 return instance;
117 }
118
119 native_types::Object parameters;
120 if (!GetCommandParameters(json, command_def, &parameters, error)) {
Alex Vakulenko5f472062014-08-14 17:54:04 -0700121 chromeos::Error::AddToPrintf(error, errors::commands::kDomain,
122 errors::commands::kCommandFailed,
123 "Failed to validate command '%s'",
124 command_name.c_str());
Alex Vakulenko8dc69af2014-08-07 10:29:42 -0700125 return instance;
126 }
127
Alex Vakulenkofedc4872014-08-20 12:38:43 -0700128 instance.reset(new CommandInstance(command_name,
129 command_def->GetCategory(),
Alex Vakulenko8dc69af2014-08-07 10:29:42 -0700130 parameters));
131 return instance;
132}
133
Alex Vakulenkof6b38712014-09-03 16:23:38 -0700134bool CommandInstance::SetProgress(int progress) {
135 if (progress < 0 || progress > 100)
136 return false;
137 if (progress != progress_) {
138 progress_ = progress;
139 SetStatus(kStatusInProgress);
140 if (proxy_)
141 proxy_->OnProgressChanged(progress_);
142 }
143 return true;
144}
145
146void CommandInstance::Abort() {
147 SetStatus(kStatusAborted);
148 RemoveFromQueue();
149 // The command will be destroyed after that, so do not access any members.
150}
151
152void CommandInstance::Cancel() {
153 SetStatus(kStatusCanceled);
154 RemoveFromQueue();
155 // The command will be destroyed after that, so do not access any members.
156}
157
158void CommandInstance::Done() {
159 SetProgress(100);
160 SetStatus(kStatusDone);
161 RemoveFromQueue();
162 // The command will be destroyed after that, so do not access any members.
163}
164
165void CommandInstance::SetStatus(const std::string& status) {
166 if (status != status_) {
167 status_ = status;
168 if (proxy_)
169 proxy_->OnStatusChanged(status_);
170 }
171}
172
173void CommandInstance::RemoveFromQueue() {
174 if (queue_) {
175 // Store this instance in unique_ptr until the end of this method,
176 // otherwise it will be destroyed as soon as CommandQueue::Remove() returns.
177 std::unique_ptr<CommandInstance> this_instance = queue_->Remove(GetID());
178 // The command instance will survive till the end of this scope.
179 }
180}
181
Alex Vakulenkoaa3a5592014-08-07 07:24:06 -0700182
183} // namespace buffet