-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathOnlineOfflineU.pas
191 lines (160 loc) · 4.2 KB
/
OnlineOfflineU.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
unit OnlineOfflineU;
interface
uses
System.Threading, System.Generics.Collections, System.MulticastEventU, idHTTP;
{$M+,O+}
{$IFOPT O-}
{$MESSAGE Fatal 'Optimization _must_ be turned on for this unit to work!'}
{$ENDIF}
{$HINTS OFF}
// Hints off in order for hiding message;
// [dcc32 Hint] OnlineOfflineU.pas(29): H2269 Overriding virtual method 'TOnlineOffline.Destroy' has lower visibility (private) than base class 'TThread' (public)
type
TOnlineState = (Offline, Online);
TStateChanged = procedure(const NewState: TOnlineState) of object;
iStateChanged = interface
['{47BF0544-238C-4721-A847-ED03C2F77113}']
procedure OnStateChanged(const NewState: TOnlineState);
end;
TMulticastStateChangedEvent = TMulticastEvent<TStateChanged>;
TOnlineOffline = class
private const
DestinationSite = 'http://www.google.com';
class var FInstance: TOnlineOffline;
private
FidHTTP: TIdHTTP;
FScanningInterval: Integer;
FOnlineState: TOnlineState;
FStateChangedNotifiers: TMulticastStateChangedEvent;
FTask: ITask;
FTerminated: Boolean;
constructor Create; reintroduce;
destructor Destroy; override;
procedure CheckState(aForceNotify: Boolean = false);
procedure DoNotify;
procedure SetOnlineState(const Value: TOnlineState);
procedure StartTask;
procedure SetScanningInterval(const Value: Integer);
public
class destructor Destroy;
class function Instance: TOnlineOffline;
procedure Start;
procedure Stop;
published
property ScanningInterval: Integer read FScanningInterval write SetScanningInterval;
property OnlineState: TOnlineState read FOnlineState write SetOnlineState;
property StateChangedNotifiers: TMulticastStateChangedEvent read FStateChangedNotifiers;
property Terminated: Boolean read FTerminated;
end;
{$HINTS ON}
function OnlineOffline: TOnlineOffline;
implementation
uses
System.Classes, System.Sysutils;
{ TOnlineOffline }
function OnlineOffline: TOnlineOffline;
begin
Result := TOnlineOffline.Instance;
end;
constructor TOnlineOffline.Create;
begin
inherited Create;
FScanningInterval := 10;
FStateChangedNotifiers := TMulticastStateChangedEvent.Create;
FOnlineState := TOnlineState.Online;
FidHTTP := TIdHTTP.Create(nil);
Start;
end;
destructor TOnlineOffline.Destroy;
begin
Stop;
FStateChangedNotifiers.Free;
FidHTTP.Free;
inherited;
end;
class destructor TOnlineOffline.Destroy;
begin
FreeAndNil(FInstance);
end;
procedure TOnlineOffline.CheckState(aForceNotify: Boolean = false);
var
NewState: TOnlineState;
begin
try
FidHTTP.Get(DestinationSite);
NewState := TOnlineState.Online;
except
NewState := TOnlineState.Offline;
end;
if aForceNotify or (NewState <> FOnlineState) then
begin
FOnlineState := NewState;
DoNotify;
end;
end;
procedure TOnlineOffline.DoNotify;
begin
TThread.Queue(TThread.Current,
procedure
begin
FStateChangedNotifiers.Invoke(FOnlineState);
end);
end;
class function TOnlineOffline.Instance: TOnlineOffline;
begin
if FInstance = nil then
FInstance := TOnlineOffline.Create;
Result := FInstance;
end;
procedure TOnlineOffline.SetOnlineState(const Value: TOnlineState);
begin
FOnlineState := Value;
DoNotify;
end;
procedure TOnlineOffline.SetScanningInterval(const Value: Integer);
begin
FScanningInterval := Value;
StartTask;
end;
procedure TOnlineOffline.Start;
begin
StartTask;
end;
procedure TOnlineOffline.StartTask;
begin
Stop;
FTerminated := false;
FTask := TTask.Run(
procedure
var
Counter: Integer;
const
InternalSleepInterval = 100;
begin
Counter := 0;
repeat
Sleep(InternalSleepInterval);
Inc(Counter);
until (Terminated) or (Counter = 2);
if Terminated then
exit;
CheckState(True);
while not Terminated do
begin
Counter := 0;
repeat
Sleep(InternalSleepInterval);
Inc(Counter);
until (Terminated) or (Counter = (FScanningInterval * MSecsPerSec) div InternalSleepInterval);
if not Terminated then
CheckState;
end;
end);
end;
procedure TOnlineOffline.Stop;
begin
FTerminated := True;
if Assigned(FTask) then
FTask.Wait;
end;
end.