Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Side by Side Diff: lib/ioIndexedDB.js

Issue 29796555: Issue 6621 (Closed)
Patch Set: Most of the changes from patch 1 Created June 4, 2018, 9:01 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « lib/io.js ('k') | metadata.edge » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * This file is part of Adblock Plus <https://adblockplus.org/>,
3 * Copyright (C) 2006-present eyeo GmbH
4 *
5 * Adblock Plus is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation.
8 *
9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 "use strict";
19
20
21 // from DefaultConfig https://github.com/localForage/localForage/blob/2cdbd74/sr c/localforage.js#L42-L51
22 const localForageDbConfig = {
23 dbName: "localforage",
24 storeName: "keyvaluepairs",
25 version: 2
26 };
27
28 const dbConfig = {
29 dbName: "adblockplus",
30 storeName: "file",
31 keyPath: "fileName",
32 version: 1
33 };
34
35 let db;
36 let localForageDb;
37 /**
38 * @type Promise
39 */
40 let migrationDone = migrateFiles();
41
42 const keyPrefix = "file:";
43
44 /**
45 * Handles migrating all files from localforage db to the new adblockplus
46 * @return {Promise}
47 * Promise to be resolved or rejected once the operation is completed
48 */
49 function migrateFiles()
50 {
51 return openDB(dbConfig)
52 .then(dbInstance =>
53 {
54 db = dbInstance;
55 return openDB(localForageDbConfig);
56 })
57 .then(dbInstance =>
58 {
59 localForageDb = dbInstance;
60 return getAllFiles(localForageDb, localForageDbConfig.storeName);
61 })
62 .then(files =>
63 files.map(file =>
64 Promise.all(saveFile(file, db, dbConfig.storeName))))
65 .then(() =>
66 clearAllStorage(localForageDb, localForageDbConfig.storeName));
67 }
68
69 function getAllFiles(dbInstance, storeName)
70 {
71 return new Promise((resolve, reject) =>
72 {
73 let transaction = dbInstance
74 .transaction([storeName], IDBTransaction.READ_ONLY);
75
76 let store = transaction.objectStore(storeName);
77 let cursorReq = store.openCursor();
78 let filesData = [];
79
80 transaction.oncomplete = event =>
81 {
82 resolve(filesData);
83 };
84
85 cursorReq.onsuccess = event =>
86 {
87 let cursor = event.currentTarget.result;
88 if (cursor)
89 {
90 let value = cursor.value;
91
92 filesData.push({
93 fileName: cursor.key,
94 content: value.content,
95 lastModified: value.lastModified
96 });
97 cursor.continue();
98 }
99 };
100
101 cursorReq.onerror = reject;
102 });
103 }
104
105 function clearAllStorage(dbInstance, storeName)
106 {
107 return new Promise((resolve, reject) =>
108 {
109 let store = getObjectStore(dbInstance, storeName);
110 let req = store.clear();
111
112 req.onsuccess = resolve;
113 req.onerror = reject;
114 });
115 }
116
117 function fileToKey(fileName)
118 {
119 return keyPrefix + fileName;
120 }
121
122 function formatFile(name, data)
123 {
124 return {
125 fileName: fileToKey(name),
126 content: Array.from(data),
127 lastModified: Date.now()
128 };
129 }
130
131 function openDB({dbName, storeName, version, keyPath})
132 {
133 return new Promise((resolve, reject) =>
134 {
135 let req = indexedDB.open(dbName, version);
136
137 req.onsuccess = event =>
138 {
139 return resolve(event.currentTarget.result);
140 };
141
142 req.onerror = reject;
143
144 req.onupgradeneeded = event =>
145 {
146 event
147 .currentTarget
148 .result
149 .createObjectStore(storeName,
150 {
151 keyPath,
152 autoIncrement: true
153 });
154 };
155 });
156 }
157
158 function getObjectStore(dbInstance, storeName)
159 {
160 return dbInstance
161 .transaction([storeName], IDBTransaction.READ_WRITE)
162 .objectStore(storeName);
163 }
164
165 function getFile(fileName, dbInstance, storeName)
166 {
167 return new Promise((resolve, reject) =>
168 {
169 let store = getObjectStore(dbInstance, storeName);
170 let req = store.get(fileToKey(fileName));
171
172 req.onsuccess = event =>
173 {
174 let result = event.currentTarget.result;
175
176 if (result)
177 resolve(result);
178 else
179 reject({type: "NoSuchFile"});
180 };
181 req.onerror = reject;
182 });
183 }
184
185 function saveFile(data, dbInstance, storeName)
186 {
187 return new Promise((resolve, reject) =>
188 {
189 let store = getObjectStore(dbInstance, storeName);
190 let req = store.put(data);
191
192 req.onsuccess = resolve;
193 req.onerror = reject;
194 });
195 }
196
197 function deleteFile(fileName, dbInstance, storeName)
198 {
199 return new Promise((resolve, reject) =>
200 {
201 let store = getObjectStore(dbInstance, storeName);
202 let req = store.delete(fileToKey(fileName));
203
204 req.onsuccess = resolve;
205 req.onerror = reject;
206 });
207 }
208
209 exports.IO =
210 {
211 /**
212 * Writes text lines to a file.
213 * @param {string} fileName
214 * Name of the file to be written
215 * @param {Iterable.<string>} data
216 * An array-like or iterable object containing the lines (without line
217 * endings)
218 * @return {Promise}
219 * Promise to be resolved or rejected once the operation is completed
220 */
221 writeToFile(fileName, data)
222 {
223 return migrationDone
224 .then(() => saveFile(formatFile(fileName, data), db, dbConfig.storeName));
225 },
226
227 /**
228 * Reads text lines from a file.
229 * @param {string} fileName
230 * Name of the file to be read
231 * @param {TextSink} listener
232 * Function that will be called for each line in the file
233 * @return {Promise}
234 * Promise to be resolved or rejected once the operation is completed
235 */
236 readFromFile(fileName, listener)
237 {
238 return migrationDone
239 .then(() => getFile(fileName, db, dbConfig.storeName))
240 .then(entry =>
241 {
242 for (let line of entry.content)
243 listener(line);
244 });
245 },
246
247 /**
248 * Retrieves file metadata.
249 * @param {string} fileName
250 * Name of the file to be looked up
251 * @return {Promise.<StatData>}
252 * Promise to be resolved with file metadata once the operation is
253 * completed
254 */
255 statFile(fileName)
256 {
257 return migrationDone
258 .then(() => getFile(fileName, db, dbConfig.storeName))
259 .then(entry =>
260 {
261 return {
262 exists: true,
263 lastModified: entry.lastModified
264 };
265 })
266 .catch(error =>
267 {
268 if (error.type == "NoSuchFile")
269 return {exists: false};
270 throw error;
271 });
272 },
273
274 /**
275 * Renames a file.
276 * @param {string} fromFile
277 * Name of the file to be renamed
278 * @param {string} newName
279 * New file name, will be overwritten if exists
280 * @return {Promise}
281 * Promise to be resolved or rejected once the operation is completed
282 */
283 renameFile(fromFile, newName)
284 {
285 return migrationDone
286 .then(() => getFile(fromFile, db, dbConfig.storeName))
287 .then(fileData =>
288 saveFile(
289 {
290 fileName: fileToKey(newName),
291 content: fileData.content,
292 lastModified: fileData.lastModified
293 },
294 db,
295 dbConfig.storeName))
296 .then(() => deleteFile(fromFile, db, dbConfig.storeName));
297 }
298 };
299
OLDNEW
« no previous file with comments | « lib/io.js ('k') | metadata.edge » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld