From 374dc8191b643e93c6dd450faf54e1ec5923b683 Mon Sep 17 00:00:00 2001 From: Matteo Salvi Date: Tue, 5 Dec 2023 00:25:54 +0100 Subject: [PATCH] fix: removed memoy leak --- library/kernel.application.pas | 136 ++++++++++++++++++------------- library/kernel.configuration.pas | 4 +- library/kernel.ticket.pas | 33 +++++--- library/lidl.itemsline.pas | 12 ++- service/grocy.service.pas | 2 +- 5 files changed, 116 insertions(+), 71 deletions(-) diff --git a/library/kernel.application.pas b/library/kernel.application.pas index cb1f505..a367058 100644 --- a/library/kernel.application.pas +++ b/library/kernel.application.pas @@ -7,7 +7,7 @@ interface uses Classes, SysUtils, mormot.core.os, CustApp, Lidl.Ticket, Kernel.Configuration, OpenFoodFacts.ProductInfo, Lidl.ItemsLine, mormot.core.json, mormot.core.base, - Grocy.Service, Grocy.Barcode, Grocy.Product, mormot.core.log, Math; + Grocy.Service, Grocy.Barcode, Grocy.Product, mormot.core.log, Math, Kernel.Ticket; type @@ -40,12 +40,15 @@ TLidlToGrocy = class(TCustomApplication) function AddGrocyProductInStock(const LidlProduct: TItemsLine; const GrocyProduct: TGrocyProduct; const LidlTicket: TLidlTicket): boolean; function AddNewGrocyProduct(LidlProduct: TItemsLine): TGrocyProduct; + procedure CheckMandatoryParams; function ConsumeGrocyProduct(LidlProduct: TItemsLine): boolean; procedure DoHelp(Sender: TObject); function InsertOFFImageInGrocy(OFFProductInfo: TOFFProductInfo): boolean; function GetGrocyProduct(LidlProduct: TItemsLine): TGrocyProduct; function GetLidlTickets: string; function GetOFFProductInfo(var LidlProduct: TItemsLine): TOFFProductInfo; + procedure LoadLidlJson; + procedure ProcessLidlTicket(const Ticket: TTicket; const LidlTicket: TLidlTicket); protected procedure DoRun; override; public @@ -82,7 +85,7 @@ TLidlToGrocy = class(TCustomApplication) implementation uses - OpenFoodFacts.Service, Grocy.ProductStock, DateUtils, Kernel.Logger, Kernel.Ticket; + OpenFoodFacts.Service, Grocy.ProductStock, DateUtils, Kernel.Logger; { TGrocyFastLidlAdder } @@ -175,6 +178,17 @@ function TLidlToGrocy.AddNewGrocyProduct(LidlProduct: TItemsLine): TGrocyProduct TLogger.InfoExit('Product inserted in Grocy. ID = %d', [GrocyProduct.Id]); end; +procedure TLidlToGrocy.CheckMandatoryParams; +begin + if ((FGrocyApiKey = '') or (FLidlToken = '') or (FGrocyApiKey = '')) then + begin + ConsoleWrite(Executable.Command.FullDescription); + Terminate; + + Exit; + end; +end; + function TLidlToGrocy.ConsumeGrocyProduct(LidlProduct: TItemsLine): boolean; begin Result := False; @@ -254,22 +268,8 @@ function TLidlToGrocy.GetOFFProductInfo(var LidlProduct: TItemsLine): TOFFProduc Result := OFFProductInfo; end; -procedure TLidlToGrocy.DoRun; -var - LidlTicket: TLidlTicket; - GrocyProduct: TGrocyProduct; - LidlProduct: TItemsLine; - Value: double; - Ticket: TTicket; +procedure TLidlToGrocy.LoadLidlJson; begin - if ((FGrocyApiKey = '') or (FLidlToken = '') or (FGrocyApiKey = '')) then - begin - ConsoleWrite(Executable.Command.FullDescription); - Terminate; - - Exit; - end; - if (FLidlJsonFilePath <> '') and FileExists(FLidlJsonFilePath) then begin TLogger.Info('Loading json from file %s', [FLidlJsonFilePath]); @@ -283,6 +283,68 @@ procedure TLidlToGrocy.DoRun; TLogger.Debug('Loading JSON', []); DynArrayLoadJson(FLidlTickets, FLidlJson, TypeInfo(TLidlTicketArray)); +end; + +procedure TLidlToGrocy.ProcessLidlTicket(const Ticket: TTicket; const LidlTicket: TLidlTicket); +var + LidlProduct: TItemsLine; + GrocyProduct: TGrocyProduct; +begin + TLogger.InfoEnter('Started processing LIDL receipt (barcode %s)', [LidlTicket.BarCode]); + + for LidlProduct in LidlTicket.ItemsLine do + begin + if (Ticket.ExistsStockedProduct(LidlProduct.CodeInput)) and + (Ticket.ExistsConsumedProduct(LidlProduct.CodeInput)) then + begin + TLogger.Info('Already processed product (barcode %s)', [LidlProduct.CodeInput]); + continue; + end; + + TLogger.InfoEnter('Started processing item (barcode %s)', [LidlProduct.CodeInput]); + + GrocyProduct := nil; + try + LidlProduct.FixQuantity; + + GrocyProduct := GetGrocyProduct(LidlProduct); + + if Assigned(GrocyProduct) then + begin + if not (Ticket.ExistsStockedProduct(LidlProduct.CodeInput)) then + begin + if AddGrocyProductInStock(LidlProduct, GrocyProduct, LidlTicket) then + Ticket.StockedProducts.Add(LidlProduct.CodeInput); + end + else + TLogger.Info('Product already added in Grocy Stock with this receipt', []); + + if not (Ticket.ExistsConsumedProduct(LidlProduct.CodeInput)) then + begin + if ConsumeGrocyProduct(LidlProduct) then + Ticket.ConsumedProducts.Add(LidlProduct.CodeInput); + end + else + TLogger.Info('Product already consumed in Grocy with this receipt', []); + end; + + FConfiguration.SaveTickets; + finally + if Assigned(GrocyProduct) then + GrocyProduct.Free; + end; + TLogger.InfoExit('Completed processing', []); + end; +end; + +procedure TLidlToGrocy.DoRun; +var + LidlTicket: TLidlTicket; + Ticket: TTicket; +begin + CheckMandatoryParams; + + LoadLidlJson; if (Length(FLidlTickets) = 0) then TLogger.Error('Invalid lidl json file', []); @@ -297,43 +359,7 @@ procedure TLidlToGrocy.DoRun; FConfiguration.InsertTicket(Ticket); end; - TLogger.InfoEnter('Started processing LIDL receipt (barcode %s)', [LidlTicket.BarCode]); - for LidlProduct in LidlTicket.ItemsLine do - begin - TLogger.InfoEnter('Started processing item (barcode %s)', [LidlProduct.CodeInput]); - GrocyProduct := nil; - try - if TryStrToFloat(LidlProduct.Quantity, Value) and (frac(Value) <> 0) then - LidlProduct.Quantity := IntToStr(Ceil(Value)); - - GrocyProduct := GetGrocyProduct(LidlProduct); - - if Assigned(GrocyProduct) then - begin - if (Ticket.StockedProducts.IndexOf(LidlProduct.CodeInput) = -1) then - begin - if AddGrocyProductInStock(LidlProduct, GrocyProduct, LidlTicket) then - Ticket.StockedProducts.Add(LidlProduct.CodeInput); - end - else - TLogger.Info('Product already added in Grocy Stock with this receipt', []); - - if (Ticket.ConsumedProducts.IndexOf(LidlProduct.CodeInput) = -1) then - begin - if ConsumeGrocyProduct(LidlProduct) then - Ticket.ConsumedProducts.Add(LidlProduct.CodeInput); - end - else - TLogger.Info('Product already consumed in Grocy with this receipt', []); - end; - - FConfiguration.SaveTickets; - finally - if Assigned(GrocyProduct) then - GrocyProduct.Free; - end; - TLogger.InfoExit('Completed processing', []); - end; + ProcessLidlTicket(Ticket, LidlTicket); FConfiguration.SaveConfig; @@ -366,7 +392,7 @@ destructor TLidlToGrocy.Destroy; if Assigned(FLidlTickets) then begin - for I := 0 to Length(FLidlTickets) - 1 do + for I := Low(FLidlTickets) to High(FLidlTickets) do FLidlTickets[I].Free; SetLength(FLidlTickets, 0); end; diff --git a/library/kernel.configuration.pas b/library/kernel.configuration.pas index 9c88888..903332c 100644 --- a/library/kernel.configuration.pas +++ b/library/kernel.configuration.pas @@ -109,6 +109,8 @@ constructor TConfiguration.Create; FGrocyQuIdPurchase := 3; FGrocyQuIdConsume := 2; FGrocyQuIdPrice := 3; + + FLidlTickets := nil; end; destructor TConfiguration.Destroy; @@ -117,7 +119,7 @@ destructor TConfiguration.Destroy; begin if Assigned(FLidlTickets) then begin - for I := 0 to Length(FLidlTickets) - 1 do + for I := Low(FLidlTickets) to High(FLidlTickets) do FLidlTickets[I].Free; SetLength(FLidlTickets, 0); end; diff --git a/library/kernel.ticket.pas b/library/kernel.ticket.pas index 134c38e..175d77f 100644 --- a/library/kernel.ticket.pas +++ b/library/kernel.ticket.pas @@ -13,16 +13,18 @@ interface TTicket = class(TSynAutoCreateFields) private - FConsumedProducts: TStrings; + FConsumedProducts: TStringList; FId: string; - FStockedProducts: TStrings; + FStockedProducts: TStringList; public - constructor Create; override; destructor Destroy; override; + + function ExistsStockedProduct(Id: string): boolean; + function ExistsConsumedProduct(Id: string): boolean; published property Id: string read FId write FId; - property StockedProducts: TStrings read FStockedProducts write FStockedProducts; - property ConsumedProducts: TStrings read FConsumedProducts write FConsumedProducts; + property StockedProducts: TStringList read FStockedProducts write FStockedProducts; + property ConsumedProducts: TStringList read FConsumedProducts write FConsumedProducts; end; TTicketArray = array of TTicket; @@ -31,20 +33,25 @@ implementation { TTicket } -constructor TTicket.Create; -begin - inherited Create; - - FStockedProducts := TStringList.Create; - FConsumedProducts := TStringList.Create; -end; - destructor TTicket.Destroy; begin FStockedProducts.Free; + FStockedProducts := nil; + FConsumedProducts.Free; + FConsumedProducts := nil; inherited Destroy; end; +function TTicket.ExistsStockedProduct(Id: string): boolean; +begin + Result := Self.StockedProducts.IndexOf(Id) <> -1; +end; + +function TTicket.ExistsConsumedProduct(Id: string): boolean; +begin + Result := Self.ConsumedProducts.IndexOf(Id) <> -1; +end; + end. diff --git a/library/lidl.itemsline.pas b/library/lidl.itemsline.pas index a30b30d..a6f3a8b 100644 --- a/library/lidl.itemsline.pas +++ b/library/lidl.itemsline.pas @@ -5,7 +5,7 @@ interface uses - Classes, SysUtils, Lidl.Discounts, mormot.core.json; + Classes, SysUtils, Lidl.Discounts, mormot.core.json, Math; type @@ -32,6 +32,8 @@ TItemsLine = class(TSynAutoCreateFields) property TaxGroupName: string read FTaxGroupName write FTaxGroupName; public destructor Destroy; override; + + procedure FixQuantity; end; TItemsLineArray = array of TItemsLine; @@ -45,4 +47,12 @@ destructor TItemsLine.Destroy; inherited Destroy; end; +procedure TItemsLine.FixQuantity; +var + Value: Double; +begin + if TryStrToFloat(FQuantity, Value) and (frac(Value) <> 0) then + FQuantity := IntToStr(Ceil(Value)); +end; + end. diff --git a/service/grocy.service.pas b/service/grocy.service.pas index 8a9e5d8..c223b0a 100644 --- a/service/grocy.service.pas +++ b/service/grocy.service.pas @@ -301,7 +301,7 @@ function TGrocyService.GetProductByName(Name: string): TGrocyProduct; if Assigned(GrocyProducts) then begin - for I := 0 to Length(GrocyProducts) - 1 do + for I := Low(GrocyProducts) to High(GrocyProducts) do GrocyProducts[I].Free; SetLength(GrocyProducts, 0); end;