Sweet, thanks for the feedback! You might want to rethink the download process, because right now, you are downloading one file at the time. TTMSFNCCloudBase can execute multiple requests at the same time, so you can create once instance of TTMSFNCCloudBase during the lifetime of your application and start multiple asynchronous requests.
ARequestResult contains unique information about the request. If you want to add additionally information you can use LBase.Request.Data* properties (such as DataString, DataBoolean)
You can indeed create/destroy LBase each time a request happens, you should do that in the callback of ExecuteRequest, but best practice is to create a unique instance in your application and use that one during the lifetime of your application.
I've understood the concept.
With this in mind it will be easy to modify it for my needs.
In your example every download manipulates the same Progressbar
and the download List holds only the finished Downloads,
but I have all informations I need to complete my code. Thanks again
now I run aground with another ( more basic ) problem.
I try to develop my "Download Manager" as a visual Component
with a property Webbrowser : TMyWebBrowser;
TMyWebBrowser = class(TTMSFNCCustomWebBrowser)
public
*property OnDownloadStateChanged: TTMSFNCWebBrowserOnDownloadStateChanged read FOnDownloadStateChanged write FOnDownloadStateChanged;*
procedure DoDownloadStateChanged(ADownload: TTMSFNCWebBrowserDownload; AState: TTMSFNCWebBrowserDownloadState; var APause: Boolean; var AResume: Boolean; var ACancel: Boolean); virtual;
end;
The Idea is :
drop it on a Form with a TTMSFNCWebbroser and connect the property;
So far so good, but I can't figure out how to recocnice the
OnDownloadStateChanged Event from the Webbrowser, without changing the code of Form1.TMSFNCWebBrowser1OnDownload...
So to speak : No Modification on Form Side. Just Drop Component & Connect.
The Event procedure DoDownloadStateChanged is virtual but :
is protected ( even in TCustomTMSFNCWebbroser )
So I can't use the Adapter Property (Webbrowser) to assign a new event handler ( inside DL Manager Class )
Or just in one sentence : How can I publish a protected OnEvent property in child class
AND : why the F.. has the DoDownloadStateChanged no ( Sender : TObject ...
I just updated my TMS Components with TMS Setup and the Bug disappeared
Now all parallel downloads fires her OnBytesReceivedChanged Events until completed.
when downloads are interrupted
I start a timer and resume after 5 secs -> this results in ghost tasks
Sometime with wrong Webbrowser-> resultfilepath ( from parallel tasks )
After the downloads are finished, these ghost tasks still resists.
When I try to delete these ghost tasks ( downloads[i].delete ) -> Access violation
It could be possible that the Edge Chromium runtime update version fixed the issue, but that could be verified against the release notes. We noticed something regarding download folder being unique for each instance of WebView so that could potentially be related.
procedure TF_Main.Timer1Timer(Sender: TObject);
begin
for var i := 0 to WB.Downloads.Count-1 do
begin
if wb.Downloads[i].State = dsInterrupted then
begin
if (WB.Downloads[i].CanResume) then
begin
wb.Downloads[i].Resume; // this causes the Ghost Tasks
WriteLogEvent('Restart',TPath.GetFileNameWithoutExtension(wb.Downloads[i].ResultFilePath), WB.Downloads[i].URI);
end;
end;
end;
Timer1.Enabled := False;
end;
procedure TF_Main.TMSFNCEdgeWebBrowser1DownloadStateChanged(Sender: TObject;
ADownload: TTMSFNCWebBrowserDownload; AState:
TTMSFNCWebBrowserDownloadState; var APause, AResume, ACancel: Boolean);
var
st: string;
ID : string;
idx : Integer;
Index : string;
Studio : string;
FileName : string;
FilePath : string;
Directory : string;
ATask : ITask;
function MoveFile(FileName : string):TProc;
var
FilePath : string;
begin
if not FileExists(FileName) then
begin
FilePath := TPath.GetDirectoryName(FileName);
ForceDirectories(FilePath);
TFile.Move(ADownload.ResultFilePath, FileName);
end;
end;
begin
idx := ADownload.Index + 1;
ID := TPath.GetFileNameWithoutExtension(ADownload.ResultFilePath);
case AState of
dsInProgress: st := 'Progress';
dsInterrupted: begin
APause := True; // set Pause to Resume after Timer1 fired
st := 'Interrupted';
// if not User cancel !! => without this you can force ghost task by caceling downloads
if ADownload.InterruptReason in [dirUserCanceled, dirDownloadProcessCrashed] then
begin
ACancel := True; // User Cancel must be set explicite !!
exit;
end
else
begin
Timer1.Enabled := True; // try to resume after 5 Sec.
end;
end;
dsCompleted: begin
st := 'Completed';
FileName := ADownload.ResultFilePath;
FileName := TPath.GetFileName(FileName);
FileName := StringReplace(FileName,'.','\',[]); // convert first Name.Part into Dir
FilePath := TPath.GetDirectoryName(Site.Media.Clips + FileName);
FileName := TPath.GetFileNameWithoutExtension(FileName);
FileName := FilePath + '\' + FileName + '.mp4';
ATask := TTask.Create(MoveFile(FileName)).Start; // move 25GB File to NAS async
Another short remark,
the OnDownloadBytesReceivedChanged
is fired with 0 Bytes in ADownload.BytesReceived or
with the same Value as transmitted in the last OnDownload.. Event
I Use the difference between the Received Bytes to calculate the DL Speed
// My Workaround for the moment
if ADownload.BytesReceived = 0 then exit;
if BytesReceivedLast = ADownload.BytesReceived then exit;
with the naming (BytesReceivedChanged) in mind I suppose this is unwanted ...
We've investigated the code and could not reproduce the ghost tasks you are referring to, if I download a single file, there is one download it stays one download even though I pause and resume. If the user cancels, then the download is interrupted and cannot be resumed again, this is normal, as the download needs to restart. The only case when a download stays the same download is if the users pauses and resumes.