Opkman: Fix memory leaks in the update feature.

git-svn-id: trunk@56950 -
This commit is contained in:
balazs 2018-01-04 10:17:33 +00:00
parent 20bc34c5fe
commit de416689cc
2 changed files with 134 additions and 144 deletions

View File

@ -185,7 +185,6 @@ begin
SerializablePackages.OnProcessJSON := @DoOnProcessJSON; SerializablePackages.OnProcessJSON := @DoOnProcessJSON;
PackageDownloader.OnJSONProgress := @DoOnJSONProgress; PackageDownloader.OnJSONProgress := @DoOnJSONProgress;
PackageDownloader.OnJSONDownloadCompleted := @DoOnJSONDownloadCompleted; PackageDownloader.OnJSONDownloadCompleted := @DoOnJSONDownloadCompleted;
StartUpdates;
FHintTimeOut := Application.HintHidePause; FHintTimeOut := Application.HintHidePause;
Application.HintHidePause := 1000000; Application.HintHidePause := 1000000;
{$IF LCL_FULLVERSION >= 1070000} {$IF LCL_FULLVERSION >= 1070000}
@ -201,7 +200,6 @@ begin
Updates := TUpdates.Create(FileName); Updates := TUpdates.Create(FileName);
Updates.OnUpdate := @DoOnUpdate; Updates.OnUpdate := @DoOnUpdate;
Updates.StartUpdate; Updates.StartUpdate;
Updates.PauseUpdate;
end; end;
procedure TMainFrm.StopUpdates; procedure TMainFrm.StopUpdates;
@ -237,7 +235,10 @@ begin
SetupControls; SetupControls;
SetupColors; SetupColors;
GetPackageList; GetPackageList;
end; end
else
if not Application.Terminated then
StartUpdates;
end; end;
procedure TMainFrm.GetPackageList(const ARepositoryHasChanged: Boolean = False); procedure TMainFrm.GetPackageList(const ARepositoryHasChanged: Boolean = False);
@ -250,9 +251,8 @@ begin
begin begin
SetupMessage(rsMainFrm_rsMessageChangingRepository); SetupMessage(rsMainFrm_rsMessageChangingRepository);
Sleep(1500); Sleep(1500);
end end;
else StopUpdates;
Updates.PauseUpdate;
SetupMessage(rsMainFrm_rsMessageDownload); SetupMessage(rsMainFrm_rsMessageDownload);
PackageDownloader.DownloadJSON(Options.ConTimeOut*1000); PackageDownloader.DownloadJSON(Options.ConTimeOut*1000);
end; end;
@ -397,10 +397,9 @@ begin
EnableDisableControls(True); EnableDisableControls(True);
SetupMessage; SetupMessage;
mJSON.Text := AJSON; mJSON.Text := AJSON;
StartUpdates;
cbAll.Checked := False; cbAll.Checked := False;
Caption := rsLazarusPackageManager + ' ' + SerializablePackages.QuickStatistics; Caption := rsLazarusPackageManager + ' ' + SerializablePackages.QuickStatistics;
if Assigned(Updates) then
Updates.StartUpdate;
end; end;
etConfig: etConfig:
begin begin
@ -675,7 +674,7 @@ begin
if CanGo then if CanGo then
begin begin
Updates.PauseUpdate; StopUpdates;
Options.LastDownloadDir := DstDir; Options.LastDownloadDir := DstDir;
Options.Changed := True; Options.Changed := True;
PackageAction := paDownloadTo; PackageAction := paDownloadTo;
@ -697,7 +696,7 @@ begin
end; end;
end; end;
SerializablePackages.RemoveErrorState; SerializablePackages.RemoveErrorState;
Updates.StartUpdate; StartUpdates;
end; end;
procedure TMainFrm.Rebuild; procedure TMainFrm.Rebuild;
@ -739,7 +738,7 @@ begin
if MessageDlgEx(rsMainFrm_PackageUpdateWarning, mtConfirmation, [mbYes, mbNo], Self) <> mrYes then if MessageDlgEx(rsMainFrm_PackageUpdateWarning, mtConfirmation, [mbYes, mbNo], Self) <> mrYes then
Exit; Exit;
Updates.PauseUpdate; StopUpdates;
PackageAction := paUpdate; PackageAction := paUpdate;
VisualTree.UpdatePackageStates; VisualTree.UpdatePackageStates;
if SerializablePackages.DownloadCount > 0 then if SerializablePackages.DownloadCount > 0 then
@ -782,7 +781,7 @@ begin
if not NeedToRebuild then if not NeedToRebuild then
begin begin
SerializablePackages.RemoveErrorState; SerializablePackages.RemoveErrorState;
Updates.StartUpdate; StartUpdates;
end; end;
end; end;
@ -845,7 +844,7 @@ begin
end; end;
NeedToRebuild := False; NeedToRebuild := False;
Updates.StopUpdate; StopUpdates;
for I := 0 to SerializablePackages.Count - 1 do for I := 0 to SerializablePackages.Count - 1 do
begin begin
for J := 0 to SerializablePackages.Items[I].LazarusPackages.Count - 1 do for J := 0 to SerializablePackages.Items[I].LazarusPackages.Count - 1 do
@ -870,7 +869,7 @@ begin
begin begin
NeedToRebuild := False; NeedToRebuild := False;
MessageDlgEx(Format(rsMainFrm_rsUninstall_Error, [LazarusPackage.Name]), mtError, [mbOk], Self); MessageDlgEx(Format(rsMainFrm_rsUninstall_Error, [LazarusPackage.Name]), mtError, [mbOk], Self);
Updates.StartUpdate; StartUpdates;
Exit; Exit;
end end
else else
@ -911,7 +910,7 @@ begin
if CanGo then if CanGo then
begin begin
Updates.PauseUpdate; StopUpdates;
PackageAction := paInstall; PackageAction := paInstall;
VisualTree.UpdatePackageStates; VisualTree.UpdatePackageStates;
if SerializablePackages.DownloadCount > 0 then if SerializablePackages.DownloadCount > 0 then
@ -953,7 +952,7 @@ begin
if not NeedToRebuild then if not NeedToRebuild then
begin begin
SerializablePackages.RemoveErrorState; SerializablePackages.RemoveErrorState;
Updates.StartUpdate; StartUpdates;
end; end;
end; end;

