Browse Source

TAppConfigJson detect file changes and autoreload

Unknown 6 years ago
parent
commit
7ea581fa4d
1 changed files with 101 additions and 17 deletions
  1. 101 17
      Quick.Config.Json.pas

+ 101 - 17
Quick.Config.Json.pas

@@ -7,7 +7,7 @@
   Author      : Kike Pérez
   Version     : 1.5
   Created     : 21/10/2017
-  Modified    : 17/01/2019
+  Modified    : 25/01/2019
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
@@ -49,25 +49,50 @@ uses
   Rest.Json.Types,
   System.JSON,
   {$ENDIF}
+  Quick.FileMonitor,
   Quick.Config.Base;
 
 type
 
+  TFileModifiedEvent = procedure of object;
+  TLoadConfigEvent = procedure of object;
+
   TAppConfigJsonProvider = class(TAppConfigProvider)
   private
     fFilename : string;
+    fFileMonitor : TFileMonitor;
+    fOnFileModified : TFileModifiedEvent;
+    fLoaded : Boolean;
+    fReloadIfFileChanged : Boolean;
+    fOnConfigLoaded : TLoadConfigEvent;
+    fOnConfigReloaded : TLoadConfigEvent;
+    fNotifyReload : TLoadConfigEvent;
+    procedure CreateFileMonitor;
+    procedure FileModifiedNotify(MonitorNotify : TMonitorNotify);
+    procedure SetFileName(const Value: string);
+    procedure SetReloadIfFileChanged(const Value: Boolean);
+    procedure SetReloadNotify(aNotifyReload : TLoadConfigEvent);
+    procedure DoNofifyReload;
+  protected
     procedure Load(cConfig : TAppConfig); override;
     procedure Save(cConfig : TAppConfig); override;
   public
-    constructor Create(const aFilename : string = ''); virtual;
-    property Filename : string read fFilename write fFilename;
+    constructor Create(const aFilename : string; aReloadIfFileChanged : Boolean = False); virtual;
+    destructor Destroy; override;
+    property Filename : string read fFilename write SetFileName;
+    property ReloadIfFileChanged : Boolean read fReloadIfFileChanged write SetReloadIfFileChanged;
+    property IsLoaded : Boolean read fLoaded;
+    property OnFileModified : TFileModifiedEvent read fOnFileModified write fOnFileModified;
+    property OnConfigLoaded : TLoadConfigEvent read fOnConfigLoaded write fOnConfigLoaded;
+    property OnConfigReloaded : TLoadConfigEvent read fOnConfigReloaded write fOnConfigReloaded;
   end;
 
   TAppConfigJson = class(TAppConfig)
   private
     function GetProvider : TAppConfigJsonProvider;
+    procedure ReloadNotify;
   public
-    constructor Create(const aFileName : string = ''); overload; virtual;
+    constructor Create(const aFilename : string; aReloadIfFileChanged : Boolean = False); virtual;
     destructor Destroy; override;
     property Provider : TAppConfigJsonProvider read GetProvider;
   end;
@@ -94,11 +119,45 @@ type
 
 implementation
 
-constructor TAppConfigJsonProvider.Create(const aFilename : string = '');
+constructor TAppConfigJsonProvider.Create(const aFilename : string; aReloadIfFileChanged : Boolean = False);
 begin
   inherited Create;
   if aFilename = '' then fFilename := TPath.ChangeExtension(ParamStr(0),'json')
     else fFilename := aFilename;
+  fLoaded := False;
+  fReloadIfFileChanged := aReloadIfFileChanged;
+  if aReloadIfFileChanged then CreateFileMonitor;
+end;
+
+procedure TAppConfigJsonProvider.CreateFileMonitor;
+begin
+  fFileMonitor := TQuickFileMonitor.Create;
+  fFileMonitor.FileName := fFilename;
+  fFileMonitor.Interval := 2000;
+  fFileMonitor.Notifies := [TMonitorNotify.mnFileModified];
+  fFileMonitor.OnFileChange := FileModifiedNotify;
+  fFileMonitor.Enabled := True;
+end;
+
+destructor TAppConfigJsonProvider.Destroy;
+begin
+  if Assigned(fFileMonitor) then fFileMonitor.Free;
+  inherited;
+end;
+
+procedure TAppConfigJsonProvider.DoNofifyReload;
+begin
+  if Assigned(fNotifyReload) then fNotifyReload
+    else raise EAppConfig.Create('Not config assigned to reload!');
+end;
+
+procedure TAppConfigJsonProvider.FileModifiedNotify(MonitorNotify : TMonitorNotify);
+begin
+  if MonitorNotify = TMonitorNotify.mnFileModified then
+  begin
+    if Assigned(fOnFileModified) then fOnFileModified;
+    if fReloadIfFileChanged then DoNofifyReload;
+  end;
 end;
 
 procedure TAppConfigJsonProvider.Load(cConfig : TAppConfig);
