1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/components/thumbnails/PageThumbsWorker.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,185 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.6 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +/** 1.9 + * A worker dedicated for the I/O component of PageThumbs storage. 1.10 + * 1.11 + * Do not rely on the API of this worker. In a future version, it might be 1.12 + * fully replaced by a OS.File global I/O worker. 1.13 + */ 1.14 + 1.15 +"use strict"; 1.16 + 1.17 +importScripts("resource://gre/modules/osfile.jsm"); 1.18 + 1.19 +let File = OS.File; 1.20 +let Type = OS.Shared.Type; 1.21 + 1.22 +/** 1.23 + * Communications with the controller. 1.24 + * 1.25 + * Accepts messages: 1.26 + * {fun:function_name, args:array_of_arguments_or_null} 1.27 + * 1.28 + * Sends messages: 1.29 + * {ok: result} / {fail: serialized_form_of_OS.File.Error} 1.30 + */ 1.31 +self.onmessage = function onmessage(msg) { 1.32 + let data = msg.data; 1.33 + let id = data.id; 1.34 + let result; 1.35 + if (!(data.fun in Agent)) { 1.36 + throw new Error("Cannot find method " + data.fun); 1.37 + } 1.38 + try { 1.39 + result = Agent[data.fun].apply(Agent, data.args); 1.40 + } catch (ex if ex instanceof StopIteration) { 1.41 + // StopIteration cannot be serialized automatically 1.42 + self.postMessage({StopIteration: true, id: id}); 1.43 + return; 1.44 + } catch (ex if ex instanceof OS.File.Error) { 1.45 + // Instances of OS.File.Error know how to serialize themselves 1.46 + // (deserialization ensures that we end up with OS-specific 1.47 + // instances of |OS.File.Error|) 1.48 + self.postMessage({fail: OS.File.Error.toMsg(ex), id:id}); 1.49 + return; 1.50 + } 1.51 + // Other exceptions do not, and should be propagated through DOM's 1.52 + // built-in mechanism for uncaught errors, although this mechanism 1.53 + // may lose interesting information. 1.54 + self.postMessage({ok: result, id:id}); 1.55 +}; 1.56 + 1.57 + 1.58 +let Agent = { 1.59 + // Checks if the specified file exists and has an age less than as 1.60 + // specifed (in seconds). 1.61 + isFileRecent: function Agent_isFileRecent(path, maxAge) { 1.62 + try { 1.63 + let stat = OS.File.stat(path); 1.64 + let maxDate = new Date(); 1.65 + maxDate.setSeconds(maxDate.getSeconds() - maxAge); 1.66 + return stat.lastModificationDate > maxDate; 1.67 + } catch (ex if ex instanceof OS.File.Error) { 1.68 + // file doesn't exist (or can't be stat'd) - must be stale. 1.69 + return false; 1.70 + } 1.71 + }, 1.72 + 1.73 + remove: function Agent_removeFile(path) { 1.74 + try { 1.75 + OS.File.remove(path); 1.76 + return true; 1.77 + } catch (e) { 1.78 + return false; 1.79 + } 1.80 + }, 1.81 + 1.82 + expireFilesInDirectory: 1.83 + function Agent_expireFilesInDirectory(path, filesToKeep, minChunkSize) { 1.84 + let entries = this.getFileEntriesInDirectory(path, filesToKeep); 1.85 + let limit = Math.max(minChunkSize, Math.round(entries.length / 2)); 1.86 + 1.87 + for (let entry of entries) { 1.88 + this.remove(entry.path); 1.89 + 1.90 + // Check if we reached the limit of files to remove. 1.91 + if (--limit <= 0) { 1.92 + break; 1.93 + } 1.94 + } 1.95 + 1.96 + return true; 1.97 + }, 1.98 + 1.99 + getFileEntriesInDirectory: 1.100 + function Agent_getFileEntriesInDirectory(path, skipFiles) { 1.101 + let iter = new OS.File.DirectoryIterator(path); 1.102 + if (!iter.exists()) { 1.103 + return []; 1.104 + } 1.105 + 1.106 + let skip = new Set(skipFiles); 1.107 + 1.108 + return [entry 1.109 + for (entry in iter) 1.110 + if (!entry.isDir && !entry.isSymLink && !skip.has(entry.name))]; 1.111 + }, 1.112 + 1.113 + moveOrDeleteAllThumbnails: 1.114 + function Agent_moveOrDeleteAllThumbnails(pathFrom, pathTo) { 1.115 + OS.File.makeDir(pathTo, {ignoreExisting: true}); 1.116 + if (pathFrom == pathTo) { 1.117 + return true; 1.118 + } 1.119 + let iter = new OS.File.DirectoryIterator(pathFrom); 1.120 + if (iter.exists()) { 1.121 + for (let entry in iter) { 1.122 + if (entry.isDir || entry.isSymLink) { 1.123 + continue; 1.124 + } 1.125 + 1.126 + 1.127 + let from = OS.Path.join(pathFrom, entry.name); 1.128 + let to = OS.Path.join(pathTo, entry.name); 1.129 + 1.130 + try { 1.131 + OS.File.move(from, to, {noOverwrite: true, noCopy: true}); 1.132 + } catch (e) { 1.133 + OS.File.remove(from); 1.134 + } 1.135 + } 1.136 + } 1.137 + iter.close(); 1.138 + 1.139 + try { 1.140 + OS.File.removeEmptyDir(pathFrom); 1.141 + } catch (e) { 1.142 + // This could fail if there's something in 1.143 + // the folder we're not permitted to remove. 1.144 + } 1.145 + 1.146 + return true; 1.147 + }, 1.148 + 1.149 + writeAtomic: function Agent_writeAtomic(path, buffer, options) { 1.150 + return File.writeAtomic(path, 1.151 + buffer, 1.152 + options); 1.153 + }, 1.154 + 1.155 + makeDir: function Agent_makeDir(path, options) { 1.156 + return File.makeDir(path, options); 1.157 + }, 1.158 + 1.159 + copy: function Agent_copy(source, dest, options) { 1.160 + return File.copy(source, dest, options); 1.161 + }, 1.162 + 1.163 + wipe: function Agent_wipe(path) { 1.164 + let iterator = new File.DirectoryIterator(path); 1.165 + try { 1.166 + for (let entry in iterator) { 1.167 + try { 1.168 + File.remove(entry.path); 1.169 + } catch (ex) { 1.170 + // If a file cannot be removed, we should still continue. 1.171 + // This can happen at least for any of the following reasons: 1.172 + // - access denied; 1.173 + // - file has been removed recently during a previous wipe 1.174 + // and the file system has not flushed that yet (yes, this 1.175 + // can happen under Windows); 1.176 + // - file has been removed by the user or another process. 1.177 + } 1.178 + } 1.179 + } finally { 1.180 + iterator.close(); 1.181 + } 1.182 + }, 1.183 + 1.184 + exists: function Agent_exists(path) { 1.185 + return File.exists(path); 1.186 + }, 1.187 +}; 1.188 +