Skip to content

Commit

Permalink
DBSession is more robust and allows for session cookies
Browse files Browse the repository at this point in the history
  • Loading branch information
danieleteti committed Jan 15, 2025
1 parent 4bdc4a4 commit a5e5f30
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 211 deletions.
90 changes: 54 additions & 36 deletions sources/MVCFramework.Session.Database.pas
Original file line number Diff line number Diff line change
Expand Up @@ -40,25 +40,31 @@ interface
JsonDataObjects;

type
[MVCTable('sessions')]
[MVCTable('dmvc_sessions')]
TMVCSessionActiveRecord = class(TMVCActiveRecord)
private
strict private
[MVCTableField('session_id', [foPrimaryKey])]
fSessionID: NullableString;
[MVCTableField('session_data', [])]
fData: string;
[MVCTableField('session_expiration', [])]
fSessionExpiration: TDateTime;
fSessionExpiration: NullableTDateTime;
//transient
fTimeout: Cardinal;
procedure SetTimeout(const Value: Cardinal);
private
fJSONData: TJsonObject;
protected
procedure OnBeforeInsertOrUpdate; override;
procedure OnAfterLoad; override;
public
constructor Create; override;
destructor Destroy; override;
procedure RefreshSessionExpiration;
property Data: string read FData write FData;
property SessionExpiration: NullableTDateTime read fSessionExpiration;
property Timeout: Cardinal read fTimeout write SetTimeout;
property SessionID: NullableString read fSessionID write fSessionID;
end;

TMVCWebSessionDatabase = class(TMVCWebSession)
Expand All @@ -68,23 +74,23 @@ TMVCWebSessionDatabase = class(TMVCWebSession)
class var gLock: TObject;
function GetItems(const AKey: string): string; override;
procedure SetItems(const AKey, AValue: string); override;
procedure LoadFromDB;
procedure UpdateToDB;
procedure InsertIntoDB;
procedure InternalApplyChanges; override;
function GetExpirationTimeStamp: NullableTDateTime; override;
public
constructor Create; overload; override;
constructor Create(const aSessionID: String; const aTimeout: UInt64); reintroduce; overload;
constructor CreateFromSessionData(const aSessionData: TMVCSessionActiveRecord); overload;
constructor CreateFromSessionData(const aSessionData: TMVCSessionActiveRecord; const aTimeout: UInt64); overload;
destructor Destroy; override;
procedure MarkAsUsed; override;
function Keys: TArray<String>; override;
function Clone: TMVCWebSession; override;
function ToString: string; override;
property SessionData: TMVCSessionActiveRecord read fSessionData;
class function CreateNewSession(const aSessionId: string; const ATimeout: UInt64): TMVCWebSession; override;
class function CreateFromSessionID(const aSessionId: string): TMVCWebSession; override;
class function TryFindSessionID(const ASessionID: String): Boolean; override;
class function CreateFromSessionID(const aSessionId: string; const ATimeout: UInt64): TMVCWebSession; override;
class function TryFindSessionID(const aSessionID: String): Boolean; override;
class procedure TryDeleteSessionID(const aSessionID: String); override;
end;

Expand All @@ -99,8 +105,8 @@ implementation
MVCFramework.SQLGenerators.Interbase,
MVCFramework.SQLGenerators.MSSQL,
MVCFramework.SQLGenerators.Sqlite,
MVCFramework.SQLGenerators.MySQL, System.DateUtils
;
MVCFramework.SQLGenerators.MySQL,
System.DateUtils;

{ TMVCWebSessionDatabase }

Expand All @@ -119,6 +125,11 @@ destructor TMVCWebSessionDatabase.Destroy;
inherited;
end;

function TMVCWebSessionDatabase.GetExpirationTimeStamp: NullableTDateTime;
begin
Result := fSessionData.SessionExpiration;
end;

function TMVCWebSessionDatabase.GetItems(const AKey: string): string;
begin
Result := fSessionData.fJSONData.S[AKey];
Expand All @@ -128,6 +139,7 @@ procedure TMVCWebSessionDatabase.InsertIntoDB;
begin
MarkAsUsed;
fSessionData.Insert;
LogW('InsertIntoDB');
end;

