I have
a download button when clicking on it, it takes about 15 seconds to download a file because it has to SFTP into the server, find the right path/files, and return response download.
HTML
<a class="btn btn-primary btn-sm text-primary btn-download-1" onclick="startDownload('1')"><i class="fa fa-download "></i></a>
Note : where 1 is the key for me to know which file it is …
Right now
the button just will trigger this function below
function startDownload(interfaceId) {
window.location = "/nodes/interface/capture/download?port=" + interfaceId;
console.log(interfaceId);
}
It basically refreshes the page and call that download route
/nodes/interface/capture/download
public function download_files()
{
$dir = '';
$portNumber = Request::get('port');
$zipMe = false;
$remotePath = "/home/john/logs/".$dir."/";
if (!isset($dir) || $dir == null) {
return redirect()->back()->withInput()->withFlashDanger('SFTP Could not connect.');
}
$acsIp = explode('://', env('ACS_URL'));
$acsIp = explode(':',$acsIp[1])[0];
$sftp = new SFTP($acsIp.':22');
if (!$sftp->login('john', '***')) {
return redirect()->back()->withInput()->withFlashDanger('SFTP Could not connect.');
}
// Get into the Specified Directory
$sftpConn = Storage::disk('sftp');
$SFTPFiles = $sftpConn->allFiles('/'.$dir);
if ( count($SFTPFiles) > 0 ) {
foreach ($SFTPFiles as $file) {
$fileName = $file;
break;
}
} else {
Log::info('Files Not found in the Remote!');
return redirect()->back()->withInput()->withFlashDanger('Files Not found in the Remote!');
}
// Create and give 777 permission to remote-files directory
if (!is_dir(public_path('remote-files/'.$dir))) {
mkdir(public_path('remote-files/'.$dir), 0777, true);
}
$filesToZip = [];
foreach ( $SFTPFiles as $fileName ) {
if ( $fileName == '..' || $fileName == '.' ) {
continue;
} else if ( $fileName == '' ) {
Log::info('File not found');
continue;
}
$fileName = explode("/", $fileName);
$onlyFileName = (!empty($fileName) && isset($fileName[1])) ? $fileName[1] : "";
$filepath = $remotePath.$onlyFileName;
if (strpos($onlyFileName , $portNumber) !== false) {
// Download the remote file at specified location in Local
if (!$sftp->get($filepath, 'remote-files/'.$dir.'/'.$onlyFileName))
{
die("Error downloading file ".$filepath);
}
$file = public_path('remote-files/'.$dir.'/').$onlyFileName;
$headers = array(
'Content-Description: File Transfer',
'Content-Type: application/octet-stream',
'Content-Disposition: attachment; filename="'.basename($file).'"',
'Cache-Control: must-revalidate',
'Pragma: public',
'Content-Length: ' . filesize($file)
);
return Response::download($file, $onlyFileName, $headers);
}
// IF File is exists in Directory
if ( file_exists( public_path('remote-files/'.$dir.'/').$onlyFileName ) ) {
$filesToZip[] = public_path('remote-files/'.$dir.'/').$onlyFileName;
Log::info('File Generated '.'remote-files/'.$dir.'/'.$onlyFileName);
// Remove Files from public/remote-files
$this->removeDirAndFiles('', public_path('remote-files/'.$dir));
exit;
} else {
Log::info('File not Generated '.'remote-files/'.$dir.'/'.$onlyFileName);
}
}
}
Result
It is working, but somehow, it stays there for 15 seconds without any sort of feedback. It’s really bad, users have no idea what is going on.
I want to show a modal say "Downloading is in progress, please don’t close the window", but I don’t know how to do that since it is mandatory for my to use a GET to download a file.I’m kind of stuck now.
2
Answers
Since the delay is at the server side, I believe you can do two ways:
Have a route to create queue jobs and determine what is the progress, and another route for user to download a downloaded files in server. The user will ping to the first route every second to determine status.
The idea is to generate a unique ID each time a session is created, store it in an Array that is shared by both
download_files()
route and another to initiatedownload_files()
and store its result.Example:
If you dont want to change anything, you can use websocket that will update download state after few operations, and send files to the client. But this would be restricted by the filesize as websocket are handled in javascript, which means download must be stored javascript object in browser memory first.
Show an overlay div that has a message of your choosing, before doing the redirect. This requires nothing to be done on the server side.
CSS
HTML