Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
emiMobile
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Mac Stephens
emiMobile
Commits
69fafe4a
Commit
69fafe4a
authored
Aug 07, 2026
by
Mac Stephens
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add WebSocket push updates with PostgreSQL notification listener and client connection handling
parent
575b7310
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
512 additions
and
205 deletions
+512
-205
emiMobile.groupproj
emiMobile.groupproj
+0
-48
Api.Database.dfm
emiMobileServer/Source/Api.Database.dfm
+7
-0
Api.Database.pas
emiMobileServer/Source/Api.Database.pas
+18
-1
Main.dfm
emiMobileServer/Source/Main.dfm
+5
-49
Main.pas
emiMobileServer/Source/Main.pas
+77
-72
WebSocket.Manager.pas
emiMobileServer/Source/WebSocket.Manager.pas
+314
-0
Ws.DataModel.pas
emiMobileServer/Source/Ws.DataModel.pas
+7
-2
Ws.Server.Module.dfm
emiMobileServer/Source/Ws.Server.Module.dfm
+0
-1
Ws.Server.Module.pas
emiMobileServer/Source/Ws.Server.Module.pas
+17
-6
emiMobileServer.ini
emiMobileServer/bin/emiMobileServer.ini
+1
-1
emiMobileServer.dproj
emiMobileServer/emiMobileServer.dproj
+12
-1
ConnectionModule.pas
webEMIMobile/ConnectionModule.pas
+1
-1
Module.Websocket.dfm
webEMIMobile/Module.Websocket.dfm
+2
-1
Module.Websocket.pas
webEMIMobile/Module.Websocket.pas
+49
-11
View.Main.dfm
webEMIMobile/View.Main.dfm
+0
-9
View.Main.pas
webEMIMobile/View.Main.pas
+1
-1
config.json
webEMIMobile/config/config.json
+1
-1
No files found.
emiMobile.groupproj
deleted
100644 → 0
View file @
575b7310
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{012E57DC-0378-4E45-B2F6-DFA72B2D10B1}</ProjectGuid>
</PropertyGroup>
<ItemGroup>
<Projects Include="emiMobileServer\emiMobileServer.dproj">
<Dependencies/>
</Projects>
<Projects Include="webEMIMobile\webEmiMobile.dproj">
<Dependencies/>
</Projects>
</ItemGroup>
<ProjectExtensions>
<Borland.Personality>Default.Personality.12</Borland.Personality>
<Borland.ProjectType/>
<BorlandProject>
<Default.Personality/>
</BorlandProject>
</ProjectExtensions>
<Target Name="emiMobileServer">
<MSBuild Projects="emiMobileServer\emiMobileServer.dproj"/>
</Target>
<Target Name="emiMobileServer:Clean">
<MSBuild Projects="emiMobileServer\emiMobileServer.dproj" Targets="Clean"/>
</Target>
<Target Name="emiMobileServer:Make">
<MSBuild Projects="emiMobileServer\emiMobileServer.dproj" Targets="Make"/>
</Target>
<Target Name="webEmiMobile">
<MSBuild Projects="webEMIMobile\webEmiMobile.dproj"/>
</Target>
<Target Name="webEmiMobile:Clean">
<MSBuild Projects="webEMIMobile\webEmiMobile.dproj" Targets="Clean"/>
</Target>
<Target Name="webEmiMobile:Make">
<MSBuild Projects="webEMIMobile\webEmiMobile.dproj" Targets="Make"/>
</Target>
<Target Name="Build">
<CallTarget Targets="emiMobileServer;webEmiMobile"/>
</Target>
<Target Name="Clean">
<CallTarget Targets="emiMobileServer:Clean;webEmiMobile:Clean"/>
</Target>
<Target Name="Make">
<CallTarget Targets="emiMobileServer:Make;webEmiMobile:Make"/>
</Target>
<Import Project="$(BDS)\Bin\CodeGear.Group.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Group.Targets')"/>
</Project>
emiMobileServer/Source/Api.Database.dfm
View file @
69fafe4a
...
@@ -1359,4 +1359,11 @@ object ApiDatabaseModule: TApiDatabaseModule
...
@@ -1359,4 +1359,11 @@ object ApiDatabaseModule: TApiDatabaseModule
Left = 162
Left = 162
Top = 42
Top = 42
end
end
object UniAlerter1: TUniAlerter
Connection = ucENTCAD
Events = 'disupdate'
OnEvent = UniAlerter1Event
Left = 324
Top = 382
end
end
end
emiMobileServer/Source/Api.Database.pas
View file @
69fafe4a
...
@@ -5,7 +5,8 @@ interface
...
@@ -5,7 +5,8 @@ interface
uses
uses
System
.
SysUtils
,
System
.
Classes
,
Data
.
DB
,
MemDS
,
DBAccess
,
Uni
,
UniProvider
,
System
.
SysUtils
,
System
.
Classes
,
Data
.
DB
,
MemDS
,
DBAccess
,
Uni
,
UniProvider
,
PostgreSQLUniProvider
,
System
.
Variants
,
System
.
Generics
.
Collections
,
System
.
IniFiles
,
PostgreSQLUniProvider
,
System
.
Variants
,
System
.
Generics
.
Collections
,
System
.
IniFiles
,
Common
.
Logging
,
Vcl
.
Forms
,
System
.
Character
,
Common
.
Ini
;
Common
.
Logging
,
Vcl
.
Forms
,
System
.
Character
,
Common
.
Ini
,
DAAlerter
,
UniAlerter
;
type
type
TApiDatabaseModule
=
class
(
TDataModule
)
TApiDatabaseModule
=
class
(
TDataModule
)
...
@@ -203,12 +204,16 @@ type
...
@@ -203,12 +204,16 @@ type
uqMapUnitsagencytype
:
TStringField
;
uqMapUnitsagencytype
:
TStringField
;
uqUnitListagencytype
:
TStringField
;
uqUnitListagencytype
:
TStringField
;
uqMapComplaintscomplaint
:
TStringField
;
uqMapComplaintscomplaint
:
TStringField
;
UniAlerter1
:
TUniAlerter
;
procedure
uqComplaintListCalcFields
(
DataSet
:
TDataSet
);
procedure
uqComplaintListCalcFields
(
DataSet
:
TDataSet
);
procedure
uqMapComplaintsCalcFields
(
DataSet
:
TDataSet
);
procedure
uqMapComplaintsCalcFields
(
DataSet
:
TDataSet
);
procedure
DataModuleCreate
(
Sender
:
TObject
);
procedure
DataModuleCreate
(
Sender
:
TObject
);
procedure
UniAlerter1Event
(
Sender
:
TDAAlerter
;
const
EventName
,
Message
:
string
);
private
private
{ Private declarations }
{ Private declarations }
public
public
CADUpdate
:
Boolean
;
function
HandleUniqueFilenames
(
const
category
:
string
):
string
;
function
HandleUniqueFilenames
(
const
category
:
string
):
string
;
function
BadgeCounts
(
const
BaseQuery
:
TUniQuery
):
Integer
;
function
BadgeCounts
(
const
BaseQuery
:
TUniQuery
):
Integer
;
end
;
end
;
...
@@ -225,6 +230,8 @@ implementation
...
@@ -225,6 +230,8 @@ implementation
procedure
TApiDatabaseModule
.
DataModuleCreate
(
Sender
:
TObject
);
procedure
TApiDatabaseModule
.
DataModuleCreate
(
Sender
:
TObject
);
begin
begin
CADUpdate
:=
False
;
ucENTCAD
.
ProviderName
:=
'PostgreSQL'
;
ucENTCAD
.
ProviderName
:=
'PostgreSQL'
;
ucENTCAD
.
Server
:=
IniEntries
.
DatabaseServer
;
ucENTCAD
.
Server
:=
IniEntries
.
DatabaseServer
;
ucENTCAD
.
Port
:=
IniEntries
.
DatabasePort
;
ucENTCAD
.
Port
:=
IniEntries
.
DatabasePort
;
...
@@ -238,6 +245,10 @@ begin
...
@@ -238,6 +245,10 @@ begin
ucENTCAD
.
ExecSQL
(
'set search_path to lems, avl, entcad, public'
);
ucENTCAD
.
ExecSQL
(
'set search_path to lems, avl, entcad, public'
);
Logger
.
Log
(
2
,
'PostgreSQL API search_path set to lems, avl, entcad, public'
);
Logger
.
Log
(
2
,
'PostgreSQL API search_path set to lems, avl, entcad, public'
);
Logger
.
Log
(
1
,
'Starting PostgreSQL disupdate listener'
);
UniAlerter1
.
Start
;
Logger
.
Log
(
1
,
'PostgreSQL disupdate listener started'
);
end
;
end
;
procedure
TApiDatabaseModule
.
uqComplaintListCalcFields
(
DataSet
:
TDataSet
);
procedure
TApiDatabaseModule
.
uqComplaintListCalcFields
(
DataSet
:
TDataSet
);
...
@@ -307,6 +318,12 @@ begin
...
@@ -307,6 +318,12 @@ begin
end
;
end
;
procedure
TApiDatabaseModule
.
UniAlerter1Event
(
Sender
:
TDAAlerter
;
const
EventName
,
Message
:
string
);
begin
if
SameText
(
EventName
,
'disupdate'
)
then
CADUpdate
:=
True
;
end
;
function
TApiDatabaseModule
.
BadgeCounts
(
const
BaseQuery
:
TUniQuery
):
Integer
;
function
TApiDatabaseModule
.
BadgeCounts
(
const
BaseQuery
:
TUniQuery
):
Integer
;
var
var
Q
:
TUniQuery
;
Q
:
TUniQuery
;
...
...
emiMobileServer/Source/Main.dfm
View file @
69fafe4a
...
@@ -23,7 +23,6 @@ object FMain: TFMain
...
@@ -23,7 +23,6 @@ object FMain: TFMain
ActivePage = tabConnectedClients
ActivePage = tabConnectedClients
Anchors = [akLeft, akTop, akRight, akBottom]
Anchors = [akLeft, akTop, akRight, akBottom]
TabOrder = 3
TabOrder = 3
ExplicitHeight = 552
object tabServerLog: TTabSheet
object tabServerLog: TTabSheet
Caption = 'Server Log'
Caption = 'Server Log'
object memoInfo: TMemo
object memoInfo: TMemo
...
@@ -36,7 +35,6 @@ object FMain: TFMain
...
@@ -36,7 +35,6 @@ object FMain: TFMain
ScrollBars = ssVertical
ScrollBars = ssVertical
TabOrder = 0
TabOrder = 0
WordWrap = False
WordWrap = False
ExplicitHeight = 524
end
end
end
end
object tabConnectedClients: TTabSheet
object tabConnectedClients: TTabSheet
...
@@ -84,7 +82,6 @@ object FMain: TFMain
...
@@ -84,7 +82,6 @@ object FMain: TFMain
Caption = 'pnlConnectedClientsActions'
Caption = 'pnlConnectedClientsActions'
ShowCaption = False
ShowCaption = False
TabOrder = 1
TabOrder = 1
ExplicitTop = 467
object btnDisconnectClient: TButton
object btnDisconnectClient: TButton
Left = 5
Left = 5
Top = 18
Top = 18
...
@@ -98,7 +95,7 @@ object FMain: TFMain
...
@@ -98,7 +95,7 @@ object FMain: TFMain
Left = 294
Left = 294
Top = 12
Top = 12
Width = 317
Width = 317
Height =
38
Height =
21
TabOrder = 1
TabOrder = 1
end
end
object btnSendClientMessage: TButton
object btnSendClientMessage: TButton
...
@@ -141,50 +138,9 @@ object FMain: TFMain
...
@@ -141,50 +138,9 @@ object FMain: TFMain
TabOrder = 2
TabOrder = 2
OnClick = btnAuthSwaggerUIClick
OnClick = btnAuthSwaggerUIClick
end
end
object pgcMain: TPageControl
Left = 8
Top = 39
Width = 784
Height = 573
Anchors = [akLeft, akTop, akRight, akBottom]
TabOrder = 3
object tabLog: TTabSheet
Caption = 'Log'
object memoInfo: TMemo
Left = 0
Top = 0
Width = 776
Height = 545
Align = alClient
ReadOnly = True
TabOrder = 0
end
end
object tabClients: TTabSheet
Caption = 'Connected Clients'
object sgClients: TStringGrid
Left = 0
Top = 0
Width = 776
Height = 545
Align = alClient
ColCount = 3
DefaultColWidth = 220
DefaultRowHeight = 20
FixedCols = 0
RowCount = 2
Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goColSizing]
TabOrder = 0
ColWidths = (
200
200
176)
end
end
end
object initTimer: TTimer
object initTimer: TTimer
OnTimer = initTimerTimer
OnTimer = initTimerTimer
Left = 4
48
Left = 4
22
Top = 4
Top = 4
end
end
object ExeInfo1: TExeInfo
object ExeInfo1: TExeInfo
...
@@ -218,12 +174,12 @@ object FMain: TFMain
...
@@ -218,12 +174,12 @@ object FMain: TFMain
UpdateOptions.CheckRequired = False
UpdateOptions.CheckRequired = False
UpdateOptions.AutoCommitUpdates = True
UpdateOptions.AutoCommitUpdates = True
StoreDefs = True
StoreDefs = True
Left =
514
Left =
490
Top =
3
Top =
5
end
end
object dsConnectedClients: TDataSource
object dsConnectedClients: TDataSource
DataSet = tblConnectedClients
DataSet = tblConnectedClients
Left = 3
78
Left = 3
52
Top = 7
Top = 7
end
end
end
end
emiMobileServer/Source/Main.pas
View file @
69fafe4a
...
@@ -3,15 +3,17 @@ unit Main;
...
@@ -3,15 +3,17 @@ unit Main;
interface
interface
uses
uses
Winapi
.
Windows
,
Winapi
.
Messages
,
System
.
SysUtils
,
System
.
Variants
,
Winapi
.
ShellApi
,
Winapi
.
Windows
,
Winapi
.
Messages
,
Winapi
.
ShellApi
,
System
.
Classes
,
Vcl
.
Graphics
,
Vcl
.
Controls
,
Vcl
.
Forms
,
Vcl
.
Dialogs
,
System
.
SysUtils
,
System
.
Variants
,
System
.
Classes
,
System
.
Generics
.
Collections
,
Vcl
.
StdCtrls
,
Vcl
.
ExtCtrls
,
Vcl
.
ComCtrls
,
Vcl
.
Grids
,
System
.
IniFiles
,
System
.
Generics
.
Collections
,
System
.
IniFiles
,
Vcl
.
Graphics
,
Vcl
.
Controls
,
Vcl
.
Forms
,
Vcl
.
Dialogs
,
Vcl
.
StdCtrls
,
Vcl
.
ExtCtrls
,
Vcl
.
ComCtrls
,
Vcl
.
Grids
,
Vcl
.
DBGrids
,
Data
.
DB
,
FireDAC
.
Stan
.
Intf
,
FireDAC
.
Stan
.
Option
,
FireDAC
.
Stan
.
Param
,
FireDAC
.
Stan
.
Error
,
FireDAC
.
DatS
,
FireDAC
.
Phys
.
Intf
,
FireDAC
.
DApt
.
Intf
,
FireDAC
.
Comp
.
DataSet
,
FireDAC
.
Comp
.
Client
,
Auth
.
Service
,
Auth
.
Server
.
Module
,
Api
.
Server
.
Module
,
App
.
Server
.
Module
,
Auth
.
Service
,
Auth
.
Server
.
Module
,
Api
.
Server
.
Module
,
App
.
Server
.
Module
,
ExeInfo
,
Api
.
Service
,
Vcl
.
ComCtrls
,
WebSocket
.
Manager
,
FireDAC
.
Stan
.
Intf
,
ExeInfo
,
Api
.
Service
,
WebSocket
.
Manager
,
Ws
.
Server
.
Module
;
FireDAC
.
Stan
.
Option
,
FireDAC
.
Stan
.
Param
,
FireDAC
.
Stan
.
Error
,
FireDAC
.
DatS
,
FireDAC
.
Phys
.
Intf
,
FireDAC
.
DApt
.
Intf
,
Data
.
DB
,
Vcl
.
Grids
,
Vcl
.
DBGrids
,
FireDAC
.
Comp
.
DataSet
,
FireDAC
.
Comp
.
Client
,
Ws
.
Server
.
Module
;
type
type
TFMain
=
class
(
TForm
)
TFMain
=
class
(
TForm
)
...
@@ -33,21 +35,19 @@ type
...
@@ -33,21 +35,19 @@ type
btnSendClientMessage
:
TButton
;
btnSendClientMessage
:
TButton
;
procedure
btnApiSwaggerUIClick
(
Sender
:
TObject
);
procedure
btnApiSwaggerUIClick
(
Sender
:
TObject
);
procedure
btnExitClick
(
Sender
:
TObject
);
procedure
btnExitClick
(
Sender
:
TObject
);
procedure
ContactFormData
(
AText
:
S
tring
);
procedure
ContactFormData
(
AText
:
s
tring
);
procedure
FormClose
(
Sender
:
TObject
;
var
Action
:
TCloseAction
);
procedure
FormClose
(
Sender
:
TObject
;
var
Action
:
TCloseAction
);
procedure
initTimerTimer
(
Sender
:
TObject
);
procedure
initTimerTimer
(
Sender
:
TObject
);
procedure
btnAuthSwaggerUIClick
(
Sender
:
TObject
);
procedure
btnAuthSwaggerUIClick
(
Sender
:
TObject
);
procedure
btnDisconnectClientClick
(
Sender
:
TObject
);
procedure
btnDisconnectClientClick
(
Sender
:
TObject
);
procedure
btnSendClientMessageClick
(
Sender
:
TObject
);
procedure
btnSendClientMessageClick
(
Sender
:
TObject
);
strict
private
strict
private
FWebSocketManager
:
TWebSocketManager
;
procedure
StartServers
;
procedure
StartServers
;
procedure
RefreshClientList
;
function
LogValue
(
const
LabelName
:
string
;
const
Value
:
string
;
FromIni
:
Boolean
):
string
;
procedure
HandleConnectedClientsChanged
;
procedure
HandleConnectedClientsChanged
;
procedure
RefreshConnectedClients
;
procedure
RefreshConnectedClients
;
function
LogValue
(
LabelName
:
string
;
Value
:
string
;
FromIni
:
Boolean
):
string
;
private
private
function
LocalBrowserUrl
(
const
Url
:
string
):
string
;
function
LocalBrowserUrl
(
Url
:
string
):
string
;
end
;
end
;
var
var
...
@@ -65,8 +65,6 @@ uses
...
@@ -65,8 +65,6 @@ uses
{$R *.dfm}
{$R *.dfm}
{ --- Event Handlers --- }
procedure
TFMain
.
btnExitClick
(
Sender
:
TObject
);
procedure
TFMain
.
btnExitClick
(
Sender
:
TObject
);
begin
begin
Close
;
Close
;
...
@@ -76,6 +74,9 @@ procedure TFMain.btnSendClientMessageClick(Sender: TObject);
...
@@ -76,6 +74,9 @@ procedure TFMain.btnSendClientMessageClick(Sender: TObject);
var
var
connectionId
:
string
;
connectionId
:
string
;
begin
begin
if
not
Assigned
(
WsServerModule
)
then
Exit
;
if
tblConnectedClients
.
IsEmpty
then
if
tblConnectedClients
.
IsEmpty
then
Exit
;
Exit
;
...
@@ -83,23 +84,24 @@ begin
...
@@ -83,23 +84,24 @@ begin
Exit
;
Exit
;
connectionId
:=
tblConnectedClients
.
FieldByName
(
'ConnectionId'
).
AsString
;
connectionId
:=
tblConnectedClients
.
FieldByName
(
'ConnectionId'
).
AsString
;
WsServerModule
.
SendMessageToClient
(
connectionId
,
edtClientMessage
.
Text
);
FWebSocketManager
.
SendMessageToClient
(
connectionId
,
edtClientMessage
.
Text
);
end
;
end
;
procedure
TFMain
.
btnDisconnectClientClick
(
Sender
:
TObject
);
procedure
TFMain
.
btnDisconnectClientClick
(
Sender
:
TObject
);
var
var
connectionId
:
string
;
connectionId
:
string
;
begin
begin
if
not
Assigned
(
WsServerModule
)
then
Exit
;
if
tblConnectedClients
.
IsEmpty
then
if
tblConnectedClients
.
IsEmpty
then
Exit
;
Exit
;
connectionId
:=
tblConnectedClients
.
FieldByName
(
'ConnectionId'
).
AsString
;
connectionId
:=
tblConnectedClients
.
FieldByName
(
'ConnectionId'
).
AsString
;
WsServerModule
.
DisconnectClient
(
connectionId
);
FWebSocketManager
.
DisconnectClient
(
connectionId
);
end
;
end
;
function
TFMain
.
LocalBrowserUrl
(
const
Url
:
string
):
string
;
function
TFMain
.
LocalBrowserUrl
(
Url
:
string
):
string
;
begin
begin
Result
:=
StringReplace
(
Url
,
'://0.0.0.0:'
,
'://localhost:'
,
[
rfIgnoreCase
]);
Result
:=
StringReplace
(
Url
,
'://0.0.0.0:'
,
'://localhost:'
,
[
rfIgnoreCase
]);
end
;
end
;
...
@@ -120,18 +122,27 @@ begin
...
@@ -120,18 +122,27 @@ begin
ShellExecute
(
Handle
,
'open'
,
PChar
(
LocalBrowserUrl
(
url
)),
nil
,
nil
,
SW_SHOWNORMAL
);
ShellExecute
(
Handle
,
'open'
,
PChar
(
LocalBrowserUrl
(
url
)),
nil
,
nil
,
SW_SHOWNORMAL
);
end
;
end
;
procedure
TFMain
.
ContactFormData
(
AText
:
S
tring
);
procedure
TFMain
.
ContactFormData
(
AText
:
s
tring
);
begin
begin
if
memoInfo
.
CanFocus
then
if
memoInfo
.
CanFocus
then
TThread
.
Queue
(
nil
,
procedure
begin
memoInfo
.
Lines
.
Add
(
AText
);
end
)
TThread
.
Queue
(
nil
,
procedure
begin
memoInfo
.
Lines
.
Add
(
AText
);
end
)
else
else
TThread
.
Synchronize
(
nil
,
procedure
begin
memoInfo
.
Lines
.
Add
(
AText
);
end
);
TThread
.
Synchronize
(
nil
,
procedure
begin
memoInfo
.
Lines
.
Add
(
AText
);
end
);
end
;
end
;
procedure
TFMain
.
initTimerTimer
(
Sender
:
TObject
);
procedure
TFMain
.
initTimerTimer
(
Sender
:
TObject
);
begin
begin
initTimer
.
Enabled
:=
False
;
initTimer
.
Enabled
:=
False
;
Caption
:=
Caption
+
' ver '
+
ExeInfo1
.
FileVersion
;
Caption
:=
Caption
+
' ver '
+
ExeInfo1
.
FileVersion
;
ServerConfig
:=
TServerConfig
.
Create
;
ServerConfig
:=
TServerConfig
.
Create
;
LoadIniEntries
;
LoadIniEntries
;
LoadServerConfig
;
LoadServerConfig
;
...
@@ -140,48 +151,18 @@ end;
...
@@ -140,48 +151,18 @@ end;
procedure
TFMain
.
FormClose
(
Sender
:
TObject
;
var
Action
:
TCloseAction
);
procedure
TFMain
.
FormClose
(
Sender
:
TObject
;
var
Action
:
TCloseAction
);
begin
begin
if
Assigned
(
WsServerModule
)
then
if
Assigned
(
WsServerModule
)
then
WsServerModule
.
OnClientsChanged
:=
nil
;
WsServerModule
.
OnClientsChanged
:=
nil
;
ServerConfig
.
Free
;
FreeAndNil
(
WsServerModule
)
;
IniEntries
.
Free
;
FreeAndNil
(
AppServerModule
)
;
AuthServerModule
.
Free
;
FreeAndNil
(
ApiServerModule
)
;
ApiServerModule
.
Free
;
FreeAndNil
(
AuthServerModule
)
;
AppServerModule
.
Free
;
FreeAndNil
(
IniEntries
)
;
WsServerModule
.
Free
;
FreeAndNil
(
ServerConfig
)
;
end
;
end
;
{ --- Connected Client List --- }
function
TFMain
.
LogValue
(
LabelName
:
string
;
Value
:
string
;
FromIni
:
Boolean
):
string
;
procedure
TFMain
.
RefreshClientList
;
var
snapshots
:
TArray
<
TConnectedClientSnapshot
>;
i
:
Integer
;
begin
snapshots
:=
WsServerModule
.
GetClientSnapshots
;
sgClients
.
RowCount
:=
Length
(
snapshots
)
+
1
;
// +1 for header row
// Header
sgClients
.
Cells
[
0
,
0
]
:=
'Connection ID'
;
sgClients
.
Cells
[
1
,
0
]
:=
'User ID'
;
sgClients
.
Cells
[
2
,
0
]
:=
'Connected At'
;
for
i
:=
0
to
Length
(
snapshots
)
-
1
do
begin
sgClients
.
Cells
[
0
,
i
+
1
]
:=
snapshots
[
i
].
ConnectionId
;
sgClients
.
Cells
[
1
,
i
+
1
]
:=
snapshots
[
i
].
UserId
;
sgClients
.
Cells
[
2
,
i
+
1
]
:=
FormatDateTime
(
'yyyy-mm-dd hh:nn:ss'
,
snapshots
[
i
].
ConnectedAt
);
end
;
tabClients
.
Caption
:=
Format
(
'Connected Clients (%d)'
,
[
Length
(
snapshots
)]);
end
;
{ --- Helpers --- }
function
TFMain
.
LogValue
(
const
LabelName
:
string
;
const
Value
:
string
;
FromIni
:
Boolean
):
string
;
begin
begin
Result
:=
LabelName
+
': '
+
Value
+
IfThen
(
FromIni
,
' [from ini]'
,
' [default]'
);
Result
:=
LabelName
+
': '
+
Value
+
IfThen
(
FromIni
,
' [from ini]'
,
' [default]'
);
end
;
end
;
...
@@ -202,26 +183,26 @@ begin
...
@@ -202,26 +183,26 @@ begin
Logger
.
Log
(
1
,
''
);
Logger
.
Log
(
1
,
''
);
Logger
.
Log
(
1
,
'--- URLs ---'
);
Logger
.
Log
(
1
,
'--- URLs ---'
);
try
try
AuthServerModule
:=
TAuthServerModule
.
Create
(
Self
);
AuthServerModule
:=
TAuthServerModule
.
Create
(
Self
);
AuthServerModule
.
StartAuthServer
(
ServerConfig
.
u
rl
,
AUTH_MODEL
);
AuthServerModule
.
StartAuthServer
(
ServerConfig
.
U
rl
,
AUTH_MODEL
);
ApiServerModule
:=
TApiServerModule
.
Create
(
Self
);
ApiServerModule
:=
TApiServerModule
.
Create
(
Self
);
ApiServerModule
.
StartApiServer
(
ServerConfig
.
u
rl
,
API_MODEL
);
ApiServerModule
.
StartApiServer
(
ServerConfig
.
U
rl
,
API_MODEL
);
AppServerModule
:=
TAppServerModule
.
Create
(
Self
);
AppServerModule
:=
TAppServerModule
.
Create
(
Self
);
AppServerModule
.
StartAppServer
(
ServerConfig
.
u
rl
);
AppServerModule
.
StartAppServer
(
ServerConfig
.
U
rl
);
WsServerModule
:=
TWsServerModule
.
Create
(
Self
);
WsServerModule
:=
TWsServerModule
.
Create
(
Self
);
F
WsServerModule
.
OnClientsChanged
:=
HandleConnectedClientsChanged
;
WsServerModule
.
OnClientsChanged
:=
HandleConnectedClientsChanged
;
FWsServerModule
.
StartWsServer
(
ServerConfig
.
Url
,
WS_MODEL
)
;
WsServerModule
.
StartWsServer
;
except
except
on
E
:
Exception
do
on
E
:
Exception
do
Logger
.
Log
(
2
,
'Failed to start server modules: '
+
E
.
Message
);
Logger
.
Log
(
2
,
'Failed to start server modules: '
+
E
.
Message
);
end
;
end
;
// Initialise the grid headers even before any client connects.
RefreshConnectedClients
;
RefreshClientList
;
end
;
end
;
procedure
TFMain
.
HandleConnectedClientsChanged
;
procedure
TFMain
.
HandleConnectedClientsChanged
;
...
@@ -237,4 +218,29 @@ procedure TFMain.RefreshConnectedClients;
...
@@ -237,4 +218,29 @@ procedure TFMain.RefreshConnectedClients;
var
var
clients
:
TArray
<
TConnectedClientSnapshot
>;
clients
:
TArray
<
TConnectedClientSnapshot
>;
client
:
TConnectedClientSnapshot
;
client
:
TConnectedClientSnapshot
;
begin
begin
\ No newline at end of file
if
not
Assigned
(
WsServerModule
)
then
Exit
;
clients
:=
WsServerModule
.
GetClientSnapshots
;
tblConnectedClients
.
DisableControls
;
try
tblConnectedClients
.
EmptyDataSet
;
for
client
in
clients
do
begin
tblConnectedClients
.
Append
;
tblConnectedClients
.
FieldByName
(
'ConnectionId'
).
AsString
:=
client
.
ConnectionId
;
tblConnectedClients
.
FieldByName
(
'UserId'
).
AsString
:=
client
.
UserId
;
tblConnectedClients
.
FieldByName
(
'ConnectedAt'
).
AsDateTime
:=
client
.
ConnectedAt
;
tblConnectedClients
.
Post
;
end
;
finally
tblConnectedClients
.
EnableControls
;
end
;
tabConnectedClients
.
Caption
:=
Format
(
'Connected Clients (%d)'
,
[
Length
(
clients
)]);
end
;
end
.
emiMobileServer/Source/WebSocket.Manager.pas
View file @
69fafe4a
unit
WebSocket
.
Manager
;
interface
uses
System
.
Classes
,
System
.
SysUtils
,
System
.
JSON
,
System
.
Generics
.
Collections
,
VCL
.
TMSFNCWebSocketServer
,
VCL
.
TMSFNCWebSocketCommon
;
const
WEBSOCKET_PORT
=
8091
;
type
TConnectedClientSnapshot
=
record
ConnectionId
:
string
;
UserId
:
string
;
ConnectedAt
:
TDateTime
;
end
;
TConnectedClient
=
class
private
FConnectionId
:
string
;
FUserId
:
string
;
FConnectedAt
:
TDateTime
;
FConnection
:
TTMSFNCWebSocketServerConnection
;
public
property
ConnectionId
:
string
read
FConnectionId
write
FConnectionId
;
property
UserId
:
string
read
FUserId
write
FUserId
;
property
ConnectedAt
:
TDateTime
read
FConnectedAt
write
FConnectedAt
;
property
Connection
:
TTMSFNCWebSocketServerConnection
read
FConnection
write
FConnection
;
end
;
TClientsChangedEvent
=
procedure
of
object
;
TWebSocketManager
=
class
private
FServer
:
TTMSFNCWebSocketServer
;
FClients
:
TObjectList
<
TConnectedClient
>;
FClientsLock
:
TObject
;
FOnClientsChanged
:
TClientsChangedEvent
;
procedure
NotifyClientsChanged
;
procedure
HandshakeResponseSent
(
Sender
:
TObject
;
AConnection
:
TTMSFNCWebSocketServerConnection
);
procedure
MessageReceived
(
Sender
:
TObject
;
AConnection
:
TTMSFNCWebSocketConnection
;
const
AMessage
:
string
);
procedure
ClientDisconnected
(
Sender
:
TObject
;
AConnection
:
TTMSFNCWebSocketConnection
);
public
constructor
Create
;
destructor
Destroy
;
override
;
procedure
Start
;
procedure
Stop
;
procedure
Broadcast
(
AMessage
:
string
);
procedure
DisconnectClient
(
AConnectionId
:
string
);
procedure
SendMessageToClient
(
AConnectionId
,
AText
:
string
);
function
GetClientSnapshots
:
TArray
<
TConnectedClientSnapshot
>;
property
OnClientsChanged
:
TClientsChangedEvent
read
FOnClientsChanged
write
FOnClientsChanged
;
end
;
implementation
uses
Common
.
Logging
;
constructor
TWebSocketManager
.
Create
;
begin
inherited
Create
;
FClientsLock
:=
TObject
.
Create
;
FClients
:=
TObjectList
<
TConnectedClient
>.
Create
(
True
);
FServer
:=
TTMSFNCWebSocketServer
.
Create
;
FServer
.
Port
:=
WEBSOCKET_PORT
;
FServer
.
UseSSL
:=
False
;
FServer
.
OnHandshakeResponseSent
:=
HandshakeResponseSent
;
FServer
.
OnMessageReceived
:=
MessageReceived
;
FServer
.
OnDisconnect
:=
ClientDisconnected
;
end
;
destructor
TWebSocketManager
.
Destroy
;
begin
Stop
;
FServer
.
Free
;
FClients
.
Free
;
FClientsLock
.
Free
;
inherited
;
end
;
procedure
TWebSocketManager
.
Start
;
begin
FServer
.
Active
:=
True
;
end
;
procedure
TWebSocketManager
.
Stop
;
begin
FServer
.
Active
:=
False
;
end
;
procedure
TWebSocketManager
.
Broadcast
(
AMessage
:
string
);
var
connections
:
TArray
<
TTMSFNCWebSocketServerConnection
>;
i
:
Integer
;
begin
TMonitor
.
Enter
(
FClientsLock
);
try
SetLength
(
connections
,
FClients
.
Count
);
for
i
:=
0
to
FClients
.
Count
-
1
do
connections
[
i
]
:=
FClients
[
i
].
Connection
;
finally
TMonitor
.
Exit
(
FClientsLock
);
end
;
for
i
:=
0
to
Length
(
connections
)
-
1
do
begin
try
connections
[
i
].
Send
(
AMessage
);
except
on
E
:
Exception
do
Logger
.
Log
(
2
,
'WebSocket broadcast failed: '
+
E
.
Message
);
end
;
end
;
end
;
procedure
TWebSocketManager
.
DisconnectClient
(
AConnectionId
:
string
);
var
client
:
TConnectedClient
;
connection
:
TTMSFNCWebSocketServerConnection
;
begin
connection
:=
nil
;
TMonitor
.
Enter
(
FClientsLock
);
try
for
client
in
FClients
do
begin
if
SameText
(
client
.
ConnectionId
,
AConnectionId
)
then
begin
connection
:=
client
.
Connection
;
Break
;
end
;
end
;
finally
TMonitor
.
Exit
(
FClientsLock
);
end
;
if
Assigned
(
connection
)
then
connection
.
SendClose
;
end
;
procedure
TWebSocketManager
.
SendMessageToClient
(
AConnectionId
,
AText
:
string
);
var
client
:
TConnectedClient
;
connection
:
TTMSFNCWebSocketServerConnection
;
json
:
TJSONObject
;
begin
connection
:=
nil
;
TMonitor
.
Enter
(
FClientsLock
);
try
for
client
in
FClients
do
begin
if
SameText
(
client
.
ConnectionId
,
AConnectionId
)
then
begin
connection
:=
client
.
Connection
;
Break
;
end
;
end
;
finally
TMonitor
.
Exit
(
FClientsLock
);
end
;
if
not
Assigned
(
connection
)
then
Exit
;
json
:=
TJSONObject
.
Create
;
try
json
.
AddPair
(
'message'
,
'test_message'
);
json
.
AddPair
(
'text'
,
AText
);
connection
.
Send
(
json
.
ToJSON
);
finally
json
.
Free
;
end
;
end
;
procedure
TWebSocketManager
.
NotifyClientsChanged
;
begin
if
Assigned
(
FOnClientsChanged
)
then
FOnClientsChanged
;
end
;
procedure
TWebSocketManager
.
HandshakeResponseSent
(
Sender
:
TObject
;
AConnection
:
TTMSFNCWebSocketServerConnection
);
var
client
:
TConnectedClient
;
guid
:
TGUID
;
begin
CreateGUID
(
guid
);
client
:=
TConnectedClient
.
Create
;
client
.
ConnectionId
:=
GUIDToString
(
guid
);
client
.
ConnectedAt
:=
Now
;
client
.
Connection
:=
AConnection
;
TMonitor
.
Enter
(
FClientsLock
);
try
FClients
.
Add
(
client
);
finally
TMonitor
.
Exit
(
FClientsLock
);
end
;
AConnection
.
OwnsUserData
:=
False
;
AConnection
.
UserData
:=
client
;
Logger
.
Log
(
1
,
'WebSocket client connected: '
+
client
.
ConnectionId
);
NotifyClientsChanged
;
end
;
procedure
TWebSocketManager
.
MessageReceived
(
Sender
:
TObject
;
AConnection
:
TTMSFNCWebSocketConnection
;
const
AMessage
:
string
);
var
json
:
TJSONValue
;
messageType
:
string
;
userId
:
string
;
connectionId
:
string
;
client
:
TConnectedClient
;
begin
json
:=
TJSONObject
.
ParseJSONValue
(
AMessage
);
try
if
not
Assigned
(
json
)
then
Exit
;
if
not
json
.
TryGetValue
<
string
>(
'message'
,
messageType
)
then
Exit
;
if
messageType
<>
'identify'
then
Exit
;
if
not
json
.
TryGetValue
<
string
>(
'userId'
,
userId
)
then
Exit
;
client
:=
TConnectedClient
(
TTMSFNCWebSocketServerConnection
(
AConnection
).
UserData
);
if
not
Assigned
(
client
)
then
Exit
;
TMonitor
.
Enter
(
FClientsLock
);
try
if
FClients
.
IndexOf
(
client
)
<
0
then
Exit
;
client
.
UserId
:=
userId
;
connectionId
:=
client
.
ConnectionId
;
finally
TMonitor
.
Exit
(
FClientsLock
);
end
;
Logger
.
Log
(
1
,
'WebSocket client identified: '
+
connectionId
+
' - '
+
userId
);
NotifyClientsChanged
;
finally
json
.
Free
;
end
;
end
;
procedure
TWebSocketManager
.
ClientDisconnected
(
Sender
:
TObject
;
AConnection
:
TTMSFNCWebSocketConnection
);
var
serverConnection
:
TTMSFNCWebSocketServerConnection
;
client
:
TConnectedClient
;
connectionId
:
string
;
userId
:
string
;
begin
serverConnection
:=
TTMSFNCWebSocketServerConnection
(
AConnection
);
client
:=
TConnectedClient
(
serverConnection
.
UserData
);
if
not
Assigned
(
client
)
then
Exit
;
connectionId
:=
client
.
ConnectionId
;
userId
:=
client
.
UserId
;
serverConnection
.
UserData
:=
nil
;
TMonitor
.
Enter
(
FClientsLock
);
try
FClients
.
Remove
(
client
);
finally
TMonitor
.
Exit
(
FClientsLock
);
end
;
Logger
.
Log
(
1
,
'WebSocket client disconnected: '
+
connectionId
+
' - '
+
userId
);
NotifyClientsChanged
;
end
;
function
TWebSocketManager
.
GetClientSnapshots
:
TArray
<
TConnectedClientSnapshot
>;
var
i
:
Integer
;
begin
TMonitor
.
Enter
(
FClientsLock
);
try
SetLength
(
Result
,
FClients
.
Count
);
for
i
:=
0
to
FClients
.
Count
-
1
do
begin
Result
[
i
].
ConnectionId
:=
FClients
[
i
].
ConnectionId
;
Result
[
i
].
UserId
:=
FClients
[
i
].
UserId
;
Result
[
i
].
ConnectedAt
:=
FClients
[
i
].
ConnectedAt
;
end
;
finally
TMonitor
.
Exit
(
FClientsLock
);
end
;
end
;
end
.
\ No newline at end of file
emiMobileServer/Source/Ws.DataModel.pas
View file @
69fafe4a
unit
Ws
.
DataModel
;
unit
Ws
.
DataModel
;
// Server-side WebSocket data model.
// Server-side WebSocket data model.
// Owns a VCL timer that fires every FIntervalMs milliseconds, queries the
// Owns a VCL timer that fires every FIntervalMs milliseconds, queries the
...
@@ -39,7 +39,7 @@ type
...
@@ -39,7 +39,7 @@ type
function
BuildUnitListJson
:
string
;
function
BuildUnitListJson
:
string
;
function
BuildComplaintListJson
:
string
;
function
BuildComplaintListJson
:
string
;
public
public
constructor
Create
(
ABroadcast
:
TWsBroadcastProc
;
AIntervalMs
:
Integer
=
30
000
);
constructor
Create
(
ABroadcast
:
TWsBroadcastProc
;
AIntervalMs
:
Integer
=
5
000
);
destructor
Destroy
;
override
;
destructor
Destroy
;
override
;
end
;
end
;
...
@@ -71,6 +71,10 @@ end;
...
@@ -71,6 +71,10 @@ end;
procedure
TWsDataModel
.
TimerFire
(
Sender
:
TObject
);
procedure
TWsDataModel
.
TimerFire
(
Sender
:
TObject
);
begin
begin
if
not
FDb
.
CADUpdate
then
Exit
;
FDb
.
CADUpdate
:=
False
;
BroadcastAll
;
BroadcastAll
;
end
;
end
;
...
@@ -247,6 +251,7 @@ begin
...
@@ -247,6 +251,7 @@ begin
complaintId
:=
FDb
.
uqMapComplaintsCOMPLAINTID
.
AsString
;
complaintId
:=
FDb
.
uqMapComplaintsCOMPLAINTID
.
AsString
;
item
.
AddPair
(
'ComplaintId'
,
complaintId
);
item
.
AddPair
(
'ComplaintId'
,
complaintId
);
item
.
AddPair
(
'Complaint'
,
FDb
.
uqMapComplaintsCOMPLAINT
.
AsString
);
item
.
AddPair
(
'DispatchDistrict'
,
FDb
.
uqMapComplaintsDISPATCHDISTRICT
.
AsString
);
item
.
AddPair
(
'DispatchDistrict'
,
FDb
.
uqMapComplaintsDISPATCHDISTRICT
.
AsString
);
item
.
AddPair
(
'Agency'
,
FDb
.
uqMapComplaintsAGENCY
.
AsString
);
item
.
AddPair
(
'Agency'
,
FDb
.
uqMapComplaintsAGENCY
.
AsString
);
item
.
AddPair
(
'AgencyName'
,
FDb
.
uqMapComplaintsAGENCY_NAME
.
AsString
);
item
.
AddPair
(
'AgencyName'
,
FDb
.
uqMapComplaintsAGENCY_NAME
.
AsString
);
...
...
emiMobileServer/Source/Ws.Server.Module.dfm
View file @
69fafe4a
object WsServerModule: TWsServerModule
object WsServerModule: TWsServerModule
OldCreateOrder = False
OnCreate = DataModuleCreate
OnCreate = DataModuleCreate
OnDestroy = DataModuleDestroy
OnDestroy = DataModuleDestroy
Height = 150
Height = 150
...
...
emiMobileServer/Source/Ws.Server.Module.pas
View file @
69fafe4a
...
@@ -17,11 +17,12 @@ type
...
@@ -17,11 +17,12 @@ type
function
GetOnClientsChanged
:
TClientsChangedEvent
;
function
GetOnClientsChanged
:
TClientsChangedEvent
;
procedure
SetOnClientsChanged
(
const
AValue
:
TClientsChangedEvent
);
procedure
SetOnClientsChanged
(
const
AValue
:
TClientsChangedEvent
);
public
public
procedure
StartWsServer
(
ABaseUrl
:
string
;
AModelName
:
string
)
;
procedure
StartWsServer
;
procedure
Broadcast
(
const
AMessage
:
string
);
procedure
Broadcast
(
const
AMessage
:
string
);
function
GetClientSnapshots
:
TArray
<
TConnectedClientSnapshot
>;
function
GetClientSnapshots
:
TArray
<
TConnectedClientSnapshot
>;
property
OnClientsChanged
:
TClientsChangedEvent
property
OnClientsChanged
:
TClientsChangedEvent
read
GetOnClientsChanged
write
SetOnClientsChanged
;
read
GetOnClientsChanged
write
SetOnClientsChanged
;
procedure
DisconnectClient
(
AConnectionId
:
string
);
procedure
SendMessageToClient
(
AConnectionId
,
AText
:
string
);
end
;
end
;
var
var
...
@@ -48,7 +49,7 @@ begin
...
@@ -48,7 +49,7 @@ begin
FManager
:=
nil
;
FManager
:=
nil
;
end
;
end
;
procedure
TWsServerModule
.
StartWsServer
(
ABaseUrl
:
string
;
AModelName
:
string
)
;
procedure
TWsServerModule
.
StartWsServer
;
begin
begin
FManager
.
Start
;
FManager
.
Start
;
Logger
.
Log
(
1
,
Format
(
'WebSocket server listening on port %d'
,
[
WEBSOCKET_PORT
]));
Logger
.
Log
(
1
,
Format
(
'WebSocket server listening on port %d'
,
[
WEBSOCKET_PORT
]));
...
@@ -58,9 +59,9 @@ begin
...
@@ -58,9 +59,9 @@ begin
begin
begin
Broadcast
(
AMessage
);
Broadcast
(
AMessage
);
end
,
end
,
30000
// broadcast
interval in ms
5000
// notification check
interval in ms
);
);
Logger
.
Log
(
1
,
'WsDataModel started (
30 s broadcast
interval)'
);
Logger
.
Log
(
1
,
'WsDataModel started (
5 s notification check
interval)'
);
end
;
end
;
procedure
TWsServerModule
.
Broadcast
(
const
AMessage
:
string
);
procedure
TWsServerModule
.
Broadcast
(
const
AMessage
:
string
);
...
@@ -68,6 +69,16 @@ begin
...
@@ -68,6 +69,16 @@ begin
FManager
.
Broadcast
(
AMessage
);
FManager
.
Broadcast
(
AMessage
);
end
;
end
;
procedure
TWsServerModule
.
DisconnectClient
(
AConnectionId
:
string
);
begin
FManager
.
DisconnectClient
(
AConnectionId
);
end
;
procedure
TWsServerModule
.
SendMessageToClient
(
AConnectionId
,
AText
:
string
);
begin
FManager
.
SendMessageToClient
(
AConnectionId
,
AText
);
end
;
function
TWsServerModule
.
GetClientSnapshots
:
TArray
<
TConnectedClientSnapshot
>;
function
TWsServerModule
.
GetClientSnapshots
:
TArray
<
TConnectedClientSnapshot
>;
begin
begin
Result
:=
FManager
.
GetClientSnapshots
;
Result
:=
FManager
.
GetClientSnapshots
;
...
...
emiMobileServer/bin/emiMobileServer.ini
View file @
69fafe4a
[Settings]
[Settings]
LogFileNum
=
74
3
LogFileNum
=
74
6
webClientVersion
=
9.4.0
webClientVersion
=
9.4.0
[Database]
[Database]
...
...
emiMobileServer/emiMobileServer.dproj
View file @
69fafe4a
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<PropertyGroup>
<ProjectGuid>{2A3028D9-BC39-4625-9BA5-0338012E2824}</ProjectGuid>
<ProjectGuid>{2A3028D9-BC39-4625-9BA5-0338012E2824}</ProjectGuid>
<ProjectVersion>20.4</ProjectVersion>
<ProjectVersion>20.4</ProjectVersion>
...
@@ -871,6 +871,9 @@
...
@@ -871,6 +871,9 @@
<Platform Name="Win64x">
<Platform Name="Win64x">
<Operation>1</Operation>
<Operation>1</Operation>
</Platform>
</Platform>
<Platform Name="WinARM64EC">
<Operation>1</Operation>
</Platform>
</DeployClass>
</DeployClass>
<DeployClass Name="ProjectiOSDeviceDebug">
<DeployClass Name="ProjectiOSDeviceDebug">
<Platform Name="iOSDevice32">
<Platform Name="iOSDevice32">
...
@@ -941,6 +944,10 @@
...
@@ -941,6 +944,10 @@
<RemoteDir>Assets</RemoteDir>
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
<Operation>1</Operation>
</Platform>
</Platform>
<Platform Name="WinARM64EC">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
</DeployClass>
<DeployClass Name="UWP_DelphiLogo44">
<DeployClass Name="UWP_DelphiLogo44">
<Platform Name="Win32">
<Platform Name="Win32">
...
@@ -951,6 +958,10 @@
...
@@ -951,6 +958,10 @@
<RemoteDir>Assets</RemoteDir>
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
<Operation>1</Operation>
</Platform>
</Platform>
<Platform Name="WinARM64EC">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
</DeployClass>
<DeployClass Name="iOS_AppStore1024">
<DeployClass Name="iOS_AppStore1024">
<Platform Name="iOSDevice64">
<Platform Name="iOSDevice64">
...
...
webEMIMobile/ConnectionModule.pas
View file @
69fafe4a
...
@@ -20,7 +20,7 @@ type
...
@@ -20,7 +20,7 @@ type
FWsUrl
:
string
;
FWsUrl
:
string
;
public
public
property
WsUrl
:
string
read
FWsUrl
;
property
WsUrl
:
string
read
FWsUrl
;
const
clientVersion
=
'
0.1
.0'
;
const
clientVersion
=
'
9.4
.0'
;
procedure
InitApp
(
SuccessProc
:
TSuccessProc
;
procedure
InitApp
(
SuccessProc
:
TSuccessProc
;
UnauthorizedAccessProc
:
TUnauthorizedAccessProc
);
UnauthorizedAccessProc
:
TUnauthorizedAccessProc
);
procedure
SetClientConfig
(
Callback
:
TVersionCheckCallback
);
procedure
SetClientConfig
(
Callback
:
TVersionCheckCallback
);
...
...
webEMIMobile/Module.Websocket.dfm
View file @
69fafe4a
object dmWebsocket: TdmWebsocket
object dmWebsocket: TdmWebsocket
OnCreate = WebDataModuleCreate
OnDestroy = WebDataModuleDestroy
Height = 480
Height = 480
Width = 640
Width = 640
object EMiMobileWebSocketClient: TWebSocketClient
object EMiMobileWebSocketClient: TWebSocketClient
...
@@ -6,7 +8,6 @@ object dmWebsocket: TdmWebsocket
...
@@ -6,7 +8,6 @@ object dmWebsocket: TdmWebsocket
Port = 443
Port = 443
HostName = 'webapps.em-sys.net'
HostName = 'webapps.em-sys.net'
PathName = '/emiMobile/ws/emimobile'
PathName = '/emiMobile/ws/emimobile'
Protocols.Strings = ()
OnConnect = EMiMobileWebSocketClientConnect
OnConnect = EMiMobileWebSocketClientConnect
OnBinaryDataReceived = EMiMobileWebSocketClientBinaryDataReceived
OnBinaryDataReceived = EMiMobileWebSocketClientBinaryDataReceived
OnDisconnect = EMiMobileWebSocketClientDisconnect
OnDisconnect = EMiMobileWebSocketClientDisconnect
...
...
webEMIMobile/Module.Websocket.pas
View file @
69fafe4a
unit
Module
.
Websocket
;
unit
Module
.
Websocket
;
interface
interface
...
@@ -11,6 +11,8 @@ type
...
@@ -11,6 +11,8 @@ type
TWsDataHandler
=
procedure
(
aData
:
TJSObject
)
of
object
;
TWsDataHandler
=
procedure
(
aData
:
TJSObject
)
of
object
;
TdmWebsocket
=
class
(
TWebDataModule
)
TdmWebsocket
=
class
(
TWebDataModule
)
procedure
WebDataModuleCreate
(
Sender
:
TObject
);
procedure
WebDataModuleDestroy
(
Sender
:
TObject
);
private
private
procedure
EMiMobileWebSocketClientConnect
(
Sender
:
TObject
);
procedure
EMiMobileWebSocketClientConnect
(
Sender
:
TObject
);
...
@@ -32,7 +34,6 @@ type
...
@@ -32,7 +34,6 @@ type
public
public
EMiMobileWebSocketClient
:
TWebSocketClient
;
EMiMobileWebSocketClient
:
TWebSocketClient
;
procedure
DataModuleCreate
(
Sender
:
TObject
);
procedure
Connect
(
const
AWsUrl
:
string
);
procedure
Connect
(
const
AWsUrl
:
string
);
// Assign these before calling Connect so that pushes are routed immediately.
// Assign these before calling Connect so that pushes are routed immediately.
...
@@ -53,11 +54,6 @@ implementation
...
@@ -53,11 +54,6 @@ implementation
{$R *.dfm}
{$R *.dfm}
procedure
TdmWebsocket
.
DataModuleCreate
(
Sender
:
TObject
);
begin
end
;
procedure
TdmWebsocket
.
Connect
(
const
AWsUrl
:
string
);
procedure
TdmWebsocket
.
Connect
(
const
AWsUrl
:
string
);
var
var
Rest
,
HostPort
,
Scheme
,
Path
,
Token
:
string
;
Rest
,
HostPort
,
Scheme
,
Path
,
Token
:
string
;
...
@@ -116,23 +112,31 @@ begin
...
@@ -116,23 +112,31 @@ begin
EMiMobileWebSocketClient
.
Port
:=
80
;
EMiMobileWebSocketClient
.
Port
:=
80
;
end
;
end
;
console
.
log
(
'WS: connecting to '
+
AWsUrl
);
EMiMobileWebSocketClient
.
UseSSL
:=
(
Scheme
=
'wss'
);
EMiMobileWebSocketClient
.
UseSSL
:=
(
Scheme
=
'wss'
);
EMiMobileWebSocketClient
.
Active
:=
True
;
EMiMobileWebSocketClient
.
Active
:=
True
;
console
.
log
(
'WS: Active set to true'
);
end
;
end
;
procedure
TdmWebsocket
.
DispatchMessage
(
const
AMessage
:
string
);
procedure
TdmWebsocket
.
DispatchMessage
(
const
AMessage
:
string
);
var
var
obj
:
TJSObject
;
obj
:
TJSObject
;
requestId
:
string
;
requestId
:
string
;
messageType
:
string
;
messageText
:
string
;
begin
begin
if
AMessage
=
''
then
if
AMessage
=
''
then
Exit
;
Exit
;
asm
asm
try
{
{
obj = JSON.parse(AMessage);
try {
}
catch
(
e
)
{
obj = JSON.parse(AMessage);
obj = null;
}
catch
(
e
)
{
obj = null;
}
}
}
end
;
end
;
...
@@ -142,8 +146,20 @@ begin
...
@@ -142,8 +146,20 @@ begin
Exit
;
Exit
;
end
;
end
;
messageType
:=
string
(
obj
[
'message'
]);
if
SameText
(
messageType
,
'test_message'
)
then
begin
messageText
:=
string
(
obj
[
'text'
]);
window
.
alert
(
messageText
);
Exit
;
end
;
requestId
:=
string
(
obj
[
'RequestId'
]);
requestId
:=
string
(
obj
[
'RequestId'
]);
if
requestId
<>
''
then
console
.
log
(
'WS: received '
+
requestId
);
if
SameText
(
requestId
,
'BADGE_COUNTS'
)
then
if
SameText
(
requestId
,
'BADGE_COUNTS'
)
then
begin
begin
if
Assigned
(
FOnBadgeCounts
)
then
FOnBadgeCounts
(
obj
);
if
Assigned
(
FOnBadgeCounts
)
then
FOnBadgeCounts
(
obj
);
...
@@ -175,8 +191,16 @@ begin
...
@@ -175,8 +191,16 @@ begin
end
;
end
;
procedure
TdmWebsocket
.
EMiMobileWebSocketClientConnect
(
Sender
:
TObject
);
procedure
TdmWebsocket
.
EMiMobileWebSocketClientConnect
(
Sender
:
TObject
);
var
msg
:
TJSObject
;
begin
begin
console
.
log
(
'WS: connected'
);
console
.
log
(
'WS: connected'
);
msg
:=
TJSObject
.
new
;
msg
[
'message'
]
:=
'identify'
;
msg
[
'userId'
]
:=
JS
.
toString
(
AuthService
.
TokenPayload
.
Properties
[
'user_name'
]);
EMiMobileWebSocketClient
.
Send
(
TJSJSON
.
stringify
(
msg
));
end
;
end
;
procedure
TdmWebsocket
.
EMiMobileWebSocketClientDataReceived
(
Sender
:
TObject
;
procedure
TdmWebsocket
.
EMiMobileWebSocketClientDataReceived
(
Sender
:
TObject
;
...
@@ -196,4 +220,18 @@ begin
...
@@ -196,4 +220,18 @@ begin
DispatchMessage
(
AMessage
);
DispatchMessage
(
AMessage
);
end
;
end
;
procedure
TdmWebsocket
.
WebDataModuleCreate
(
Sender
:
TObject
);
begin
console
.
log
(
'WS: datamodule created'
);
EMiMobileWebSocketClient
.
OnConnect
:=
EMiMobileWebSocketClientConnect
;
EMiMobileWebSocketClient
.
OnDisconnect
:=
EMiMobileWebSocketClientDisconnect
;
EMiMobileWebSocketClient
.
OnMessageReceived
:=
EMiMobileWebSocketClientMessageReceived
;
end
;
procedure
TdmWebsocket
.
WebDataModuleDestroy
(
Sender
:
TObject
);
begin
end
;
end
.
end
.
webEMIMobile/View.Main.dfm
View file @
69fafe4a
...
@@ -238,13 +238,4 @@ object FViewMain: TFViewMain
...
@@ -238,13 +238,4 @@ object FViewMain: TFViewMain
Left = 42
Left = 42
Top = 434
Top = 434
end
end
object wsClient: TWebSocketClient
Port = 8091
HostName = '127.0.0.1'
OnConnect = wsClientConnect
OnDisconnect = wsClientDisconnect
OnDataReceived = wsClientDataReceived
Left = 62
Top = 654
end
end
end
webEMIMobile/View.Main.pas
View file @
69fafe4a
unit
View
.
Main
;
unit
View
.
Main
;
interface
interface
...
...
webEMIMobile/config/config.json
View file @
69fafe4a
...
@@ -2,5 +2,5 @@
...
@@ -2,5 +2,5 @@
"AuthUrl"
:
"http://localhost:2009/emimobile/auth/"
,
"AuthUrl"
:
"http://localhost:2009/emimobile/auth/"
,
"ApiUrl"
:
"http://localhost:2009/emimobile/api/"
,
"ApiUrl"
:
"http://localhost:2009/emimobile/api/"
,
"AppUrl"
:
"http://localhost:2009/emimobile/app/"
,
"AppUrl"
:
"http://localhost:2009/emimobile/app/"
,
"WsUrl"
:
"ws://localhost:2009/emiMobile/ws/emimobile
"
"WsUrl"
:
"ws://localhost:8091/
"
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment