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
24namespace weave {
25
26class 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.
44  bool IsEmpty() const { return map_.empty(); }
45
46  // Returns the number of commands in the queue.
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