Index: Slim/Player/Squeezebox.pm =================================================================== --- Slim/Player/Squeezebox.pm (revision 27530) +++ Slim/Player/Squeezebox.pm (working copy) @@ -338,11 +338,9 @@ main::INFOLOG && $log->info("$model v. $from could be upgraded to v. $to if the file existed."); - # We now download firmware from the internet. In the case of no internet connection - # we want to check if the file has appeared later. This timer will check every 10 minutes - Slim::Utils::Timers::killOneTimer( $client, \&checkFirmwareUpgrade ); - Slim::Utils::Timers::setTimer( $client, time() + 600, \&checkFirmwareUpgrade ); - + # Try to start a background download + Slim::Utils::Firmware::downloadAsync($file2, {cb => \&checkFirmwareUpgrade, pt => [$client]}); + # display an error message $client->showBriefly( { 'line' => [ $client->string( 'FIRMWARE_MISSING' ), $client->string( 'FIRMWARE_MISSING_DESC' ) ] @@ -360,9 +358,8 @@ =head2 checkFirmwareUpgrade($client) -This timer is run every 10 minutes if a client is out of date and a firmware file is not -present in the Firmware directory. Another timer in Slim::Utils::Firmware may have -downloaded firmware in the background, so if the file has appeared, we will prompt +This callback is run when Slim::Utils::Firmware has +downloaded firmware in the background, so we will prompt the user to upgrade their firmware by holding BRIGHTNESS =cut Index: Slim/Utils/Firmware.pm =================================================================== --- Slim/Utils/Firmware.pm (revision 27530) +++ Slim/Utils/Firmware.pm (working copy) @@ -205,7 +205,7 @@ undef, time(), sub { - downloadAsync( $version_file, \&init_version_done, $version_file, $model ); + downloadAsync( $version_file, {cb => \&init_version_done, pt => [$version_file, $model]} ); }, ); } @@ -235,7 +235,7 @@ if ( !-e $fw_file ) { main::INFOLOG && $log->info("Downloading $model firmware to: $fw_file"); - downloadAsync( $fw_file, \&init_fw_done, $fw_file, $model ); + downloadAsync( $fw_file, {cb => \&init_fw_done, pt => [$fw_file, $model]} ); } else { main::INFOLOG && $log->info("$model firmware is up to date: $fw_file"); @@ -465,9 +465,26 @@ =cut +# Keep track of what files are being downloaded and their callbacks +my %filesDownloading; + sub downloadAsync { - my $file = shift; - my ( $cb, @pt ) = @_; + my ($file, $args) = @_; + $args ||= {}; + + # Are we already downloading? + my $callbacks; + if (!$args->{'retry'} && ($callbacks = $filesDownloading{$file})) { + # If we we have more than one caller expecting a callback then stash them here + if ($args->{'cb'}) { + # XXX maybe check that we do not already have this tuple + push @$callbacks, $args; + } + return; + } + + # Use an empty array ref as the default true value + $filesDownloading{$file} ||= []; # URL to download my $url = BASE() . '/' . $::VERSION . '/' . basename($file); @@ -477,10 +494,9 @@ \&downloadAsyncDone, \&downloadAsyncError, { + %$args, saveAs => "$file.tmp", file => $file, - cb => $cb, - pt => \@pt, }, ); @@ -497,9 +513,8 @@ sub downloadAsyncDone { my $http = shift; - my $file = $http->params('file'); - my $cb = $http->params('cb'); - my $pt = $http->params('pt'); + my $args = $http->params(); + my $file = $args->{'file'}; my $url = $http->url; # make sure we got the file @@ -511,11 +526,7 @@ $http = Slim::Networking::SimpleAsyncHTTP->new( \&downloadAsyncSHADone, \&downloadAsyncError, - { - file => $file, - cb => $cb, - pt => $pt, - }, + $args, ); $http->get( $url . '.sha' ); @@ -529,9 +540,8 @@ sub downloadAsyncSHADone { my $http = shift; - my $file = $http->params('file'); - my $cb = $http->params('cb'); - my $pt = $http->params('pt') || []; + my $args = $http->params(); + my $file = $args->{'file'}; # get checksum my ($sum) = $http->content =~ m/([a-f0-9]{40})/; @@ -554,9 +564,20 @@ # reset back off time $CHECK_TIME = INITIAL_RETRY_TIME; + my $cb = $args->{'cb'}; if ( $cb && ref $cb eq 'CODE' ) { - $cb->( @{$pt} ); + $cb->( @{$args->{'pt'} || []} ); + } + + # Pick up extra callbacks waiting for this file + foreach $args (@$filesDownloading{$file}) { + my $cb = $args->{'cb'}; + if ( $cb && ref $cb eq 'CODE' ) { + $cb->( @{$args->{'pt'} || []} ); + } } + + delete $filesDownloading{$file}; } else { downloadAsyncError( $http, "Validation of firmware $file failed, SHA1 checksum did not match" ); @@ -600,6 +621,7 @@ file => $file, cb => $cb, pt => $pt, + retry=> 1, }, );