Title: How to work TRtcDelayedCall? Post by: agsoft on February 22, 2010, 10:34:44 AM In the MSG_Server demo, User A is chating User B.
flow of chat infomation: SendText->SendData->TriggerCallback->GetCallback->TRtcDelayedCall.Wakeup (-------------------------------------------------- function Params: 1.SendText(const from_name, to_name, text:string) 2.SendData(const to_name:string; data:TRtcValueObject); 3.TriggerCallback(uname: string); 4.GetCallback(uname: string): TRtcDelayedCall; cb:=PrepareDelayedCall(10000, Param, MsgGetDataExecute); ------------------------------------------------------------) My Question: 1.How can User A locate User B with TRtcDelayedCall(PrepareDelayedCall have not any TRtcConnection)? TRtcDelayedCall Already haved TRtcConnection(User B)? 2.How TriggerCallback obtain params(chat infomation text)? (PrepareDelayedCall(10000, Param, MsgGetDataExecute);) 3.Callback function only use TRtcDelayedCall?Is there another simple method of callback function? 4.Can you provider another detail demo about TRtcDelayedCall? I debug the code,but it broken frequency. Title: Re: How to work TRtcDelayedCall? Post by: D.Tkalcec (RTC) on February 22, 2010, 05:31:32 PM Did you read this FAQ topic (http://realthinclient.com/sdkarchive/indexef7cef7c.html)?
Best Regards, Danijel Tkalcec Title: Re: How to work TRtcDelayedCall? Post by: D.Tkalcec (RTC) on February 22, 2010, 06:26:17 PM The important thing about "Delayed Calls" is that the Client does NOT have anything to do with them. "Delayed Calls" are entirely implemented on the Server. The Client will only call a remote function on the Server and wait for a result. The Server will then create a TRtcDelayedCall object and put the server-side remote function into "delayed call" state, from which the remote function can either be awaken using the TRtcDelayedCall.WakeUp method, or will be waken up after a timeout set when creating the TRtcDelayedCall object expires.
In other words, "Delayed Calls" are used to implement a remote function on the Server so that its response can be delayed in case there is no data currently ready for sending back to the Client, keeping the Client waiting for a response and allowing other parts of the Server code to call that same remote functions OnExecute event again after a timeout or in case any other part of the Server code should call the WakeUp method on the TRtcDelayedCall object created in that remote function. Here is the "GetData" remote function, which is implemented in the "TMessanger_Provider.MsgGetDataExecute" method in the rtcMessengerProvider unit. That function is called continually by the RTC Messenger Client to check if there is data for that Client waiting. I have extended it here with more detailed comments about every line of code used there, to make it more plausible and try to explain all the important pieces you need to put together to correctly implement RTC Delayed Calls: procedure TMessenger_Provider.MsgGetDataExecute(Sender: TRtcConnection; Param: TRtcFunctionInfo; Result: TRtcValue); var thischeck:TDateTime; arr:TRtcArray; cb:TRtcDelayedCall; begin cb:=nil; { Since we want Data, it would be a good idea to check if the user has authenticated himself before calling the remote function. That is implemented in the CheckLogin() function in the RTC Messenger Server example. The function should raise an exception if the user is not logged in, to prevent the rest of the remote function code to be executed. We should give that function access to the Sender parameter, since it has the complete connection info including our Session. } // CheckLogin(Sender, Param); { We will be setting "delayed" to TRUE below to signal ourselves that this Execute method is being called after it was put into a "Delayed Call" state, which means that we should either have data ready for sending (WakeUp was called), or a timeout has happened and we should return an empty result to the Client. } if not Param.asBoolean['delayed'] then begin { Set "delayed" parameter to TRUE, before preparing the call, because only changes we do to Param before we send it to the PrepareDelayedCall function will be memorized, while any changes we do to Param afterwards will be discarded. } Param.asBoolean['delayed']:=true; { Prepare delayed call object "cb", which will time out 10 seconds after it was posted, if "WaitFor" is NOT called on it before that. PrepareDelayedCall meeds to be called with our Param object as well as THIS event (MsgGetDataExecute in this case, see above). } cb:=PrepareDelayedCall(10000, Param, MsgGetDataExecute); { Once we have the DelayedCall object "cb", we should store it somewhere from where the rest of our Server code will be able to find it when more data is prepared for this Client. How and where you store this info is entirely up to you, but you should make sure your code is thread-safe if your Server is MultiThreaded, because you should be able to store, restore and access the object from other threads. } // user.SetCallback(Param['user'],cb); end; { Now that we have the delayed call object "cb" created and stored in a place where the rest of our Server code can find it and call "WakeUp" if there is more data ready for this Client, we should check if data is already waiting for this client to be picked up. RTC Messenger Server demo implements the GetData() method for this purpose. } // arr:=user.GetData(Param['user'],Param['check'],thischeck); { If there is data ready for the Client, the function above should give it to us, so we can send it to the Client as a Result. } if assigned(arr) then begin { We should remove the Delayed Call object (cb) from where ever we might have stored it before, so it will NOT be used to try and wake this remote function call up again, since we are now going to return a result, so the delayed call object is no longer valid. } // user.SetCallback(Param['user'],nil); { If we have just created the Delayed Call object (cb<>nil), we should also use CancelDealyedCall to free any memory allocated by the object, since we will not be needing it anymore (exiting function, returning result). } CancelDelayedCall(cb); { Here, we should prepare the Result for our Client by using the Data returned above (data returned from the GetData, in our example). } //with Result.NewRecord do // begin // asObject['data']:=arr; // asDateTime['check']:=thischeck; // end; end { If there is no data waiting and this we have prepared a Delayed Call object (above), we should use PostDelayedCall to post our Delayed Call (put this function to sleep so it can be called after our specified timeout or when another part of the Server code uses our Delayed Call objects WakeUp method to wake us up. } else if assigned(cb) then begin PostDelayedCall(cb); { Posting the delayed call object will stop executing any code beyond the "PostDelayedCall" line, since PostDelayedCall method will silently raise an exception to signal the underlying RTC SDK that this remote function should be put into "delayed response" state. } end { If no data is waiting and we have not prepared a Delayed Call object, which means that our previously prepared "cb" object has timet out but there was no data ready for sending, we should return a result which will make the Client know that there is no data waiting. Sending an empty result should do the trick, provided the Client is implemented to use Result.isNULL as a correct response from the Server saying there is no data. } else begin // not setting a Result will send Result.isNull=TRUE to the Client. end; end; I have put RTC function calls and important variable assignments in BOLD, so you can distinguish them easier from other user functions and code. The client, as said, will simply be calling the remote function on the Server and wait for a result. It is also a good idea to use a Timer or something similar on the Client to continue asking the Server for more data (also called "polling"). I hope this explains the basics. How you store the "cb" object so that your Server application can find it to wake the remote function up, and how or where you store your user data, is entirely up to you. If you need a working example, take a close look at the RTC Messenger Client and Server demos. Best Regards, Danijel Tkalcec Title: Re: How to work TRtcDelayedCall? Post by: agsoft on February 23, 2010, 09:28:18 AM thank you for your answer.
I write some logs in the messager server,so i understand TRtcDelayedCall now. this is logs: only one user login logs:<ClientCall is added in the client> SendData:To_Name->zmd -- 2010-2-23 15:57:26.218 Write_File:D:\MyVcl\RTC\RTC\Demos\RTC_Messenger\RtcMessengerData\User.zmd.msg.data -- 2010-2-23 15:57:26.218 TriggerCallback:zmd -- 2010-2-23 15:57:26.218 GetCallback:zmd -- 2010-2-23 15:57:26.218 MsgGetDataExecute Event:FC=GetData;RE=3;user:T=3"zmd";check:D=;ClientCall:B=T; -- 2010-2-23 15:57:26.234 PrepareDelayedCall:FC=GetData;RE=4;user:T=3"zmd";check:D=;ClientCall:B=T;delayed:B=T; -- 2010-2-23 15:57:26.234 SetCallback:zmd -- 2010-2-23 15:57:26.250 SetCallback to nil -- 2010-2-23 15:57:26.250 CancelDelayedCall:zmd -- 2010-2-23 15:57:26.250 sent data now:AR=1;RE=1;logout:T=6"tintin"; -- 2010-2-23 15:57:26.250 MsgGetDataExecute Event:FC=GetData;RE=3;user:T=3"zmd";check:D=2010-2-23 15:57:28.0;ClientCall:B=T; -- 2010-2-23 15:57:26.250 PrepareDelayedCall:FC=GetData;RE=4;user:T=3"zmd";check:D=2010-2-23 15:57:28.0;ClientCall:B=T;delayed:B=T; -- 2010-2-23 15:57:26.265 SetCallback:zmd -- 2010-2-23 15:57:26.265 PostDelayedCall:zmd -- 2010-2-23 15:57:26.265 only one user idle logs(10 seconds): MsgGetDataExecute Event:FC=GetData;RE=4;user:T=3"zmd";check:D=;ClientCall:B=T;delayed:B=T; -- 2010-2-23 15:59:46.328 MsgGetDataExecute Event:FC=GetData;RE=3;user:T=3"zmd";check:D=;ClientCall:B=T; -- 2010-2-23 15:59:46.328 PrepareDelayedCall:FC=GetData;RE=4;user:T=3"zmd";check:D=;ClientCall:B=T;delayed:B=T; -- 2010-2-23 15:59:46.343 SetCallback:zmd -- 2010-2-23 15:59:46.343 PostDelayedCall:zmd -- 2010-2-23 15:59:46.359 tow user talk logs: MsgSendText<from:zmd,To:tintin,text:123456 -- 2010-2-23 16:17:48.843 SendData:To_Name->tintin -- 2010-2-23 16:17:48.859 Write_File:D:\MyVcl\RTC\RTC\Demos\RTC_Messenger\RtcMessengerData\User.tintin.msg.data -- 2010-2-23 16:17:48.875 TriggerCallback:tintin -- 2010-2-23 16:17:48.875 GetCallback:tintin -- 2010-2-23 16:17:48.875 TriggerCallback:WakeUp -->tintin -- 2010-2-23 16:17:48.875 MsgGetDataExecute Event:FC=GetData;RE=4;user:T=6"tintin";check:D=;ClientCall:B=T;delayed:B=T; -- 2010-2-23 16:17:48.875 SetCallback to nil -- 2010-2-23 16:17:48.890 CancelDelayedCall:tintin -- 2010-2-23 16:17:48.890 sent data now:AR=1;RE=2;from:T=3"zmd";text:T=6"123456"; -- 2010-2-23 16:17:48.890 MsgGetDataExecute Event:FC=GetData;RE=3;user:T=6"tintin";check:D=2010-2-23 16:17:50.0;ClientCall:B=T; -- 2010-2-23 16:17:48.906 PrepareDelayedCall:FC=GetData;RE=4;user:T=6"tintin";check:D=2010-2-23 16:17:50.0;ClientCall:B=T;delayed:B=T; -- 2010-2-23 16:17:48.906 SetCallback:tintin -- 2010-2-23 16:17:48.906 PostDelayedCall:tintin -- 2010-2-23 16:17:48.921 |