This repository has been archived by the owner on Sep 14, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 16
/
nosotime.pas
185 lines (162 loc) · 4.7 KB
/
nosotime.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
unit NosoTime;
{
Nosotime 1.3
September 20th, 2023
Noso Time Unit for time synchronization on Noso project.
Requires indy package. (To-do: remove this dependancy)
Changes:
- Random use of NTP servers.
- Async process limited to every 5 seconds.
- Block time related functions.
- Test NTPs.
}
{$mode ObjFPC}{$H+}
interface
uses
Classes, SysUtils, IdSNTP, DateUtils, strutils;
Type
TThreadUpdateOffset = class(TThread)
private
Hosts: string;
protected
procedure Execute; override;
public
constructor Create(const CreatePaused: Boolean; const THosts:string);
end;
Function GetNetworkTimestamp(hostname:string):int64;
function TimestampToDate(timestamp:int64):String;
Function GetTimeOffset(NTPServers:String):int64;
Function UTCTime:Int64;
Function UTCTimeStr:String;
Procedure UpdateOffset(NTPServers:String);
function TimeSinceStamp(Lvalue:int64):string;
Function BlockAge():integer;
Function NextBlockTimeStamp():Int64;
Function IsBlockOpen():boolean;
Var
NosoT_TimeOffset : int64 = 0;
NosoT_LastServer : string = '';
NosoT_LastUpdate : int64 = 0;
IMPLEMENTATION
constructor TThreadUpdateOffset.Create(const CreatePaused: Boolean; const THosts:string);
begin
inherited Create(CreatePaused);
Hosts := THosts;
end;
procedure TThreadUpdateOffset.Execute;
Begin
GetTimeOffset(Hosts);
End;
{Returns the data from the specified NTP server [Hostname]}
Function GetNetworkTimestamp(hostname:string):int64;
var
NTPClient: TIdSNTP;
begin
result := 0;
NTPClient := TIdSNTP.Create(nil);
TRY
NTPClient.Host := hostname;
NTPClient.Active := True;
NTPClient.ReceiveTimeout:=500;
result := DateTimeToUnix(NTPClient.DateTime);
if result <0 then result := 0;
EXCEPT on E:Exception do
result := 0;
END; {TRY}
NTPClient.Free;
end;
{Returns a UNIX timestamp in a human readeable format}
function TimestampToDate(timestamp:int64):String;
begin
result := DateTimeToStr(UnixToDateTime(TimeStamp));
end;
{
Uses a random NTP server from the list provided to set the value of the local variables.
NTPservers string must use NosoCFG format: server1:server2:server3:....serverX:
If directly invoked, will block the main thread until finish. (not recommended except on app launchs)
}
Function GetTimeOffset(NTPServers:String):int64;
var
Counter : integer = 0;
ThisNTP : int64;
MyArray : array of string;
RanNumber : integer;
Begin
Result := 0;
NTPServers := StringReplace(NTPServers,':',' ',[rfReplaceAll, rfIgnoreCase]);
NTPServers := Trim(NTPServers);
MyArray := SplitString(NTPServers,' ');
Rannumber := Random(length(MyArray));
For Counter := 0 to length(MyArray)-1 do
begin
ThisNTP := GetNetworkTimestamp(MyArray[Rannumber]);
if ThisNTP>0 then
begin
Result := ThisNTP - DateTimeToUnix(Now);
NosoT_LastServer := MyArray[Rannumber];
NosoT_LastUpdate := UTCTime;
break;
end;
Inc(RanNumber);
If RanNumber >= length(MyArray)-1 then RanNumber := 0;
end;
NosoT_TimeOffset := Result;
End;
{Returns the UTC UNIX timestamp}
Function UTCTime:Int64;
Begin
Result := DateTimeToUnix(Now, False) +NosoT_TimeOffset;
End;
{Implemented for easy compatibility with nosowallet}
Function UTCTimeStr:String;
Begin
Result := InttoStr(DateTimeToUnix(Now, False) +NosoT_TimeOffset);
End;
{Implemented to allow an async update of the offset; can be called every 5 seconds max}
Procedure UpdateOffset(NTPServers:String);
const
LastRun : int64 = 0;
var
LThread : TThreadUpdateOffset;
Begin
if UTCTime <= LastRun+4 then exit;
LastRun := UTCTime;
LThread := TThreadUpdateOffset.Create(true,NTPservers);
LThread.FreeOnTerminate:=true;
LThread.Start;
End;
{Tool: returns a simple string with the time elapsed since the provided timestamp [LValue]}
function TimeSinceStamp(Lvalue:int64):string;
var
Elapsed : Int64 = 0;
Begin
Elapsed := UTCTime - Lvalue;
if Elapsed div 60 < 1 then result := IntToStr(Elapsed)+'s'
else if Elapsed div 3600 < 1 then result := IntToStr(Elapsed div 60)+'m'
else if Elapsed div 86400 < 1 then result := IntToStr(Elapsed div 3600)+'h'
else if Elapsed div 2592000 < 1 then result := IntToStr(Elapsed div 86400)+'d'
else if Elapsed div 31536000 < 1 then result := IntToStr(Elapsed div 2592000)+'M'
else result := IntToStr(Elapsed div 31536000)+' Y';
end;
{Return the current block age}
Function BlockAge():integer;
Begin
Result := UTCtime mod 600;
End;
{Returns the expected timestamp for next block}
Function NextBlockTimeStamp():Int64;
var
currTime : int64;
Remains : int64;
Begin
CurrTime := UTCTime;
Remains := 600-(CurrTime mod 600);
Result := CurrTime+Remains;
End;
{Returns if the current block is in operation period}
Function IsBlockOpen():boolean;
Begin
result := true;
if ( (BlockAge<10) or (BlockAge>585) ) then result := false;
End;
END. // END UNIT