OLD | NEW |
---|---|
1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/background_fetch/background_fetch_data_manager.h" | 5 #include "content/browser/background_fetch/background_fetch_data_manager.h" |
6 | 6 |
7 #include "base/memory/ptr_util.h" | 7 #include "base/memory/ptr_util.h" |
8 #include "content/browser/background_fetch/background_fetch_context.h" | 8 #include "content/browser/background_fetch/background_fetch_context.h" |
9 #include "content/browser/background_fetch/background_fetch_job_response_data.h" | |
9 #include "content/browser/background_fetch/background_fetch_request_info.h" | 10 #include "content/browser/background_fetch/background_fetch_request_info.h" |
11 #include "content/public/browser/blob_handle.h" | |
12 #include "content/public/browser/browser_context.h" | |
13 #include "content/public/browser/download_interrupt_reasons.h" | |
14 #include "content/public/browser/download_item.h" | |
10 | 15 |
11 namespace content { | 16 namespace content { |
12 | 17 |
13 BackgroundFetchDataManager::BackgroundFetchDataManager( | 18 BackgroundFetchDataManager::BackgroundFetchDataManager( |
14 BackgroundFetchContext* background_fetch_context) | 19 BrowserContext* browser_context) |
15 : background_fetch_context_(background_fetch_context) { | 20 : browser_context_(browser_context), weak_ptr_factory_(this) { |
16 DCHECK(background_fetch_context_); | 21 DCHECK(browser_context_); |
17 // TODO(harkness) Read from persistent storage and recreate requests. | 22 // TODO(harkness) Read from persistent storage and recreate requests. |
18 } | 23 } |
19 | 24 |
20 BackgroundFetchDataManager::~BackgroundFetchDataManager() = default; | 25 BackgroundFetchDataManager::~BackgroundFetchDataManager() = default; |
21 | 26 |
22 std::unique_ptr<BackgroundFetchJobData> | 27 void BackgroundFetchDataManager::CreateRequest( |
23 BackgroundFetchDataManager::CreateRequest( | |
24 std::unique_ptr<BackgroundFetchJobInfo> job_info, | 28 std::unique_ptr<BackgroundFetchJobInfo> job_info, |
25 BackgroundFetchRequestInfos request_infos) { | 29 BackgroundFetchRequestInfos request_infos) { |
26 JobIdentifier id(job_info->service_worker_registration_id(), job_info->tag()); | 30 JobIdentifier id(job_info->service_worker_registration_id(), job_info->tag()); |
27 // Ensure that this is not a duplicate request. | 31 // Ensure that this is not a duplicate request. |
28 if (service_worker_tag_map_.find(id) != service_worker_tag_map_.end()) { | 32 if (service_worker_tag_map_.find(id) != service_worker_tag_map_.end()) { |
29 DVLOG(1) << "Origin " << job_info->origin() | 33 DVLOG(1) << "Origin " << job_info->origin() |
30 << " has already created a batch request with tag " | 34 << " has already created a batch request with tag " |
31 << job_info->tag(); | 35 << job_info->tag(); |
32 // TODO(harkness) Figure out how to return errors like this. | 36 // TODO(harkness) Figure out how to return errors like this. |
33 return nullptr; | 37 return; |
34 } | 38 } |
35 | 39 |
36 // Add the request to our maps and return a JobData to track the individual | 40 // Add the JobInfo to the in-memory map, and write the individual requests out |
37 // files in the request. | 41 // to storage. |
42 job_info->set_num_requests(request_infos.size()); | |
38 const std::string job_guid = job_info->guid(); | 43 const std::string job_guid = job_info->guid(); |
39 service_worker_tag_map_[id] = job_guid; | 44 service_worker_tag_map_[id] = job_guid; |
40 WriteJobToStorage(std::move(job_info), std::move(request_infos)); | 45 WriteJobToStorage(std::move(job_info), std::move(request_infos)); |
41 // TODO(harkness): Remove data when the job is complete. | |
42 | |
43 return base::MakeUnique<BackgroundFetchJobData>( | |
44 ReadRequestsFromStorage(job_guid)); | |
45 } | 46 } |
46 | 47 |
47 void BackgroundFetchDataManager::WriteJobToStorage( | 48 void BackgroundFetchDataManager::WriteJobToStorage( |
48 std::unique_ptr<BackgroundFetchJobInfo> job_info, | 49 std::unique_ptr<BackgroundFetchJobInfo> job_info, |
49 BackgroundFetchRequestInfos request_infos) { | 50 BackgroundFetchRequestInfos request_infos) { |
50 // TODO(harkness): Replace these maps with actually writing to storage. | |
51 // TODO(harkness): Check for job_guid clash. | 51 // TODO(harkness): Check for job_guid clash. |
52 const std::string job_guid = job_info->guid(); | 52 const std::string job_guid = job_info->guid(); |
53 job_map_[job_guid] = std::move(job_info); | 53 job_map_[job_guid] = std::move(job_info); |
54 request_map_[job_guid] = std::move(request_infos); | 54 |
55 // Make an explicit copy of the original requests | |
56 // TODO(harkness): Replace this with actually writing to storage. | |
57 std::vector<BackgroundFetchRequestInfo> requests; | |
58 for (const auto& request_info : request_infos) { | |
59 requests.emplace_back(*(request_info.get())); | |
60 } | |
61 request_map_[job_guid] = std::move(requests); | |
62 | |
63 // |request_infos| will be destroyed when it leaves scope here. | |
55 } | 64 } |
56 | 65 |
57 // TODO(harkness): This should be changed to read (and cache) small numbers of | 66 void BackgroundFetchDataManager::WriteRequestToStorage( |
58 // the RequestInfos instead of returning all of them. | 67 const std::string& job_guid, |
59 BackgroundFetchRequestInfos& | 68 BackgroundFetchRequestInfo* request_info) { |
60 BackgroundFetchDataManager::ReadRequestsFromStorage( | 69 std::vector<BackgroundFetchRequestInfo>& request_infos = |
70 request_map_[job_guid]; | |
71 | |
72 // Copy the updated |request_info| over the in-memory version. | |
73 for (size_t i = 0; i < request_infos.size(); i++) { | |
74 if (request_infos[i].guid() == request_info->guid()) | |
75 request_infos[i] = *request_info; | |
76 } | |
77 } | |
78 | |
79 std::unique_ptr<BackgroundFetchRequestInfo> | |
80 BackgroundFetchDataManager::GetRequestInfo(const std::string& job_guid, | |
81 size_t request_index) const { | |
82 // Explicitly create a copy. When this is persisted to StorageWorkerStorage, | |
83 // the request_map_ will not exist. | |
84 auto iter = request_map_.find(job_guid); | |
85 DCHECK(iter != request_map_.end()); | |
86 const std::vector<BackgroundFetchRequestInfo>& request_infos = iter->second; | |
87 | |
88 DCHECK(request_index <= request_infos.size()); | |
89 BackgroundFetchRequestInfo request_info = | |
90 *(request_infos.begin() + request_index); | |
Peter Beverloo
2017/03/25 03:38:50
Why wouldn't request_infos[request_index] work?
harkness
2017/03/26 16:13:18
I could do that, but then the method couldn't be c
Peter Beverloo
2017/03/26 22:32:39
This can't be const anyway - conceptually it could
harkness
2017/03/27 07:32:37
Changed.
| |
91 return base::MakeUnique<BackgroundFetchRequestInfo>(request_info); | |
92 } | |
93 | |
94 void BackgroundFetchDataManager::GetJobResponse( | |
95 const std::string& job_guid, | |
96 const BackgroundFetchResponseCompleteCallback& callback) { | |
97 BackgroundFetchJobInfo* job_info = job_map_[job_guid].get(); | |
98 DCHECK(job_info); | |
99 | |
100 // Create a BackgroundFetchJobResponseData object which will aggregate | |
101 // together the response blobs. | |
102 job_info->set_job_response_data( | |
103 base::MakeUnique<BackgroundFetchJobResponseData>(job_info->num_requests(), | |
104 std::move(callback))); | |
Peter Beverloo
2017/03/25 03:38:50
This std::move() doesn't do anything because |call
harkness
2017/03/26 16:13:18
Done.
| |
105 | |
106 // Iterate over the requests and create blobs for each response. | |
107 for (size_t request_index = 0; request_index < job_info->num_requests(); | |
108 request_index++) { | |
109 // TODO(harkness): This will need to be asynchronous. | |
110 std::unique_ptr<BackgroundFetchRequestInfo> request_info = | |
111 GetRequestInfo(job_guid, request_index); | |
112 | |
113 // TODO(harkness): Only create a blob response if the request was | |
114 // successful. Otherwise create an error response. | |
115 content::BrowserContext::CreateFileBackedBlob( | |
Peter Beverloo
2017/03/25 03:38:50
That method only exists to bridge UI thread calls
harkness
2017/03/26 16:13:18
Won't the DataManager need access to the browser c
Peter Beverloo
2017/03/26 22:32:39
We'd give it the ServiceWorkerContextWrapper inste
harkness
2017/03/27 07:32:37
Fair enough.
| |
116 browser_context_, request_info->file_path(), 0 /* offset */, | |
117 request_info->received_bytes(), | |
118 base::Time() /* expected_modification_time */, | |
119 base::Bind(&BackgroundFetchDataManager::DidGetRequestResponse, | |
120 weak_ptr_factory_.GetWeakPtr(), job_guid, request_index)); | |
121 } | |
122 } | |
123 | |
124 void BackgroundFetchDataManager::DidGetRequestResponse( | |
125 const std::string& job_guid, | |
126 int request_sequence_number, | |
127 std::unique_ptr<BlobHandle> blob_handle) { | |
128 BackgroundFetchJobInfo* job_info = job_map_[job_guid].get(); | |
129 DCHECK(job_info); | |
130 | |
131 BackgroundFetchJobResponseData* job_response_data = | |
132 job_info->job_response_data(); | |
133 DCHECK(job_response_data); | |
134 | |
135 job_response_data->AddResponse(request_sequence_number, | |
136 std::move(blob_handle)); | |
137 } | |
138 | |
139 bool BackgroundFetchDataManager::UpdateRequestState( | |
140 const std::string& job_guid, | |
141 const std::string& request_guid, | |
142 DownloadItem::DownloadState state, | |
143 DownloadInterruptReason interrupt_reason) { | |
144 // Find the request and set the state and the interrupt reason. | |
145 BackgroundFetchJobInfo* job_info = job_map_[job_guid].get(); | |
146 DCHECK(job_info); | |
Peter Beverloo
2017/03/25 03:38:50
This is the sort of error condition that we'll hav
harkness
2017/03/26 16:13:18
The only way I could see this being hit would be i
| |
147 BackgroundFetchRequestInfo* request = | |
148 job_info->GetActiveRequest(request_guid); | |
149 DCHECK(request); | |
150 request->set_state(state); | |
151 request->set_interrupt_reason(interrupt_reason); | |
152 | |
153 // If the request is now finished, remove it from the active requests. | |
154 switch (state) { | |
155 case DownloadItem::DownloadState::COMPLETE: | |
156 case DownloadItem::DownloadState::CANCELLED: | |
157 WriteRequestToStorage(job_guid, request); | |
158 job_info->RemoveActiveRequest(request_guid); | |
159 case DownloadItem::DownloadState::IN_PROGRESS: | |
160 case DownloadItem::DownloadState::INTERRUPTED: | |
161 case DownloadItem::DownloadState::MAX_DOWNLOAD_STATE: | |
162 break; | |
163 } | |
164 | |
165 // Return a boolean indicating whether there are more requests to be | |
166 // processed. | |
167 return job_info->HasRequestsRemaining(); | |
168 } | |
169 | |
170 void BackgroundFetchDataManager::UpdateRequestStorageState( | |
171 const std::string& job_guid, | |
172 const std::string& request_guid, | |
173 const base::FilePath& file_path, | |
174 int64_t received_bytes) { | |
175 BackgroundFetchJobInfo* job_info = job_map_[job_guid].get(); | |
176 DCHECK(job_info); | |
177 BackgroundFetchRequestInfo* request = | |
178 job_info->GetActiveRequest(request_guid); | |
179 DCHECK(request); | |
180 request->set_file_path(file_path); | |
181 request->set_received_bytes(received_bytes); | |
182 } | |
183 | |
184 const BackgroundFetchRequestInfo& | |
185 BackgroundFetchDataManager::GetNextBackgroundFetchRequestInfo( | |
61 const std::string& job_guid) { | 186 const std::string& job_guid) { |
62 return request_map_[job_guid]; | 187 BackgroundFetchJobInfo* job_info = job_map_[job_guid].get(); |
188 DCHECK(job_info); | |
189 | |
190 // TODO(harkness): This needs to be async when it queries real storage. | |
191 std::unique_ptr<BackgroundFetchRequestInfo> request_info = | |
192 GetRequestInfo(job_guid, job_info->next_request_index()); | |
193 const std::string request_guid = request_info->guid(); | |
194 job_info->AddActiveRequest(std::move(request_info)); | |
195 return *job_info->GetActiveRequest(request_guid); | |
196 } | |
197 | |
198 bool BackgroundFetchDataManager::IsComplete(const std::string& job_guid) const { | |
199 auto iter = job_map_.find(job_guid); | |
200 DCHECK(iter != job_map_.end()); | |
201 return iter->second->IsComplete(); | |
202 } | |
203 | |
204 bool BackgroundFetchDataManager::HasRequestsRemaining( | |
205 const std::string& job_guid) const { | |
206 auto iter = job_map_.find(job_guid); | |
207 DCHECK(iter != job_map_.end()); | |
208 return iter->second->HasRequestsRemaining(); | |
209 } | |
210 | |
211 void BackgroundFetchDataManager::UpdateRequestDownloadGuid( | |
212 const std::string& job_guid, | |
213 const std::string& request_guid, | |
214 const std::string& download_guid) { | |
Peter Beverloo
2017/03/25 03:38:50
I'd love to simplify the data model away from GUID
harkness
2017/03/26 16:13:18
I do hate that we have to have the download_guid a
Peter Beverloo
2017/03/26 22:32:39
Good!
harkness
2017/03/27 07:32:38
All the knowledge now on the JobInfo are things th
| |
215 BackgroundFetchJobInfo* job_info = job_map_[job_guid].get(); | |
216 DCHECK(job_info); | |
217 BackgroundFetchRequestInfo* request = | |
218 job_info->GetActiveRequest(request_guid); | |
219 DCHECK(request); | |
220 request->set_download_guid(download_guid); | |
63 } | 221 } |
64 | 222 |
65 } // namespace content | 223 } // namespace content |
OLD | NEW |