Home | History | Annotate | Download | only in sdk
      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 
     31 window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem;
     32 
     33 /**
     34  * @constructor
     35  * @param {!string} dirPath
     36  * @param {!string} name
     37  * @param {!function(?WebInspector.TempFile)} callback
     38  */
     39 WebInspector.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 
    121 WebInspector.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  */
    215 WebInspector.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 
    225 WebInspector.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  */
    307 WebInspector.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 
    315 WebInspector.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  */
    354 WebInspector.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