~ubuntu-branches/ubuntu/vivid/emscripten/vivid-proposed

« back to all changes in this revision

Viewing changes to src/library_idbfs.js

  • Committer: Package Import Robot
  • Author(s): Sylvestre Ledru
  • Date: 2014-01-19 14:12:40 UTC
  • mfrom: (4.1.2 sid)
  • Revision ID: package-import@ubuntu.com-20140119141240-nfiw0p8033oitpfz
Tags: 1.9.0~20140119~7dc8c2f-1
* New snapshot release (Closes: #733714)
* Provide sources for javascript and flash. Done in orig-tar.sh
  Available in third_party/websockify/include/web-socket-js/src/
  (Closes: #735903)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
mergeInto(LibraryManager.library, {
 
2
  $IDBFS__deps: ['$FS', '$MEMFS', '$PATH'],
 
3
  $IDBFS: {
 
4
    dbs: {},
 
5
    indexedDB: function() {
 
6
      return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
 
7
    },
 
8
    DB_VERSION: 20,
 
9
    DB_STORE_NAME: 'FILE_DATA',
 
10
    // reuse all of the core MEMFS functionality
 
11
    mount: function(mount) {
 
12
      return MEMFS.mount.apply(null, arguments);
 
13
    },
 
14
    // the only custom function IDBFS implements is to handle
 
15
    // synchronizing the wrapped MEMFS with a backing IDB instance
 
16
    syncfs: function(mount, populate, callback) {
 
17
      IDBFS.getLocalSet(mount, function(err, local) {
 
18
        if (err) return callback(err);
 
19
 
 
20
        IDBFS.getRemoteSet(mount, function(err, remote) {
 
21
          if (err) return callback(err);
 
22
 
 
23
          var src = populate ? remote : local;
 
24
          var dst = populate ? local : remote;
 
25
 
 
26
          IDBFS.reconcile(src, dst, callback);
 
27
        });
 
28
      });
 
29
    },
 
30
    reconcile: function(src, dst, callback) {
 
31
      var total = 0;
 
32
 
 
33
      var create = {};
 
34
      for (var key in src.files) {
 
35
        if (!src.files.hasOwnProperty(key)) continue;
 
36
        var e = src.files[key];
 
37
        var e2 = dst.files[key];
 
38
        if (!e2 || e.timestamp > e2.timestamp) {
 
39
          create[key] = e;
 
40
          total++;
 
41
        }
 
42
      }
 
43
 
 
44
      var remove = {};
 
45
      for (var key in dst.files) {
 
46
        if (!dst.files.hasOwnProperty(key)) continue;
 
47
        var e = dst.files[key];
 
48
        var e2 = src.files[key];
 
49
        if (!e2) {
 
50
          remove[key] = e;
 
51
          total++;
 
52
        }
 
53
      }
 
54
 
 
55
      if (!total) {
 
56
        // early out
 
57
        return callback(null);
 
58
      }
 
59
 
 
60
      var completed = 0;
 
61
      function done(err) {
 
62
        if (err) return callback(err);
 
63
        if (++completed >= total) {
 
64
          return callback(null);
 
65
        }
 
66
      };
 
67
 
 
68
      // create a single transaction to handle and IDB reads / writes we'll need to do
 
69
      var db = src.type === 'remote' ? src.db : dst.db;
 
70
      var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readwrite');
 
71
      transaction.onerror = function transaction_onerror() { callback(this.error); };
 
72
      var store = transaction.objectStore(IDBFS.DB_STORE_NAME);
 
73
 
 
74
      for (var path in create) {
 
75
        if (!create.hasOwnProperty(path)) continue;
 
76
        var entry = create[path];
 
77
 
 
78
        if (dst.type === 'local') {
 
79
          // save file to local
 
80
          try {
 
81
            if (FS.isDir(entry.mode)) {
 
82
              FS.mkdir(path, entry.mode);
 
83
            } else if (FS.isFile(entry.mode)) {
 
84
              var stream = FS.open(path, 'w+', 0666);
 
85
              FS.write(stream, entry.contents, 0, entry.contents.length, 0, true /* canOwn */);
 
86
              FS.close(stream);
 
87
            }
 
88
            done(null);
 
89
          } catch (e) {
 
90
            return done(e);
 
91
          }
 
92
        } else {
 
93
          // save file to IDB
 
94
          var req = store.put(entry, path);
 
95
          req.onsuccess = function req_onsuccess() { done(null); };
 
96
          req.onerror = function req_onerror() { done(this.error); };
 
97
        }
 
98
      }
 
99
 
 
100
      for (var path in remove) {
 
101
        if (!remove.hasOwnProperty(path)) continue;
 
102
        var entry = remove[path];
 
103
 
 
104
        if (dst.type === 'local') {
 
105
          // delete file from local
 
106
          try {
 
107
            if (FS.isDir(entry.mode)) {
 
108
              // TODO recursive delete?
 
109
              FS.rmdir(path);
 
110
            } else if (FS.isFile(entry.mode)) {
 
111
              FS.unlink(path);
 
112
            }
 
113
            done(null);
 
114
          } catch (e) {
 
115
            return done(e);
 
116
          }
 
117
        } else {
 
118
          // delete file from IDB
 
119
          var req = store.delete(path);
 
120
          req.onsuccess = function req_onsuccess() { done(null); };
 
121
          req.onerror = function req_onerror() { done(this.error); };
 
122
        }
 
123
      }
 
124
    },
 
125
    getLocalSet: function(mount, callback) {
 
126
      var files = {};
 
127
 
 
128
      function isRealDir(p) {
 
129
        return p !== '.' && p !== '..';
 
130
      };
 
131
      function toAbsolute(root) {
 
132
        return function(p) {
 
133
          return PATH.join2(root, p);
 
134
        }
 
135
      };
 
136
 
 
137
      var check = FS.readdir(mount.mountpoint)
 
138
        .filter(isRealDir)
 
139
        .map(toAbsolute(mount.mountpoint));
 
140
 
 
141
      while (check.length) {
 
142
        var path = check.pop();
 
143
        var stat, node;
 
144
 
 
145
        try {
 
146
          var lookup = FS.lookupPath(path);
 
147
          node = lookup.node;
 
148
          stat = FS.stat(path);
 
149
        } catch (e) {
 
150
          return callback(e);
 
151
        }
 
152
 
 
153
        if (FS.isDir(stat.mode)) {
 
154
          check.push.apply(check, FS.readdir(path)
 
155
            .filter(isRealDir)
 
156
            .map(toAbsolute(path)));
 
157
 
 
158
          files[path] = { mode: stat.mode, timestamp: stat.mtime };
 
159
        } else if (FS.isFile(stat.mode)) {
 
160
          files[path] = { contents: node.contents, mode: stat.mode, timestamp: stat.mtime };
 
161
        } else {
 
162
          return callback(new Error('node type not supported'));
 
163
        }
 
164
      }
 
165
 
 
166
      return callback(null, { type: 'local', files: files });
 
167
    },
 
168
    getDB: function(name, callback) {
 
169
      // look it up in the cache
 
170
      var db = IDBFS.dbs[name];
 
171
      if (db) {
 
172
        return callback(null, db);
 
173
      }
 
174
      var req;
 
175
      try {
 
176
        req = IDBFS.indexedDB().open(name, IDBFS.DB_VERSION);
 
177
      } catch (e) {
 
178
        return onerror(e);
 
179
      }
 
180
      req.onupgradeneeded = function req_onupgradeneeded() {
 
181
        db = req.result;
 
182
        db.createObjectStore(IDBFS.DB_STORE_NAME);
 
183
      };
 
184
      req.onsuccess = function req_onsuccess() {
 
185
        db = req.result;
 
186
        // add to the cache
 
187
        IDBFS.dbs[name] = db;
 
188
        callback(null, db);
 
189
      };
 
190
      req.onerror = function req_onerror() {
 
191
        callback(this.error);
 
192
      };
 
193
    },
 
194
    getRemoteSet: function(mount, callback) {
 
195
      var files = {};
 
196
 
 
197
      IDBFS.getDB(mount.mountpoint, function(err, db) {
 
198
        if (err) return callback(err);
 
199
 
 
200
        var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readonly');
 
201
        transaction.onerror = function transaction_onerror() { callback(this.error); };
 
202
 
 
203
        var store = transaction.objectStore(IDBFS.DB_STORE_NAME);
 
204
        store.openCursor().onsuccess = function store_openCursor_onsuccess(event) {
 
205
          var cursor = event.target.result;
 
206
          if (!cursor) {
 
207
            return callback(null, { type: 'remote', db: db, files: files });
 
208
          }
 
209
 
 
210
          files[cursor.key] = cursor.value;
 
211
          cursor.continue();
 
212
        };
 
213
      });
 
214
    }
 
215
  }
 
216
});