blob: e08527bfec8e8e3a259407bf1421e908a23d9c2c [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;
14}
15
Vitaly Buka695a5fb2015-10-06 16:26:08 -070016void CommandQueue::AddCommandAddedCallback(const CommandCallback& callback) {
Vitaly Bukaae0f3a12015-05-11 16:27:30 -070017 on_command_added_.push_back(callback);
Vitaly Buka72410b22015-05-13 13:48:59 -070018 // Send all pre-existed commands.
19 for (const auto& command : map_)
20 callback.Run(command.second.get());
Vitaly Bukaae0f3a12015-05-11 16:27:30 -070021}
22
Vitaly Buka695a5fb2015-10-06 16:26:08 -070023void CommandQueue::AddCommandRemovedCallback(const CommandCallback& callback) {
Vitaly Bukaae0f3a12015-05-11 16:27:30 -070024 on_command_removed_.push_back(callback);
25}
26
Vitaly Bukac6029262015-10-07 09:29:13 -070027void CommandQueue::AddCommandHandler(
28 const std::string& command_name,
29 const Device::CommandHandlerCallback& callback) {
Vitaly Buka695a5fb2015-10-06 16:26:08 -070030 if (!command_name.empty()) {
31 CHECK(default_command_callback_.is_null())
32 << "Commands specific handler are not allowed after default one";
33
34 for (const auto& command : map_) {
Vitaly Buka0209da42015-10-08 00:07:18 -070035 if (command.second->GetState() == Command::State::kQueued &&
Vitaly Buka695a5fb2015-10-06 16:26:08 -070036 command.second->GetName() == command_name) {
Vitaly Bukac6029262015-10-07 09:29:13 -070037 callback.Run(command.second);
Vitaly Buka695a5fb2015-10-06 16:26:08 -070038 }
39 }
40
41 CHECK(command_callbacks_.emplace(command_name, callback).second)
42 << command_name << " already has handler";
43
44 } else {
45 for (const auto& command : map_) {
Vitaly Buka0209da42015-10-08 00:07:18 -070046 if (command.second->GetState() == Command::State::kQueued &&
Vitaly Buka695a5fb2015-10-06 16:26:08 -070047 command_callbacks_.find(command.second->GetName()) ==
48 command_callbacks_.end()) {
Vitaly Bukac6029262015-10-07 09:29:13 -070049 callback.Run(command.second);
Vitaly Buka695a5fb2015-10-06 16:26:08 -070050 }
51 }
52
53 CHECK(default_command_callback_.is_null()) << "Already has default handler";
54 default_command_callback_ = callback;
55 }
56}
57
Anton Muhin5191e812014-10-30 17:49:48 +040058void CommandQueue::Add(std::unique_ptr<CommandInstance> instance) {
59 std::string id = instance->GetID();
60 LOG_IF(FATAL, id.empty()) << "Command has no ID";
Vitaly Bukac6029262015-10-07 09:29:13 -070061 instance->AttachToQueue(this);
Alex Vakulenkoaa3a5592014-08-07 07:24:06 -070062 auto pair = map_.insert(std::make_pair(id, std::move(instance)));
63 LOG_IF(FATAL, !pair.second) << "Command with ID '" << id
64 << "' is already in the queue";
Vitaly Bukaae0f3a12015-05-11 16:27:30 -070065 for (const auto& cb : on_command_added_)
66 cb.Run(pair.first->second.get());
Vitaly Buka695a5fb2015-10-06 16:26:08 -070067
68 auto it_handler = command_callbacks_.find(pair.first->second->GetName());
69
70 if (it_handler != command_callbacks_.end())
Vitaly Bukac6029262015-10-07 09:29:13 -070071 it_handler->second.Run(pair.first->second);
Vitaly Buka695a5fb2015-10-06 16:26:08 -070072 else if (!default_command_callback_.is_null())
Vitaly Bukac6029262015-10-07 09:29:13 -070073 default_command_callback_.Run(pair.first->second);
Vitaly Buka695a5fb2015-10-06 16:26:08 -070074
Vitaly Buka2a9b30f2015-04-01 10:51:59 -070075 Cleanup();
Alex Vakulenkoaa3a5592014-08-07 07:24:06 -070076}
77
Vitaly Buka2a9b30f2015-04-01 10:51:59 -070078void CommandQueue::DelayedRemove(const std::string& id) {
Alex Vakulenkoaa3a5592014-08-07 07:24:06 -070079 auto p = map_.find(id);
Vitaly Buka2a9b30f2015-04-01 10:51:59 -070080 if (p == map_.end())
81 return;
82 remove_queue_.push(std::make_pair(
83 base::Time::Now() + base::TimeDelta::FromMinutes(kRemoveCommandDelayMin),
84 id));
85 Cleanup();
86}
87
88bool CommandQueue::Remove(const std::string& id) {
89 auto p = map_.find(id);
90 if (p == map_.end())
91 return false;
Vitaly Bukac6029262015-10-07 09:29:13 -070092 std::shared_ptr<CommandInstance> instance = p->second;
93 instance->DetachFromQueue();
Vitaly Buka2a9b30f2015-04-01 10:51:59 -070094 map_.erase(p);
Vitaly Bukaae0f3a12015-05-11 16:27:30 -070095 for (const auto& cb : on_command_removed_)
96 cb.Run(instance.get());
Vitaly Buka2a9b30f2015-04-01 10:51:59 -070097 return true;
98}
99
100void CommandQueue::Cleanup() {
101 while (!remove_queue_.empty() && remove_queue_.front().first < Now()) {
102 Remove(remove_queue_.front().second);
103 remove_queue_.pop();
Alex Vakulenkoaa3a5592014-08-07 07:24:06 -0700104 }
Vitaly Buka2a9b30f2015-04-01 10:51:59 -0700105}
106
107void CommandQueue::SetNowForTest(base::Time now) {
108 test_now_ = now;
109}
110
111base::Time CommandQueue::Now() const {
112 return test_now_.is_null() ? base::Time::Now() : test_now_;
Alex Vakulenkoaa3a5592014-08-07 07:24:06 -0700113}
114
Alex Vakulenkofedc4872014-08-20 12:38:43 -0700115CommandInstance* CommandQueue::Find(const std::string& id) const {
Alex Vakulenkoaa3a5592014-08-07 07:24:06 -0700116 auto p = map_.find(id);
117 return (p != map_.end()) ? p->second.get() : nullptr;
118}
119
Vitaly Bukab6f015a2015-07-09 14:59:23 -0700120} // namespace weave