Vitaly Buka | 4615e0d | 2015-10-14 15:35:12 -0700 | [diff] [blame] | 1 | // Copyright 2015 The Weave Authors. All rights reserved. |
Alex Vakulenko | aa3a559 | 2014-08-07 07:24:06 -0700 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
Stefan Sauer | 2d16dfa | 2015-09-25 17:08:35 +0200 | [diff] [blame] | 5 | #include "src/commands/command_instance.h" |
Alex Vakulenko | aa3a559 | 2014-08-07 07:24:06 -0700 | [diff] [blame] | 6 | |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 7 | #include <base/values.h> |
Vitaly Buka | 7b382ac | 2015-08-03 13:50:01 -0700 | [diff] [blame] | 8 | #include <weave/enum_to_string.h> |
Vitaly Buka | 0801a1f | 2015-08-14 10:03:46 -0700 | [diff] [blame] | 9 | #include <weave/error.h> |
Alex Vakulenko | 4e4dfd4 | 2015-08-06 14:01:42 -0700 | [diff] [blame] | 10 | #include <weave/export.h> |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 11 | |
Stefan Sauer | 2d16dfa | 2015-09-25 17:08:35 +0200 | [diff] [blame] | 12 | #include "src/commands/command_dictionary.h" |
| 13 | #include "src/commands/command_queue.h" |
Stefan Sauer | 2d16dfa | 2015-09-25 17:08:35 +0200 | [diff] [blame] | 14 | #include "src/commands/schema_constants.h" |
Stefan Sauer | 2d16dfa | 2015-09-25 17:08:35 +0200 | [diff] [blame] | 15 | #include "src/json_error_codes.h" |
Vitaly Buka | 70f77d9 | 2015-10-07 15:42:40 -0700 | [diff] [blame] | 16 | #include "src/utils.h" |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 17 | |
Vitaly Buka | b6f015a | 2015-07-09 14:59:23 -0700 | [diff] [blame] | 18 | namespace weave { |
Alex Vakulenko | aa3a559 | 2014-08-07 07:24:06 -0700 | [diff] [blame] | 19 | |
Vitaly Buka | 15f5909 | 2015-07-24 16:54:32 -0700 | [diff] [blame] | 20 | namespace { |
| 21 | |
Vitaly Buka | 0209da4 | 2015-10-08 00:07:18 -0700 | [diff] [blame] | 22 | const EnumToStringMap<Command::State>::Map kMapStatus[] = { |
| 23 | {Command::State::kQueued, "queued"}, |
| 24 | {Command::State::kInProgress, "inProgress"}, |
| 25 | {Command::State::kPaused, "paused"}, |
| 26 | {Command::State::kError, "error"}, |
| 27 | {Command::State::kDone, "done"}, |
| 28 | {Command::State::kCancelled, "cancelled"}, |
| 29 | {Command::State::kAborted, "aborted"}, |
| 30 | {Command::State::kExpired, "expired"}, |
Vitaly Buka | 15f5909 | 2015-07-24 16:54:32 -0700 | [diff] [blame] | 31 | }; |
| 32 | |
Vitaly Buka | 0209da4 | 2015-10-08 00:07:18 -0700 | [diff] [blame] | 33 | const EnumToStringMap<Command::Origin>::Map kMapOrigin[] = { |
| 34 | {Command::Origin::kLocal, "local"}, |
| 35 | {Command::Origin::kCloud, "cloud"}, |
Vitaly Buka | 15f5909 | 2015-07-24 16:54:32 -0700 | [diff] [blame] | 36 | }; |
| 37 | |
Vitaly Buka | 47a1f6f | 2015-10-07 18:09:57 -0700 | [diff] [blame] | 38 | bool ReportInvalidStateTransition(ErrorPtr* error, |
Vitaly Buka | 0209da4 | 2015-10-08 00:07:18 -0700 | [diff] [blame] | 39 | Command::State from, |
| 40 | Command::State to) { |
Vitaly Buka | 47a1f6f | 2015-10-07 18:09:57 -0700 | [diff] [blame] | 41 | Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain, |
| 42 | errors::commands::kInvalidState, |
| 43 | "State switch impossible: '%s' -> '%s'", |
| 44 | EnumToString(from).c_str(), EnumToString(to).c_str()); |
| 45 | return false; |
Vitaly Buka | c602926 | 2015-10-07 09:29:13 -0700 | [diff] [blame] | 46 | } |
| 47 | |
Vitaly Buka | 15f5909 | 2015-07-24 16:54:32 -0700 | [diff] [blame] | 48 | } // namespace |
| 49 | |
| 50 | template <> |
Vitaly Buka | 0209da4 | 2015-10-08 00:07:18 -0700 | [diff] [blame] | 51 | LIBWEAVE_EXPORT EnumToStringMap<Command::State>::EnumToStringMap() |
Vitaly Buka | 15f5909 | 2015-07-24 16:54:32 -0700 | [diff] [blame] | 52 | : EnumToStringMap(kMapStatus) {} |
| 53 | |
| 54 | template <> |
Vitaly Buka | 0209da4 | 2015-10-08 00:07:18 -0700 | [diff] [blame] | 55 | LIBWEAVE_EXPORT EnumToStringMap<Command::Origin>::EnumToStringMap() |
Vitaly Buka | 15f5909 | 2015-07-24 16:54:32 -0700 | [diff] [blame] | 56 | : EnumToStringMap(kMapOrigin) {} |
Alex Vakulenko | f6b3871 | 2014-09-03 16:23:38 -0700 | [diff] [blame] | 57 | |
Alex Vakulenko | 5ef7579 | 2015-03-19 15:50:44 -0700 | [diff] [blame] | 58 | CommandInstance::CommandInstance(const std::string& name, |
Vitaly Buka | 0209da4 | 2015-10-08 00:07:18 -0700 | [diff] [blame] | 59 | Command::Origin origin, |
Alex Vakulenko | 36bf1b5 | 2015-11-23 09:35:37 -0800 | [diff] [blame] | 60 | const base::DictionaryValue& parameters) |
Alex Vakulenko | 2c7740a | 2015-11-30 08:51:29 -0800 | [diff] [blame] | 61 | : name_{name}, origin_{origin} { |
Alex Vakulenko | 36bf1b5 | 2015-11-23 09:35:37 -0800 | [diff] [blame] | 62 | parameters_.MergeDictionary(¶meters); |
Alex Vakulenko | aa3a559 | 2014-08-07 07:24:06 -0700 | [diff] [blame] | 63 | } |
| 64 | |
Vitaly Buka | c3d4e97 | 2015-07-21 09:55:25 -0700 | [diff] [blame] | 65 | CommandInstance::~CommandInstance() { |
Vitaly Buka | 157b16a | 2015-07-31 16:20:48 -0700 | [diff] [blame] | 66 | FOR_EACH_OBSERVER(Observer, observers_, OnCommandDestroyed()); |
Vitaly Buka | c3d4e97 | 2015-07-21 09:55:25 -0700 | [diff] [blame] | 67 | } |
Anton Muhin | b66a930 | 2014-11-10 22:15:22 +0400 | [diff] [blame] | 68 | |
Vitaly Buka | 8d8d219 | 2015-07-21 22:25:09 -0700 | [diff] [blame] | 69 | const std::string& CommandInstance::GetID() const { |
| 70 | return id_; |
| 71 | } |
| 72 | |
| 73 | const std::string& CommandInstance::GetName() const { |
| 74 | return name_; |
| 75 | } |
| 76 | |
Vitaly Buka | 0209da4 | 2015-10-08 00:07:18 -0700 | [diff] [blame] | 77 | Command::State CommandInstance::GetState() const { |
| 78 | return state_; |
Vitaly Buka | 8d8d219 | 2015-07-21 22:25:09 -0700 | [diff] [blame] | 79 | } |
| 80 | |
Vitaly Buka | 0209da4 | 2015-10-08 00:07:18 -0700 | [diff] [blame] | 81 | Command::Origin CommandInstance::GetOrigin() const { |
Vitaly Buka | 8d8d219 | 2015-07-21 22:25:09 -0700 | [diff] [blame] | 82 | return origin_; |
| 83 | } |
| 84 | |
Vitaly Buka | c430560 | 2015-11-24 23:33:09 -0800 | [diff] [blame] | 85 | const base::DictionaryValue& CommandInstance::GetParameters() const { |
| 86 | return parameters_; |
Vitaly Buka | 8d8d219 | 2015-07-21 22:25:09 -0700 | [diff] [blame] | 87 | } |
| 88 | |
Vitaly Buka | c430560 | 2015-11-24 23:33:09 -0800 | [diff] [blame] | 89 | const base::DictionaryValue& CommandInstance::GetProgress() const { |
| 90 | return progress_; |
Vitaly Buka | 8d8d219 | 2015-07-21 22:25:09 -0700 | [diff] [blame] | 91 | } |
| 92 | |
Vitaly Buka | c430560 | 2015-11-24 23:33:09 -0800 | [diff] [blame] | 93 | const base::DictionaryValue& CommandInstance::GetResults() const { |
| 94 | return results_; |
Alex Vakulenko | aa3a559 | 2014-08-07 07:24:06 -0700 | [diff] [blame] | 95 | } |
| 96 | |
Vitaly Buka | 47a1f6f | 2015-10-07 18:09:57 -0700 | [diff] [blame] | 97 | const Error* CommandInstance::GetError() const { |
| 98 | return error_.get(); |
| 99 | } |
| 100 | |
Vitaly Buka | 4f4e228 | 2015-07-23 17:50:07 -0700 | [diff] [blame] | 101 | bool CommandInstance::SetProgress(const base::DictionaryValue& progress, |
Vitaly Buka | 0801a1f | 2015-08-14 10:03:46 -0700 | [diff] [blame] | 102 | ErrorPtr* error) { |
Vitaly Buka | 4f4e228 | 2015-07-23 17:50:07 -0700 | [diff] [blame] | 103 | // Change status even if progress unchanged, e.g. 0% -> 0%. |
Vitaly Buka | 0209da4 | 2015-10-08 00:07:18 -0700 | [diff] [blame] | 104 | if (!SetStatus(State::kInProgress, error)) |
Vitaly Buka | 47a1f6f | 2015-10-07 18:09:57 -0700 | [diff] [blame] | 105 | return false; |
| 106 | |
Alex Vakulenko | 36bf1b5 | 2015-11-23 09:35:37 -0800 | [diff] [blame] | 107 | if (!progress_.Equals(&progress)) { |
| 108 | progress_.Clear(); |
| 109 | progress_.MergeDictionary(&progress); |
Vitaly Buka | 157b16a | 2015-07-31 16:20:48 -0700 | [diff] [blame] | 110 | FOR_EACH_OBSERVER(Observer, observers_, OnProgressChanged()); |
Vitaly Buka | 4f4e228 | 2015-07-23 17:50:07 -0700 | [diff] [blame] | 111 | } |
Vitaly Buka | 47a1f6f | 2015-10-07 18:09:57 -0700 | [diff] [blame] | 112 | |
Vitaly Buka | 4f4e228 | 2015-07-23 17:50:07 -0700 | [diff] [blame] | 113 | return true; |
| 114 | } |
| 115 | |
Vitaly Buka | 2f54897 | 2015-10-08 19:34:49 -0700 | [diff] [blame] | 116 | bool CommandInstance::Complete(const base::DictionaryValue& results, |
| 117 | ErrorPtr* error) { |
Alex Vakulenko | 36bf1b5 | 2015-11-23 09:35:37 -0800 | [diff] [blame] | 118 | if (!results_.Equals(&results)) { |
| 119 | results_.Clear(); |
| 120 | results_.MergeDictionary(&results); |
Vitaly Buka | 157b16a | 2015-07-31 16:20:48 -0700 | [diff] [blame] | 121 | FOR_EACH_OBSERVER(Observer, observers_, OnResultsChanged()); |
Vitaly Buka | 4f4e228 | 2015-07-23 17:50:07 -0700 | [diff] [blame] | 122 | } |
Vitaly Buka | 47a1f6f | 2015-10-07 18:09:57 -0700 | [diff] [blame] | 123 | // Change status even if result is unchanged. |
Vitaly Buka | 0209da4 | 2015-10-08 00:07:18 -0700 | [diff] [blame] | 124 | bool result = SetStatus(State::kDone, error); |
Vitaly Buka | 47a1f6f | 2015-10-07 18:09:57 -0700 | [diff] [blame] | 125 | RemoveFromQueue(); |
| 126 | // The command will be destroyed after that, so do not access any members. |
| 127 | return result; |
| 128 | } |
| 129 | |
| 130 | bool CommandInstance::SetError(const Error* command_error, ErrorPtr* error) { |
| 131 | error_ = command_error ? command_error->Clone() : nullptr; |
Vitaly Buka | 375f328 | 2015-10-07 18:34:15 -0700 | [diff] [blame] | 132 | FOR_EACH_OBSERVER(Observer, observers_, OnErrorChanged()); |
Vitaly Buka | 0209da4 | 2015-10-08 00:07:18 -0700 | [diff] [blame] | 133 | return SetStatus(State::kError, error); |
Vitaly Buka | 4f4e228 | 2015-07-23 17:50:07 -0700 | [diff] [blame] | 134 | } |
| 135 | |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 136 | namespace { |
| 137 | |
| 138 | // Helper method to retrieve command parameters from the command definition |
Alex Vakulenko | 2c7740a | 2015-11-30 08:51:29 -0800 | [diff] [blame] | 139 | // object passed in as |json|. |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 140 | // On success, returns |true| and the validated parameters and values through |
| 141 | // |parameters|. Otherwise returns |false| and additional error information in |
| 142 | // |error|. |
Alex Vakulenko | 36bf1b5 | 2015-11-23 09:35:37 -0800 | [diff] [blame] | 143 | std::unique_ptr<base::DictionaryValue> GetCommandParameters( |
| 144 | const base::DictionaryValue* json, |
Alex Vakulenko | 36bf1b5 | 2015-11-23 09:35:37 -0800 | [diff] [blame] | 145 | ErrorPtr* error) { |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 146 | // Get the command parameters from 'parameters' property. |
Alex Vakulenko | 36bf1b5 | 2015-11-23 09:35:37 -0800 | [diff] [blame] | 147 | std::unique_ptr<base::DictionaryValue> params; |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 148 | const base::Value* params_value = nullptr; |
Alex Vakulenko | f784e21 | 2015-04-20 12:33:52 -0700 | [diff] [blame] | 149 | if (json->Get(commands::attributes::kCommand_Parameters, ¶ms_value)) { |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 150 | // Make sure the "parameters" property is actually an object. |
Alex Vakulenko | 36bf1b5 | 2015-11-23 09:35:37 -0800 | [diff] [blame] | 151 | const base::DictionaryValue* params_dict = nullptr; |
| 152 | if (!params_value->GetAsDictionary(¶ms_dict)) { |
Vitaly Buka | 0801a1f | 2015-08-14 10:03:46 -0700 | [diff] [blame] | 153 | Error::AddToPrintf(error, FROM_HERE, errors::json::kDomain, |
| 154 | errors::json::kObjectExpected, |
| 155 | "Property '%s' must be a JSON object", |
| 156 | commands::attributes::kCommand_Parameters); |
Alex Vakulenko | 36bf1b5 | 2015-11-23 09:35:37 -0800 | [diff] [blame] | 157 | return params; |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 158 | } |
Alex Vakulenko | 36bf1b5 | 2015-11-23 09:35:37 -0800 | [diff] [blame] | 159 | params.reset(params_dict->DeepCopy()); |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 160 | } else { |
| 161 | // "parameters" are not specified. Assume empty param list. |
Alex Vakulenko | 36bf1b5 | 2015-11-23 09:35:37 -0800 | [diff] [blame] | 162 | params.reset(new base::DictionaryValue); |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 163 | } |
Alex Vakulenko | 36bf1b5 | 2015-11-23 09:35:37 -0800 | [diff] [blame] | 164 | return params; |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 165 | } |
| 166 | |
| 167 | } // anonymous namespace |
| 168 | |
Alex Vakulenko | fedc487 | 2014-08-20 12:38:43 -0700 | [diff] [blame] | 169 | std::unique_ptr<CommandInstance> CommandInstance::FromJson( |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 170 | const base::Value* value, |
Vitaly Buka | 0209da4 | 2015-10-08 00:07:18 -0700 | [diff] [blame] | 171 | Command::Origin origin, |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 172 | const CommandDictionary& dictionary, |
Alex Vakulenko | d1978d3 | 2015-04-29 17:33:26 -0700 | [diff] [blame] | 173 | std::string* command_id, |
Vitaly Buka | 0801a1f | 2015-08-14 10:03:46 -0700 | [diff] [blame] | 174 | ErrorPtr* error) { |
Alex Vakulenko | fedc487 | 2014-08-20 12:38:43 -0700 | [diff] [blame] | 175 | std::unique_ptr<CommandInstance> instance; |
Alex Vakulenko | d1978d3 | 2015-04-29 17:33:26 -0700 | [diff] [blame] | 176 | std::string command_id_buffer; // used if |command_id| was nullptr. |
| 177 | if (!command_id) |
| 178 | command_id = &command_id_buffer; |
| 179 | |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 180 | // Get the command JSON object from the value. |
| 181 | const base::DictionaryValue* json = nullptr; |
| 182 | if (!value->GetAsDictionary(&json)) { |
Vitaly Buka | 0801a1f | 2015-08-14 10:03:46 -0700 | [diff] [blame] | 183 | Error::AddTo(error, FROM_HERE, errors::json::kDomain, |
| 184 | errors::json::kObjectExpected, |
| 185 | "Command instance is not a JSON object"); |
Alex Vakulenko | d1978d3 | 2015-04-29 17:33:26 -0700 | [diff] [blame] | 186 | command_id->clear(); |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 187 | return instance; |
| 188 | } |
| 189 | |
Alex Vakulenko | d1978d3 | 2015-04-29 17:33:26 -0700 | [diff] [blame] | 190 | // Get the command ID from 'id' property. |
| 191 | if (!json->GetString(commands::attributes::kCommand_Id, command_id)) |
| 192 | command_id->clear(); |
| 193 | |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 194 | // Get the command name from 'name' property. |
| 195 | std::string command_name; |
Alex Vakulenko | f784e21 | 2015-04-20 12:33:52 -0700 | [diff] [blame] | 196 | if (!json->GetString(commands::attributes::kCommand_Name, &command_name)) { |
Vitaly Buka | 0801a1f | 2015-08-14 10:03:46 -0700 | [diff] [blame] | 197 | Error::AddTo(error, FROM_HERE, errors::commands::kDomain, |
| 198 | errors::commands::kPropertyMissing, "Command name is missing"); |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 199 | return instance; |
| 200 | } |
| 201 | // Make sure we know how to handle the command with this name. |
Anton Muhin | cfde869 | 2014-11-25 03:36:59 +0400 | [diff] [blame] | 202 | auto command_def = dictionary.FindCommand(command_name); |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 203 | if (!command_def) { |
Vitaly Buka | 0801a1f | 2015-08-14 10:03:46 -0700 | [diff] [blame] | 204 | Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain, |
| 205 | errors::commands::kInvalidCommandName, |
| 206 | "Unknown command received: %s", command_name.c_str()); |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 207 | return instance; |
| 208 | } |
| 209 | |
Alex Vakulenko | 2c7740a | 2015-11-30 08:51:29 -0800 | [diff] [blame] | 210 | auto parameters = GetCommandParameters(json, error); |
Alex Vakulenko | 36bf1b5 | 2015-11-23 09:35:37 -0800 | [diff] [blame] | 211 | if (!parameters) { |
Vitaly Buka | 0801a1f | 2015-08-14 10:03:46 -0700 | [diff] [blame] | 212 | Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain, |
| 213 | errors::commands::kCommandFailed, |
| 214 | "Failed to validate command '%s'", command_name.c_str()); |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 215 | return instance; |
| 216 | } |
| 217 | |
Alex Vakulenko | 2c7740a | 2015-11-30 08:51:29 -0800 | [diff] [blame] | 218 | instance.reset(new CommandInstance{command_name, origin, *parameters}); |
Alex Vakulenko | d1978d3 | 2015-04-29 17:33:26 -0700 | [diff] [blame] | 219 | |
| 220 | if (!command_id->empty()) |
| 221 | instance->SetID(*command_id); |
Anton Muhin | 5191e81 | 2014-10-30 17:49:48 +0400 | [diff] [blame] | 222 | |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 223 | return instance; |
| 224 | } |
| 225 | |
Vitaly Buka | 906d39e | 2015-03-24 10:08:26 -0700 | [diff] [blame] | 226 | std::unique_ptr<base::DictionaryValue> CommandInstance::ToJson() const { |
| 227 | std::unique_ptr<base::DictionaryValue> json{new base::DictionaryValue}; |
| 228 | |
| 229 | json->SetString(commands::attributes::kCommand_Id, id_); |
| 230 | json->SetString(commands::attributes::kCommand_Name, name_); |
Alex Vakulenko | 36bf1b5 | 2015-11-23 09:35:37 -0800 | [diff] [blame] | 231 | json->Set(commands::attributes::kCommand_Parameters, parameters_.DeepCopy()); |
| 232 | json->Set(commands::attributes::kCommand_Progress, progress_.DeepCopy()); |
| 233 | json->Set(commands::attributes::kCommand_Results, results_.DeepCopy()); |
Vitaly Buka | 0209da4 | 2015-10-08 00:07:18 -0700 | [diff] [blame] | 234 | json->SetString(commands::attributes::kCommand_State, EnumToString(state_)); |
Vitaly Buka | 70f77d9 | 2015-10-07 15:42:40 -0700 | [diff] [blame] | 235 | if (error_) { |
| 236 | json->Set(commands::attributes::kCommand_Error, |
| 237 | ErrorInfoToJson(*error_).release()); |
| 238 | } |
Vitaly Buka | 906d39e | 2015-03-24 10:08:26 -0700 | [diff] [blame] | 239 | |
| 240 | return json; |
| 241 | } |
| 242 | |
Vitaly Buka | 67b5355 | 2015-07-21 10:36:56 -0700 | [diff] [blame] | 243 | void CommandInstance::AddObserver(Observer* observer) { |
Vitaly Buka | 157b16a | 2015-07-31 16:20:48 -0700 | [diff] [blame] | 244 | observers_.AddObserver(observer); |
| 245 | } |
| 246 | |
| 247 | void CommandInstance::RemoveObserver(Observer* observer) { |
| 248 | observers_.RemoveObserver(observer); |
Anton Muhin | b66a930 | 2014-11-10 22:15:22 +0400 | [diff] [blame] | 249 | } |
| 250 | |
Vitaly Buka | 47a1f6f | 2015-10-07 18:09:57 -0700 | [diff] [blame] | 251 | bool CommandInstance::Pause(ErrorPtr* error) { |
Vitaly Buka | 0209da4 | 2015-10-08 00:07:18 -0700 | [diff] [blame] | 252 | return SetStatus(State::kPaused, error); |
Alex Vakulenko | f6b3871 | 2014-09-03 16:23:38 -0700 | [diff] [blame] | 253 | } |
| 254 | |
Vitaly Buka | 47a1f6f | 2015-10-07 18:09:57 -0700 | [diff] [blame] | 255 | bool CommandInstance::Abort(const Error* command_error, ErrorPtr* error) { |
| 256 | error_ = command_error ? command_error->Clone() : nullptr; |
Vitaly Buka | 375f328 | 2015-10-07 18:34:15 -0700 | [diff] [blame] | 257 | FOR_EACH_OBSERVER(Observer, observers_, OnErrorChanged()); |
Vitaly Buka | 0209da4 | 2015-10-08 00:07:18 -0700 | [diff] [blame] | 258 | bool result = SetStatus(State::kAborted, error); |
Alex Vakulenko | f6b3871 | 2014-09-03 16:23:38 -0700 | [diff] [blame] | 259 | RemoveFromQueue(); |
| 260 | // The command will be destroyed after that, so do not access any members. |
Vitaly Buka | 47a1f6f | 2015-10-07 18:09:57 -0700 | [diff] [blame] | 261 | return result; |
Alex Vakulenko | f6b3871 | 2014-09-03 16:23:38 -0700 | [diff] [blame] | 262 | } |
| 263 | |
Vitaly Buka | 47a1f6f | 2015-10-07 18:09:57 -0700 | [diff] [blame] | 264 | bool CommandInstance::Cancel(ErrorPtr* error) { |
Vitaly Buka | 0209da4 | 2015-10-08 00:07:18 -0700 | [diff] [blame] | 265 | bool result = SetStatus(State::kCancelled, error); |
Alex Vakulenko | f6b3871 | 2014-09-03 16:23:38 -0700 | [diff] [blame] | 266 | RemoveFromQueue(); |
| 267 | // The command will be destroyed after that, so do not access any members. |
Vitaly Buka | 47a1f6f | 2015-10-07 18:09:57 -0700 | [diff] [blame] | 268 | return result; |
Alex Vakulenko | f6b3871 | 2014-09-03 16:23:38 -0700 | [diff] [blame] | 269 | } |
| 270 | |
Vitaly Buka | 0209da4 | 2015-10-08 00:07:18 -0700 | [diff] [blame] | 271 | bool CommandInstance::SetStatus(Command::State status, ErrorPtr* error) { |
| 272 | if (status == state_) |
Vitaly Buka | 47a1f6f | 2015-10-07 18:09:57 -0700 | [diff] [blame] | 273 | return true; |
Vitaly Buka | 0209da4 | 2015-10-08 00:07:18 -0700 | [diff] [blame] | 274 | if (status == State::kQueued) |
| 275 | return ReportInvalidStateTransition(error, state_, status); |
| 276 | switch (state_) { |
| 277 | case State::kDone: |
| 278 | case State::kCancelled: |
| 279 | case State::kAborted: |
| 280 | case State::kExpired: |
| 281 | return ReportInvalidStateTransition(error, state_, status); |
| 282 | case State::kQueued: |
| 283 | case State::kInProgress: |
| 284 | case State::kPaused: |
| 285 | case State::kError: |
Vitaly Buka | 47a1f6f | 2015-10-07 18:09:57 -0700 | [diff] [blame] | 286 | break; |
Alex Vakulenko | f6b3871 | 2014-09-03 16:23:38 -0700 | [diff] [blame] | 287 | } |
Vitaly Buka | 0209da4 | 2015-10-08 00:07:18 -0700 | [diff] [blame] | 288 | state_ = status; |
| 289 | FOR_EACH_OBSERVER(Observer, observers_, OnStateChanged()); |
Vitaly Buka | 47a1f6f | 2015-10-07 18:09:57 -0700 | [diff] [blame] | 290 | return true; |
Alex Vakulenko | f6b3871 | 2014-09-03 16:23:38 -0700 | [diff] [blame] | 291 | } |
| 292 | |
| 293 | void CommandInstance::RemoveFromQueue() { |
Vitaly Buka | 2a9b30f | 2015-04-01 10:51:59 -0700 | [diff] [blame] | 294 | if (queue_) |
| 295 | queue_->DelayedRemove(GetID()); |
Alex Vakulenko | f6b3871 | 2014-09-03 16:23:38 -0700 | [diff] [blame] | 296 | } |
| 297 | |
Vitaly Buka | b6f015a | 2015-07-09 14:59:23 -0700 | [diff] [blame] | 298 | } // namespace weave |