summaryrefslogtreecommitdiffstats
path: root/chrome/browser/chromeos/extensions/file_manager/job_event_router.cc
blob: e9fa5832d757bed22c94895c949cbed709da21e5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/extensions/file_manager/job_event_router.h"

#include <cmath>

#include "base/thread_task_runner_handle.h"
#include "chrome/browser/chromeos/drive/file_system_core_util.h"
#include "chrome/browser/chromeos/file_manager/app_id.h"
#include "chrome/browser/profiles/profile.h"
#include "content/public/browser/browser_thread.h"

using content::BrowserThread;
namespace file_manager_private = extensions::api::file_manager_private;

namespace file_manager {
namespace {

// Utility function to check if |job_info| is a file uploading job.
bool IsUploadJob(drive::JobType type) {
  return (type == drive::TYPE_UPLOAD_NEW_FILE ||
          type == drive::TYPE_UPLOAD_EXISTING_FILE);
}

}  // namespace

JobEventRouter::JobEventRouter(const base::TimeDelta& event_delay)
    : event_delay_(event_delay),
      num_completed_bytes_(0),
      num_total_bytes_(0),
      weak_factory_(this) {
}

JobEventRouter::~JobEventRouter() {
}

void JobEventRouter::OnJobAdded(const drive::JobInfo& job_info) {
  OnJobUpdated(job_info);
}

void JobEventRouter::OnJobUpdated(const drive::JobInfo& job_info) {
  DCHECK(thread_checker_.CalledOnValidThread());
  if (!drive::IsActiveFileTransferJobInfo(job_info))
    return;

  // Add new job info.
  UpdateBytes(job_info);
  drive_jobs_[job_info.job_id] = make_linked_ptr(new drive::JobInfo(job_info));

  ScheduleDriveFileTransferEvent(
      job_info, file_manager_private::TRANSFER_STATE_IN_PROGRESS,
      false /* immediate */);
}

void JobEventRouter::OnJobDone(const drive::JobInfo& job_info,
                               drive::FileError error) {
  DCHECK(thread_checker_.CalledOnValidThread());
  if (!drive::IsActiveFileTransferJobInfo(job_info))
    return;

  const file_manager_private::TransferState state =
      error == drive::FILE_ERROR_OK
          ? file_manager_private::TRANSFER_STATE_COMPLETED
          : file_manager_private::TRANSFER_STATE_FAILED;

  drive::JobInfo completed_job = job_info;
  completed_job.num_completed_bytes = completed_job.num_total_bytes;
  UpdateBytes(completed_job);

  ScheduleDriveFileTransferEvent(job_info, state, true /* immediate */);

  // Forget about the job.
  drive_jobs_.erase(job_info.job_id);
  if (!drive_jobs_.size()) {
    num_completed_bytes_ = 0L;
    num_total_bytes_ = 0L;
  }
}

void JobEventRouter::UpdateBytes(const drive::JobInfo& job_info) {
  int64 last_completed_bytes = 0;
  int64 last_total_bytes = 0;
  if (drive_jobs_.count(job_info.job_id)) {
    last_completed_bytes = drive_jobs_[job_info.job_id]->num_completed_bytes;
    last_total_bytes = drive_jobs_[job_info.job_id]->num_total_bytes;
  }
  num_completed_bytes_ += job_info.num_completed_bytes - last_completed_bytes;
  num_total_bytes_ += job_info.num_total_bytes - last_total_bytes;
}

void JobEventRouter::ScheduleDriveFileTransferEvent(
    const drive::JobInfo& job_info,
    file_manager_private::TransferState state,
    bool immediate) {
  const bool no_pending_task = !pending_event_;

  // Update the latest event.
  pending_event_.reset(new file_manager_private::FileTransferStatus);
  const GURL url =
      ConvertDrivePathToFileSystemUrl(job_info.file_path, kFileManagerAppId);
  pending_event_->file_url = url.spec();
  pending_event_->transfer_state = state;
  pending_event_->transfer_type =
      IsUploadJob(job_info.job_type)
          ? file_manager_private::TRANSFER_TYPE_UPLOAD
          : file_manager_private::TRANSFER_TYPE_DOWNLOAD;

  if (immediate) {
    SendDriveFileTransferEvent();
  } else if (no_pending_task) {
    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
        FROM_HERE, base::Bind(&JobEventRouter::SendDriveFileTransferEvent,
                              weak_factory_.GetWeakPtr()),
        event_delay_);
  }
}

void JobEventRouter::SendDriveFileTransferEvent() {
  if (!pending_event_)
    return;
  // JavaScript does not have 64-bit integers. Instead we use double, which
  // is in IEEE 754 formant and accurate up to 52-bits in JS, and in practice
  // in C++. Larger values are rounded.
  pending_event_->num_total_jobs = drive_jobs_.size();
  pending_event_->processed = num_completed_bytes_;
  pending_event_->total = num_total_bytes_;

  BroadcastEvent(
      extensions::events::FILE_MANAGER_PRIVATE_ON_FILE_TRANSFERS_UPDATED,
      file_manager_private::OnFileTransfersUpdated::kEventName,
      file_manager_private::OnFileTransfersUpdated::Create(*pending_event_));
  pending_event_.reset();
}

}  // namespace file_manager