How to send log events to client (delphi) example

Hi

I am trying to create a log visualizer in the client to see events of the server. I’m using Delphi and Remoting SDK.
What I am struggling now is in how to send real time data to client.

Is there any example of how to do it?
Does it slows down too much the server?

Hi,

you can examine these samples:

Hi
I verified the sample (HTTP Chat codefirst) and tried to implement a simple event/subscribe in our current infrastructure.
We already have codefirst Server/client implemented in production so we tried to implement just a simple method (tried to mimic sample’s login method).

We created an InMemorySessionManager and an EventRepository and hooked them up:

 FEventRepository.SessionManager := FSessionManager;
 FEventRepository.Message :=  FRoMessage; // server's FRoMessage

In our RoDataModule descendent, we coded RORemoteDataModuleCreate event to tell RO infra which session/event manager:

procedure TautenticacaoService.RORemoteDataModuleCreate(Sender: TObject);
begin
  EventRepository := getServer.EventRepository;
  SessionManager := getServer.SessionManager;
end;

When a client runs server’s code, it returns an “Abstract error” whenever we tried to get Session ou ClientID fields:

function TautenticacaoService.Login(
  const aUserID: Unicodestring): Unicodestring;
var
  ev: IRoEventWriter<IHTTPChatEvents>;
begin
  Session.Values['UserID'] := aUserID;
  result := GUIDToString(Session.SessionID); // ABSTRACT ERROR
  FCS.Enter;
  try
    RegisterEventClient(ClientID, 'HTTPChatEvents'); // ABSTRACT ERROR
    RegisterEventClient(ClientID, 'HTTPBroadCastEvents');
    ev := (EventRepository.GetWriter<IHTTPChatEvents>(Session.SessionID));
    ev.ExcludeSender := false; //para enviar para ele mesmo
    ev.Event.OnSendMessage(aUserID, 'teste', false );
  finally
    FCS.Leave;
  end;

end;

Should I have to set something else in order to make SessionManager work?

Hi,

Can you create a simple testcase that reproduces this issue, pls?
you can attach it hare or drop email to support@

I created and zipped it but I couldn’t attach it here (it shows an error). I will send it to support. Could you, please, verify if you have received?

The error in the sample is here:

function TchatService.Login( aUserId: string ) : string;
var
  ev: IRoEventWriter<IHTTPChatEvents>;
begin
  Session.Values['UserID'] := aUserID;
  result := GUIDToString(Session.SessionID);
  FCS.Enter;
  try
    RegisterEventClient(ClientID, EID_HTTPChatEvents);
    ev := (serverDataModule.EventRepository.GetWriter<IHTTPChatEvents>(Session.SessionID));

    ev.ExcludeSender := false; 
    ev.Event.OnSendMessage(aUserID, 'teste', false ); // ABSTRACT ERROR
  finally
    FCS.Leave;
  end;

end;

Hi,

as expected. TROEventRepository is base class that contains abstract methods that are implemented in descendants.

try to use TROInMemoryEventRepository instead:

 fEventRepository := TROInMemoryEventRepository.Create(self);

Hi
Now it runs flawlessly but I don’t receive any messages.
At client, the code is:

TClientForm = class(TForm, IHttpChatEvents)
    Message: TROBinMessage;
    Channel: TROWinInetHTTPChannel;
    RORemoteService: TRORemoteService;
    Button1: TButton;
    eventReceiver: TROEventReceiver;
    mmMessages: TMemo;
    procedure Button1Click(Sender: TObject);
  private
    procedure OnSendMessage(const aSenderUserID: Unicodestring; const aMessage: Unicodestring; const aIsPrivateMessage: Boolean);
    { Private declarations }
  public
    { Public declarations }
  end;
procedure TClientForm.Button1Click(Sender: TObject);
var
  userId: string;
begin
  EventReceiver.RegisterEventHandlers([EID_HTTPChatEvents], [Self]);
  { Starts polling }
  EventReceiver.Active := TRUE;
  userId := (RORemoteService as IchatService).Login('MARK');
  showMessage(userId);
end;

and

procedure TClientForm.OnSendMessage(const aSenderUserID,
  aMessage: Unicodestring; const aIsPrivateMessage: Boolean);
begin
  mmMessages.Lines.Add(aMessage); //DON'T ACCESS HERE
end;

Hi,

You haven’t assigned EventRepository for your service so events won’t be sent …

add

procedure TchatService.RORemoteDataModuleCreate(Sender: TObject);
begin
  Self.EventRepository := ServerDataModule.eventRepository;
end;

30942.zip (222.8 KB)

Hi
My mistake! But even adding that, I don’t receive any messages.
Does the zip attached is a working sample?

I tried to compile it but it complains that there is no uRONullable in chatLibrary_intf

Hi,

what version of Remoting SDK are you using?

try to regenerate files from .RemoteRODL

I am using version 10.0.0.1585
I couldn’t generate it because I cannot build server exe in order to update the interface.

why you can’t build server-side?

Code-First server-side doesn’t require _Intf for building.
you can replace constant EID* with it’s value like

  RegisterEventClient(ClientID, 'HTTPChatEvents');

In order to use constant EID*, I had to use _intf at server function. Replacing them with its values, it worked and sent messages flawlessly.
Thanks

Just a small question: RO generates this constant

const EID_HTTPLogEvents: string = 'HTTPLogEvents';

in the interface file from where?

I have this event sink:

[ROEventSink]
  IHTTPLogEvents = interface(IROEventSink)
  ['{75F9A466-518A-4B09-9DC4-9272B1EEFD95}']
    procedure OnSendLog(const aMessage: UnicodeString );
  end;

It generates ‘HTTPLogEvents’ constant from the name of the interface?

Hi,

You can specify event sink as

  [ROEventSink("myname")]
  IHTTPLogEvents = interface(IROEventSink)
  ['{75F9A466-518A-4B09-9DC4-9272B1EEFD95}']
    procedure OnSendLog(const aMessage: UnicodeString );
  end;

in this case, it will be generates as EID_myname = 'myname';

otherwise, I prefix will be removed and it will be generated as EID_HTTPLogEvents = 'HTTPLogEvents'.

Great

Last question, in order to stop listening to all interfaces, could I use:

UnregisterEventClient(ClientID);

Hi,

yes

RegisterEventClient and UnregisterEventClient methods work in pair

Hi

Another small question: When someone is connected to a server (TInMemorySessionManager) and server is shutdown (without client disconnecting), server was showing an exception when it was freeing TInMemorySessionManager.

After adding this line, the server does not complain:

FSessionManager.ClearSessions(false);

So, two questions:
Is it OK to do that? we’re hooking this line to destroy event in the form that has TRoHttpServer.

Is there a way to send a message to clients just before that in order to clean up things there?

We tried to hook an eventSink and send a message just before destroying the server but the message never gets there:

procedure TServerHttp.desconectAllSessions();
var
  ev: IRoEventWriter<IHTTPLogEvents>;
begin
  inherited;
  ev := (FEventRepository.GetWriter<IHTTPLogEvents>(EmptyGUID));
  ev.Event.OnMandatoryClose( 'Server is closing...');

  FSessionManager.ClearSessions(false);

end;