Commit d1e2352c by Mac Stephens

Add startup version check with ConnectionModule gate and Bootstrap modal reload prompt

parent fbd70441
*.exe
*.dll
*.bpl
*.bpi
*.dcp
......
object DMConnection: TDMConnection
Height = 256
Width = 337
object ApiConnection: TXDataWebConnection
Left = 48
Top = 80
end
object xdwcApi: TXDataWebClient
Connection = ApiConnection
Left = 187
Top = 84
end
end
unit ConnectionModule;
interface
uses
System.SysUtils, System.Classes,
WEBLib.Modules,
XData.Web.Connection, XData.Web.Client;
type
TVersionCheckCallback = reference to procedure(success: Boolean; errorMessage: string);
TDMConnection = class(TWebDataModule)
ApiConnection: TXDataWebConnection;
xdwcApi: TXDataWebClient;
procedure ApiConnectionError(error: TXDataWebConnectionError);
procedure XDataWebClientError(error: TXDataClientError);
private
configLoaded: Boolean;
versionCheckPending: Boolean;
pendingCallback: TVersionCheckCallback;
procedure LoadConfig(loadedProc: TProc<Boolean>);
public
const clientVersion = '0.1.0';
procedure InitApp(readyProc: TProc);
procedure SetClientConfig(callback: TVersionCheckCallback);
end;
var
DMConnection: TDMConnection;
implementation
uses
JS, Web,
XData.Web.Request,
XData.Web.Response;
{$R *.dfm}
procedure TDMConnection.ApiConnectionError(error: TXDataWebConnectionError);
begin
if versionCheckPending and Assigned(pendingCallback) then
begin
versionCheckPending := False;
pendingCallback(False, 'Unable to reach server to verify version. Please reload.');
pendingCallback := nil;
end;
end;
procedure TDMConnection.XDataWebClientError(error: TXDataClientError);
begin
if versionCheckPending and Assigned(pendingCallback) then
begin
versionCheckPending := False;
pendingCallback(False, 'Unable to verify version. Please reload.');
pendingCallback := nil;
end;
end;
procedure TDMConnection.LoadConfig(loadedProc: TProc<Boolean>);
procedure onSuccess(response: IHttpResponse);
var
obj: TJSObject;
apiUrl: string;
begin
apiUrl := '';
if response.StatusCode = 200 then
begin
obj := TJSObject(TJSJSON.parse(response.ContentAsText));
apiUrl := JS.toString(obj['ApiUrl']);
end;
if apiUrl <> '' then
begin
ApiConnection.URL := apiUrl;
configLoaded := True;
loadedProc(True);
end
else
loadedProc(False);
end;
procedure onError;
begin
loadedProc(False);
end;
var
conn: TXDataWebConnection;
begin
if configLoaded then
begin
loadedProc(True);
Exit;
end;
conn := TXDataWebConnection.Create(nil);
try
conn.SendRequest(THttpRequest.Create('config/config.json'), @onSuccess, @onError);
finally
conn.Free;
end;
end;
procedure TDMConnection.InitApp(readyProc: TProc);
begin
if Assigned(readyProc) then
readyProc;
end;
procedure TDMConnection.SetClientConfig(callback: TVersionCheckCallback);
procedure configLoadedProc(success: Boolean);
begin
if not success then
begin
callback(False, 'Missing or invalid config/config.json (ApiUrl).');
Exit;
end;
pendingCallback := callback;
versionCheckPending := True;
xdwcApi.Connection := ApiConnection;
ApiConnection.Open(
procedure
begin
xdwcApi.RawInvoke('IApiService.VerifyVersion', [clientVersion],
procedure(response: TXDataClientResponse)
var
jsonResult: TJSObject;
errorMsg: string;
begin
versionCheckPending := False;
jsonResult := TJSObject(response.Result);
if Assigned(jsonResult) and jsonResult.HasOwnProperty('error') then
errorMsg := string(jsonResult['error'])
else
errorMsg := '';
if errorMsg <> '' then
pendingCallback(False, errorMsg)
else
pendingCallback(True, '');
pendingCallback := nil;
end);
end);
end;
begin
LoadConfig(@configLoadedProc);
end;
end.
......@@ -11,29 +11,79 @@ uses
View.CustomSoftware in 'View.CustomSoftware.pas' {FCustomSoftware: TWebForm} {*.html},
View.AboutUs in 'View.AboutUs.pas' {FAboutUs: TWebForm} {*.html},
View.ContactUs in 'View.ContactUs.pas' {FContactUs: TWebForm} {*.html},
Utils in 'Utils.pas';
Utils in 'Utils.pas',
ConnectionModule in 'ConnectionModule.pas' {DMConnection: TWebDataModule};
{$R *.res}
procedure ShowVersionModal(const errorMessage, clientVer: string);
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
asm
var dlg = document.createElement("dialog");
dlg.classList.add("shadow", "rounded", "border", "p-4");
dlg.style.maxWidth = "520px";
dlg.style.width = "92%";
dlg.style.fontFamily = "system-ui, sans-serif";
dlg.innerHTML =
"<h5 class='fw-bold mb-3 text-danger'>EM Systems web site</h5>" +
"<p class='mb-3' style='white-space: pre-wrap;'>" + errorMessage + "</p>" +
"<div class='text-end'>" +
"<button id='refreshBtn' class='btn btn-danger'>Reload</button></div>";
document.body.appendChild(dlg);
dlg.showModal();
document.getElementById("refreshBtn").addEventListener("click", function () {
var base = location.origin + location.pathname;
location.replace(base + "?ver=" + clientVer + "&r=" + Date.now() + location.hash);
});
end;
end;
procedure StartRouting;
begin
asm
// Set a handler to scroll to top on every hash change
window.addEventListener('hashchange', function() {
window.scrollTo(0, 0);
}, false);
// Ensure navigation to the home form if no hash is present
if (window.location.hash === '') {
window.location.hash = '#FHome';
}
end;
if not Application.Route then
begin
Application.CreateForm(TFHome, FHome);
end;
procedure StartApplication;
var
clientVer: string;
begin
clientVer := TDMConnection.clientVersion;
DMConnection.InitApp(
procedure
begin
DMConnection.SetClientConfig(
procedure(success: Boolean; errorMessage: string)
begin
if success then
StartRouting
else
ShowVersionModal(errorMessage, clientVer);
end
);
end
);
end;
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TDMConnection, DMConnection);
StartApplication;
Application.Run;
end.
......@@ -9,6 +9,7 @@ procedure ShowStatusMessage(const AMessage, AClass: string; const AElementId: st
procedure HideStatusMessage(const AElementId: string);
procedure ShowSpinner(SpinnerID: string);
procedure HideSpinner(SpinnerID: string);
procedure ShowNotificationModal(msg: string);
implementation
......@@ -61,6 +62,13 @@ begin
SpinnerElement := TJSHTMLElement(document.getElementById(SpinnerID));
if Assigned(SpinnerElement) then
begin
// Move spinner to the <body> if it's not already there
asm
if (SpinnerElement.parentNode !== document.body) {
document.body.appendChild(SpinnerElement);
}
end;
SpinnerElement.classList.remove('d-none');
SpinnerElement.classList.add('d-block');
end;
......@@ -78,4 +86,35 @@ begin
end;
end;
procedure ShowNotificationModal(msg: string);
begin
asm
var modal = document.getElementById('contact_notification_modal');
var label = document.getElementById('contact_notification_modal_body');
var closeBtn = document.getElementById('btn_modal_close');
if (label) label.innerText = msg;
// Ensure modal is a direct child of <body>
if (modal && modal.parentNode !== document.body) {
document.body.appendChild(modal);
}
// Button simply closes the modal
if (closeBtn) {
closeBtn.onclick = function () {
var existing = bootstrap.Modal.getInstance(modal);
if (existing) {
existing.hide();
}
};
}
// Show the Bootstrap modal
var bsModal = new bootstrap.Modal(modal, { keyboard: false });
bsModal.show();
end;
end;
end.
......@@ -209,16 +209,10 @@ object FContactUs: TFContactUs
WidthPercent = 100.000000000000000000
OnClick = btnSubmitClick
end
object XDataWebConnection1: TXDataWebConnection
OnConnect = XDataWebConnection1Connect
OnError = XDataWebConnection1Error
Left = 209
Top = 492
end
object XDataWebClient1: TXDataWebClient
Connection = XDataWebConnection1
OnError = XDataWebClient1Error
Left = 368
Top = 490
object xdwcEmail: TXDataWebClient
Connection = DMConnection.ApiConnection
OnError = xdwcEmailError
Left = 412
Top = 512
end
end
......@@ -120,3 +120,21 @@
<div></div><div></div><div></div><div></div>
</div>
</div>
<div class="modal fade" id="contact_notification_modal" tabindex="-1" aria-labelledby="main_lblmodal" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content shadow-lg">
<div class="modal-header">
<h5 class="modal-title" id="contact_notification_modal">Info</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body fs-6 fw-bold" id="contact_notification_modal_body">
Please contact EMSystems to solve the issue.
</div>
<div class="modal-footer justify-content-center">
<button type="button" id="btn_modal_close" class="btn btn-primary">Close</button>
</div>
</div>
</div>
</div>
......@@ -6,9 +6,9 @@ uses
System.SysUtils, System.Classes, WEBLib.Graphics, WEBLib.Forms, Vcl.StdCtrls,
WEBLib.StdCtrls, Vcl.Controls, WEBLib.Dialogs, Vcl.Imaging.pngimage,
WEBLib.ExtCtrls, WEBLib.Controls, Web, JS, WEBLib.Menus, WEBLib.WebCtrls,
XData.Web.Connection, XData.Web.Client, Data.DB,
XData.Web.Connection, XData.Web.Client, Data.DB, Utils,
XData.Web.JsonDataset, XData.Web.Dataset, Vcl.Grids,
WEBLib.DBCtrls, WEBLib.DB, WEBLib.Grids, WEBLib.CDS, WEBLib.REST, Utils,
WEBLib.DBCtrls, WEBLib.DB, WEBLib.Grids, WEBLib.CDS, WEBLib.REST,
WEBLib.WebTools, System.NetEncoding, WEBLib.RegularExpressions,
WEBLib.Toast, XData.Web.Request, XData.Web.Response;
......@@ -26,10 +26,9 @@ type
edtEmail: TWebEdit;
edtSubject: TWebEdit;
memoMessage: TWebMemo;
XDataWebConnection1: TXDataWebConnection;
XDataWebClient1: TXDataWebClient;
btnSubmit: TWebButton;
btnPublicSafety: TWebButton;
xdwcEmail: TXDataWebClient;
procedure btnHomeClick(Sender: TObject);
procedure btnAboutUsClick(Sender: TObject);
......@@ -38,17 +37,15 @@ type
procedure btnCustomSoftwareClick(Sender: TObject);
procedure btnPublicSafetyClick(Sender: TObject);
procedure btnSubmitClick(Sender: TObject);
procedure XDataWebConnection1Connect(Sender: TObject);
procedure XDataWebClient1Error(error: TXDataClientError);
procedure XDataWebConnection1Error(error: TXDataWebConnectionError);
procedure WebFormCreate(Sender: TObject);
procedure WebFormClose(Sender: TObject; var Action: TCloseAction);
procedure xdwcEmailError(Error: TXDataClientError);
private
{ Private declarations }
function IsInputValid: Boolean;
function IsEmailValid(AEmail: String): Boolean;
function IsEmailValid(const email: String): Boolean;
[async] procedure SendEmail;
[async] procedure InitializeConnection;
public
procedure NavScrollSizing;
end;
......@@ -61,43 +58,29 @@ implementation
{$R *.dfm}
uses
View.AboutUs,
View.Home,
View.CustomSoftware,
View.PublicSafety,
View.RecordsManagement;
ConnectionModule,
View.Home,
View.PublicSafety,
View.RecordsManagement,
View.CustomSoftware,
View.AboutUs;
procedure TFContactUs.WebFormCreate(Sender: TObject);
begin
Application.ThemeColor := clTMSWEB;
NavScrollSizing;
InitializeConnection;
end;
[async] procedure TFContactUs.InitializeConnection;
var
Conn: TXDataWebConnection;
Resp: IHttpResponse;
Obj: TJSObject;
begin
try
Conn := TXDataWebConnection.Create(nil);
Resp := await(Conn.SendRequestAsync(THttpRequest.Create('config/config.json')));
Obj := TJSObject(TJSJSON.parse(Resp.ContentAsText));
XDataWebConnection1.URL := string(Obj['ApiUrl']);
XDataWebClient1.Connection := XDataWebConnection1;
console.log('XData connection initialized with URL: ', XDataWebConnection1.URL);
except
on E: Exception do
begin
ShowMessage('Failed to load configuration or initialize XData: ' + E.Message);
end;
end;
procedure TFContactUs.xdwcEmailError(Error: TXDataClientError);
begin
ShowNotificationModal('Error when attempting to send: ' + error.ErrorMessage);
end;
procedure TFContactUs.WebFormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := caFree;
end;
procedure TFContactUs.NavScrollSizing;
begin
......@@ -105,7 +88,7 @@ begin
window.addEventListener('scroll', function() {
var navbar = document.querySelector('.em-navbar-wrap .navbar');
var logo = document.querySelector('.em-brand img');
var scrollDistance = 50; // Adjust based on your preference
var scrollDistance = 50;
if (window.scrollY > scrollDistance) {
navbar.classList.add('scrolled');
......@@ -118,132 +101,99 @@ begin
end;
end;
procedure TFContactUs.btnSubmitClick(Sender: TObject);
begin
if IsInputValid then
begin
XDataWebConnection1.Connected := True;
end
else
ShowMessage('Please complete all fields and ensure the email address is valid.');
end;
function TFContactUs.IsEmailValid(AEmail: String): Boolean;
function TFContactUs.IsEmailValid(const email: string): Boolean;
const
CPattern = '^\w+([\.-]?w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$';
pattern = '^[^\s@]+@[^\s@]+\.[^\s@]+$';
begin
Result := TRegEx.IsMatch( AEmail, CPattern );
Result := TRegEx.IsMatch(email.Trim, pattern);
end;
function TFContactUs.IsInputValid: Boolean;
var
LEmailValid: Boolean;
LComplete: Boolean;
nameOk: Boolean;
emailOk: Boolean;
subjectOk: Boolean;
messageOk: Boolean;
begin
LEmailValid := IsEmailValid( edtEmail.Text );
LComplete := (edtName.Text <> '') and
(edtSubject.Text <> '') and
(edtEmail.Text <> '');
Result := LEmailValid and LComplete;
nameOk := edtName.Text.Trim <> '';
emailOk := IsEmailValid(edtEmail.Text);
subjectOk := edtSubject.Text.Trim <> '';
messageOk := memoMessage.Text.Trim <> '';
Result := nameOk and emailOk and subjectOk and messageOk;
end;
procedure TFContactUs.XDataWebConnection1Error(error: TXDataWebConnectionError);
begin
ShowMessage('Error Connecting to XData Server');
end;
procedure TFContactUs.XDataWebConnection1Connect(Sender: TObject);
procedure TFContactUs.btnSubmitClick(Sender: TObject);
begin
console.log('Connected to XData server, Sending Email');
SendEmail();
end;
if not IsInputValid then
begin
ShowNotificationModal('Please complete all fields and ensure the email address is valid.');
Exit;
end;
if not DMConnection.ApiConnection.Connected then
begin
DMConnection.ApiConnection.Open(
procedure
begin
SendEmail;
end);
Exit;
end;
procedure TFContactUs.XDataWebClient1Error(Error: TXDataClientError);
begin
console.log('Error: ', Error.ErrorMessage, ' RequestId: ', Error.RequestId, ' Code: ', Error.ErrorCode, ' Request Url: ', Error.RequestUrl);
SendEmail;
end;
procedure TFContactUs.SendEmail;
var
xdcResponse: TXDataClientResponse;
begin
try
xdcResponse := await(XDataWebClient1.RawInvokeAsync('IApiService.SendEmail',
[edtName.Text, edtEmail.Text, edtSubject.Text, memoMessage.Text]));
ShowMessage('Your message has been sent successfully. Please check your email for a response in the next 48 hours.');
// Clears the input fields after successful email sending
xdwcEmail.RawInvoke('IApiService.SendEmail',
[edtName.Text, edtEmail.Text, edtSubject.Text, memoMessage.Text],
procedure(response: TXDataClientResponse)
begin
ShowNotificationModal('Your message has been sent successfully. Please check your email for a response in the next 48 hours.');
edtName.Text := '';
edtEmail.Text := '';
edtSubject.Text := '';
memoMessage.Text := '';
// Disconnects after sending the email
XDataWebConnection1.Connected := False;
except
on E: EXDataClientRequestException do
begin
ShowMessage('Error when attempting to send: ' + E.Message);
// Optionally disconnect even on error if you intend to reset the connection state
XDataWebConnection1.Connected := False;
end;
end;
end);
end;
procedure TFContactUs.WebFormClose(Sender: TObject; var Action: TCloseAction);
procedure TFContactUs.btnHomeClick(Sender: TObject);
begin
Action := caFree;
Close;
Application.CreateForm(TFHome, FHome);
end;
procedure TFContactUs.btnCustomSoftwareClick(Sender: TObject);
procedure TFContactUs.btnPublicSafetyClick(Sender: TObject);
begin
Close;
Application.CreateForm(TFCustomSoftware, FCustomSoftware);
Application.CreateForm(TFPublicSafety, FPublicSafety);
end;
procedure TFContactUs.btnRecordsManagementClick(Sender: TObject);
begin
Close;
Application.CreateForm(TFRecordsManagement, FRecordsManagement);
end;
procedure TFContactUs.btnPublicSafetyClick(Sender: TObject);
begin
Close;
Application.CreateForm(TFPublicSafety, FPublicSafety);
end;
procedure TFContactUs.btnContactUsClick(Sender: TObject);
procedure TFContactUs.btnCustomSoftwareClick(Sender: TObject);
begin
Close;
Application.CreateForm(TFContactUs, FContactUs);
Application.CreateForm(TFCustomSoftware, FCustomSoftware);
end;
procedure TFContactUs.btnAboutUsClick(Sender: TObject);
begin
Close;
Application.CreateForm(TFAboutUs, FAboutUs);
end;
procedure TFContactUs.btnHomeClick(Sender: TObject);
procedure TFContactUs.btnContactUsClick(Sender: TObject);
begin
Close;
Application.CreateForm(TFHome, FHome);
Application.CreateForm(TFContactUs, FContactUs);
end;
initialization
RegisterClass(TFContactUs);
......
......@@ -131,3 +131,5 @@
© 2011-2024 EM Systems Inc
</div>
</footer>
......@@ -132,6 +132,11 @@
<DesignClass>TWebForm</DesignClass>
</DCCReference>
<DCCReference Include="Utils.pas"/>
<DCCReference Include="ConnectionModule.pas">
<Form>DMConnection</Form>
<FormType>dfm</FormType>
<DesignClass>TWebDataModule</DesignClass>
</DCCReference>
<None Include="css\App.css"/>
<None Include="images\job-gcdf1cf1d3_1920-1536x925.jpg">
<ResourceType>RCDATA</ResourceType>
......@@ -224,7 +229,7 @@
<DeployFile LocalName="Win32\Debug\EMSystemsWebsite.exe" Configuration="Debug" Class="ProjectOutput"/>
<DeployFile LocalName="Win32\Debug\EMSystemsWebsite.exe" Configuration="Debug" Class="ProjectOutput">
<Platform Name="Win32">
<RemoteName>EMSystemsWebsite.exe</RemoteName>
<RemoteName>emSystemsWebsite.exe</RemoteName>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
......
[Settings]
memoLogLevel=3
fileLogLevel=4
LogFileNum=10
LogFileNum=12
webClientVersion=0.1.1
[SMTP]
Host=mail.em-sys.net
......
[2026-01-14 15:16:07.252][1] --- Initialization Timer Triggered ---
[2026-01-14 15:16:07.254][1] Exe version: 1.0.0.0
[2026-01-14 15:16:07.260][1] --TServerConfig.Create - start
[2026-01-14 15:16:07.271][1] --TServerConfig.Create - end
[2026-01-14 15:16:07.287][1] --LoadServerConfig - start
[2026-01-14 15:16:07.289][1] -- Config file: serverconfig.json
[2026-01-14 15:16:07.300][1] -- Config file found.
[2026-01-14 15:16:07.307][1] --TServerConfig.Create - start
[2026-01-14 15:16:07.315][1] --TServerConfig.Create - end
[2026-01-14 15:16:07.324][1] -- localConfig loaded from config file
[2026-01-14 15:16:07.332][1] -- serverConfig.Free - called
[2026-01-14 15:16:07.339][1] -- serverConfig := localConfig - called
[2026-01-14 15:16:07.350][1] -------------------------------------------------------------
[2026-01-14 15:16:07.357][1] -- serverConfig.Server url: http://localhost:2002/website/
[2026-01-14 15:16:07.367][1] -- serverConfig.adminPassword: whatisthisusedfor
[2026-01-14 15:16:07.376][1] -- serverConfig.jwtTokenSecret: super_secret0123super_secret4567
[2026-01-14 15:16:07.387][1] -- serverConfig.webAppFolder: static
[2026-01-14 15:16:07.395][1] --LoadServerConfig - end
[2026-01-14 15:16:07.415][1] ******************************************************
[2026-01-14 15:16:07.423][1] emWebsite XData Server
[2026-01-14 15:16:07.432][1] Version: 1.0.0.0
[2026-01-14 15:16:07.442][1] by EM Systems, Inc.
[2026-01-14 15:16:07.452][1] ******************************************************
[2026-01-14 15:16:07.476][1] --- StartApiServer: Initializing ---
[2026-01-14 15:16:07.527][1] XData Server started at: http://localhost:2002/website/
[2026-01-14 15:16:07.529][1] --- StartApiServer: Complete ---
[2026-01-14 15:16:07.543][1] API Server started at: http://localhost:2002/website/
[2026-01-14 15:16:07.568][1] App server module listening at "http://localhost:2002/website/app", rootDir: static
[2026-01-14 15:16:07.583][1] App Server started at: http://localhost:2002/website/app
[2026-01-14 15:16:07.592][1] --- StartServer: Complete ---
[2026-01-14 16:27:34.851][1] --- Initialization Timer Triggered ---
[2026-01-14 16:27:34.860][1] Exe version: 1.0.0.0
[2026-01-14 16:27:34.869][1] --TServerConfig.Create - start
[2026-01-14 16:27:34.876][1] --TServerConfig.Create - end
[2026-01-14 16:27:34.887][1] --LoadServerConfig - start
[2026-01-14 16:27:34.899][1] -- Config file: serverconfig.json
[2026-01-14 16:27:34.906][1] -- Config file found.
[2026-01-14 16:27:34.916][1] --TServerConfig.Create - start
[2026-01-14 16:27:34.927][1] --TServerConfig.Create - end
[2026-01-14 16:27:34.936][1] -- localConfig loaded from config file
[2026-01-14 16:27:34.948][1] -- serverConfig.Free - called
[2026-01-14 16:27:34.958][1] -- serverConfig := localConfig - called
[2026-01-14 16:27:34.969][1] -------------------------------------------------------------
[2026-01-14 16:27:34.982][1] -- serverConfig.Server url: http://localhost:2002/website/
[2026-01-14 16:27:34.990][1] -- serverConfig.adminPassword: whatisthisusedfor
[2026-01-14 16:27:34.998][1] -- serverConfig.jwtTokenSecret: super_secret0123super_secret4567
[2026-01-14 16:27:35.007][1] -- serverConfig.webAppFolder: static
[2026-01-14 16:27:35.017][1] --LoadServerConfig - end
[2026-01-14 16:27:35.035][1] ******************************************************
[2026-01-14 16:27:35.044][1] emWebsite XData Server
[2026-01-14 16:27:35.056][1] Version: 1.0.0.0
[2026-01-14 16:27:35.064][1] by EM Systems, Inc.
[2026-01-14 16:27:35.077][1] ******************************************************
[2026-01-14 16:27:35.095][1] --- StartApiServer: Initializing ---
[2026-01-14 16:27:35.151][1] XData Server started at: http://localhost:2002/website/
[2026-01-14 16:27:35.151][1] --- StartApiServer: Complete ---
[2026-01-14 16:27:35.161][1] API Server started at: http://localhost:2002/website/
[2026-01-14 16:27:35.202][1] App server module listening at "http://localhost:2002/website/app", rootDir: static
[2026-01-14 16:27:35.202][1] App Server started at: http://localhost:2002/website/app
[2026-01-14 16:27:35.214][1] --- StartServer: Complete ---
[2026-01-14 16:27:48.874][2] VerifyVersion: client=0.1.0 server= mismatch=False
[2026-01-14 15:19:58.305][1] --- Initialization Timer Triggered ---
[2026-01-14 15:19:58.314][1] Exe version: 1.0.0.0
[2026-01-14 15:19:58.317][1] --TServerConfig.Create - start
[2026-01-14 15:19:58.327][1] --TServerConfig.Create - end
[2026-01-14 15:19:58.335][1] --LoadServerConfig - start
[2026-01-14 15:19:58.349][1] -- Config file: serverconfig.json
[2026-01-14 15:19:58.353][1] -- Config file found.
[2026-01-14 15:19:58.359][1] --TServerConfig.Create - start
[2026-01-14 15:19:58.375][1] --TServerConfig.Create - end
[2026-01-14 15:19:58.384][1] -- localConfig loaded from config file
[2026-01-14 15:19:58.391][1] -- serverConfig.Free - called
[2026-01-14 15:19:58.398][1] -- serverConfig := localConfig - called
[2026-01-14 15:19:58.405][1] -------------------------------------------------------------
[2026-01-14 15:19:58.412][1] -- serverConfig.Server url: http://localhost:2002/website/
[2026-01-14 15:19:58.419][1] -- serverConfig.adminPassword: whatisthisusedfor
[2026-01-14 15:19:58.427][1] -- serverConfig.jwtTokenSecret: super_secret0123super_secret4567
[2026-01-14 15:19:58.436][1] -- serverConfig.webAppFolder: static
[2026-01-14 15:19:58.447][1] --LoadServerConfig - end
[2026-01-14 15:19:58.462][1] ******************************************************
[2026-01-14 15:19:58.471][1] emWebsite XData Server
[2026-01-14 15:19:58.478][1] Version: 1.0.0.0
[2026-01-14 15:19:58.487][1] by EM Systems, Inc.
[2026-01-14 15:19:58.497][1] ******************************************************
[2026-01-14 15:19:58.516][1] --- StartApiServer: Initializing ---
[2026-01-14 15:19:58.570][1] XData Server started at: http://localhost:2002/website/
[2026-01-14 15:19:58.572][1] --- StartApiServer: Complete ---
[2026-01-14 15:19:58.582][1] API Server started at: http://localhost:2002/website/
[2026-01-14 15:19:58.611][1] App server module listening at "http://localhost:2002/website/app", rootDir: static
[2026-01-14 15:19:58.622][1] App Server started at: http://localhost:2002/website/app
[2026-01-14 15:19:58.633][1] --- StartServer: Complete ---
[2026-01-14 16:31:20.130][1] --- Initialization Timer Triggered ---
[2026-01-14 16:31:20.154][1] Exe version: 1.0.0.0
[2026-01-14 16:31:20.158][1] --TServerConfig.Create - start
[2026-01-14 16:31:20.170][1] --TServerConfig.Create - end
[2026-01-14 16:31:20.180][1] --LoadServerConfig - start
[2026-01-14 16:31:20.192][1] -- Config file: serverconfig.json
[2026-01-14 16:31:20.208][1] -- Config file found.
[2026-01-14 16:31:20.221][1] --TServerConfig.Create - start
[2026-01-14 16:31:20.232][1] --TServerConfig.Create - end
[2026-01-14 16:31:20.239][1] -- localConfig loaded from config file
[2026-01-14 16:31:20.251][1] -- serverConfig.Free - called
[2026-01-14 16:31:20.259][1] -- serverConfig := localConfig - called
[2026-01-14 16:31:20.267][1] -------------------------------------------------------------
[2026-01-14 16:31:20.282][1] -- serverConfig.Server url: http://localhost:2002/website/
[2026-01-14 16:31:20.286][1] -- serverConfig.adminPassword: whatisthisusedfor
[2026-01-14 16:31:20.296][1] -- serverConfig.jwtTokenSecret: super_secret0123super_secret4567
[2026-01-14 16:31:20.304][1] -- serverConfig.webAppFolder: static
[2026-01-14 16:31:20.315][1] --LoadServerConfig - end
[2026-01-14 16:31:20.336][1] ******************************************************
[2026-01-14 16:31:20.349][1] emWebsite XData Server
[2026-01-14 16:31:20.360][1] Version: 1.0.0.0
[2026-01-14 16:31:20.369][1] by EM Systems, Inc.
[2026-01-14 16:31:20.380][1] ******************************************************
[2026-01-14 16:31:20.399][1] --- StartApiServer: Initializing ---
[2026-01-14 16:31:20.460][1] XData Server started at: http://localhost:2002/website/
[2026-01-14 16:31:20.462][1] --- StartApiServer: Complete ---
[2026-01-14 16:31:20.472][1] API Server started at: http://localhost:2002/website/
[2026-01-14 16:31:20.506][1] App server module listening at "http://localhost:2002/website/app", rootDir: static
[2026-01-14 16:31:20.509][1] App Server started at: http://localhost:2002/website/app
[2026-01-14 16:31:20.522][1] --- StartServer: Complete ---
[2026-01-14 16:31:32.520][1] Contact form submitted. Name: Mac, Email: mac@em-sys.net, Subject: Test Subject, Message: testmessage
[2026-01-14 16:33:27.606][2] VerifyVersion: client=0.1.0 server= mismatch=False
[2026-01-14 16:43:34.930][2] VerifyVersion: client=0.1.0 server= mismatch=False
[2026-01-14 16:43:55.931][1] Contact form submitted. Name: mac, Email: mac@em-sys.net, Subject: test3, Message: test3
[2026-01-14 16:48:02.149][2] VerifyVersion: client=0.1.0 server= mismatch=False
[2026-01-14 16:48:15.513][1] Contact form submitted. Name: Mac, Email: mac@em-sys.net, Subject: test4, Message: test4
[2026-01-14 16:49:42.682][2] VerifyVersion: client=0.1.0 server=0.1.1 mismatch=True
[2026-01-14 16:49:45.939][2] VerifyVersion: client=0.1.0 server=0.1.1 mismatch=True
[2026-01-14 15:21:18.212][1] --- Initialization Timer Triggered ---
[2026-01-14 15:21:18.214][1] Exe version: 1.0.0.0
[2026-01-14 15:21:18.226][1] --TServerConfig.Create - start
[2026-01-14 15:21:18.234][1] --TServerConfig.Create - end
[2026-01-14 15:21:18.245][1] --LoadServerConfig - start
[2026-01-14 15:21:18.251][1] -- Config file: serverconfig.json
[2026-01-14 15:21:18.259][1] -- Config file found.
[2026-01-14 15:21:18.271][1] --TServerConfig.Create - start
[2026-01-14 15:21:18.277][1] --TServerConfig.Create - end
[2026-01-14 15:21:18.286][1] -- localConfig loaded from config file
[2026-01-14 15:21:18.291][1] -- serverConfig.Free - called
[2026-01-14 15:21:18.300][1] -- serverConfig := localConfig - called
[2026-01-14 15:21:18.307][1] -------------------------------------------------------------
[2026-01-14 15:21:18.316][1] -- serverConfig.Server url: http://localhost:2002/website/
[2026-01-14 15:21:18.322][1] -- serverConfig.adminPassword: whatisthisusedfor
[2026-01-14 15:21:18.331][1] -- serverConfig.jwtTokenSecret: super_secret0123super_secret4567
[2026-01-14 15:21:18.333][1] -- serverConfig.webAppFolder: static
[2026-01-14 15:21:18.342][1] --LoadServerConfig - end
[2026-01-14 15:21:18.363][1] ******************************************************
[2026-01-14 15:21:18.370][1] emWebsite XData Server
[2026-01-14 15:21:18.376][1] Version: 1.0.0.0
[2026-01-14 15:21:18.387][1] by EM Systems, Inc.
[2026-01-14 15:21:18.395][1] ******************************************************
[2026-01-14 15:21:18.416][1] --- StartApiServer: Initializing ---
[2026-01-14 15:21:18.460][1] XData Server started at: http://localhost:2002/website/
[2026-01-14 15:21:18.469][1] --- StartApiServer: Complete ---
[2026-01-14 15:21:18.476][1] API Server started at: http://localhost:2002/website/
[2026-01-14 15:21:18.521][1] App server module listening at "http://localhost:2002/website/app", rootDir: static
[2026-01-14 15:21:18.521][1] App Server started at: http://localhost:2002/website/app
[2026-01-14 15:21:18.536][1] --- StartServer: Complete ---
[2026-01-14 15:27:38.658][1] --- Initialization Timer Triggered ---
[2026-01-14 15:27:38.664][1] Exe version: 1.0.0.0
[2026-01-14 15:27:38.678][1] --TServerConfig.Create - start
[2026-01-14 15:27:38.688][1] --TServerConfig.Create - end
[2026-01-14 15:27:38.701][1] --LoadServerConfig - start
[2026-01-14 15:27:38.715][1] -- Config file: serverconfig.json
[2026-01-14 15:27:38.726][1] -- Config file found.
[2026-01-14 15:27:38.734][1] --TServerConfig.Create - start
[2026-01-14 15:27:38.746][1] --TServerConfig.Create - end
[2026-01-14 15:27:38.762][1] -- localConfig loaded from config file
[2026-01-14 15:27:38.765][1] -- serverConfig.Free - called
[2026-01-14 15:27:38.779][1] -- serverConfig := localConfig - called
[2026-01-14 15:27:38.781][1] -------------------------------------------------------------
[2026-01-14 15:27:38.783][1] -- serverConfig.Server url: http://localhost:2002/website/
[2026-01-14 15:27:38.785][1] -- serverConfig.adminPassword: whatisthisusedfor
[2026-01-14 15:27:38.795][1] -- serverConfig.jwtTokenSecret: super_secret0123super_secret4567
[2026-01-14 15:27:38.804][1] -- serverConfig.webAppFolder: static
[2026-01-14 15:27:38.819][1] --LoadServerConfig - end
[2026-01-14 15:27:38.839][1] ******************************************************
[2026-01-14 15:27:38.858][1] emWebsite XData Server
[2026-01-14 15:27:38.872][1] Version: 1.0.0.0
[2026-01-14 15:27:38.891][1] by EM Systems, Inc.
[2026-01-14 15:27:38.902][1] ******************************************************
[2026-01-14 15:27:38.916][1] --- StartApiServer: Initializing ---
[2026-01-14 15:27:38.989][1] XData Server started at: http://localhost:2002/website/
[2026-01-14 15:27:38.989][1] --- StartApiServer: Complete ---
[2026-01-14 15:27:39.013][1] API Server started at: http://localhost:2002/website/
[2026-01-14 15:27:39.085][1] App server module listening at "http://localhost:2002/website/app", rootDir: static
[2026-01-14 15:27:39.101][1] App Server started at: http://localhost:2002/website/app
[2026-01-14 15:27:39.116][1] --- StartServer: Complete ---
[2026-01-14 16:00:07.088][2] VerifyVersion: client=0.1.0 server=0.1.1 mismatch=True
[2026-01-14 16:00:11.648][2] VerifyVersion: client=0.1.0 server=0.1.1 mismatch=True
[2026-01-14 16:00:29.157][2] VerifyVersion: client=0.1.0 server=0.1.0 mismatch=False
[2026-01-14 16:17:07.622][2] VerifyVersion: client=0.1.0 server=0.1.0 mismatch=False
[2026-01-14 16:17:32.669][2] VerifyVersion: client=0.1.0 server=0.1.0 mismatch=False
[2026-01-14 16:25:28.559][2] VerifyVersion: client=0.1.0 server= mismatch=False
......@@ -3,13 +3,14 @@ unit Api.Service;
interface
uses
XData.Service.Common;
XData.Service.Common, System.JSON;
type
[ServiceContract]
IApiService = interface(IInvokable)
['{46B3B095-5873-4452-B338-AEE009604DED}']
[HttpGet] function SendEmail(Name, Email, Subject, Body: string): string;
[HttpGet] function VerifyVersion(ClientVersion: string): TJSONObject;
end;
implementation
......
......@@ -8,7 +8,7 @@ uses
IdSMTP, IdMessage, IdSSLOpenSSL, IdText, IdExplicitTLSClientServerBase,
IdIOHandlerSocket, IdException, IdSSL, IdSMTPBase, IdGlobal, IdStack, IdWinsock2,
IdStackConsts, IdIOHandler, IdIOHandlerStack, IdBaseComponent,
IdStackConsts, IdIOHandler, IdIOHandlerStack, IdBaseComponent, System.JSON,
IdComponent, IdTCPConnection, IdTCPClient, IdMessageClient, VCL.Forms, Api.Service;
type
......@@ -16,6 +16,7 @@ type
TApiService = class(TInterfacedObject, IApiService)
public
function SendEmail(Name, Email, Subject, Body: string): string;
function VerifyVersion(ClientVersion: string): TJSONObject;
end;
implementation
......@@ -97,6 +98,36 @@ begin
end;
function TApiService.VerifyVersion(ClientVersion: string): TJSONObject;
var
iniFile: TIniFile;
iniPath: string;
webClientVersion: string;
errorMsg: string;
begin
iniPath := ChangeFileExt(Application.ExeName, '.ini');
iniFile := TIniFile.Create(iniPath);
try
webClientVersion := iniFile.ReadString('Settings', 'webClientVersion', '');
finally
iniFile.Free;
end;
errorMsg := '';
if (webClientVersion <> '') and (ClientVersion <> webClientVersion) then
errorMsg := Format('Client version mismatch. Server expects %s but client is %s.',
[webClientVersion, ClientVersion]);
Result := TJSONObject.Create;
Result.AddPair('webClientVersion', webClientVersion);
if errorMsg <> '' then
Result.AddPair('error', errorMsg);
Logger.Log(2, Format('VerifyVersion: client=%s server=%s mismatch=%s',
[ClientVersion, webClientVersion, BoolToStr(errorMsg <> '', True)]));
end;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment