Skip to content

Commit 499a1f7

Browse files
ADD: Rest CMD to shutdown
1 parent ddb3648 commit 499a1f7

File tree

5 files changed

+90
-7
lines changed

5 files changed

+90
-7
lines changed

src/CopyCommander2.lpi

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@
152152
</Linking>
153153
</CompilerOptions>
154154
<Debugging>
155-
<Exceptions Count="3">
155+
<Exceptions Count="4">
156156
<Item1>
157157
<Name Value="EAbort"/>
158158
</Item1>
@@ -162,6 +162,9 @@
162162
<Item3>
163163
<Name Value="EFOpenError"/>
164164
</Item3>
165+
<Item4>
166+
<Name Value="Exception"/>
167+
</Item4>
165168
</Exceptions>
166169
</Debugging>
167170
</CONFIG>

src/rest.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Zombie paths are used to control the application (visible to the user), to enabl
1717
| --- | --- | --- | --- |
1818
| GET | [/API/status](#get-apistatus) | normal | get current state of application
1919
| GET | [/API/view/list](#get-apiviewlist) | normal | get list of content from a spezific view
20+
| POST | [/API/shutdown](#post-apishutdown) | normal | shutdown CopyCommander2
2021
| POST | [/API/zombie/setdir](#post-apizombiesetdir) | zombie | set directory path for left or right view
2122

2223
## GET /API/status
@@ -183,6 +184,36 @@ Creates a new job to copy, move, or delete files/folders.
183184
}
184185
```
185186

187+
## POST /API/shutdown
188+
189+
Shuts down the CopyCommander2 application.
190+
191+
### Request
192+
193+
**Method:** POST
194+
**Path:** `/API/shutdown`
195+
**Content-Type:** `application/json`
196+
197+
### Request Schema
198+
199+
| Field | Type | Required | Description |
200+
|-------|------|----------|-------------|
201+
| `skipJobs` | boolean | No | Whether to skip currently running jobs (default: false) |
202+
203+
### Example Request
204+
205+
```json
206+
{
207+
"skipJobs": true
208+
}
209+
```
210+
211+
### Response
212+
213+
**HTTP Status Codes:**
214+
- `200 OK` - Application shutdown initiated successfully
215+
- `403 Forbidden` - Shutdown not allowed (jobs are running and skipJobs is false)
216+
186217
## POST /API/zombie/setdir
187218

188219
Sets the directory path for either the left or right view.

src/unit1.pas

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,7 @@
299299
public
300300
fWorkThread: TWorkThread; // Bäh wieder Private machen !
301301
fLeftView, fRightView: TView; // Bäh wieder Private machen !
302+
fShutdownbyRestRequest: Boolean;
302303
Procedure LoadDir(Dir: String; Var View: TView; ForceElementBufferRefresh: Boolean = false);
303304
Procedure AddToJobQueue(Const Job: TJob); //Fügt non LCL Blocking in die JobQueue ein
304305
End;
@@ -636,7 +637,7 @@
636637
startup := true;
637638
fJobFifo := TJobFifo.create;
638639
GetElementCountBuffer := Nil;
639-
640+
fShutdownbyRestRequest := false;
640641
CheckAndMaybeEnableRestAPI;
641642
End;
642643

@@ -688,6 +689,9 @@
688689
End;
689690

690691
Procedure TForm1.ApplicationProperties1Idle(Sender: TObject; Var Done: Boolean);
692+
Const
693+
CloseTimer: QWord = 0;
694+
CloseTimeout = 250; // Das Verzögert das automatische beenden, in der Hoffnung, dass die ggf. noch Ausstehende Antwort auf jeden Fall raus geht.
691695
Var
692696
j: TJob;
693697
Begin
@@ -739,6 +743,17 @@
739743
End;
740744
HandleJobQueue();
741745
End;
746+
If fShutdownbyRestRequest Then Begin
747+
// TODO: Prüfen ob gerade noch was gesendet wird (kann die LTPComponente dass ?)
748+
If CloseTimer = 0 Then Begin
749+
CloseTimer := GetTickCount64;
750+
End
751+
Else Begin
752+
If GetTickCount64 > CloseTimer + CloseTimeout Then Begin
753+
close;
754+
End;
755+
End;
756+
End;
742757
sleep(1);
743758
End;
744759

src/urest.pas

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
(******************************************************************************)
22
(* uRest.pas 11.08.2025 *)
33
(* *)
4-
(* Version : 0.04 *)
4+
(* Version : 0.05 *)
55
(* *)
66
(* Author : Uwe Schächterle (Corpsman) *)
77
(* *)
@@ -26,6 +26,7 @@
2626
(* 0.02 - Initial version (client) *)
2727
(* 0.03 - ADD HTTPHeader to getHandler *)
2828
(* 0.04 - support more detailed post results *)
29+
(* 0.05 - support post with no params *)
2930
(* *)
3031
(******************************************************************************)
3132

@@ -674,16 +675,15 @@
674675
j := Nil;
675676
Try
676677
j := jp.Parse(Body.Text);
677-
If Not assigned(j) Then Raise exception.create('Blub'); // Wir wollen einfach in den Fehlerhandler ;)
678678
Except
679679
// Fehler Anfrage nicht Parsbar
680680
SendResponce(
681681
400, '{"error":' + StringToJsonString('Post ' + Path + ' without valid data') + '}',
682682
aSocket
683683
);
684+
exit;
684685
End;
685686
jp.Free;
686-
If Not assigned(j) Then exit;
687687
End;
688688
// Suchen eines Passenden Handlers für den Pfad
689689
For i := 0 To high(fPostPaths) Do Begin
@@ -696,11 +696,11 @@
696696
Else Begin
697697
SendResponce(PostRes.HTTPCode, '', aSocket);
698698
End;
699-
j.free;
699+
If assigned(j) Then j.free;
700700
exit;
701701
End;
702702
End;
703-
j.free;
703+
If assigned(j) Then j.free;
704704
// Fehler kein Handler definiert
705705
SendResponce(
706706
501,

src/urestapi.pas

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
* Alle Post Methoden
6161
*)
6262
Function Setdir(Sender: TObject; Const aPath: String; Const aContent: TJSONObj): TPostResult;
63+
Function Shutdown(Sender: TObject; Const aPath: String; Const aContent: TJSONObj): TPostResult;
6364
Function Job(Sender: TObject; Const aPath: String; Const aContent: TJSONObj): TPostResult;
6465
public
6566
Constructor Create; virtual;
@@ -118,6 +119,7 @@
118119
fServer.RegisterGetHandler('/api/status', @GetStatus);
119120
fServer.RegisterGetHandler('/api/view/list', @GetViewList);
120121
fServer.RegisterPostHandler('/api/job', @Job);
122+
fServer.RegisterPostHandler('/api/shutdown', @Shutdown);
121123

122124
If ZombieMode Then Begin
123125
fServer.RegisterPostHandler('/api/zombie/setdir', @Setdir);
@@ -245,6 +247,38 @@
245247
End;
246248
End;
247249

250+
Function TRestAPIDummy.Shutdown(Sender: TObject; Const aPath: String;
251+
Const aContent: TJSONObj): TPostResult;
252+
Var
253+
jv: TJSONValue;
254+
SkipJobs: Boolean;
255+
Begin
256+
SkipJobs := false;
257+
result.HTTPCode := 400;
258+
result.Content := Nil;
259+
If assigned(aContent) Then Begin
260+
Try
261+
jv := aContent.FindPath('skipJobs') As TJSONValue;
262+
If assigned(jv) Then Begin
263+
SkipJobs := lowercase(trim(jv.Value)) = 'true';
264+
End;
265+
Except
266+
exit;
267+
End;
268+
End;
269+
If (Not SkipJobs) And form1.fWorkThread.Busy Then Begin
270+
result.HTTPCode := 403;
271+
result.Content := TextNode('status', 'pending jobs, no permission to skip jobs.');
272+
exit;
273+
End
274+
Else Begin
275+
result.HTTPCode := 200;
276+
result.Content := TextNode('status', 'ok');
277+
End;
278+
// Set Flag "Shutdown"
279+
Form1.fShutdownbyRestRequest := true;
280+
End;
281+
248282
Function TRestAPIDummy.Job(Sender: TObject; Const aPath: String;
249283
Const aContent: TJSONObj): TPostResult;
250284

0 commit comments

Comments
 (0)