View File

@ -34,8 +34,7 @@ uses
// LazUtils // LazUtils
Laz2_XMLCfg, Laz2_XMLCfg,
// OpkMan // OpkMan
opkman_timer, opkman_serializablepackages, opkman_serializablepackages, opkman_options, opkman_common, opkman_const,
opkman_options, opkman_common, opkman_const,
{$IFDEF FPC311}fphttpclient{$ELSE}opkman_httpclient{$ENDIF}, {$IFDEF FPC311}fphttpclient{$ELSE}opkman_httpclient{$ENDIF},
{$IFDEF FPC311}zipper{$ELSE}opkman_zip{$ENDIF}; {$IFDEF FPC311}zipper{$ELSE}opkman_zip{$ENDIF};
@ -98,26 +97,25 @@ type
{ TUpdates } { TUpdates }
TUpdates = class(TThread) TUpdates = class(TThread)
private private
FXML: TXMLConfig;
FHTTPClient: TFPHTTPClient; FHTTPClient: TFPHTTPClient;
FTimer: TThreadTimer;
FUpdatePackage: TUpdatePackage; FUpdatePackage: TUpdatePackage;
FStarted: Boolean;
FVersion: Integer; FVersion: Integer;
FNeedToBreak: Boolean; FNeedToBreak: Boolean;
FNeedToUpdate: Boolean;
FBusyUpdating: Boolean; FBusyUpdating: Boolean;
FBusySaving: Boolean;
FOpenSSLAvailable: Boolean; FOpenSSLAvailable: Boolean;
FOnUpdate: TNotifyEvent; FOnUpdate: TNotifyEvent;
FPaused: Boolean; FTime: QWORD;
FInterval: Cardinal;
FFileName: String;
function GetUpdateInfo(const AURL: String; var AJSON: TJSONStringType): Boolean; function GetUpdateInfo(const AURL: String; var AJSON: TJSONStringType): Boolean;
procedure DoOnTimer(Sender: TObject);
procedure DoOnUpdate; procedure DoOnUpdate;
procedure Load; procedure Load;
procedure Save; procedure Save;
procedure AssignPackageData(AMetaPackage: TMetaPackage); procedure AssignPackageData(AMetaPackage: TMetaPackage);
procedure ResetPackageData(AMetaPackage: TMetaPackage); procedure ResetPackageData(AMetaPackage: TMetaPackage);
procedure CheckForOpenSSL; procedure CheckForOpenSSL;
procedure CheckForUpdates;
function IsTimeToUpdate: Boolean; function IsTimeToUpdate: Boolean;
protected protected
procedure Execute; override; procedure Execute; override;
@ -126,7 +124,6 @@ type
destructor Destroy; override; destructor Destroy; override;
procedure StartUpdate; procedure StartUpdate;
procedure StopUpdate; procedure StopUpdate;
procedure PauseUpdate;
published published
property OnUpdate: TNotifyEvent read FOnUpdate write FOnUpdate; property OnUpdate: TNotifyEvent read FOnUpdate write FOnUpdate;
end; end;
@ -236,8 +233,11 @@ constructor TUpdates.Create(const AFileName: String);
begin begin
inherited Create(True); inherited Create(True);
FreeOnTerminate := True; FreeOnTerminate := True;
FXML := TXMLConfig.Create(AFileName); FFileName := AFileName;
FHTTPClient := TFPHTTPClient.Create(nil); FHTTPClient := TFPHTTPClient.Create(nil);
{$IFDEF FPC311}
FHTTPClient.IOTimeout := Options.ConTimeOut;
{$ENDIF}
if Options.ProxyEnabled then if Options.ProxyEnabled then
begin begin
FHTTPClient.Proxy.Host:= Options.ProxyServer; FHTTPClient.Proxy.Host:= Options.ProxyServer;
@ -246,19 +246,10 @@ begin
FHTTPClient.Proxy.Password:= Options.ProxyPassword; FHTTPClient.Proxy.Password:= Options.ProxyPassword;
end; end;
FUpdatePackage := TUpdatePackage.Create; FUpdatePackage := TUpdatePackage.Create;
FTimer := nil;
end; end;
destructor TUpdates.Destroy; destructor TUpdates.Destroy;
begin begin
FXML.Clear;
FXML.Free;
if Assigned(FTimer) then
begin
if FTimer.Enabled then
FTimer.StopTimer;
FTimer.Terminate;
end;
FHTTPClient.Free; FHTTPClient.Free;
FUpdatePackage.Free; FUpdatePackage.Free;
inherited Destroy; inherited Destroy;
@ -275,44 +266,50 @@ var
MetaPkg: TMetaPackage; MetaPkg: TMetaPackage;
LazarusPkg: TLazarusPackage; LazarusPkg: TLazarusPackage;
HasUpdate: Boolean; HasUpdate: Boolean;
FXML: TXMLConfig;
begin begin
if (not Assigned(SerializablePackages)) or (SerializablePackages.Count = 0) then if (not Assigned(SerializablePackages)) or (SerializablePackages.Count = 0) then
Exit; Exit;
FXML := TXMLConfig.Create(FFileName);
FVersion := FXML.GetValue('Version/Value', 0); try
PackageCount := FXML.GetValue('Count/Value', 0); FVersion := FXML.GetValue('Version/Value', 0);
for I := 0 to PackageCount - 1 do PackageCount := FXML.GetValue('Count/Value', 0);
begin for I := 0 to PackageCount - 1 do
Path := 'Package' + IntToStr(I) + '/';
PackageName := FXML.GetValue(Path + 'Name', '');
MetaPkg := SerializablePackages.FindMetaPackage(PackageName, fpbPackageName);
if MetaPkg <> nil then
begin begin
HasUpdate := False; Path := 'Package' + IntToStr(I) + '/';
MetaPkg.DownloadZipURL := FXML.GetValue(Path + 'DownloadZipURL', ''); PackageName := FXML.GetValue(Path + 'Name', '');
MetaPkg.DisableInOPM := FXML.GetValue(Path + 'DisableInOPM', False); MetaPkg := SerializablePackages.FindMetaPackage(PackageName, fpbPackageName);
MetaPkg.Rating := FXML.GetValue(Path + 'Rating', 0); if MetaPkg <> nil then
LazarusPkgCount := FXML.GetValue(Path + 'Count', 0);
for J := 0 to LazarusPkgCount - 1 do
begin begin
SubPath := Path + 'PackageFile' + IntToStr(J) + '/'; HasUpdate := False;
LazarusPkgName := FXML.GetValue(SubPath + 'Name', ''); MetaPkg.DownloadZipURL := FXML.GetValue(Path + 'DownloadZipURL', '');
LazarusPkg := MetaPkg.FindLazarusPackage(LazarusPkgName); MetaPkg.DisableInOPM := FXML.GetValue(Path + 'DisableInOPM', False);
if LazarusPkg <> nil then MetaPkg.Rating := FXML.GetValue(Path + 'Rating', 0);
LazarusPkgCount := FXML.GetValue(Path + 'Count', 0);
for J := 0 to LazarusPkgCount - 1 do
begin begin
LazarusPkg.UpdateVersion := FXML.GetValue(SubPath + 'UpdateVersion', ''); SubPath := Path + 'PackageFile' + IntToStr(J) + '/';
LazarusPkg.ForceNotify := FXML.GetValue(SubPath + 'ForceNotify', False); LazarusPkgName := FXML.GetValue(SubPath + 'Name', '');
LazarusPkg.InternalVersion := FXML.GetValue(SubPath + 'InternalVersion', 0);; LazarusPkg := MetaPkg.FindLazarusPackage(LazarusPkgName);
LazarusPkg.InternalVersionOld := FXML.GetValue(SubPath + 'InternalVersionOld', 0); if LazarusPkg <> nil then
LazarusPkg.RefreshHasUpdate; begin
if not HasUpdate then LazarusPkg.UpdateVersion := FXML.GetValue(SubPath + 'UpdateVersion', '');
HasUpdate := (LazarusPkg.HasUpdate) and (LazarusPkg.InstalledFileVersion < LazarusPkg.UpdateVersion); LazarusPkg.ForceNotify := FXML.GetValue(SubPath + 'ForceNotify', False);
LazarusPkg.InternalVersion := FXML.GetValue(SubPath + 'InternalVersion', 0);;
LazarusPkg.InternalVersionOld := FXML.GetValue(SubPath + 'InternalVersionOld', 0);
LazarusPkg.RefreshHasUpdate;
if not HasUpdate then
HasUpdate := (LazarusPkg.HasUpdate) and (LazarusPkg.InstalledFileVersion < LazarusPkg.UpdateVersion);
end;
end; end;
MetaPkg.HasUpdate := HasUpdate;
end; end;
MetaPkg.HasUpdate := HasUpdate;
end; end;
finally
FXML.Free;
end; end;
Synchronize(@DoOnUpdate); if Assigned(FOnUpdate) and (not FNeedToBreak) then
Synchronize(@DoOnUpdate);
end; end;
procedure TUpdates.Save; procedure TUpdates.Save;
@ -321,33 +318,40 @@ var
Path, SubPath: String; Path, SubPath: String;
MetaPkg: TMetaPackage; MetaPkg: TMetaPackage;
LazarusPkg: TLazarusPackage; LazarusPkg: TLazarusPackage;
FXML: TXMLConfig;
begin begin
if (not Assigned(SerializablePackages)) or (SerializablePackages.Count = 0) then if (not Assigned(SerializablePackages)) or (SerializablePackages.Count = 0) or (FBusySaving) then
Exit; Exit;
FXML.Clear; FBusySaving := True;
FXML.SetDeleteValue('Version/Value', OpkVersion, 0); FXML := TXMLConfig.CreateClean(FFileName);
FXML.SetDeleteValue('Count/Value', SerializablePackages.Count, 0); try
for I := 0 to SerializablePackages.Count - 1 do FXML.SetDeleteValue('Version/Value', OpkVersion, 0);
begin FXML.SetDeleteValue('Count/Value', SerializablePackages.Count, 0);
MetaPkg := SerializablePackages.Items[I]; for I := 0 to SerializablePackages.Count - 1 do
Path := 'Package' + IntToStr(I) + '/';
FXML.SetDeleteValue(Path + 'Name', MetaPkg.Name, '');
FXML.SetDeleteValue(Path + 'DownloadZipURL', MetaPkg.DownloadZipURL, '');
FXML.SetDeleteValue(Path + 'DisableInOPM', MetaPkg.DisableInOPM, False);
FXML.SetDeleteValue(Path + 'Rating', MetaPkg.Rating, 0);
FXML.SetDeleteValue(Path + 'Count', SerializablePackages.Items[I].LazarusPackages.Count, 0);
for J := 0 to SerializablePackages.Items[I].LazarusPackages.Count - 1 do
begin begin
SubPath := Path + 'PackageFile' + IntToStr(J) + '/'; MetaPkg := SerializablePackages.Items[I];
LazarusPkg := TLazarusPackage(SerializablePackages.Items[I].LazarusPackages.Items[J]); Path := 'Package' + IntToStr(I) + '/';
FXML.SetDeleteValue(SubPath + 'Name', LazarusPkg.Name, ''); FXML.SetDeleteValue(Path + 'Name', MetaPkg.Name, '');
FXML.SetDeleteValue(SubPath + 'UpdateVersion', LazarusPkg.UpdateVersion, ''); FXML.SetDeleteValue(Path + 'DownloadZipURL', MetaPkg.DownloadZipURL, '');
FXML.SetDeleteValue(SubPath + 'ForceNotify', LazarusPkg.ForceNotify, False); FXML.SetDeleteValue(Path + 'DisableInOPM', MetaPkg.DisableInOPM, False);
FXML.SetDeleteValue(SubPath + 'InternalVersion', LazarusPkg.InternalVersion, 0); FXML.SetDeleteValue(Path + 'Rating', MetaPkg.Rating, 0);
FXML.SetDeleteValue(SubPath + 'InternalVersionOld', LazarusPkg.InternalVersionOld, 0); FXML.SetDeleteValue(Path + 'Count', SerializablePackages.Items[I].LazarusPackages.Count, 0);
for J := 0 to SerializablePackages.Items[I].LazarusPackages.Count - 1 do
begin
SubPath := Path + 'PackageFile' + IntToStr(J) + '/';
LazarusPkg := TLazarusPackage(SerializablePackages.Items[I].LazarusPackages.Items[J]);
FXML.SetDeleteValue(SubPath + 'Name', LazarusPkg.Name, '');
FXML.SetDeleteValue(SubPath + 'UpdateVersion', LazarusPkg.UpdateVersion, '');
FXML.SetDeleteValue(SubPath + 'ForceNotify', LazarusPkg.ForceNotify, False);
FXML.SetDeleteValue(SubPath + 'InternalVersion', LazarusPkg.InternalVersion, 0);
FXML.SetDeleteValue(SubPath + 'InternalVersionOld', LazarusPkg.InternalVersionOld, 0);
end;
end; end;
FXML.Flush;
finally
FXML.Free;
FBusySaving := False;
end; end;
FXML.Flush;
end; end;
procedure TUpdates.AssignPackageData(AMetaPackage: TMetaPackage); procedure TUpdates.AssignPackageData(AMetaPackage: TMetaPackage);
@ -357,6 +361,8 @@ var
LazarusPkg: TLazarusPackage; LazarusPkg: TLazarusPackage;
UpdLazPkgs: TUpdateLazPackages; UpdLazPkgs: TUpdateLazPackages;
begin begin
if FBusySaving then
Exit;
HasUpdate := False; HasUpdate := False;
AMetaPackage.DownloadZipURL := FUpdatePackage.FUpdatePackageData.DownloadZipURL; AMetaPackage.DownloadZipURL := FUpdatePackage.FUpdatePackageData.DownloadZipURL;
AMetaPackage.DisableInOPM := FUpdatePackage.FUpdatePackageData.DisableInOPM; AMetaPackage.DisableInOPM := FUpdatePackage.FUpdatePackageData.DisableInOPM;
@ -382,6 +388,8 @@ var
I: Integer; I: Integer;
LazarusPkg: TLazarusPackage; LazarusPkg: TLazarusPackage;
begin begin
if FBusySaving then
Exit;
AMetaPackage.DownloadZipURL := ''; AMetaPackage.DownloadZipURL := '';
AMetaPackage.DisableInOPM := False; AMetaPackage.DisableInOPM := False;
AMetaPackage.HasUpdate := False; AMetaPackage.HasUpdate := False;
@ -442,6 +450,8 @@ end;
function TUpdates.IsTimeToUpdate: Boolean; function TUpdates.IsTimeToUpdate: Boolean;
begin begin
Result := Assigned(SerializablePackages) and (FOpenSSLAvailable) and
(not FBusyUpdating) and (not FNeedToBreak);
case Options.CheckForUpdates of case Options.CheckForUpdates of
0: Result := MinutesBetween(Now, Options.LastUpdate) >= 2; 0: Result := MinutesBetween(Now, Options.LastUpdate) >= 2;
1: Result := HoursBetween(Now, Options.LastUpdate) >= 1; 1: Result := HoursBetween(Now, Options.LastUpdate) >= 1;
@ -452,12 +462,6 @@ begin
end; end;
end; end;
procedure TUpdates.DoOnTimer(Sender: TObject);
begin
if (FTimer.Enabled) and (not FNeedToBreak) and (IsTimeToUpdate) then
FNeedToUpdate := True;
end;
function TUpdates.GetUpdateInfo(const AURL: String; var AJSON: TJSONStringType): Boolean; function TUpdates.GetUpdateInfo(const AURL: String; var AJSON: TJSONStringType): Boolean;
var var
URL: String; URL: String;
@ -480,7 +484,6 @@ begin
begin begin
MS.Position := 0; MS.Position := 0;
SetLength(AJSON, MS.Size); SetLength(AJSON, MS.Size);
MS.Read(Pointer(AJSON)^, Length(AJSON)); MS.Read(Pointer(AJSON)^, Length(AJSON));
Result := Length(AJSON) > 0; Result := Length(AJSON) > 0;
{since the class name has changed form "UpdatePackageFiles" to "UpdateLazPackages", {since the class name has changed form "UpdatePackageFiles" to "UpdateLazPackages",
@ -504,79 +507,67 @@ begin
FOnUpdate(Self); FOnUpdate(Self);
end; end;
procedure TUpdates.Execute; procedure TUpdates.CheckForUpdates;
var var
I: Integer; I: Integer;
JSON: TJSONStringType; JSON: TJSONStringType;
begin begin
CheckForOpenSSL; FBusyUpdating := True;
try
Options.LastUpdate := Now;
Options.Changed := True;
for I := 0 to SerializablePackages.Count - 1 do
begin
if FNeedToBreak then
Break;
JSON := '';
if GetUpdateInfo(Trim(SerializablePackages.Items[I].DownloadURL), JSON) then
begin
if FUpdatePackage.LoadFromJSON(JSON) then
AssignPackageData(SerializablePackages.Items[I])
else
ResetPackageData(SerializablePackages.Items[I]);
end
else
ResetPackageData(SerializablePackages.Items[I]);
end;
if Assigned(FOnUpdate) and (not FNeedToBreak) then
Synchronize(@DoOnUpdate);
finally
FBusyUpdating := False;
end;
end;
procedure TUpdates.Execute;
begin
while not Terminated do while not Terminated do
begin begin
if Assigned(SerializablePackages) and (FNeedToUpdate) and (not FBusyUpdating) and (not FPaused) and (FOpenSSLAvailable) then Sleep(1);
if (GetTickCount64 - FTime > FInterval) then
begin begin
Options.LastUpdate := Now; FTime := GetTickCount64;
Options.Changed := True; if IsTimeToUpdate then
FBusyUpdating := True; CheckForUpdates;
try
for I := 0 to SerializablePackages.Count - 1 do
begin
if FPaused then
Break;
if (not FNeedToBreak) then
begin
JSON := '';
if GetUpdateInfo(Trim(SerializablePackages.Items[I].DownloadURL), JSON) then
begin
if FUpdatePackage.LoadFromJSON(JSON) then
AssignPackageData(SerializablePackages.Items[I])
else
ResetPackageData(SerializablePackages.Items[I]);
end
else
ResetPackageData(SerializablePackages.Items[I]);
end
else
FHTTPClient.Terminate;
end;
if Assigned(FOnUpdate) and (not FNeedToBreak) and (not FPaused) then
Synchronize(@DoOnUpdate);
finally
FBusyUpdating := False;
FNeedToUpdate := False;
end;
end; end;
Sleep(1000); if FNeedToBreak then
Break;
end; end;
end; end;
procedure TUpdates.StartUpdate; procedure TUpdates.StartUpdate;
begin begin
Load; Load;
FPaused := False; CheckForOpenSSL;
if FStarted then FTime := GetTickCount64;
Exit; FInterval := 6000;
FOpenSSLAvailable := False;
FStarted := True;
FTimer := TThreadTimer.Create;
FTimer.Interval := 5000;
FTimer.OnTimer := @DoOnTimer;
FTimer.StartTimer;
Start; Start;
end; end;
procedure TUpdates.StopUpdate; procedure TUpdates.StopUpdate;
begin begin
FNeedToBreak := True;
Save; Save;
FTimer.StopTimer;
FStarted := False;
FHTTPClient.Terminate; FHTTPClient.Terminate;
end; FNeedToBreak := True;
procedure TUpdates.PauseUpdate;
begin
FPaused := True;
Save;
end; end;
end. end.