fabiotj Posted March 10, 2025 Posted March 10, 2025 I need to start a TUniTimer in the ServerModule that will check the active sessions of the application and perform some processes in the database. But when I try to do as below I get an Access Violation error: procedure TServerModule.CleanupTimerEvent(Sender: TObject); var myQuery : TFDQuery; begin myQuery := TFDQuery.Create(Self); myQuery.Connection := MainModule.SQLConnection; (here the Access Violation error occurs). end; This is just a simple example. In my real case I call a procedure and inside it I access the MainModule.SQLConnection. What is the correct way to access it? After doing a lot of research here on the Forum, I have tried several approaches but without success. Quote
Abaksoft Posted March 12, 2025 Posted March 12, 2025 On 3/10/2025 at 8:13 PM, fabiotj said: I need to start a TUniTimer in the ServerModule ... Goodmorning Fabio, You have two problems here : 1. First is about Sessions : - ServerModule has the control of all sessions - You can not control one session with ServerModule - So, the simple fact of writing things on ServerModule, that affect one session will cause an AV (acces violation) Like : UniMainModule... UniMainForm... To better understand : You can not do this : procedure TUniServerModule.UniGUIServerModuleCreate(Sender: TObject); begin MainModule.UniMainModule.v1:=11; // Or UniMainForm... end; (v1 is declared on UniMainModule) For doing this, we are asking to the server to Set a variable v1 on a session (but wich session ???) that is why the AV appears. 2. Second is about Timer : - UniTimer is dedicated for Sessions (MainForm, UniMainModule, ...) - UniThreadTimer is dedicated for ServerModule. You have to lock and release it before using your procedures inside : procedure TUniServerModule.UniThreadTimer1Timer(Sender: TObject); begin UniThreadTimer1.Lock; try //============== Procedure_DoingSomeThings; //============== finally UniThreadTimer1.Release; end; end; 1 Quote
fabiotj Posted March 12, 2025 Author Posted March 12, 2025 Thank you very much for the explanation. ThreadTimer = OK. But, 1) Can I have an exclusive FDConnection (although I know it is not indicated) in the ServerModule to perform a simple Query operation? 2) Or is there still a way to specify which section I want to use so that through it I can access the FDConnection of the MainModule? Something like: myQuery.Connection := EspecSession(SessionID).MainModule.SQLConneciton; Quote
eduardosuruagy Posted March 12, 2025 Posted March 12, 2025 Use a SqlConection in the ServerModule 1 Quote
fabiotj Posted March 12, 2025 Author Posted March 12, 2025 I managed to do it with a direct connection to the ServerModule. Thanks Eduardo. If someone later reads this post and knows how to access a specific MainModule of a session or even how to access anything in a specific session, I would appreciate it because it could be useful in the future. Quote
Abaksoft Posted March 12, 2025 Posted March 12, 2025 2 hours ago, fabiotj said: it could be useful in the future. Sure, ... i think Websokets is a keyword. I didn't play with it, but i already hear a such approach. 1 Quote
fabiotj Posted March 12, 2025 Author Posted March 12, 2025 Yes, I tried websocket before using the current method, but when I went to implement the dedicated websocekt server to run in conjunction with HyperServer I encountered many local problems to run as a Windows service etc... so due to urgency I gave up, but WebSocket really is very good, my project worked with it but not on HyperServer because it is Multi-Instance. Quote
Abaksoft Posted March 12, 2025 Posted March 12, 2025 7 hours ago, fabiotj said: Something like: myQuery.Connection := EspecSession(SessionID).MainModule.SQLConneciton; The Classical method in Unigui for connection to a DB, is to connect on UniMainModule.OnCreate Event for each new session (using pooling). Why are you trying to connect a second time from UniSeverModule and pointing to this UniMainModule connection ? What is the pupose ? Quote
Norm Posted March 12, 2025 Posted March 12, 2025 (edited) 8 hours ago, fabiotj said: I managed to do it with a direct connection to the ServerModule. Thanks Eduardo. Instead of putting the sqlConnection in the ServerModule I do it in a separate DataModule that I reference from the ServerModule. That way I avoid cluttering the ServerModule with database handling functions. I also use this to handle incoming API requests. e.g. unit ServerModule; interface uses Classes, SysUtils, uniGUIServer, uniGUIMainModule, uniGUIApplication, uIdCustomHTTPServer, uniGUITypes, MainModule, uniThreadTimer, uniGuiServerUtils, SyncObjs; type TUniServerModule = class(TUniGUIServerModule) .... ..... end; function UniServerModule: TUniServerModule; implementation {$R *.dfm} uses UniGUIVars, uIdGlobal, //My data module dData; ... ... procedure TUniServerModule.TimerTimer(Sender: TObject); begin Timer.Lock; try //*** Call datamodule methods dmDB.CheckConnections; finally Timer.Release; end; end; function TUniServerModule.HandleHTTPPostRequest(var wPostBody: String; wIPAddress : String; var wRespText: String) : Integer; begin Timer.Emanled := false; try //*** Call datamodule methods Result := dmDB.HandlePostRequest(wPostBody, wIPAddress, wRespText); finally Timer.Enabled := True; end; end; procedure TUniServerModule.UniGUIServerModuleHTTPCommand( ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo; var Handled: Boolean); var aParams : String; aStream : TStream; aPostBody : string; aHTML : String; aData : TStringList; aRespNo : Integer; aRespText : String; aIPAddress : String; begin if (ARequestInfo.Command = 'GET') and (ARequestInfo.URI = '/') then begin .... .... end else if ARequestInfo.Command = 'POST' then begin aParams := UpperCase(ARequestInfo.URI); aStream := ARequestInfo.PostStream; if assigned(aStream) then begin aStream.Position := 0; aPostBody := ReadStringFromStream(aStream); aRespNo := HandleHTTPPostRequest(aPostBody, aIPAddress, aRespText); AResponseInfo.ResponseNo := aRespNo; AResponseInfo.FreeContentStream := True; AResponseInfo.ContentStream := TStringStream.Create(aPostBody); AResponseInfo.ContentLength := AResponseInfo.ContentStream.Size; AResponseInfo.ContentType := 'application/json'; Handled := True; end end end; Edited March 12, 2025 by Norm Typo 1 1 Quote
fabiotj Posted March 13, 2025 Author Posted March 13, 2025 Hi Norm. Interesting, thanks for sharing. Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.