This commit is contained in:
Adrien Duermael 2015-05-22 18:00:57 -07:00
Родитель 037bc18a6d
Коммит 4f80c5d0db
3 изменённых файлов: 132 добавлений и 36 удалений

Просмотреть файл

@ -2,6 +2,7 @@ var _ = require('underscore');
var $ = require('jquery'); var $ = require('jquery');
var React = require('react/addons'); var React = require('react/addons');
var Radial = require('./Radial.react'); var Radial = require('./Radial.react');
var ContainerProgress = require('./ContainerProgress.react');
var ContainerHomePreview = require('./ContainerHomePreview.react'); var ContainerHomePreview = require('./ContainerHomePreview.react');
var ContainerHomeLogs = require('./ContainerHomeLogs.react'); var ContainerHomeLogs = require('./ContainerHomeLogs.react');
var ContainerHomeFolders = require('./ContainerHomeFolders.react'); var ContainerHomeFolders = require('./ContainerHomeFolders.react');
@ -51,22 +52,29 @@ var ContainerHome = React.createClass({
); );
} else if (this.props.container && this.props.container.State.Downloading) { } else if (this.props.container && this.props.container.State.Downloading) {
if (this.props.container.Progress !== undefined) { if (this.props.container.Progress !== undefined) {
if (this.props.container.Progress > 0) {
body = ( let fields = [];
<div className="details-progress"> let values = [];
<h2>Downloading Image</h2> let sum = 0.0;
<Radial progress={Math.min(Math.round(this.props.container.Progress), 99)} thick={true} gray={true}/>
</div> for (let i = 0; i < this.props.container.Progress.amount; i++) {
);
} else { values.push(Math.round(this.props.container.Progress.progress[i].value));
body = ( sum += this.props.container.Progress.progress[i].value;
<div className="details-progress">
<h2>Downloading Image</h2>
<Radial spin="true" progress="90" thick={true} transparent={true}/>
</div>
);
} }
sum = sum / this.props.container.Progress.amount;
fields.push(<h2>{Math.round(sum*100)/100}%</h2>)
fields.push(<ContainerProgress pBar1={values[0]} pBar2={values[1]} pBar3={values[2]} pBar4={values[3]} />);
body = (
<div className="details-progress">
<h2>Downloading Image</h2>
{fields}
</div>
);
} else if (this.props.container.State.Waiting) { } else if (this.props.container.State.Waiting) {
body = ( body = (
<div className="details-progress"> <div className="details-progress">

Просмотреть файл

@ -97,11 +97,15 @@ class ContainerStore {
this.setState({containers}); this.setState({containers});
} }
// Receives the name of the container and columns of progression
// A column represents progression for one or more layers
progress ({name, progress}) { progress ({name, progress}) {
let containers = this.containers; let containers = this.containers;
if (containers[name]) { if (containers[name]) {
containers[name].Progress = progress; containers[name].Progress = progress;
} }
this.setState({containers}); this.setState({containers});
} }

Просмотреть файл

@ -178,9 +178,16 @@ export default {
delete this.placeholders[name]; delete this.placeholders[name];
localStorage.setItem('placeholders', JSON.stringify(this.placeholders)); localStorage.setItem('placeholders', JSON.stringify(this.placeholders));
this.createContainer(name, {Image: imageName}); this.createContainer(name, {Image: imageName});
}, progress => { },
// progress is actually the progression PER LAYER (combined in columns)
// not total because it's not accurate enough
progress => {
containerServerActions.progress({name, progress}); containerServerActions.progress({name, progress});
}, () => { },
() => {
containerServerActions.waiting({name, waiting: true}); containerServerActions.waiting({name, waiting: true});
}); });
}, },
@ -310,7 +317,7 @@ export default {
stream.setEncoding('utf8'); stream.setEncoding('utf8');
stream.on('data', json => { stream.on('data', json => {
let data = JSON.parse(json); let data = JSON.parse(json);
console.log(data); // console.log(data);
if (data.status === 'pull' || data.status === 'untag' || data.status === 'delete') { if (data.status === 'pull' || data.status === 'untag' || data.status === 'delete') {
return; return;
@ -344,6 +351,9 @@ export default {
return !existingIds.has(layerSize.Id); return !existingIds.has(layerSize.Id);
}); });
console.log("existingIds:" + existingIds.size)
console.log("layersToDownload:" + layersToDownload.length)
this.client.pull(repository + ':' + tag, (err, stream) => { this.client.pull(repository + ':' + tag, (err, stream) => {
if (err) { if (err) {
callback(err); callback(err);
@ -351,16 +361,45 @@ export default {
} }
stream.setEncoding('utf8'); stream.setEncoding('utf8');
// layerProgress contains progression infos for all layers
let layerProgress = layersToDownload.reduce(function (r, layer) { let layerProgress = layersToDownload.reduce(function (r, layer) {
if (_.findWhere(images, {Id: layer.Id})) { if (_.findWhere(images, {Id: layer.Id})) {
r[layer.Id] = 1; // If the layer is already here, we set current and total to 1
r[layer.Id] = {current:1, total:1, column:-1};
} else { } else {
r[layer.Id] = 0; // At this point, the total layer size is unknown
// so we set total to -1 to avoid displaying it
r[layer.Id] = {current:0, total:-1, column:-1};
} }
return r; return r;
}, {}); }, {});
let timeout = null;
let layersToLoad = _.keys(layerProgress).length;
console.log("nbLayers:" + layersToLoad)
// Split the loading in a few columns for more feedback
let columns = {};
columns.amount = 4; // arbitrary
columns.progress = []; // layerIDs, nbLayers, maxLayers, progress value
columns.toFill = 0; // the current column index, waiting for layer IDs to be displayed
for (let i = 0; i < columns.amount; i++)
{
let layerAmount = Math.ceil(layersToLoad / (columns.amount - i))
layersToLoad -= layerAmount;
columns.progress[i] = { layerIDs:[], nbLayers:0 , maxLayers:layerAmount , value:0.0 };
}
// scheduled to inform about progression at given interval
let tick = null;
// data is associated with one layer only (can be identified with id)
stream.on('data', str => { stream.on('data', str => {
var data = JSON.parse(str); var data = JSON.parse(str);
@ -374,34 +413,79 @@ export default {
} }
if (data.status === 'Already exists') { if (data.status === 'Already exists') {
layerProgress[data.id] = 1;
//layerProgress[data.id].current = 1;
//layerProgress[data.id].total = 1;
} else if (data.status === 'Downloading') { } else if (data.status === 'Downloading') {
let current = data.progressDetail.current;
let total = data.progressDetail.total; // aduermael: How total could be <= 0 ?
// if (data.progressDetail.total <= 0) {
// progressCallback(0);
// return;
// } else {
layerProgress[data.id].current = data.progressDetail.current;
layerProgress[data.id].total = data.progressDetail.total;
// Assign to a column if not done yet
if (layerProgress[data.id].column == -1)
{
// test if we can still add layers to that column
if (columns.progress[columns.toFill].nbLayers == columns.progress[columns.toFill].maxLayers) columns.toFill++;
layerProgress[data.id].column = columns.toFill;
columns.progress[columns.toFill].layerIDs.push(data.id);
columns.progress[columns.toFill].nbLayers++;
if (total <= 0) {
progressCallback(0);
return;
} else {
layerProgress[data.id] = current / total;
} }
//}
let sum = _.values(layerProgress).reduce((pv, sv) => pv + sv, 0); if (!tick) {
let numlayers = _.keys(layerProgress).length; tick = setInterval( function(){
// console.log(JSON.stringify(layerProgress))
var totalProgress = sum / numlayers * 100; // update values
for (let i = 0; i < columns.amount; i++)
{
columns.progress[i].value = 0.0;
// Start only if the column has accurate values for all layers
if (columns.progress[i].nbLayers == columns.progress[i].maxLayers)
{
let layer;
let totalSum = 0;
let currentSum = 0;
if (!timeout) { for (let j = 0; j < columns.progress[i].nbLayers; j++)
progressCallback(totalProgress); {
timeout = setTimeout(() => { layer = layerProgress[columns.progress[i].layerIDs[j]];
timeout = null; totalSum += layer.total;
}, 100); currentSum += layer.current;
}
if (totalSum > 0) columns.progress[i].value = 100.0 * currentSum / totalSum;
else columns.progress[i].value = 0.0;
}
}
progressCallback(columns);
},33);
} }
} }
}); });
stream.on('end', function () { stream.on('end', function () {
clearInterval(tick);
callback(); callback();
}); });
}); });
}); });
}); });