packagemanager-service.js 7.92 KB
/*
 *
 * ADOBE CONFIDENTIAL
 * __________________
 *
 *  Copyright 2017 Adobe Systems Incorporated
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Adobe Systems Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Adobe Systems Incorporated and its
 * suppliers and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Adobe Systems Incorporated.
 */

/* globals Promise */
define('screens/player/firmware/packagemanager/impl/packagemanager-service', [
    'screens/player/firmware/packagemanager/packagemanager',
    'screens/player/firmware/packagemanager/spi/sync',
    'screens/player/firmware/preferences/preferences',
    'screens/player/firmware/filesystem/filesystem',
    'screens/player/shared/serviceadmin',
    'eventemitter',
    'underscore'
], function(PackageManager, SyncSpi, Preferences, FilesystemService, ServiceAdmin, EventEmitter, _) {
    'use strict';

    /**
     * template of the file name that contains the 'firmware' timestamp.
     * @type {string}
     */
    var TIMESTAMP_FILENAME_TEMPLATE = 'pge-package-update-{uid}.json';

    /**
     * name of the file that contains the 'firmware' timestamp.
     * @type {string}
     * @deprecated
     */
    var TIMESTAMP_FILENAME = 'pge-package-update.json';

    /**
     * Reads the timestamp when the package was last modified.
     * @memberof PackageManagerService
     *
     * @param {string} path Path to the package.
     * @param {string?} uid Package unique id (used to find the pge-package-update file).
     * @returns {Promise} A promise that resolves with the timestamp or 0 if not defined.
     */
    function getLastModified(path, uid) {
        var filesystemService = ServiceAdmin.getService(FilesystemService.serviceName);

        return filesystemService.getUserDataPath()
            .then(function(userDataPath) {
                if (uid) {
                    return filesystemService.joinPath([userDataPath, path, 'www', TIMESTAMP_FILENAME_TEMPLATE.replace('{uid}', uid)]);
                }
                // backward compatibility: check for old file name
                return filesystemService.joinPath([userDataPath, path, 'www', TIMESTAMP_FILENAME]);
            }).then(function(timestampFilePath) {
                return filesystemService.readFileAsText(timestampFilePath);
            }).then(function(txt) {
                var data = JSON.parse(txt);
                console.log('getLastModified: timestamp contents for ' + path + ' is ', data);
                return data.lastModified;
            }).catch(function(e) {
                if (uid) {
                    // backward compatibility: give an extra try without the uid
                    return getLastModified(path);
                }
                console.log('getLastModified: error reading timestamp file.', e);
                return Promise.reject(e);
            });
    }

    /**
     * Update the specified package.
     * @memberof PackageManagerService
     *
     * @param {String} url The url to the update package
     * @param {String} path The path to extract the package to
     * @param {String} mode Un-packing mode
     * @param {String} title Friendly package title
     * @return {Promise} A Promise that an updated package was downloaded
     *
     * @private
     */
    function createUpdatePromise(url, path, mode, title) {
        var self = this;

        return new Promise(function(resolve, reject) {
            var syncSpi = ServiceAdmin.getService(SyncSpi.serviceName);
            var lastProgress = '';
            var lastStatus = -1;
            var lastProgressLogged = 0;
            var lastProgressEmitted = 0;

            var onProgress = function(data) {
                var hash = data.status + '-' + data.progress;
                if (lastProgress === hash) {
                    return;
                }
                var now = (new Date()).getTime();
                if (now - lastProgressLogged > 500 || lastStatus !== data.status) {
                    console.log(data.statusText + ' - ' + data.progress + '% - ' + title);
                    lastProgressLogged = now;
                }
                if (now - lastProgressEmitted > 100 || lastStatus !== data.status) {
                    lastProgressEmitted = now;
                    self.emit(PackageManager.EVENTS.SYNC_PROGRESS, {
                        title: title,
                        url: url,
                        status: data.status,
                        progress: data.progress
                    });
                }
                lastStatus = data.status;
            };

            syncSpi.sync(url, path, mode, onProgress)
                .then(function() {
                    resolve({
                        title: title,
                        url: url
                    });
                })
                .catch(function(e) {
                    reject({
                        title: title,
                        url: url,
                        error: e
                    });
                });
            self.emit(PackageManager.EVENTS.SYNC_STARTED, {
                title: title,
                url: url
            });

        });
    }

    /**
     * Package Manager implementation.
     *
     * @class PackageManagerImpl
     */
    var PackageManagerService = function() {
    };

    PackageManagerService.prototype = _.assign({}, EventEmitter.prototype, PackageManager,
        /** @lends PackageManagerService.prototype */ {

        /**
         * @memberof PackageManagerService
         * @inheritdoc
         */
        activate: function() {
            return new Promise(function(resolve) {
                ServiceAdmin.onServiceHighestRankedStart(SyncSpi.serviceName, function() {
                    resolve();
                });
            }).then(function() {
                return new Promise(function(resolve) {
                    ServiceAdmin.onServiceHighestRankedStart(Preferences.serviceName, function() {
                        resolve();
                    });
                });
            });
        },

        /**
         * @memberof PackageManagerService
         * @inheritdoc
         */
        updatePackage: function(urlPath, path, expiration, mode, title, uid) {

            var self = this;
            var preferences = ServiceAdmin.getService(Preferences.serviceName).getPreferences();
            var packageUrl = preferences.server + urlPath;

            if (expiration) {
                return getLastModified.call(self, path, uid)
                    .catch(function(e) {
                        console.log('Cannot read timestamp. Forcing update assuming the package does not exist yet', e);
                        return Promise.resolve(0);
                    })
                    .then(function(ts) {
                        if (ts < expiration) {
                            console.log('Updating expired package (' + ts + ' < ' + expiration + ')');
                            return createUpdatePromise.call(self, packageUrl, path, mode, title);
                        }

                        console.log('Package is not expired. Skipping update (' + ts + ' >= ' + expiration + ')');
                        return Promise.resolve({
                            title: title,
                            url: packageUrl
                        });
                    });
            }

            return createUpdatePromise.call(self, packageUrl, path, mode, title);
        }
    });

    return PackageManagerService;
});

/* istanbul ignore next */
require([
    'screens/player/firmware/packagemanager/impl/packagemanager-service',
    'screens/player/shared/serviceadmin'
], function(PackageManagerService, ServiceAdmin) {
    'use strict';
    ServiceAdmin.register(new PackageManagerService());
});