cordova-app-loader icon indicating copy to clipboard operation
cordova-app-loader copied to clipboard

Fall back to last working version

Open dsc8x opened this issue 10 years ago • 8 comments

Hey :)

If an update fails, why not fall back to the last working version, instead of the bundled version? Wouldn't that be way better?

dsc8x avatar Feb 19 '15 03:02 dsc8x

Yes and no!

Yes: it would be WAY better because users don't fall back many versions. No: In order to do this safely, we need to "backup" the entire app. This effectively doubles the size of your app in your storage.

As for practical implementation, this would be an idea:

  • Before update: Copy current app files to backup location. Store current manifest as backup_manifest
  • On bootstrap: Check localStorage:
    • Is there localStorage manifest? If yes, use that.
    • Is there localStorage backup_manifest? If yes, use that. Save as manifest in localStorage.
    • Else, download Manifest.json

I am open for Pull Request. If more people like it, I might implement it myself in the future (I am quite busy doing paid work at the moment)

markmarijnissen avatar Mar 04 '15 08:03 markmarijnissen

I am looking into this.

arieljake avatar Apr 09 '15 11:04 arieljake

yay!

dsc8x avatar Apr 10 '15 20:04 dsc8x

+1

ashconnell avatar Apr 17 '15 03:04 ashconnell

+1

micky2be avatar Apr 17 '15 06:04 micky2be

I'm finally starting on this, but is anyone around for some questions?

arieljake avatar May 18 '15 07:05 arieljake

Ok, if I can get some feedback that would be great.

What I figured to do was separate the download process from the update process. That way we don't touch the existing configuration/manifest if the download fails. To do that, I thought to create a separate cache for the download step:

this.cache = new CordovaFileCache(options);  
this.downloadCache = new CordovaFileCache({
    fs: options.fs,
    retry: options.retry,
    cacheBuster: options.cacheBuster,
    serverRoot: options.serverRoot,
    localRoot: options.localRoot + "-dwnld"
  });

then, in AppLoader.prototype.download we use that downloadCache to get the files:

self.downloadCache.add(self._toBeDownloaded);

return self.downloadCache.download(onprogress)
    .then(function() {
      self._updateReady = true;        
    });

and finally, in AppLoader.prototype.update, we finalize the process by deleting and copying files, including from the download cache to the live cache:

if(this._updateReady) {
    // update manifest
    localStorage.setItem('manifest',JSON.stringify(this.newManifest));

    return self.cache.remove(self._toBeDeleted,true)
      .then(function(){
        return Promise.all(self._toBeCopied.map(function(file){
          return self.cache._fs.download(BUNDLE_ROOT + file,self.cache.localRoot + file);
        }));
      })
      .then(function() {
        return Promise.all(self.downloadCache.list(),self._toBeDownloaded.map(function(file){
          var srcPath = self.downloadCache.toPath(file);
          var destPath = self.cache.toPath(file);

          return self.downloadCache._fs.read(srcPath)
            .then(function(fileContents) {
              return self.cache._fs.write(destPath, fileContents);
            });
        }));
      })
      .then(function(){
        self._toBeDeleted = [];
        self._toBeDownloaded = [];

        if(reload !== false) location.reload();

        return self.newManifest;
      });
  }

Anyone see an issue here? Mark, am I moving files from one cache to the other correctly?

arieljake avatar May 18 '15 09:05 arieljake

anyone?

arieljake avatar May 24 '15 22:05 arieljake