procedure TMVCWebSessionDatabase.InternalApplyChanges;
Expand All @@ -141,34 +153,25 @@ function TMVCWebSessionDatabase.Keys: TArray<String>;
Result := [''];
end;

procedure TMVCWebSessionDatabase.LoadFromDB;
procedure TMVCWebSessionDatabase.MarkAsUsed;
var
lFutureExpiration: TDateTime;
begin
Log.Info('Loading session %s from database', [SessionId], LOG_TAG);
fSessionData := TMVCActiveRecord.GetByPK<TMVCSessionActiveRecord>(Self.SessionId, False);
if not Assigned(fSessionData) then
begin
fSessionData := TMVCSessionActiveRecord.Create;
fSessionData.fSessionID := Self.SessionId;
fSessionData.fTimeout := Self.Timeout;
MarkAsUsed;
fSessionData.Insert;
end
else
if fSessionData.SessionExpiration.HasValue then
begin
UpdateToDB;
lFutureExpiration := Now() + OneMinute * Timeout;
if FormatDateTime('yyyymmddhhnn', lFutureExpiration) > FormatDateTime('yyyymmddhhnn', fSessionData.SessionExpiration) then
begin
inherited;
fSessionData.RefreshSessionExpiration;
end;
end;
end;

procedure TMVCWebSessionDatabase.MarkAsUsed;
begin
inherited;
fSessionData.fSessionExpiration := Now + OneMinute * Timeout;
end;

procedure TMVCWebSessionDatabase.UpdateToDB;
begin
MarkAsUsed;
fSessionData.Update(True);
LogW('UpdateToDB');
end;

procedure TMVCWebSessionDatabase.SetItems(const AKey, AValue: string);
Expand Down Expand Up @@ -212,27 +215,28 @@ constructor TMVCWebSessionDatabase.Create(const aSessionID: String; const aTimeo
Create;
FSessionId := aSessionID;
FTimeout := aTimeout;
fSessionData.fSessionID := aSessionID;
fSessionData.fTimeout := aTimeout;
fSessionData.SessionID := aSessionID;
fSessionData.Timeout := aTimeout;
end;

constructor TMVCWebSessionDatabase.CreateFromSessionData(const aSessionData: TMVCSessionActiveRecord);
constructor TMVCWebSessionDatabase.CreateFromSessionData(const aSessionData: TMVCSessionActiveRecord; const aTimeout: UInt64);
begin
inherited Create;
fSessionData := aSessionData;
fSessionId := fSessionData.fSessionID;
fTimeout := fSessionData.fTimeout;
fSessionId := fSessionData.SessionID;
fSessionData.Timeout := aTimeout;
SetTimeout(aTimeout);
end;

class function TMVCWebSessionDatabase.CreateFromSessionID(const aSessionId: string): TMVCWebSession;
class function TMVCWebSessionDatabase.CreateFromSessionID(const aSessionId: string; const aTimeout: UInt64): TMVCWebSession;
var
lSessDB: TMVCSessionActiveRecord;
begin
Result := nil;
lSessDB := TMVCActiveRecord.GetByPK<TMVCSessionActiveRecord>(aSessionId, False);
if lSessDB <> nil then
begin
Result := TMVCWebSessionDatabase.CreateFromSessionData(lSessDB);
Result := TMVCWebSessionDatabase.CreateFromSessionData(lSessDB, aTimeout);
end;
end;

Expand Down Expand Up @@ -276,6 +280,20 @@ procedure TMVCSessionActiveRecord.OnBeforeInsertOrUpdate;
fData := fJSONData.ToJSON(True)
end;

procedure TMVCSessionActiveRecord.RefreshSessionExpiration;
begin
if fTimeout = 0 then
fSessionExpiration.Clear
else
fSessionExpiration := RecodeSecond(Now() + OneMinute * fTimeout, 0);
end;

procedure TMVCSessionActiveRecord.SetTimeout(const Value: Cardinal);
begin
fTimeout := Value;
RefreshSessionExpiration;
end;

initialization

TMVCSessionFactory.GetInstance.RegisterSessionType('dbactiverecord', TMVCWebSessionDatabase);
Expand Down
Loading

0 comments on commit a5e5f30

Please sign in to comment.