Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 63 additions & 2 deletions emhttp/plugins/dynamix.plugin.manager/Plugins.page
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,71 @@ function initlist() {
$('#plugin_table').tablesorter({sortList:[[4,0],[1,0]],sortAppend:[[1,0]],headers:{0:{sorter:false},5:{sorter:false}},textAttribute:'data'});
$('.desc_readmore').readmore({maxHeight:80,moreLink:"<a href='#'><i class='fa fa-chevron-down'></i></a>",lessLink:"<a href='#'><i class='fa fa-chevron-up'></i></a>"});
$('div.spinner.fixed').hide('slow');
loadlist();
checkPlugins();
}
});
}
// Update check, parallel + non-blocking. Instead of one serial sweep that
// blocks on the slowest/unreachable plugin, fire one bounded-concurrency
// request per installed plugin. Each row resolves independently; a slow or
// failed check only affects its own row (never the page), and times out into a
// definite "cannot check" state instead of spinning forever.
var pluginUpdates = 0;
function checkPlugin(plg) {
var name = plg.replace(/\.plg$/,'');
return $.ajax({url:'/plugins/dynamix.plugin.manager/include/ShowPlugins.php',data:{one:name},timeout:20000})
.done(function(data){
data = (data||'').split('\0');
updateInfo(data[0]);
pluginUpdates += (parseInt(data[1],10) || 0);
})
.fail(function(){
var id = name.replace(/\./g,'-');
$('#sid-'+id).attr('data','4').html("<span class='red-text'><i class='fa fa-exclamation-triangle fa-fw'></i>&nbsp;<?=_('cannot check')?></span>");
});
}
function checkPlugins(reset) {
var queue = [], seen = {};
// class 'remove' is on both the checkbox and the button for each plugin, so
// dedupe by data attribute to avoid checking every plugin twice
$('input.remove').each(function(){
var d=$(this).attr('data');
if (d && !seen[d]) {
seen[d]=1;
queue.push(d);
if (reset) {
var id = d.replace(/\.plg$/,'').replace(/\./g,'-');
$('#sid-'+id).attr('data','0').html("<span style='color:#267CA8'><i class='fa fa-refresh fa-spin fa-fw'></i>&nbsp;<?=_('checking')?>...</span>");
}
}
});
pluginUpdates = 0;
$('#updateall').hide();
$('#checkall').find('input').prop('disabled',true);
var total = queue.length, done = 0, idx = 0, active = 0, MAX = 6;
if (!total) { $('#checkall').find('input').prop('disabled',false); return; }
function pump() {
while (active < MAX && idx < total) {
active++;
checkPlugin(queue[idx++]).always(function(){
active--; done++;
// Refresh the sort cache in place (do NOT 'update', which re-applies
// sortList and re-sorts by Status). Each check changes a row's Status
// rank, so 'update' would make rows jump around as results land. Rows
// stay in their initial order; a later header click still sorts on the
// current data because the cache is kept fresh.
$('#plugin_table').trigger('updateCache');
if (done == total) {
if (pluginUpdates > 1) $('#updateall').show(); else $('#updateall').hide();
$('#checkall').find('input').prop('disabled',false);
} else {
pump();
}
});
}
}
pump();
}
function loadlist(id,check) {
if (id) timers.plugins = setTimeout(function(){$('div.spinner.fixed').show('slow');},500);
$.get('/plugins/dynamix.plugin.manager/include/ShowPlugins.php',{audit:id,check:check||<?=$check?>},function(data) {
Expand Down Expand Up @@ -145,7 +206,7 @@ function loadlist(id,check) {
}
$(function() {
initlist();
$('.tabs-container').append("<span id='checkall' class='status vhshift'><input type='button' value=\"_(Check For Updates)_\" onclick='openPlugin(\"checkall\",\"_(Plugin Update Check)_\",\":return\")' disabled></span>");
$('.tabs-container').append("<span id='checkall' class='status vhshift'><input type='button' value=\"_(Check For Updates)_\" onclick='checkPlugins(true)' disabled></span>");
$('.tabs-container').append("<span id='updateall' class='status vhshift' style='display:none;margin-left:12px'><input type='button' value=\"_(Update All Plugins)_\" onclick='updateList()'></span>");
$('.tabs-container').append("<span id='removeall' class='status vhshift' style='display:none;margin-left:12px'><input type='button' value=\"_(Remove Selected Plugins)_\" onclick='removeList()'></span>");
});
Expand Down
8 changes: 8 additions & 0 deletions emhttp/plugins/dynamix.plugin.manager/include/ShowPlugins.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
$check = unscript(_var($_GET,'check'));
$cmd = unscript(_var($_GET,'cmd'));
$init = unscript(_var($_GET,'init'));
$one = unscript(_var($_GET,'one')); // single-plugin update check (fired per row, in parallel)
$empty = true;
$install = false;
$updates = 0;
Expand Down Expand Up @@ -56,6 +57,13 @@
}
}

// Restrict to a single installed plugin so its (network) update check can run
// in parallel with the others, instead of the legacy serial sweep that blocks
// the page on the slowest/unreachable plugin. Goes through the normal update
// check path below (no $audit, $check stays falsy) and returns just this
// plugin's vid-/sid- line.
if ($one) $plugins = "/var/log/plugins/".basename($one,'.plg').".plg";

delete_file($alerts);
foreach (glob($plugins,GLOB_NOSORT) as $plugin_link) {
//only consider symlinks
Expand Down
11 changes: 9 additions & 2 deletions emhttp/plugins/dynamix.plugin.manager/scripts/plugin
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,10 @@ function download($url, $name, &$error, $write=true) {
if (($perror = pclose($file)) != 0) {
$error = "$plg download failure: ".error_desc($perror);
return false;
} elseif (filesize($name) == 0) {
}
clearstatcache(true, $name);
if (filesize($name) == 0) {
$error = "$plg download failure: zero-length file";
if ($write) write("plugin: download failure: zero-length file\r","\n");
return false;
} else {
Expand Down Expand Up @@ -330,7 +333,11 @@ function plugin($method, $plugin_file, &$error) {

// validate plugin download without installation
if ($method == 'validate') {
$name = '/tmp/validate-plugin.tmp';
$name = tempnam('/tmp', 'validate-plugin-');
if ($name === false) {
$error = "unable to create validation temporary file";
return false;
}
foreach ($xml->FILE as $file) if ($file->URL) {
if (!$file->SHA256 and !$file->MD5) continue;
if ( (download($file->URL, $name, $error, false) === false) && (download(filter_url($file->URL), $name, $error, false) === false) ) {
Expand Down
Loading