1868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// found in the LICENSE file.
490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/child/fileapi/webfilewriter_impl.h"
690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/bind.h"
83240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch#include "base/synchronization/waitable_event.h"
9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/child/child_thread.h"
10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/child/fileapi/file_system_dispatcher.h"
11a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "content/child/worker_task_runner.h"
1290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace content {
1490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace {
1690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
17a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)FileSystemDispatcher* GetFileSystemDispatcher() {
18a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  return ChildThread::current() ?
19a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      ChildThread::current()->file_system_dispatcher() : NULL;
2090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
2190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}  // namespace
2390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
24a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)typedef FileSystemDispatcher::StatusCallback StatusCallback;
25a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)typedef FileSystemDispatcher::WriteCallback WriteCallback;
26a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
27a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// This instance may be created outside main thread but runs mainly
28a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// on main thread.
29a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)class WebFileWriterImpl::WriterBridge
30a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    : public base::RefCountedThreadSafe<WriterBridge> {
31a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) public:
323240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  WriterBridge(WebFileWriterImpl::Type type)
33a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      : request_id_(0),
343240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch        thread_id_(WorkerTaskRunner::Instance()->CurrentWorkerId()),
353240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch        written_bytes_(0) {
363240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    if (type == WebFileWriterImpl::TYPE_SYNC)
373240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch      waitable_event_.reset(new base::WaitableEvent(false, false));
383240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  }
39a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
40a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  void Truncate(const GURL& path, int64 offset,
41a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                const StatusCallback& status_callback) {
42a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    status_callback_ = status_callback;
43a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    if (!GetFileSystemDispatcher())
44a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      return;
45a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    ChildThread::current()->file_system_dispatcher()->Truncate(
46a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        path, offset, &request_id_,
47a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        base::Bind(&WriterBridge::DidFinish, this));
48a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
49a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
5058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  void Write(const GURL& path, const std::string& id, int64 offset,
51a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)             const WriteCallback& write_callback,
52a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)             const StatusCallback& error_callback) {
53a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    write_callback_ = write_callback;
54a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    status_callback_ = error_callback;
55a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    if (!GetFileSystemDispatcher())
56a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      return;
57a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    ChildThread::current()->file_system_dispatcher()->Write(
5858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        path, id, offset, &request_id_,
59a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        base::Bind(&WriterBridge::DidWrite, this),
60a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        base::Bind(&WriterBridge::DidFinish, this));
61a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
62a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
63a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  void Cancel(const StatusCallback& status_callback) {
64a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    status_callback_ = status_callback;
65a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    if (!GetFileSystemDispatcher())
66a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      return;
67a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    ChildThread::current()->file_system_dispatcher()->Cancel(
68a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        request_id_,
69a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        base::Bind(&WriterBridge::DidFinish, this));
70a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
71a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
723240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  base::WaitableEvent* waitable_event() {
733240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    return waitable_event_.get();
743240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  }
753240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch
763240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  void WaitAndRun() {
773240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    waitable_event_->Wait();
783240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    DCHECK(!results_closure_.is_null());
793240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    results_closure_.Run();
803240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  }
813240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch
82a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) private:
83a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  friend class base::RefCountedThreadSafe<WriterBridge>;
84a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  virtual ~WriterBridge() {}
85a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
86a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  void DidWrite(int64 bytes, bool complete) {
873240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    written_bytes_ += bytes;
883240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    if (waitable_event_ && !complete)
893240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch      return;
903240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    PostTaskToWorker(base::Bind(write_callback_, written_bytes_, complete));
91a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
92a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void DidFinish(base::File::Error status) {
94a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    PostTaskToWorker(base::Bind(status_callback_, status));
95a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
96a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
97a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  void PostTaskToWorker(const base::Closure& closure) {
983240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    written_bytes_ = 0;
993240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    if (!thread_id_) {
1003240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch      DCHECK(!waitable_event_);
101a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      closure.Run();
1023240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch      return;
1033240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    }
1043240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    if (waitable_event_) {
1053240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch      results_closure_ = closure;
1063240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch      waitable_event_->Signal();
1073240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch      return;
1083240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    }
1093240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    WorkerTaskRunner::Instance()->PostTask(thread_id_, closure);
110a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
111a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
112a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  StatusCallback status_callback_;
113a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  WriteCallback write_callback_;
114a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  int request_id_;
115a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  int thread_id_;
1163240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  int written_bytes_;
1173240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  scoped_ptr<base::WaitableEvent> waitable_event_;
1183240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  base::Closure results_closure_;
119a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)};
120a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
12190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)WebFileWriterImpl::WebFileWriterImpl(
122f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)     const GURL& path, blink::WebFileWriterClient* client,
1233240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch     Type type,
124a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)     base::MessageLoopProxy* main_thread_loop)
12590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  : WebFileWriterBase(path, client),
126a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    main_thread_loop_(main_thread_loop),
1273240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    bridge_(new WriterBridge(type)) {
12890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
12990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
13090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)WebFileWriterImpl::~WebFileWriterImpl() {
13190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
13290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
13390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void WebFileWriterImpl::DoTruncate(const GURL& path, int64 offset) {
134a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  RunOnMainThread(base::Bind(&WriterBridge::Truncate, bridge_,
135a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      path, offset,
136a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      base::Bind(&WebFileWriterImpl::DidFinish, AsWeakPtr())));
13790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
13890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
13958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void WebFileWriterImpl::DoWrite(
14058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const GURL& path, const std::string& blob_id, int64 offset) {
14158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  RunOnMainThread(base::Bind(&WriterBridge::Write, bridge_,
14258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      path, blob_id, offset,
14358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      base::Bind(&WebFileWriterImpl::DidWrite, AsWeakPtr()),
14458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      base::Bind(&WebFileWriterImpl::DidFinish, AsWeakPtr())));
14558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
14658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
14790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void WebFileWriterImpl::DoCancel() {
148a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  RunOnMainThread(base::Bind(&WriterBridge::Cancel, bridge_,
149a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      base::Bind(&WebFileWriterImpl::DidFinish, AsWeakPtr())));
150a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
151a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
152a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void WebFileWriterImpl::RunOnMainThread(const base::Closure& closure) {
1533240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  if (main_thread_loop_->RunsTasksOnCurrentThread()) {
1543240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    DCHECK(!bridge_->waitable_event());
155a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    closure.Run();
1563240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    return;
1573240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  }
1583240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  main_thread_loop_->PostTask(FROM_HERE, closure);
1593240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  if (bridge_->waitable_event())
1603240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    bridge_->WaitAndRun();
16190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
16290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
16390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}  // namespace content
164