1 // Copyright 2015 The Weave 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 #ifndef LIBWEAVE_SRC_COMMANDS_COMMAND_QUEUE_H_
6 #define LIBWEAVE_SRC_COMMANDS_COMMAND_QUEUE_H_
7 
8 #include <map>
9 #include <memory>
10 #include <queue>
11 #include <string>
12 #include <utility>
13 #include <vector>
14 
15 #include <base/callback.h>
16 #include <base/macros.h>
17 #include <base/time/default_clock.h>
18 #include <base/time/time.h>
19 #include <weave/device.h>
20 #include <weave/provider/task_runner.h>
21 
22 #include "src/commands/command_instance.h"
23 
24 namespace weave {
25 
26 class CommandQueue final {
27  public:
28   CommandQueue(provider::TaskRunner* task_runner, base::Clock* clock);
29 
30   // TODO: Remove AddCommandAddedCallback and AddCommandRemovedCallback.
31   using CommandCallback = base::Callback<void(Command* command)>;
32 
33   // Adds notifications callback for a new command is added to the queue.
34   void AddCommandAddedCallback(const CommandCallback& callback);
35 
36   // Adds notifications callback for a command is removed from the queue.
37   void AddCommandRemovedCallback(const CommandCallback& callback);
38 
39   void AddCommandHandler(const std::string& component_path,
40                          const std::string& command_name,
41                          const Device::CommandHandlerCallback& callback);
42 
43   // Checks if the command queue is empty.
IsEmpty()44   bool IsEmpty() const { return map_.empty(); }
45 
46   // Returns the number of commands in the queue.
GetCount()47   size_t GetCount() const { return map_.size(); }
48 
49   // Adds a new command to the queue. Each command in the queue has a unique
50   // ID that identifies that command instance in this queue.
51   // One shouldn't attempt to add a command with the same ID.
52   void Add(std::unique_ptr<CommandInstance> instance);
53 
54   // Selects command identified by |id| ready for removal. Command will actually
55   // be removed after some time.
56   void RemoveLater(const std::string& id);
57 
58   // Finds a command instance in the queue by the instance |id|. Returns
59   // nullptr if the command with the given |id| is not found. The returned
60   // pointer should not be persisted for a long period of time.
61   CommandInstance* Find(const std::string& id) const;
62 
63  private:
64   friend class CommandQueueTest;
65 
66   // Removes a command identified by |id| from the queue.
67   bool Remove(const std::string& id);
68 
69   // Removes old commands scheduled by RemoveLater() to be deleted after
70   // |cutoff_time|.
71   void Cleanup(const base::Time& cutoff_time);
72 
73   // Schedule a cleanup task to be run after the specified |delay|.
74   void ScheduleCleanup(base::TimeDelta delay);
75 
76   // Perform removal of scheduled commands (by calling Cleanup()) and scheduling
77   // another cleanup task if the removal queue is still not empty.
78   void PerformScheduledCleanup();
79 
80   provider::TaskRunner* task_runner_{nullptr};
81   base::Clock* clock_{nullptr};
82 
83   // ID-to-CommandInstance map.
84   std::map<std::string, std::shared_ptr<CommandInstance>> map_;
85 
86   // Queue of commands to be removed, keeps them sorted by the timestamp
87   // (earliest first). This is done to tolerate system clock changes.
88   template <typename T>
89   using InversePriorityQueue =
90       std::priority_queue<T, std::vector<T>, std::greater<T>>;
91   InversePriorityQueue<std::pair<base::Time, std::string>> remove_queue_;
92 
93   using CallbackList = std::vector<CommandCallback>;
94   CallbackList on_command_added_;
95   CallbackList on_command_removed_;
96   std::map<std::string, Device::CommandHandlerCallback> command_callbacks_;
97   Device::CommandHandlerCallback default_command_callback_;
98 
99   // WeakPtr factory for controlling the lifetime of command queue cleanup
100   // tasks.
101   base::WeakPtrFactory<CommandQueue> weak_ptr_factory_{this};
102   DISALLOW_COPY_AND_ASSIGN(CommandQueue);
103 };
104 
105 }  // namespace weave
106 
107 #endif  // LIBWEAVE_SRC_COMMANDS_COMMAND_QUEUE_H_
108