@@ -106,9 +165,6 @@ var
   json : TStrings;
   Serializer : TJsonSerializer;
 begin
-  //create object with rtti if nil
-  //if not Assigned(Config) then Config := InitObject;
-
   if (not FileExists(fFilename)) and (CreateIfNotExists) then
   begin
     TAppConfig(cConfig).DefaultValues;
@@ -130,8 +186,14 @@ begin
     finally
       json.Free;
     end;
+    if not fLoaded then
+    begin
+      fLoaded := True;
+      if Assigned(fOnConfigLoaded) then fOnConfigLoaded;
+    end
+    else if Assigned(fOnConfigReloaded) then fOnConfigReloaded;
   except
-    on e : Exception do raise e;
+    on e : Exception do raise EAppConfig.Create(e.Message);
   end;
 end;
 
@@ -139,11 +201,8 @@ procedure TAppConfigJsonProvider.Save(cConfig : TAppConfig);
 var
   json : TStrings;
   Serializer : TJsonSerializer;
-  ctx : TRttiContext;
-  rprop : TRttiProperty;
 begin
-  //create object with rtti if nil
-  if not Assigned(cConfig) then cConfig := TAppConfigJson.Create;
+  if not Assigned(cConfig) then cConfig := TAppConfigJson.Create(fFilename,fReloadIfFileChanged);
 
   try
     json := TStringList.Create;
@@ -157,21 +216,40 @@ begin
         serializer.Free;
       end;
       json.SaveToFile(fFilename);
-      cConfig.LastSaved := Now;
     finally
       json.Free;
     end;
   except
-    on e : Exception do raise e;
+    on e : Exception do raise EAppConfig.Create(e.Message);
   end;
 end;
 
 
+procedure TAppConfigJsonProvider.SetFileName(const Value: string);
+begin
+  fFilename := Value;
+  if Assigned(fFileMonitor) then fFileMonitor.Free;
+  if fReloadIfFileChanged then CreateFileMonitor;
+end;
+
+procedure TAppConfigJsonProvider.SetReloadIfFileChanged(const Value: Boolean);
+begin
+  fReloadIfFileChanged := Value;
+  if Assigned(fFileMonitor) then fFileMonitor.Free;
+  if fReloadIfFileChanged then CreateFileMonitor;
+end;
+
+procedure TAppConfigJsonProvider.SetReloadNotify(aNotifyReload: TLoadConfigEvent);
+begin
+  fNotifyReload := aNotifyReload;
+end;
+
 { TAppConfigJson }
 
-constructor TAppConfigJson.Create(const aFileName : string = '');
+constructor TAppConfigJson.Create(const aFilename : string; aReloadIfFileChanged : Boolean = False);
 begin
-  inherited Create(TAppConfigJsonProvider.Create(aFileName));
+  inherited Create(TAppConfigJsonProvider.Create(aFileName,aReloadIfFileChanged));
+  TAppConfigJsonProvider(fProvider).SetReloadNotify(ReloadNotify);
 end;
 
 destructor TAppConfigJson.Destroy;
@@ -181,7 +259,13 @@ end;
 
 function TAppConfigJson.GetProvider: TAppConfigJsonProvider;
 begin
+  if not Assigned(fProvider) then raise EAppConfig.Create('No provider assigned!');
   Result := TAppConfigJsonProvider(fProvider);
 end;
 
+procedure TAppConfigJson.ReloadNotify;
+begin
+  Self.Load;
+end;
+
 end.