diff --git a/src/js/client.js b/src/js/client.js index 9a501aab6..123707576 100644 --- a/src/js/client.js +++ b/src/js/client.js @@ -63,9 +63,6 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout // variable available only here to avoid this._property pattern var token = null; - // Keep this in sync with docs and constants.js, docker.js - var DEFAULT_MEMORY_LIMIT = 1024 * 1024 * 256; - function ClientError(statusCode, messageOrObject) { Error.call(this); this.name = this.constructor.name; @@ -218,8 +215,7 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout update: { box: null, apps: null }, progress: {}, region: null, - size: null, - memory: 0 + size: null }; this._installedApps = []; this._installedAppsById = {}; @@ -1760,16 +1756,6 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout }); }; - Client.prototype.enoughResourcesAvailable = function (app) { - var needed = app.manifest.memoryLimit || DEFAULT_MEMORY_LIMIT; // RAM+Swap - var used = this.getInstalledApps().reduce(function (prev, cur) { return prev + (cur.memoryLimit || cur.manifest.memoryLimit || DEFAULT_MEMORY_LIMIT); }, 0); - var roundedMemory = Math.round(this.getConfig().memory / (1024 * 1024 * 1024)) * 1024 * 1024 * 1024; // round to nearest GB - var totalMemory = roundedMemory * 1.5; // cloudron-system-setup.sh creates equal amount of swap. 1.5 factor is arbitrary - var available = (totalMemory || 0) - used; - - return (available - needed) >= 0; - }; - Client.prototype.uploadFile = function (appId, file, progressCallback, callback) { var fd = new FormData(); fd.append('file', file); diff --git a/src/views/appstore.js b/src/views/appstore.js index 798b71102..fbd393dfe 100644 --- a/src/views/appstore.js +++ b/src/views/appstore.js @@ -24,6 +24,7 @@ angular.module('Application').controller('AppStoreController', ['$scope', '$loca $scope.validSubscription = false; $scope.unstableApps = false; $scope.subscription = {}; + $scope.memory = null; // { memory, swap } $scope.showView = function (view) { // wait for dialog to be fully closed to avoid modal behavior breakage when moving to a different view already @@ -96,7 +97,17 @@ angular.module('Application').controller('AppStoreController', ['$scope', '$loca }, showForm: function (force) { - if (Client.enoughResourcesAvailable($scope.appInstall.app) || force) { + var app = $scope.appInstall.app; + var DEFAULT_MEMORY_LIMIT = 1024 * 1024 * 256; + + var needed = app.manifest.memoryLimit || DEFAULT_MEMORY_LIMIT; // RAM+Swap + var used = Client.getInstalledApps().reduce(function (prev, cur) { return prev + (cur.memoryLimit || cur.manifest.memoryLimit || DEFAULT_MEMORY_LIMIT); }, 0); + var totalMemory = ($scope.memory.memory + $scope.memory.swap) * 1.5; + var available = (totalMemory || 0) - used; + + var enoughResourcesAvailable = (available - needed) >= 0; + + if (enoughResourcesAvailable || force) { $scope.appInstall.state = 'installForm'; $('#collapseMediaLinksCarousel').collapse('hide'); $('#collapseResourceConstraint').collapse('hide'); @@ -551,6 +562,16 @@ angular.module('Application').controller('AppStoreController', ['$scope', '$loca }); } + function getMemory(callback) { + Client.memory(function (error, memory) { + if (error) console.error(error); + + $scope.memory = memory; + + callback(); + }); + } + function init() { $scope.ready = false; @@ -573,7 +594,11 @@ angular.module('Application').controller('AppStoreController', ['$scope', '$loca }); } - Client.onReady(init); + Client.onReady(function () { + getMemory(function () { + init(); + }); + }); // note: do not use hide.bs.model since it is called immediately from switchToAppsView which is already in angular scope $('#appInstallModal').on('hidden.bs.modal', function () {