-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathCoreApiClient.pas
More file actions
140 lines (117 loc) · 3.35 KB
/
Copy pathCoreApiClient.pas
File metadata and controls
140 lines (117 loc) · 3.35 KB
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
unit CoreApiClient;
interface
uses
Winapi.Windows, System.SysUtils, System.Classes, System.Generics.Collections,
SingBoxConfig, System.Net.HttpClient, System.Net.URLClient, Logger;
type
TCoreApiClient = class
private
FClashApiConfig: TClashApiConfig;
FLogger: TLogger;
FHttpClient: THTTPClient;
procedure Log(const AMessage: string);
public
constructor Create(AClashApiConfig: TClashApiConfig; ALogger: TLogger);
destructor Destroy; override;
function IsConfigured: boolean;
function CheckReady: boolean;
procedure SendClashApiRequest(method, path, data: string; timeoutMs: integer = 1000);
end;
implementation
constructor TCoreApiClient.Create(AClashApiConfig: TClashApiConfig; ALogger: TLogger);
begin
FClashApiConfig := AClashApiConfig;
FLogger := ALogger;
FHttpClient := THTTPClient.Create;
FHttpClient.ProxySettings := TProxySettings.Create('http://direct');
end;
destructor TCoreApiClient.Destroy;
begin
FreeAndNil(FHttpClient);
inherited;
end;
function TCoreApiClient.IsConfigured: boolean;
begin
result := FClashApiConfig.IsConfigured;
end;
function TCoreApiClient.CheckReady: boolean;
begin
result := false;
if not IsConfigured then
exit;
try
Log('API check...');
SendClashApiRequest('GET', '/version', '');
Log('API check: successful.');
result := true;
except
on E: Exception do
begin
Log(trim('API check: failed. ' + E.Message));
end;
end;
end;
procedure TCoreApiClient.SendClashApiRequest(method, path, data: string; timeoutMs: integer);
var
client: THTTPClient;
body: TStringStream;
headers: TNetHeaders;
url: string;
response: IHTTPResponse;
startTick: UInt64;
elapsedMs: UInt64;
requestInfo: string;
begin
if not IsConfigured then
raise Exception.Create('Clash API is not configured.');
url := 'http://' + FClashApiConfig.externalController + path;
client := FHttpClient;
client.ConnectionTimeout := timeoutMs;
client.SendTimeout := timeoutMs;
client.ResponseTimeout := timeoutMs;
body := TStringStream.Create(data, TEncoding.UTF8);
try
SetLength(headers, 2);
headers[0].name := 'Authorization';
headers[0].value := 'Bearer ' + FClashApiConfig.secret;
headers[1].name := 'Content-Type';
headers[1].value := 'application/json';
startTick := GetTickCount64;
try
if SameText(method, 'GET') then
begin
response := client.Get(url, nil, headers);
end
else if SameText(method, 'PUT') then
begin
response := client.Put(url, body, nil, headers);
end
else if SameText(method, 'DELETE') then
begin
response := client.Delete(url, nil, headers);
end
else
begin
raise Exception.Create('Invalid method.');
end;
if response.StatusCode div 100 <> 2 then
raise Exception.CreateFmt('HTTP %d.', [response.StatusCode]);
except
on E: Exception do
begin
elapsedMs := GetTickCount64 - startTick;
requestInfo := method + ' ' + path;
if data <> '' then
requestInfo := requestInfo + ' ' + data;
raise Exception.CreateFmt('%s after %d ms. [%s] %s', [requestInfo, elapsedMs, E.ClassName, trim(E.Message)]);
end;
end;
finally
body.Free;
end;
end;
procedure TCoreApiClient.Log(const AMessage: string);
begin
FLogger.Log('API', AMessage);
end;
end.