• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2013 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 *     * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *     * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 *     * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem;
32
33/**
34 * @constructor
35 * @param {!string} dirPath
36 * @param {!string} name
37 * @param {!function(?WebInspector.TempFile)} callback
38 */
39WebInspector.TempFile = function(dirPath, name, callback)
40{
41    this._fileEntry = null;
42    this._writer = null;
43
44    /**
45     * @param {!FileSystem} fs
46     * @this {WebInspector.TempFile}
47     */
48    function didInitFs(fs)
49    {
50        fs.root.getDirectory(dirPath, { create: true }, didGetDir.bind(this), errorHandler);
51    }
52
53    /**
54     * @param {!DirectoryEntry} dir
55     * @this {WebInspector.TempFile}
56     */
57    function didGetDir(dir)
58    {
59        dir.getFile(name, { create: true }, didCreateFile.bind(this), errorHandler);
60    }
61
62    /**
63     * @param {!FileEntry} fileEntry
64     * @this {WebInspector.TempFile}
65     */
66    function didCreateFile(fileEntry)
67    {
68        this._fileEntry = fileEntry;
69        fileEntry.createWriter(didCreateWriter.bind(this), errorHandler);
70    }
71
72    /**
73     * @param {!FileWriter} writer
74     * @this {WebInspector.TempFile}
75     */
76    function didCreateWriter(writer)
77    {
78        /**
79         * @this {WebInspector.TempFile}
80         */
81        function didTruncate(e)
82        {
83            this._writer = writer;
84            writer.onwrite = null;
85            writer.onerror = null;
86            callback(this);
87        }
88
89        function onTruncateError(e)
90        {
91            WebInspector.messageSink.addErrorMessage("Failed to truncate temp file " + e.code + " : " + e.message);
92            callback(null);
93        }
94
95        if (writer.length) {
96            writer.onwrite = didTruncate.bind(this);
97            writer.onerror = onTruncateError;
98            writer.truncate(0);
99        } else {
100            this._writer = writer;
101            callback(this);
102        }
103    }
104
105    function errorHandler(e)
106    {
107        WebInspector.messageSink.addErrorMessage("Failed to create temp file " + e.code + " : " + e.message);
108        callback(null);
109    }
110
111    /**
112     * @this {WebInspector.TempFile}
113     */
114    function didClearTempStorage()
115    {
116        window.requestFileSystem(window.TEMPORARY, 10, didInitFs.bind(this), errorHandler);
117    }
118    WebInspector.TempFile._ensureTempStorageCleared(didClearTempStorage.bind(this));
119}
120
121WebInspector.TempFile.prototype = {
122    /**
123     * @param {!string} data
124     * @param {!function(boolean)} callback
125     */
126    write: function(data, callback)
127    {
128        var blob = new Blob([data], {type: 'text/plain'});
129        this._writer.onerror = function(e)
130        {
131            WebInspector.messageSink.addErrorMessage("Failed to write into a temp file: " + e.message);
132            callback(false);
133        }
134        this._writer.onwrite = function(e)
135        {
136            callback(true);
137        }
138        this._writer.write(blob);
139    },
140
141    finishWriting: function()
142    {
143        this._writer = null;
144    },
145
146    /**
147     * @param {function(?string)} callback
148     */
149    read: function(callback)
150    {
151        /**
152         * @param {!File} file
153         */
154        function didGetFile(file)
155        {
156            var reader = new FileReader();
157
158            /**
159             * @this {FileReader}
160             */
161            reader.onloadend = function(e)
162            {
163                callback(/** @type {?string} */ (this.result));
164            }
165            reader.onerror = function(error)
166            {
167                WebInspector.messageSink.addErrorMessage("Failed to read from temp file: " + error.message);
168            }
169            reader.readAsText(file);
170        }
171        function didFailToGetFile(error)
172        {
173            WebInspector.messageSink.addErrorMessage("Failed to load temp file: " + error.message);
174            callback(null);
175        }
176        this._fileEntry.file(didGetFile, didFailToGetFile);
177    },
178
179    /**
180     * @param {!WebInspector.OutputStream} outputStream
181     * @param {!WebInspector.OutputStreamDelegate} delegate
182     */
183    writeToOutputSteam: function(outputStream, delegate)
184    {
185        /**
186         * @param {!File} file
187         */
188        function didGetFile(file)
189        {
190            var reader = new WebInspector.ChunkedFileReader(file, 10*1000*1000, delegate);
191            reader.start(outputStream);
192        }
193
194        function didFailToGetFile(error)
195        {
196            WebInspector.messageSink.addErrorMessage("Failed to load temp file: " + error.message);
197            outputStream.close();
198        }
199
200        this._fileEntry.file(didGetFile, didFailToGetFile);
201    },
202
203    remove: function()
204    {
205        if (this._fileEntry)
206            this._fileEntry.remove(function() {});
207    }
208}
209
210/**
211 * @constructor
212 * @param {!string} dirPath
213 * @param {!string} name
214 */
215WebInspector.BufferedTempFileWriter = function(dirPath, name)
216{
217    this._chunks = [];
218    this._tempFile = null;
219    this._isWriting = false;
220    this._finishCallback = null;
221    this._isFinished = false;
222    new WebInspector.TempFile(dirPath, name, this._didCreateTempFile.bind(this));
223}
224
225WebInspector.BufferedTempFileWriter.prototype = {
226    /**
227     * @param {!string} data
228     */
229    write: function(data)
230    {
231        if (!this._chunks)
232            return;
233        if (this._finishCallback)
234            throw new Error("No writes are allowed after close.");
235        this._chunks.push(data);
236        if (this._tempFile && !this._isWriting)
237            this._writeNextChunk();
238    },
239
240    /**
241     * @param {!function(?WebInspector.TempFile)} callback
242     */
243    close: function(callback)
244    {
245        this._finishCallback = callback;
246        if (this._isFinished)
247            callback(this._tempFile);
248        else if (!this._isWriting && !this._chunks.length)
249            this._notifyFinished();
250    },
251
252    _didCreateTempFile: function(tempFile)
253    {
254        this._tempFile = tempFile;
255        if (!tempFile) {
256            this._chunks = null;
257            this._notifyFinished();
258            return;
259        }
260        if (this._chunks.length)
261            this._writeNextChunk();
262    },
263
264    _writeNextChunk: function()
265    {
266        var chunkSize = 0;
267        var endIndex = 0;
268        for (; endIndex < this._chunks.length; endIndex++) {
269            chunkSize += this._chunks[endIndex].length;
270            if (chunkSize > 10 * 1000 * 1000)
271                break;
272        }
273        var chunk = this._chunks.slice(0, endIndex + 1).join("");
274        this._chunks.splice(0, endIndex + 1);
275        this._isWriting = true;
276        this._tempFile.write(chunk, this._didWriteChunk.bind(this));
277    },
278
279    _didWriteChunk: function(success)
280    {
281        this._isWriting = false;
282        if (!success) {
283            this._tempFile = null;
284            this._chunks = null;
285            this._notifyFinished();
286            return;
287        }
288        if (this._chunks.length)
289            this._writeNextChunk();
290        else if (this._finishCallback)
291            this._notifyFinished();
292    },
293
294    _notifyFinished: function()
295    {
296        this._isFinished = true;
297        if (this._tempFile)
298            this._tempFile.finishWriting();
299        if (this._finishCallback)
300            this._finishCallback(this._tempFile);
301    }
302}
303
304/**
305 * @constructor
306 */
307WebInspector.TempStorageCleaner = function()
308{
309    this._worker = new SharedWorker("temp_storage_shared_worker/TempStorageSharedWorker.js", "TempStorage");
310    this._callbacks = [];
311    this._worker.port.onmessage = this._handleMessage.bind(this);
312    this._worker.port.onerror = this._handleError.bind(this);
313}
314
315WebInspector.TempStorageCleaner.prototype = {
316    /**
317     * @param {!function()} callback
318     */
319    ensureStorageCleared: function(callback)
320    {
321        if (this._callbacks)
322            this._callbacks.push(callback);
323        else
324            callback();
325    },
326
327    _handleMessage: function(event)
328    {
329        if (event.data.type === "tempStorageCleared") {
330            if (event.data.error)
331                WebInspector.messageSink.addErrorMessage(event.data.error);
332            this._notifyCallbacks();
333        }
334    },
335
336    _handleError: function(event)
337    {
338        WebInspector.messageSink.addErrorMessage(WebInspector.UIString("Failed to clear temp storage: %s", event.data));
339        this._notifyCallbacks();
340    },
341
342    _notifyCallbacks: function()
343    {
344        var callbacks = this._callbacks;
345        this._callbacks = null;
346        for (var i = 0; i < callbacks.length; i++)
347            callbacks[i]();
348    }
349}
350
351/**
352 * @param {!function()} callback
353 */
354WebInspector.TempFile._ensureTempStorageCleared = function(callback)
355{
356    if (!WebInspector.TempFile._storageCleaner)
357        WebInspector.TempFile._storageCleaner = new WebInspector.TempStorageCleaner();
358    WebInspector.TempFile._storageCleaner.ensureStorageCleared(callback);
359}
360