blob: 134dc1c1cce4db030089f815d006261d57a2bd09 [file] [log] [blame]
Vitaly Buka4615e0d2015-10-14 15:35:12 -07001// Copyright 2015 The Weave Authors. All rights reserved.
Alex Vakulenkoaa3a5592014-08-07 07:24:06 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Stefan Sauer2d16dfa2015-09-25 17:08:35 +02005#include "src/commands/command_queue.h"
Alex Vakulenkoaa3a5592014-08-07 07:24:06 -07006
Vitaly Bukaae0f3a12015-05-11 16:27:30 -07007#include <base/bind.h>
Vitaly Buka2a9b30f2015-04-01 10:51:59 -07008#include <base/time/time.h>
9
Vitaly Bukab6f015a2015-07-09 14:59:23 -070010namespace weave {
Alex Vakulenkoaa3a5592014-08-07 07:24:06 -070011
Vitaly Buka2a9b30f2015-04-01 10:51:59 -070012namespace {
13const int kRemoveCommandDelayMin = 5;
Alex Vakulenko88f55d82015-12-03 15:30:27 -080014
15std::string GetCommandHandlerKey(const std::string& component_path,
16 const std::string& command_name) {
17 return component_path + ":" + command_name;
18}
Vitaly Buka2a9b30f2015-04-01 10:51:59 -070019}
20
Vitaly Buka695a5fb2015-10-06 16:26:08 -070021void CommandQueue::AddCommandAddedCallback(const CommandCallback& callback) {
Vitaly Bukaae0f3a12015-05-11 16:27:30 -070022 on_command_added_.push_back(callback);
Vitaly Buka72410b22015-05-13 13:48:59 -070023 // Send all pre-existed commands.
24 for (const auto& command : map_)
25 callback.Run(command.second.get());
Vitaly Bukaae0f3a12015-05-11 16:27:30 -070026}
27
Vitaly Buka695a5fb2015-10-06 16:26:08 -070028void CommandQueue::AddCommandRemovedCallback(const CommandCallback& callback) {
Vitaly Bukaae0f3a12015-05-11 16:27:30 -070029 on_command_removed_.push_back(callback);
30}
31
Vitaly Bukac6029262015-10-07 09:29:13 -070032void CommandQueue::AddCommandHandler(
Alex Vakulenko88f55d82015-12-03 15:30:27 -080033 const std::string& component_path,
Vitaly Bukac6029262015-10-07 09:29:13 -070034 const std::string& command_name,
35 const Device::CommandHandlerCallback& callback) {
Vitaly Buka695a5fb2015-10-06 16:26:08 -070036 if (!command_name.empty()) {
37 CHECK(default_command_callback_.is_null())
38 << "Commands specific handler are not allowed after default one";
39
40 for (const auto& command : map_) {
Vitaly Buka0209da42015-10-08 00:07:18 -070041 if (command.second->GetState() == Command::State::kQueued &&
Alex Vakulenko88f55d82015-12-03 15:30:27 -080042 command.second->GetName() == command_name &&
43 command.second->GetComponent() == component_path) {
Vitaly Bukac6029262015-10-07 09:29:13 -070044 callback.Run(command.second);
Vitaly Buka695a5fb2015-10-06 16:26:08 -070045 }
46 }
47
Alex Vakulenko88f55d82015-12-03 15:30:27 -080048 std::string key = GetCommandHandlerKey(component_path, command_name);
49 CHECK(command_callbacks_.insert(std::make_pair(key, callback)).second)
Vitaly Buka695a5fb2015-10-06 16:26:08 -070050 << command_name << " already has handler";
51
52 } else {
Alex Vakulenko88f55d82015-12-03 15:30:27 -080053 CHECK(component_path.empty())
54 << "Default handler must not be component-specific";
Vitaly Buka695a5fb2015-10-06 16:26:08 -070055 for (const auto& command : map_) {
Alex Vakulenko88f55d82015-12-03 15:30:27 -080056 std::string key = GetCommandHandlerKey(command.second->GetComponent(),
57 command.second->GetName());
Vitaly Buka0209da42015-10-08 00:07:18 -070058 if (command.second->GetState() == Command::State::kQueued &&
Alex Vakulenko88f55d82015-12-03 15:30:27 -080059 command_callbacks_.find(key) == command_callbacks_.end()) {
Vitaly Bukac6029262015-10-07 09:29:13 -070060 callback.Run(command.second);
Vitaly Buka695a5fb2015-10-06 16:26:08 -070061 }
62 }
63
64 CHECK(default_command_callback_.is_null()) << "Already has default handler";
65 default_command_callback_ = callback;
66 }
67}
68
Anton Muhin5191e812014-10-30 17:49:48 +040069void CommandQueue::Add(std::unique_ptr<CommandInstance> instance) {
70 std::string id = instance->GetID();
71 LOG_IF(FATAL, id.empty()) << "Command has no ID";
Vitaly Bukac6029262015-10-07 09:29:13 -070072 instance->AttachToQueue(this);
Alex Vakulenkoaa3a5592014-08-07 07:24:06 -070073 auto pair = map_.insert(std::make_pair(id, std::move(instance)));
74 LOG_IF(FATAL, !pair.second) << "Command with ID '" << id
75 << "' is already in the queue";
Vitaly Bukaae0f3a12015-05-11 16:27:30 -070076 for (const auto& cb : on_command_added_)
77 cb.Run(pair.first->second.get());
Vitaly Buka695a5fb2015-10-06 16:26:08 -070078
Alex Vakulenko88f55d82015-12-03 15:30:27 -080079 std::string key = GetCommandHandlerKey(pair.first->second->GetComponent(),
80 pair.first->second->GetName());
81 auto it_handler = command_callbacks_.find(key);
Vitaly Buka695a5fb2015-10-06 16:26:08 -070082
83 if (it_handler != command_callbacks_.end())
Vitaly Bukac6029262015-10-07 09:29:13 -070084 it_handler->second.Run(pair.first->second);
Vitaly Buka695a5fb2015-10-06 16:26:08 -070085 else if (!default_command_callback_.is_null())
Vitaly Bukac6029262015-10-07 09:29:13 -070086 default_command_callback_.Run(pair.first->second);
Vitaly Buka695a5fb2015-10-06 16:26:08 -070087
Vitaly Buka2a9b30f2015-04-01 10:51:59 -070088 Cleanup();
Alex Vakulenkoaa3a5592014-08-07 07:24:06 -070089}
90
Vitaly Buka2a9b30f2015-04-01 10:51:59 -070091void CommandQueue::DelayedRemove(const std::string& id) {
Alex Vakulenkoaa3a5592014-08-07 07:24:06 -070092 auto p = map_.find(id);
Vitaly Buka2a9b30f2015-04-01 10:51:59 -070093 if (p == map_.end())
94 return;
95 remove_queue_.push(std::make_pair(
96 base::Time::Now() + base::TimeDelta::FromMinutes(kRemoveCommandDelayMin),
97 id));
98 Cleanup();
99}
100
101bool CommandQueue::Remove(const std::string& id) {
102 auto p = map_.find(id);
103 if (p == map_.end())
104 return false;
Vitaly Bukac6029262015-10-07 09:29:13 -0700105 std::shared_ptr<CommandInstance> instance = p->second;
106 instance->DetachFromQueue();
Vitaly Buka2a9b30f2015-04-01 10:51:59 -0700107 map_.erase(p);
Vitaly Bukaae0f3a12015-05-11 16:27:30 -0700108 for (const auto& cb : on_command_removed_)
109 cb.Run(instance.get());
Vitaly Buka2a9b30f2015-04-01 10:51:59 -0700110 return true;
111}
112
113void CommandQueue::Cleanup() {
114 while (!remove_queue_.empty() && remove_queue_.front().first < Now()) {
115 Remove(remove_queue_.front().second);
116 remove_queue_.pop();
Alex Vakulenkoaa3a5592014-08-07 07:24:06 -0700117 }
Vitaly Buka2a9b30f2015-04-01 10:51:59 -0700118}
119
120void CommandQueue::SetNowForTest(base::Time now) {
121 test_now_ = now;
122}
123
124base::Time CommandQueue::Now() const {
125 return test_now_.is_null() ? base::Time::Now() : test_now_;
Alex Vakulenkoaa3a5592014-08-07 07:24:06 -0700126}
127
Alex Vakulenkofedc4872014-08-20 12:38:43 -0700128CommandInstance* CommandQueue::Find(const std::string& id) const {
Alex Vakulenkoaa3a5592014-08-07 07:24:06 -0700129 auto p = map_.find(id);
130 return (p != map_.end()) ? p->second.get() : nullptr;
131}
132
Vitaly Bukab6f015a2015-07-09 14:59:23 -0700133} // namespace weave