1// Copyright 2014 The Chromium 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#include "chrome/browser/chromeos/file_system_provider/request_manager.h"
6
7#include "base/files/file.h"
8#include "base/stl_util.h"
9
10namespace chromeos {
11namespace file_system_provider {
12namespace {
13
14// Timeout in seconds, before a request is considered as stale and hence
15// aborted.
16const int kDefaultTimeout = 10;
17
18}  // namespace
19
20std::string RequestTypeToString(RequestType type) {
21  switch (type) {
22    case REQUEST_UNMOUNT:
23      return "REQUEST_UNMOUNT";
24    case GET_METADATA:
25      return "GET_METADATA";
26    case READ_DIRECTORY:
27      return "READ_DIRECTORY";
28    case OPEN_FILE:
29      return "OPEN_FILE";
30    case CLOSE_FILE:
31      return "CLOSE_FILE";
32    case READ_FILE:
33      return "READ_FILE";
34    case TESTING:
35      return "TESTING";
36  }
37  NOTREACHED();
38  return "";
39}
40
41RequestManager::RequestManager()
42    : next_id_(1),
43      timeout_(base::TimeDelta::FromSeconds(kDefaultTimeout)),
44      weak_ptr_factory_(this) {}
45
46RequestManager::~RequestManager() {
47  // Abort all of the active requests.
48  RequestMap::iterator it = requests_.begin();
49  while (it != requests_.end()) {
50    const int request_id = it->first;
51    ++it;
52    RejectRequest(request_id, base::File::FILE_ERROR_ABORT);
53  }
54
55  DCHECK_EQ(0u, requests_.size());
56  STLDeleteValues(&requests_);
57}
58
59int RequestManager::CreateRequest(RequestType type,
60                                  scoped_ptr<HandlerInterface> handler) {
61  // The request id is unique per request manager, so per service, thereof
62  // per profile.
63  int request_id = next_id_++;
64
65  // If cycled the int, then signal an error.
66  if (requests_.find(request_id) != requests_.end())
67    return 0;
68
69  Request* request = new Request;
70  request->handler = handler.Pass();
71  request->timeout_timer.Start(FROM_HERE,
72                               timeout_,
73                               base::Bind(&RequestManager::OnRequestTimeout,
74                                          weak_ptr_factory_.GetWeakPtr(),
75                                          request_id));
76  requests_[request_id] = request;
77
78  FOR_EACH_OBSERVER(Observer, observers_, OnRequestCreated(request_id, type));
79
80  // Execute the request implementation. In case of an execution failure,
81  // unregister and return 0. This may often happen, eg. if the providing
82  // extension is not listening for the request event being sent.
83  // In such case, we should abort as soon as possible.
84  if (!request->handler->Execute(request_id)) {
85    DestroyRequest(request_id);
86    return 0;
87  }
88
89  FOR_EACH_OBSERVER(Observer, observers_, OnRequestExecuted(request_id));
90
91  return request_id;
92}
93
94bool RequestManager::FulfillRequest(int request_id,
95                                    scoped_ptr<RequestValue> response,
96                                    bool has_more) {
97  RequestMap::iterator request_it = requests_.find(request_id);
98  if (request_it == requests_.end())
99    return false;
100
101  request_it->second->handler->OnSuccess(request_id, response.Pass(), has_more);
102
103  FOR_EACH_OBSERVER(
104      Observer, observers_, OnRequestFulfilled(request_id, has_more));
105
106  if (!has_more)
107    DestroyRequest(request_id);
108  else
109    request_it->second->timeout_timer.Reset();
110
111  return true;
112}
113
114bool RequestManager::RejectRequest(int request_id, base::File::Error error) {
115  RequestMap::iterator request_it = requests_.find(request_id);
116  if (request_it == requests_.end())
117    return false;
118
119  request_it->second->handler->OnError(request_id, error);
120
121  FOR_EACH_OBSERVER(Observer, observers_, OnRequestRejected(request_id, error));
122
123  DestroyRequest(request_id);
124
125  return true;
126}
127
128void RequestManager::SetTimeoutForTesting(const base::TimeDelta& timeout) {
129  timeout_ = timeout;
130}
131
132size_t RequestManager::GetActiveRequestsForLogging() const {
133  return requests_.size();
134}
135
136void RequestManager::AddObserver(Observer* observer) {
137  DCHECK(observer);
138  observers_.AddObserver(observer);
139}
140
141void RequestManager::RemoveObserver(Observer* observer) {
142  DCHECK(observer);
143  observers_.RemoveObserver(observer);
144}
145
146RequestManager::Request::Request() {}
147
148RequestManager::Request::~Request() {}
149
150void RequestManager::OnRequestTimeout(int request_id) {
151  FOR_EACH_OBSERVER(Observer, observers_, OnRequestTimeouted(request_id));
152
153  RejectRequest(request_id, base::File::FILE_ERROR_ABORT);
154}
155
156void RequestManager::DestroyRequest(int request_id) {
157  RequestMap::iterator request_it = requests_.find(request_id);
158  if (request_it == requests_.end())
159    return;
160
161  delete request_it->second;
162  requests_.erase(request_it);
163
164  FOR_EACH_OBSERVER(Observer, observers_, OnRequestDestroyed(request_id));
165}
166
167}  // namespace file_system_provider
168}  // namespace chromeos
169