123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817 |
- unit webideintf;
- {$mode objfpc}{$H+}
- interface
- uses
- fpMimeTypes, Classes, SysUtils, StrUtils, httpdefs, fphttpclient,custhttpapp, fpjson, jsonparser, httproute;
- Const
- SFilesURL = '/Project/';
- SIDEURL = '/IDE/';
- Type
- TClientObject = Class(TObject)
- Private
- FID: Int64;
- public
- Procedure FromJSON(aJSON : TJSONObject); virtual; abstract;
- Procedure ToJSON(aJSON : TJSONObject); virtual; abstract;
- Property ID : Int64 Read FID Write FID;
- end;
- { TIDEClient }
- TIDEClient = Class(TClientObject)
- private
- FURL: String;
- Public
- Procedure FromJSON(aJSON : TJSONObject); override;
- Procedure ToJSON(aJSON : TJSONObject); override;
- Property URL : String Read FURL Write FURL;
- end;
- { TIDEExchange }
- TIDEExchange = Class(TClientObject)
- private
- FClientID: Int64;
- FName: String;
- FPayLoad: TJSONData;
- Public
- Destructor Destroy; override;
- Procedure FromJSON(aJSON : TJSONObject); override;
- Procedure ToJSON(aJSON : TJSONObject); override;
- Property ClientID : Int64 Read FClientID Write FClientID;
- Property Name : String Read FName Write FName;
- Property PayLoad : TJSONData Read FPayLoad Write FPayLoad;
- end;
- TIDEAction = Class(TIDEExchange)
- end;
- { TClientObjectList }
- TClientObjectList = Class(TThreadList)
- Public
- Function FindID(aID : int64) : TClientObject;
- end;
- { TIDECommand }
- TIDECommand = Class(TIDEExchange)
- private
- FConfirmed: Boolean;
- FNeedsConfirmation: Boolean;
- FSent: Boolean;
- Public
- Property NeedsConfirmation : Boolean Read FNeedsConfirmation Write FNeedsConfirmation;
- Property Sent : Boolean Read FSent Write FSent;
- Property Confirmed : Boolean Read FConfirmed Write FConfirmed;
- end;
- { TIDEThread }
- TIDEThread = Class(TThread)
- Private
- FHandler : TFPHTTPServerHandler;
- FExceptionClass : String;
- FExceptionMessage : String;
- Public
- Constructor Create(aHandler : TFPHTTPServerHandler);
- Procedure Execute; override;
- end;
- TIDENotification = Procedure(Sender : TObject; aExchange : TIDEExchange) of object;
- TIDEClientNotification = Procedure(Sender : TObject; aClient : TIDEClient) of object;
- TIDERequestNotification = Procedure(Sender : TObject; aURL : String) of object;
- { TIDEServer }
- TIDEServer = Class(TComponent)
- private
- FOnRequest: TIDERequestNotification;
- FQuitting : Boolean;
- FClients,
- FCommands,
- FActions : TClientObjectList;
- FIDCounter: Int64;
- FOnAction: TIDENotification;
- FOnClient: TIDEClientNotification;
- FOnClientRemoved: TIDEClientNotification;
- FOnConfirmCommand: TIDENotification;
- FProjectDir: String;
- FWebHandler : TFPHTTPServerHandler;
- FThread : TIDEThread;
- FLastAction : TIDEAction;
- FLastCommand : TIDECommand;
- FLastClient : TIDEClient;
- function CheckClient(aRequest: TRequest): INt64;
- procedure DeActivatedThread(Sender: TObject);
- function Do404(is404: boolean; aResponse: TResponse): Boolean;
- procedure DoEvent(aProc: TThreadMethod);
- procedure DoQuit(ARequest: TRequest; AResponse: TResponse);
- procedure DoRouteRequest(Sender: TObject; ARequest: TRequest; AResponse: TResponse);
- function GetAction(Index : Integer): TIDEAction;
- function GetActionCount: Integer;
- function GetPort: Integer;
- function GetActive: Boolean;
- procedure SetActive(AValue: Boolean);
- procedure SetPort(AValue: Integer);
- procedure SetProjectDir(AValue: String);
- Protected
- procedure RegisterRoutes; virtual;
- // HTTP request extraction
- procedure GetClientObjectFromRequest(ARequest: TRequest; AObject: TClientObject);
- function GetActionFromRequest(ARequest: TRequest): TIDEAction;
- function GetCommandFromRequest(ARequest: TRequest): TIDECommand;
- function GetClientFromRequest(ARequest: TRequest): TIDEClient;
- function GetJSONFromRequest(ARequest: TRequest): TJSONObject;
- // Sending responses
- procedure SendClientObjectResponse(AObject: TClientObject; AResponse: TResponse);
- Procedure SendJSONResponse(aJSON : TJSONObject; aResponse : TResponse);
- // HTTP route handlers
- procedure DoDeleteAction(ARequest: TRequest; AResponse: TResponse); virtual;
- procedure DoDeleteClient(ARequest: TRequest; AResponse: TResponse); virtual;
- procedure DoGetCommand(ARequest: TRequest; AResponse: TResponse);virtual;
- procedure DoGetFile(ARequest: TRequest; AResponse: TResponse);virtual;
- procedure DoPostAction(ARequest: TRequest; AResponse: TResponse);virtual;
- procedure DoPostClient(ARequest: TRequest; AResponse: TResponse);virtual;
- procedure DoPutCommand(ARequest: TRequest; AResponse: TResponse);virtual;
- // Event handler synchronisation. Rework this to objects
- Procedure DoOnAction;
- Procedure DoOnConfirmCommand;
- Procedure DoOnClientAdded;
- Procedure DoOnClientRemoved;
- Public
- Constructor Create(aOwner : TComponent); override;
- Destructor Destroy; override;
- Function GetNextCounter : Int64;
- // Public API to communicate with browser
- Function SendCommand(aCommand : TIDECommand) : Int64;
- Procedure GetClientActions(aClientID : Int64; aList : TFPList);
- Function DeleteAction(aID: Int64; Const aClientID : Int64 = -1): Boolean;
- // Public properties
- Property ProjectDir : String Read FProjectDir Write SetProjectDir;
- Property Port : Integer Read GetPort Write SetPort;
- Property Active : Boolean read GetActive write SetActive;
- Property ActionCount : Integer Read GetActionCount;
- Property Action[Index : Integer] : TIDEAction Read GetAction;
- // Events
- Property OnRequest : TIDERequestNotification Read FOnRequest Write FOnRequest;
- Property OnConfirmCommand : TIDENotification Read FOnConfirmCommand Write FOnConfirmCommand;
- Property OnAction : TIDENotification Read FOnAction Write FOnAction;
- Property OnClientAdded : TIDEClientNotification Read FOnClient Write FOnClient;
- Property OnClientRemoved : TIDEClientNotification Read FOnClientRemoved Write FOnClientRemoved;
- end;
- implementation
- { TClientObjectList }
- function TClientObjectList.FindID(aID: int64): TClientObject;
- Var
- L : TList;
- I : integer;
- begin
- Result:=Nil;
- L:=LockList;
- try
- I:=L.Count-1;
- While (Result=Nil) and (I>=0) do
- begin
- Result:=TClientObject(L[i]);
- if Result.ID<>aID then
- Result:=nil;
- Dec(I);
- end;
- finally
- UnlockList;
- end;
- end;
- { TIDEClient }
- procedure TIDEClient.FromJSON(aJSON: TJSONObject);
- begin
- FID:=aJSON.Get('id',Int64(-1));
- FURL:=aJSON.Get('url','');
- end;
- procedure TIDEClient.ToJSON(aJSON: TJSONObject);
- begin
- aJSON.Add('id',ID);
- aJSON.Add('url',url);
- end;
- { TIDEExchange }
- destructor TIDEExchange.Destroy;
- begin
- FreeAndNil(FPayload);
- Inherited;
- end;
- procedure TIDEExchange.FromJSON(aJSON: TJSONObject);
- Var
- P : TJSONObject;
- begin
- ID:=aJSON.Get('id',Int64(0));
- Name:=aJSON.Get('name','');
- P:=aJSON.Get('payload',TJSONObject(Nil));
- if Assigned(P) then
- Payload:=aJSON.Extract('payload');
- end;
- procedure TIDEExchange.ToJSON(aJSON: TJSONObject);
- begin
- aJSON.Add('id',ID);
- aJSON.Add('name',name);
- if Assigned(Payload) then
- aJSON.Add('payload',Payload.Clone);
- end;
- { TIDEThread }
- constructor TIDEThread.Create(aHandler: TFPHTTPServerHandler);
- begin
- FHandler:=AHandler;
- FreeOnTerminate:=True;
- Inherited Create(False);
- end;
- procedure TIDEThread.Execute;
- begin
- try
- FHandler.Run;
- FHandler:=nil;
- except
- On E : Exception do
- begin
- FExceptionClass:=E.ClassName;
- FExceptionMessage:=E.Message;
- end;
- end;
- end;
- { TIDEServer }
- function TIDEServer.GetAction(Index : Integer): TIDEAction;
- Var
- L : TList;
- begin
- L:=FActions.LockList;
- try
- Result:=TIDEAction(L.Items[Index]);
- finally
- FActions.UnlockList;
- end;
- end;
- procedure TIDEServer.DeActivatedThread(Sender: TObject);
- begin
- FThread:=Nil;
- end;
- function TIDEServer.GetActionCount: Integer;
- Var
- L : TList;
- begin
- L:=FActions.LockList;
- try
- Result:=L.Count;
- finally
- FActions.UnlockList;
- end;
- end;
- function TIDEServer.GetActive: Boolean;
- begin
- Result:=Assigned(FThread);
- end;
- function TIDEServer.GetPort: Integer;
- begin
- Result:=FWebHandler.Port;
- end;
- procedure TIDEServer.SetActive(AValue: Boolean);
- begin
- if Active=AValue then Exit;
- if AValue then
- begin
- FThread:=TIDEThread.Create(FWebHandler);
- FThread.OnTerminate:=@DeActivatedThread;
- end
- else
- begin
- FWebHandler.Terminate; // will cause thread to stop.
- try
- // Send a Quit request just in case. Normally this should fail.
- FQuitting:=True;
- TFPHTTPClient.SimpleGet(Format('http://localhost:%d/Quit',[Port]));
- except
- FQuitting:=False;
- end;
- end;
- end;
- procedure TIDEServer.SetPort(AValue: Integer);
- begin
- FWebHandler.Port:=aValue;
- end;
- procedure TIDEServer.SetProjectDir(AValue: String);
- begin
- if FProjectDir=AValue then Exit;
- FProjectDir:=IncludeTrailingPathDelimiter(AValue);
- end;
- procedure TIDEServer.DoOnAction;
- begin
- If Assigned(FOnAction) then
- FonAction(Self,FLastAction);
- FLastAction:=Nil;
- end;
- procedure TIDEServer.DoOnConfirmCommand;
- begin
- If Assigned(FOnAction) then
- FonAction(Self,FLastCommand);
- FLastCommand:=Nil;
- end;
- procedure TIDEServer.DoOnClientAdded;
- begin
- if Assigned(FOnClient) then
- FOnClient(Self,FLastClient);
- FLastClient:=Nil;
- end;
- procedure TIDEServer.DoOnClientRemoved;
- begin
- if Assigned(FOnClientRemoved) then
- FOnClientRemoved(Self,FLastClient);
- FLastClient:=Nil;
- end;
- procedure TIDEServer.DoGetCommand(ARequest: TRequest; AResponse: TResponse);
- Var
- L : TList;
- I : integer;
- J,C : TJSONObject;
- A :TJSONArray;
- Cmd : TIDECommand;
- L2 : TFPList;
- aClient : Int64;
- begin
- aClient:=CheckClient(aRequest);
- J:=nil;
- A:=nil;
- L:=FCommands.LockList;
- try
- L2:=TFPList.Create;
- J:=TJSONObject.Create;
- A:=TJSONArray.Create;
- J.Add('commands',A);
- For I:=0 to L.Count-1 do
- begin
- CMD:=TIDECommand(L[i]);
- if Not Cmd.Sent and (Cmd.ClientID=aClient) then
- begin
- C:=TJSONObject.Create;
- Cmd.ToJSON(C);
- A.Add(C);
- L2.Add(CMD);
- end;
- end;
- SendJSONResponse(J,aResponse);
- // Remove sent from list
- for I:=0 to L2.Count-1 do
- begin
- Cmd:=TIDECommand(L2[i]);
- if Cmd.NeedsConfirmation then
- Cmd.Sent:=True
- else
- begin
- Cmd.Free;
- L.Remove(Cmd);
- end;
- end;
- finally
- J.Free;
- FCommands.UnLockList;
- l2.Free;
- end;
- end;
- procedure TIDEServer.DoPutCommand(ARequest: TRequest; AResponse: TResponse);
- Var
- cmd,oCmd : TIDECommand;
- aID,aClient : Int64;
- begin
- aClient:=CheckClient(aRequest);
- aID:=StrToIntDef(aRequest.RouteParams['ID'],-1);
- cmd:=TIDECommand.Create;
- try
- GetClientObjectFromRequest(aRequest,Cmd);
- cmd.ClientID:=aClient;
- oCmd:=TIDECommand(FCommands.FindID(aID));
- if Do404((oCmd=Nil) or (oCmd.ClientID<>aClient),aResponse) then
- exit;
- // Later on we can add more modifications
- oCmd.Confirmed:=True;
- aResponse.Code:=204;
- aResponse.CodeText:='OK';
- aResponse.SendResponse;
- FLastCommand:=oCmd;
- DoEvent(@DoOnConfirmCommand);
- FCommands.Remove(oCmd);
- Finally
- cmd.Free;
- end;
- end;
- procedure TIDEServer.DoQuit(ARequest: TRequest; AResponse: TResponse);
- begin
- if FQuitting then
- aResponse.Code:=200
- else
- aResponse.Code:=401;
- aResponse.SendResponse;
- end;
- procedure TIDEServer.DoRouteRequest(Sender: TObject; ARequest: TRequest; AResponse: TResponse);
- begin
- If Assigned(FonRequest) then
- FOnRequest(Self,aRequest.URI);
- end;
- function TIDEServer.GetJSONFromRequest(ARequest: TRequest): TJSONObject;
- var
- D : TJSONData;
- begin
- if ARequest.ContentType<>'application/json' then
- Raise Exception.Create('Not valid JSON payload: content type must be application/json');
- D:=GetJSON(ARequest.Content);
- if Not (D is TJSONObject) then
- begin
- FreeAndNil(D);
- Raise EJSON.Create('Payload is valid JSON but not a JSON object');
- end;
- Result:=D as TJSONObject;
- end;
- procedure TIDEServer.SendJSONResponse(aJSON: TJSONObject; aResponse: TResponse);
- Var
- JS : TJSONStringType;
- begin
- JS:=aJSON.AsJSON;
- aResponse.FreeContentStream:=True;
- aResponse.ContentStream:=TMemoryStream.Create;
- aResponse.ContentStream.WriteBuffer(JS[1],Length(JS));
- aResponse.ContentLength:=Length(JS);
- aResponse.ContentType:='application/json';
- aResponse.SendResponse;
- end;
- procedure TIDEServer.GetClientObjectFromRequest(ARequest: TRequest; AObject: TClientObject);
- Var
- J : TJSONObject;
- begin
- J:=GetJSONFromRequest(aRequest);
- try
- AObject.FromJSON(J);
- finally
- J.Free;
- end;
- end;
- procedure TIDEServer.SendClientObjectResponse(AObject: TClientObject; AResponse: TResponse);
- Var
- J : TJSONObject;
- begin
- J:=TJSONObject.Create;
- try
- aObject.ToJSON(J);
- SendJSONResponse(J,aResponse);
- finally
- J.Free;
- end;
- end;
- function TIDEServer.GetActionFromRequest(ARequest: TRequest): TIDEAction;
- begin
- Result:=TIDEAction.Create;
- try
- GetClientObjectFromRequest(aRequest,Result);
- except
- Result.Free;
- raise;
- end;
- end;
- function TIDEServer.GetCommandFromRequest(ARequest: TRequest): TIDECommand;
- begin
- Result:=TIDECommand.Create;
- try
- GetClientObjectFromRequest(aRequest,Result);
- except
- Result.Free;
- Raise;
- end;
- end;
- function TIDEServer.GetClientFromRequest(ARequest: TRequest): TIDEClient;
- begin
- Result:=TIDEClient.Create;
- try
- GetClientObjectFromRequest(aRequest,Result);
- except
- Result.Free;
- Raise;
- end;
- end;
- procedure TIDEServer.DoPostAction(ARequest: TRequest; AResponse: TResponse);
- var
- A : TIDEAction;
- aId,aClient : Int64;
- begin
- aClient:=CheckClient(aRequest);
- aID:=StrToInt64Def(aRequest.RouteParams['ID'],-1);
- Try
- A:=GetACtionFromRequest(aRequest);
- A.ClientID:=aClient;
- if A.ID=0 then
- a.ID:=aID;
- FActions.Add(A);
- FLastAction:=A;
- DoEvent(@DoOnAction);
- AResponse.Code:=201;
- AResponse.Codetext:='Created';
- except
- On E: Exception do
- begin
- AResponse.Code:=400;
- AResponse.Codetext:='Invalid Param';
- AResponse.Content:='Invalid data ('+E.ClassName+'): '+E.Message;
- end;
- end;
- aResponse.SendResponse;
- end;
- function TIDEServer.CheckClient(aRequest: TRequest): INt64;
- Var
- S : String;
- begin
- S:=ARequest.RouteParams['Client'];
- if (S='') then
- Raise EJSON.Create('Missing client ID in request');
- if Not TryStrToInt64(S,Result) then
- Raise EJSON.CreateFmt('Invalid client ID: %s',[S]);
- end;
- procedure TIDEServer.DoDeleteAction(ARequest: TRequest; AResponse: TResponse);
- var
- SID : String;
- ID,aClient : Int64;
- begin
- Try
- aClient:=CheckClient(ARequest);
- SID:=ARequest.RouteParams['ID'];
- ID:=StrtoInt64Def(SID,-1);
- if Do404((ID=-1) or not (DeleteAction(ID,aClient)),aResponse) then
- exit;
- AResponse.Code:=204;
- AResponse.Codetext:='No content';
- aResponse.SendResponse;
- except
- On E: Exception do
- begin
- AResponse.Code:=400;
- AResponse.Codetext:='Invalid Param';
- AResponse.Content:='Invalid data ('+E.ClassName+'): '+E.Message;
- end;
- end;
- end;
- procedure TIDEServer.DoGetFile(ARequest: TRequest; AResponse: TResponse);
- Var
- FN : String;
- begin
- FN:=ARequest.URL;
- if AnsiStartsText(SFilesURL,FN) then
- Delete(FN,1,Length(SFilesURL));
- FN:=ExpandFileName(FProjectDir+FN);
- if Pos('..',ExtractRelativepath(FProjectDir,FN))<>0 then
- begin
- aResponse.Code:=401;
- aResponse.CodeText:='Forbidden';
- aResponse.Content:='<H1>Forbidden</H1>';
- end
- else if Do404(Not FileExists(FN),aResponse) then
- exit;
- aResponse.FreeContentStream:=True;
- aResponse.ContentStream:=TFileStream.Create(FN,fmOpenRead or fmShareDenyWrite);
- aResponse.ContentLength:=aResponse.ContentStream.Size;
- aResponse.ContentType:=MimeTypes.GetMimeType(ExtractFileExt(FN));
- if aResponse.ContentType='' then
- aResponse.ContentType:='text/html';
- aResponse.SendResponse;
- end;
- constructor TIDEServer.Create(aOwner: TComponent);
- begin
- Inherited;
- FProjectDir:=ExtractFilePath(Paramstr(0));
- FActions:=TClientObjectList.Create;
- FCommands:=TClientObjectList.Create;
- FClients:=TClientObjectList.Create;
- FWebHandler:=TFPHTTPServerHandler.Create(Self);
- FWebHandler.Port:=8080;
- RegisterRoutes;
- end;
- procedure TIDEServer.DoEvent(aProc : TThreadMethod);
- begin
- if Assigned(FThread) then
- FThread.Synchronize(aProc)
- else
- aProc;
- end;
- procedure TIDEServer.DoPostClient(ARequest: TRequest; AResponse: TResponse);
- Var
- aClient : TIDEClient;
- begin
- aClient:=GetClientFromRequest(aRequest);
- aClient.FID:=GetNextCounter;
- FClients.Add(aClient);
- SendClientObjectResponse(aClient,aResponse);
- FLastClient:=aClient;
- DoEvent(@DoOnClientAdded);
- end;
- function TIDEServer.Do404(is404: boolean; aResponse: TResponse): Boolean;
- begin
- Result:=is404;
- if Result then
- begin
- aResponse.Code:=404;
- aResponse.Codetext:='Not found';
- aResponse.SendResponse;
- end;
- end;
- procedure TIDEServer.DoDeleteClient(ARequest: TRequest; AResponse: TResponse);
- Var
- aClientID : Int64;
- aClient : TIDEClient;
- begin
- aClientID:=CheckClient(aRequest);
- aClient:=TIDEClient(FClients.FindID(aClientID));
- if Do404(not Assigned(aClient),aResponse) then
- exit;
- FLastClient:=aClient;
- DoEvent(@DoOnClientRemoved);
- FClients.Remove(aClient);
- end;
- procedure TIDEServer.RegisterRoutes;
- begin
- // get command
- HTTPRouter.RegisterRoute(SIDEURL+'Quit',rmGet,@DoQuit);
- HTTPRouter.RegisterRoute(SIDEURL+'Client/',rmPost,@DoPostClient);
- HTTPRouter.RegisterRoute(SIDEURL+'Client/:Client',rmDelete,@DoDeleteClient);
- HTTPRouter.RegisterRoute(SIDEURL+'Command/:Client/',rmGet,@DoGetCommand);
- // PUT command for confirm.
- HTTPRouter.RegisterRoute(SIDEURL+'Command/:Client/:ID',rmPut,@DoPutCommand);
- // POST action
- HTTPRouter.RegisterRoute(SIDEURL+'Action/:Client/:ID',rmPost,@DoPostAction);
- HTTPRouter.RegisterRoute(SIDEURL+'Action/:Client/:ID',rmDelete,@DoDeleteAction);
- // GET file
- HTTPRouter.RegisterRoute(SFilesURL+'*',rmGet,@DoGetFile,true);
- HTTPRouter.BeforeRequest:=@DoRouteRequest;
- end;
- destructor TIDEServer.Destroy;
- begin
- Active:=False;
- While Active do
- Sleep(20);
- FreeAndNil(FActions);
- FreeAndNil(FCommands);
- FreeAndNil(FClients);
- inherited Destroy;
- end;
- function TIDEServer.GetNextCounter: Int64;
- begin
- Inc(FIDCounter);
- Result:=FIDCounter;
- end;
- function TIDEServer.SendCommand(aCommand: TIDECommand): Int64;
- begin
- Result:=GetNextCounter;
- aCommand.ID:=Result;
- FCommands.Add(aCommand);
- end;
- function TIDEServer.DeleteAction(aID: Int64; const aClientID: Int64): Boolean;
- Var
- P : TIDEAction;
- L : TList;
- I : Integer;
- begin
- P:=nil;
- L:=FActions.LockList;
- try
- I:=L.Count-1;
- While (I>=0) and (P=Nil) do
- begin
- P:=TIDEAction(L[i]);
- if P.ID<>AID then P:=Nil;
- Dec(i)
- end;
- finally
- L.Free;
- end;
- Result:=(P<>Nil) and ((aClientID=-1) or (P.ClientID=aClientID));
- if Result then
- FActions.Remove(P);
- end;
- procedure TIDEServer.GetClientActions(aClientID: Int64; aList: TFPList);
- Var
- P : TIDEAction;
- L : TList;
- I : Integer;
- begin
- P:=nil;
- L:=FActions.LockList;
- try
- I:=L.Count-1;
- While (I>=0) and (P=Nil) do
- begin
- P:=TIDEAction(L[i]);
- if P.ClientID=aClientID then
- begin
- aList.Add(P);
- L.Delete(I);
- end;
- Dec(i);
- end;
- finally
- L.Free;
- end;
- end;
- end.
|