RTC Forums
May 24, 2022, 03:42:13 PM *
Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length
 
   Home   Help Login Register  
Pages: [1]
  Print  
Author Topic: How to work TRtcDelayedCall?  (Read 2883 times)
agsoft
Newbie
*
Posts: 15


« 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)Wink
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.
Logged
D.Tkalcec (RTC)
Administrator
*****
Posts: 1870


« Reply #1 on: February 22, 2010, 05:31:32 PM »

Did you read this FAQ topic?

Best Regards,
Danijel Tkalcec
Logged
D.Tkalcec (RTC)
Administrator
*****
Posts: 1870


« Reply #2 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
Logged
agsoft
Newbie
*
Posts: 15


« Reply #3 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


Logged
Pages: [1]
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.21 | SMF © 2015, Simple Machines Valid XHTML 1.0! Valid CSS!
Page created in 0.026 seconds with 17 queries.