Sorry, but the only examples available are the ones I've already mentioned above.
Anyway ... because you have said that you are already using some mechanism to periodically request data from your Server and have mentioned "easy integration", I think that using "delayed calls" with RTC remote functions will be faster for you to implement than using a completely new set of components.
Even though this is the "old approach" which does require more manual coding and is probably more complicated than using RTC Gateway and Gate Client components, I don't really think there is so much to learn if you already know how to get data from a Server to a Client.
I will try to explain now how "delayed calls" work with RTC Remote Fuctions (in a "few" sentences), then include the "MsgGetDataExecute" method implementation, which is used by the RTC Messenger Server to implement the "get" remote function, which in turn is used by the RTC Messenger Client to get any data currently stored for that Client on the Server.
First, you will need a separate TRtcHttpClient component on your Client and you will need to use that component exclusively for sending requests to get data from the Server. The frequency of these requests does not really matter, because the Server will dictate how often a response is sent back if there is no data available.
The "gist" of "delayed calls" is the "
OnExecute" event on the Server, where the remote function used by the Client to get new data has to be implemented.
It is not much different from what you are already doing now when periodically sending requests for data, but since you want the Clients to be notified almost immediately when new data is available from the Server, you will need to keep a remote function call in a "delayed response" state, so you can use a "WakeUp" method on a "TRtcDelayedCall" object (will be explained below), which you will create using the "PrepareDelayedCall" procedure from inside your "OnExecute" event on the Server (just keep reading
).
When writing your Server-side code to handle "delayed calls", you can either choose to have two different method implementations, one for direct calls made by Clients and a separate method for calls made internally when data is available, or ... as I've done it in the RTC Messenger Server example, simply store the current state of the remote function in one of the (unused) remote function parameters, like - for example - Param.asBoolean['delayed'] - which I am setting to TRUE when the remote function is called directly, so it will be TRUE later - when the same event is called as a result of "delayed calls" triggering.
You will also need to declare a local variable of type "
TRtcDelayedCall" in your "
OnExecute" event, so you can create an instance of it using the "
PrepareDelayedCall" procedure (function declared in the "rtcSrvModule" unit) AFTER you have made sure the this Client is allowed to access data on your Server, but BEFORE you start checking if any data is available for that Client.
Since I am using the Param.asBoolean['delayed'] parameter to memorize the state of my remote function call, I will be creating a new "TRtcDelayedCall" object only if Param.asBoolean['delayed']=FALSE, but you can also have two separate event implementations if you want.
In either case, you will use the "
PrepareDelayedCall" function if you want to have the abbility to delay a response if no data is available and call the same function internally again when data becomes available later.
Here are the "PrepareDelayedCall" function parameteres:
1. maximum allowed delay (in milliseconds) before a result has to be sent,
2. remote function call object (Param:TRtcFunctionInfo) and the
3. remote function call event (usually - the even you currently implementing).
When you get a new "
TRtcDelayedCall" object, make sure to
store it somewhere in your own structures and associate it with the user (Client) making this remote function call, so you can use the "
WakeUp" method on the "
TRtcDelayedCall" object when new data becomes available for that user (Client).
This "
TRtcDelayedCall" object will be used to ensure that the "remote function call event" (whatever you've used as the 3rd parameter to the "PrepareDelayedCall" function) is triggered with remote function call parameters (whatever you have used as 2nd parameter) after the timeout (used as 1st parameter), or whenever you call the "
WakeUp" method on the "TRtcDelayedCall" object - which you've received and should have stored somewhere in your structures associated with that user (client).
Once you have that "
TRtcDelayedCall" object
safely stored away inside your own structures, where it is accessible from any other parts of your code responsible for storing data for Clients, you can now check (from the same "OnExecute" event) if there is data available for that user (Client).
If there is data ready to be send immediately back to the user (Client) from the "OnExecute" event, if you have created a new "TRtcDelayedCall" object in this event, you should now REMOVE it from your own structures (make sure you will NOT be using that object anymore if new data arrives) and call the "
CancelDelayedCall" procedure to
free the "
TRtcDelayedCall" object (avoid memory leaks), becuase that object is no longer required nor useful once we return any result back to the Client.
You can then prepare the Result for that Cient (as usual) and exist the remote function normally.
On the other hand ... if there was NO DATA ready to be sent back to the Client and you have created a new "TRtcDelayedCall" object (see above) and stored it safely in your own structures (so you can use its "WakeUp" method when new data does become available for the Client), you should use the "
PostDelayedCall" procedure before you exist the "OnExecute" event to post your newly created "delayed call" and put your Clients conneciton with its remote function call into a "delayed response" state. This allows you to use the "
WakeUp" method on the (previously created) "
TRtcDelayedCall" object (which you should have stored somewhere in your structures and assiciated with that user/Client) to wake trigger this remote funciton call (where a new check for data will be made and a Result prepared for the Client) when new data does become available.
Or ... if there was NO DATA ready to be sent back to the Client, but you have NOT created a NEW "TRtcDelayedCall" object now, you should only REMOTE any previously created and stored "TRtcDelayedCall" objects from your own structures - before exiting the "OnExecute" event handler.
Here is the entire "MsgGetDataExecute" method implementation, which you can also find in the "rtcMessengerProvider.pas" unit. As you will see, even though my explanation was quite long, there is not a lot of code involved ...
procedure TMessenger_Provider.MsgGetDataExecute(Sender: TRtcConnection; Param: TRtcFunctionInfo; Result: TRtcValue);
var
thischeck:TDateTime;
arr:TRtcArray;
cb:TRtcDelayedCall;
begin
cb:=nil;
CheckLogin(Sender, Param['user']);
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, which will be triggered in 10 seconds
in case the callback function is not used until then. }
cb:=PrepareDelayedCall(10000, Param, MsgGetDataExecute);
user.SetCallback(Param['user'],cb);
end;
arr:=user.GetData(Param['user'],Param['check'],thischeck);
if assigned(arr) then
begin
// don't need delayed call, new data is ready to be sent now!
user.SetCallback(Param['user'],nil);
if assigned(cb) then
CancelDelayedCall(cb);
with Result.NewRecord do
begin
asObject['data']:=arr;
asDateTime['check']:=thischeck;
end;
end
else if assigned(cb) then
PostDelayedCall(cb)
else
user.SetCallback(Param['user'],nil);
end;
The "user" object in that example above is an instance of a custom class, which is implemented in the "rtcMessenger" unit in the Demos/DataProviders folder ad part of the RTC Messenger Server Demo and used for user management and data storage. You can check that unit for the actual implementation, if you need more details how it works.
If you have more question, feel free to ask.
Best Regards,
Danijel Tkalcec