Jump to content

Clément

Members
  • Content Count

    365
  • Joined

  • Last visited

  • Days Won

    4

Everything posted by Clément

  1. Clément

    Debugger in 10.3.3 is useless :'(

    Well, I re-installed 10.3.3 and the problem persists. Going back to 10.3.2
  2. I used it by accident twice. UNDO is a life safer indeed. Never ever since. I guess we should build a "black list" of IDE feature we should avoid.
  3. Hi, I have no idea where to ask for help, but hopefully that post might help other Delphi developers. I'll try not to make an advertise 😁 I've build a program to help Network Administrator to monitor a network with two editions: Community edition (Free) and Professional Edition (Paid). The Community edition has the basic functionality and can be upgraded to Professional Edition. I've build an eStore to control the license and payments ( Delphi / PHP). The application show the modules to purchase and launch a link to the payment service provider (PSP). Once the payment is done, my eStore receives a notification from the PSP, processes it and the license is unlocked. Currently I'm supporting Paypal for international purchase and Paypal and Cielo for local purchase ( Purchase made in Brazil ). Both Paypal and Cielo are working flawlessly, but some friends told me that Paypal is not well seen by companies and will search for other application just because "Paypal is not company friendly". I was wondering if someone has a better experience with some other PSP that can be added/integrated in my store. As I intend to sell oversea what are the options I have that are "company friendly" that can work with Delphi. I will mostly focus on credit card payment. TIA, Clément
  4. Hi, I'm using TSslHttpAppSrv in a Delphi Rio project. I'm following the example and I manage to build my AppServer. Very cool! There are some points that I would like to understand better and maybe improve a little. I create a "TcoreWebServerThread" derived from TThread that creates an instance of TcoreWebServer. TcoreWebServer is a descendant of TSslHttpAppSrv. I hooked event_ClientConnect to OnClientConnect. procedure TcoreWebServer.event_ClientConnect(Sender, Client: TObject; Error: Word); var lRemoteClient : TcoreWebServerClientConnection; begin lRemoteClient := TcoreWebServerClientConnection(Client); lRemoteClient.WSessionCookie := 'dhsWeb_' + lRemoteClient.HostTag+ '_'+ Port; lRemoteClient.OnBgException := event_ClientBgException; fLogRequest[ lRemoteClient.WebLogIdx ].logFmt('Thread ID %d',[ThreadID]); end; This Connection is created in the context of coreServerThread. That same Thread will handle the Authorization, Permission and the URLHandler. It is too much for the server thread to handle, specially because Authorization (custom) and Permission will be checked against Database. Most of my TURLHandler descendants will also query a Database. Some will be slow ( Reports or Large data transfers). I must use a separate thread. And here's the problem. Where is the best place to create that thread? I haven't found a way to create the client connection in another thread. In the event_ClientConnect I would like "client" parameter to be in its own thread. This way all Authorization, Permission and TURLHandler execution would happen without blocking the main WebServer thread. Once I create the Client in a it's own thread context, I need to handle my Database Connection. I derived a class from TWebSessionData called ( TcoreWebServerWebSession ) : TcoreWebServerWebSession = Class( TWebSessionData ) private FLoginChallenge: String; FUserCode: String; FLastRequest: TDateTime; FRequestCount: Integer; FLogonTime: TDateTime; FIP: String; FSQLConnection: IcoreSQLConnection; public constructor Create( aOwner : TComponent ); override; property UserCode : String read FUserCode write FUserCode; property LogonTime : TDateTime read FLogonTime write FLogonTime; property RequestCount : Integer read FRequestCount write FRequestCount; property LastRequest : TDateTime read FLastRequest write FLastRequest; property IP : String read FIP write FIP; property LoginChallenge : String read FLoginChallenge write FLoginChallenge; property SQLConnection : IcoreSQLConnection read FSQLConnection; End; The property SQLConnection is an interface, and it's life time will be different from the WebSession's. I would like to return the SQLConnection back to its pool as soon as the user request is done. ( All the database connection pooling is already done! ). All the requests will return a JSON object. So, basically I need to place the ClientConnection on a separate thread that will Acquired a Database Connection from a pool and assign it to coreWebServerWEbSession.SQLConnection. This connection will be used to Authorize, Check permission and execute TURLHandler. Once Finished I would like to release it back to it's pool. No bad for a Sunday brainstorm TIA, Clément
  5. Clément

    Studying TSslHttpAppSrv

    Thanks for taking your time to answer! I'm still studying the best course of action. All client connections will receive a response very fast. For synchronous request, I want to return an answer with a maximum delay of 2s. For Asynchronous request the response will be very fast, just the time to spawn a thread ( as you saw in the example). The example is just a test, the final version will mostly look like: procedure TWSWebAPIHandler.Execute; var lJsPostedData : TJsonObject; lPath : String; begin inherited; if IsLogged then begin lJsPostedData := TJsonObject.ParseJSONValue( Client.PostedData ) as TJSONObject ; lPath := Client.Path; TWSWebServerAPIThread.Create( LPath, lJsPostedData); AnswerString('', '', '', '<HTML><BODY>WebAPI called - '+Client.Path+' </BODY></HTML>'); end else AnswerString('', '', '', '<HTML><BODY>Not logged </BODY></HTML>'); Finish; end; I thought I might need access to TURLHandler from within the thread. But that's not the case anymore. By the way, The user authentication is done very fast ( I'm already connecting to a database to get the credentials in the context of the TcoreWebServer). The performance is great. I need to polish some classes and interfaces to start the project. I will decorate my class definitions with attributes like [Operation(Sync)] or [Operation(Async)] to know if I need to spawn a thread or not in the API call layer. Thanks, Clément
  6. Clément

    Studying TSslHttpAppSrv

    Hi, I have two questions: 1) In my implementation I see that fUrlHandler.Client messages are processed by TCoreWebServer message pump. Would that be a problem? I could instead pass TURLHandler's FWndHandle, but still would have to PostMessage that would be processed in TCoreWebServer thread 2) Some database operation can take a few hours to complete. From the source code, TURLHandler is released after calling fUrlHandler.Finish. Would maintain a TUrhHandler instance live for a few hours be an issue? TIA, Clément
  7. Clément

    Studying TSslHttpAppSrv

    I found a way to get the result I want. I just hope it is the right way. I wrote a TUrlHandler descendant that spawn a thread. One of those parameters is the TUrlHandler instance. The code looks like this: procedure TWSWebAPIHandler.Execute; var lJsPostedData : TJsonObject; lPath : String; begin inherited; if IsLogged then begin lJsPostedData := TJsonObject.ParseJSONValue( Client.PostedData ) as TJSONObject ; lPath := Client.Path; TWSWebServerAPIThread.Create( LPath, lJsPostedData, Self ); // AnswerString('', '', '', '<HTML><BODY>WebAPI called - '+Client.Path+' </BODY></HTML>'); end; // Finish; end; As you can see I commented the answer string and the finish. They are in the Thread implementation: constructor TWSWebServerAPIThread.Create(const aPath: String; aPostedData: TJsonObject; aURLHandler: TcoreWebServerHandler); begin FreeOnTerminate := True; fPostedData := aPostedData; fPath := aPath; fURLHandler := aURLHandler; inherited create(False); end; procedure TWSWebServerAPIThread.Execute; begin inherited; Sleep(9000); fURLHandler.AnswerString('','','','<HTML><BODY>In a thread for '+fPath+' with '+fPostedData.ToString+'</BODY></HTML>'); fURLHandler.Finish; end; The Sleep(9000) is there just to simulate a long database operation. I have tested the calling from 3 different REST Client and every response came at 9s as expected. (Without that thread, the requests will return at 9s, 12s and 18s. Exactly what I'm trying to avoid). This codes uses an instance of TUrlHandler because it seems to me that every request will get an instance of the corresponding TURLHandler. Is it thread safe to call it that way? TIA, Clément
  8. Clément

    Studying TSslHttpAppSrv

    Sure. My concern is the response to the request. I don't want the user to wait longer than (s)he needs to. I will divide my request in Sync and Async calls. Sync calls should be very fast and it might work without a database thread (I will do some test as soon as I manage to create a thread for the client connection). Async calls on the other hand might take several hours.
  9. Clément

    Studying TSslHttpAppSrv

    This server will run as a Windows Service. It may be a bad habit, but I don't like to share the service thread with my applications. I will have a look. I need SocketThrdServer features in TsslHttpAppSrv. It makes no sense going back. This is the tricky part. Some requests will be synchronous and some asynchronous. Synchronous request will have the database in the same thread as the client connection. This is the fast kind of request. Usually a result is expected from 1ms to less than 2s (in my case). The asynchronous request will release the client connection as soon as possible. It will trigger a process that sill handle longer requests and alert the users once it's completed.
  10. Clément

    Interesting article about dying languages

    This is the kind of article that falls in the wrong hands and I always hear: "I know more people that talk Latin than delphi programmers". "What? A new project in Delphi? Are you nuts?" Hopefully Delphi Community edition will help re-popularize (is that even a word?) it. The fact is that most script base language programmed by young developers do REST calls (or something like), so as long as you GET, DELETE, POST and PUT in fancy syntax you are in a modern langue!
  11. Hi, I'm using Delphi Rio. I have this thread that respond to Windows Messages using PostThreadMessage called from the main thread or any other thread. It is fast and working fine. procedure TdhsLoggerThread.Execute; var lMsg : TMsg; lCOunt : Integer; begin inherited; fLogs := TObjectDictionary<String,TdhsLoggerItemData>.Create([doOwnsValues]); try gLoggerThreadID := ThreadID; PeekMessage( lMsg, 0 , WM_USER , WM_USER , PM_NOREMOVE ); //FTimerID := SetTimer(0,0,1000,nil); #1 lCount := 0; while GetMessage( lMsg, 0, 0 , 0 ) do begin inc(lCount); DoProcessMessages( lMsg ); // if (lCOunt mod 1000) = 0 then #2 // DoFlushLogs; #2 end; // KillTimer(0,FTimerID); #1 DoFlushLogs; finally fLogs.Free; end; end; If I run the code as posted ( commenting #1 & #2), during my stress test with 200000 calls, lCount shows the correct number of processed messages (200005). I need to FlushLogs every second, so I added the code I marked with #1, I'm receiving WM_TIMER messages, but some of my messages are lost and lCount shows 195453 calls ( The count varies but I usually losing between 5000 to 10000 messages) . Every message has information I can't loose, so missing messages is a big no no! If I comment #1 and uncomment #2 I get all the calls as expected. No problems with DoFlushLogs then, so I'm messing up SetTimer call or it is not supposed to be called the I'm calling it. Am I using correctly SetTimer? I'm trying to avoid creating another thread just to control the timer, is there another way create a timer in the same thread without loosing my messages? ( I don't want to use Sleep() ). All I need is to timely flushlogs. If there's no other way, I will create a ThreadedTimer. TIA, Clément
  12. This is what I suspected too. I managed to track every message I sent to the thread and it broke at 5k messages, the process managed to write 2k logs before going bananas. In this new design, I'm using fewer messages. One to register the Logger and One to unregister it.
  13. When I found the mistake I picture your ghostbuster sign with a " I told you so " message. Anyway, there were a lot of things to consider. I had to redesign the solution since I will have to deal with slow medias and the message queue in windows has room for 10000 messages. This is why I like this forum, it keeps me less stupid. Thanks for the heads up!
  14. @Fr0sT.Brutal thanks for the tip. Unfortunately I made a very stupid mistake. During my tests I generated over 1.000.000 posts and of course I was NOT checking the post result. Messages where stacking faster than they would be processed. Anyway, I had to redesign. To make a long story short, the routine is almost 20x faster than logging directly to a file .
  15. Googling around I found that WaitForMultipleObjects might be a better candidate since the LoggerThread will never deal with GUI messaging, and will most probably be working in a Windows Service. I wrote my message pumping using WaitForMultipleObjects but it's not working. That's the bug I'm dealing with. But as I have MsgMsgWaitForMultipleObjects working, I won't waste more than an hour figuring out what's wrong. I need to start Multi-thread test.
  16. I'm using a queue also. I'm passing data from client-part log to the thread part via PostThreadMessages. I trust windows messaging and atomic operations to avoid using Critical sections. Also I making sure that all objects allocated in the client-part context are released in the client-part. I have to deal with a small bug, but I believe that very soon I will start stress testing with multi-threads and hopefully I won't mess my installation (to much )
  17. I'm not at the office right now, but the main code is very similar to the one below: procedure Tform1.OnButton1Click( Sender : Tobject ); var lLog : IdhsLogger; begin lLog := TdhsLogger.Create('Test', TdhsLoggerWriterFileStream.Create( ExtractFilePath( ParamStr(0) ) ) ); for i := 0 to 200 * 1000 do lLog.WriteFMT('Logging test %d',[i]); end; lLog will postThreadmessages to TdhsLoggerThread ( the code I posted above ). Just by commenting the lines I got the results I wrote. When all goes well , the log file must end with: 200000: 20190917 17:02:00.999 Logging test 200000 The first number ( 200000 ) is the editors ( notepad++) line number. It must match the logging test message number. When I use SetTimer, the log ends showing: 195432: 20190917 17:02:00.999 Logging test 200000 The writing is synchronized up to 60.000 or 70.000 entries than 5.000 to 10.000 Logging test are missing. In my new implementation I'm using MsgWaitForMultipleObjects and all 200.000 logs entries are displayed. I changed my stress test to 500.000 logs entries and then to 1.000.000 log entries. The log file ended up as expected (The editor's 500000th line shows "Logging test 500000" and the 1000000th line shows "Logging test 1000000". I will revisit the implementation using SetTimer to compare the differences. Anyway MsgWaitForMultipleObjects has a 1s timeout that flushes the logs just like SetTimer triggering WM_TIMER. The exact same stress test. The classes and method calls are the same in both implementation. The only difference is how I'm dealing with the TIMEOUT.
  18. That seems to be the way to go. I avoided using it in the beginning because MsgWaitForMultipleObjectsEx handles a lot more messages and events than I actually need. But there's this parameters in the documentation where I can set QS_TIMER or QS_POSTMESSAGE that might do the trick! Thanks
  19. If I don't use timers I will have to depend on messages to flush. So I might end up with a lot of "unflushed" log. I would depend on the client to call a "flush logs", that would be wrong.
  20. This really should be fixed! Debugging this code structure will be more common as soon as 10.4 will fix inline declaration or when LSP will be released. procedure TTest.Test; begin if SomeCondition then begin var Qry := 'select * from sometable'; Check(Qry); // Breakpoint: S shows 'A' - Output in check = 'A' end; {..} if SomeOtherCondition then begin var Qry := 'select * from sometable where condition'; Check(Qry); // Breakpoint: S shows 'A' - should have been 'C' - Output in check = 'C' end; {..} while SomeCondition do begin var Qry := SomeFunction( SomeParameter ); Check(Qry); end; end; I'm not saying this construction is good or not, but if the new feature allows it, should work as advertised! Don't have much hair left to pull out.
  21. Clément

    Application blocking (suspended)

    the icon is called "econo mode" and when you hover over the leaf icon in Task Manager’s Status column, you will now see a tooltip describing what it means (this app is suspending processes to help improve system performance). My machine shows 2 applications with that leaf (Settings and Cortana). Both applications are responding. Here's another link with a better article: https://technidad.com/what-is-this-new-green-leaf-icon-in-task-manager-of-windows-10/ How the Green Leaf feature works and what it actually does As you know, the task manager is a window in which you can view all the processes. You can view all your running apps and also the different background processes. The processes that have a Green Leaf icon beside them are a bit different from the other processes. These are the processes which are actually ‘suspended’. This can save your computers RAM, without significantly affecting the performance of the processes. You could say that Windows puts these applications in the ‘Ready state’ or ‘blocks’ them from being executed by the processor. Windows could do it when the app requires a human input/output. Also, you won’t feel any lag because of the Green Leaf feature while switching between processes. A blessing for computers with lower specs It is expected that the introduction of this new feature in several versions of Windows 10 will be a blessing for computers with lower specs. The feature is so smart that it can turn your RAM more efficient than before and you can enjoy faster speeds of computing and reduced lags. By suspending the apps until you launch them the Green Leaf feature does a really good job.Also, after the app is launch you will notice in the task manager that the Green Leaf icon disappears. hth,
  22. Clément

    Application blocking (suspended)

    This might shed some light: https://superuser.com/questions/1406692/what-does-the-leaf-symbol-in-the-status-column-of-the-task-manager-mean "Do note, the faster your computer is, the less likely it is that windows needs to suspend processes. So some users with fast pc's may not see any suspended process, while people with a slower pc may see a lot of them." HTH
  23. Clément

    news about the beta of 10.3.4

    Amateurs! Delphi 10 Rock in Rio III If you insist in using X.... Delphi X-Rio III ( I should be in marketing )
  24. Clément

    Good practices with nested methods

    Hi, The code you posted is full of traps! While it's ok to play with scope you could end it with unexpected behavior when debugging should someone alter the disposition of the declarations ( There's always this guy that wants to optimize stuff). Another thing I always keep in mind. Nested methods are good candidate to private methods. Be sure to write safe code when future comes and avoid breaking working code because you WILL cut and paste that code and WILL suffer the cut and paste syndrome !
  25. Clément

    news about the beta of 10.3.4

    I guess you heard of 10.3.4 before everybody else. From the latest roadmap 10.3.3 should be released late 2019 and 10.4 was postponed to early 2020. You can check it out here: https://community.idera.com/developer-tools/b/blog/posts/august-2019-delphi-android-beta-plans-august-roadmap-update
×