Switch to: V9V8V7V6V5

Notifications in Valentina Server

Notifications are supported in Valentina Server 6.x and later.

Introduction

Notification is a kind of message with a string-based payload. It can be produced either by any customer or by vKernel (system) itself and is communicated through the so-called “notification channels”. We introduce those “channels” (which are similar to IM`s chatting rooms) in order to have notifications more granulated. While there is a kind of a sender on the one side of a channel there are notification channel's subscribers on the other side. They listen to the channel (usually in dedicated thread) and react somehow to the notifications sent.

In other words the sender pushes a notification to the notification channel and then it is spread among the subscribers asynchronously (the receipt of notifications is processed in different thread/process and does not correspond to the “main” thread. Ultimately it is only about listening to some “notification channel” and reacting to the messages there).

Pay attention to the fact that notifications can be used both locally and under vServer. It is similar to sql-triggers - it does something as a reaction to some event. For example - you can send a notification from your stored procedure and the other clients (or even you yourself- sort of inter-process/thread communication) can react to that notification asynchronously.

Details

The only vServer's property you should check is the port for the notification connection. vClient will receive and use this port during regular connect procedure itself. So you shouldn`t do anything special in your app to use notifications over network.

...
[NOTIFICATION]
; Port to broadcast notifications to the clients.
; 0 - do not use Notification feature.
Port_NOTIFICATION=15436
...

There are only few simple interfaces:

I_NotificationCenter is an interface for (un)subscribing to the channels and sending notifications.

class I_NotificationCenter 
{
    ...
    virtual Subscribe( String inChannel );
    virtual UnSubscribe( String inChannel );
    virtual Notify(
	const String&		inChannel,
	const String&		inPayload,
	ENotificationPriority	inPriority = NormalPriority );
    ...

};

NotificationQueue is for getting notifications received from the subscribed channels.

        ...

	// Make NQ available to get/set notifications.
	// (NQ is in open state normally).
	//
	void Open( void );

	// Make NQ unavailable to get/set notifications.
	// (Mainly for interrupting  WaitForNotification() runned
	// in another thread).
	//
	void Close( void );
			
	// Get pending Notification from the queue or return NULL
	// immediately.
	//
	Notification_Ptr GetNotification( void );

	// Blocks current thread until either timeout reached
	// (0 - no timeout) or some notification comes to the queue
	// or NQ closed from some thread.
	//
	// !!! Don't call this method from the sinle-threaded app !!!
	// because of endless waiting there.
	//
	Notification_Ptr WaitForNotification( vuint32 in_TimeOut_ms = 0 );

        ...

Notification

    ...
    time_t					mTimeStamp;
    size_t					mInitiatorClientID;	// 0 - means "system".
    String					mChannel;		// kind of notification.
    String					mPayLoad;		// user can put here anything.
    bool					mIsSystem;		// to differ "system" notifications from user ones.
    ENotificationPriority	                mPriority;
    ...

Examples

There are some code snippets to show how to use notifications.

	// PREPARE:
	I_Connection_Ptr pConnection = GetConnection();
	if( pConnection == NULL )
        {
            // Local mode:
	    pConnection = QI( VSQL::GetLocalConnection(), I_Connection );
        }

	I_NotificationCenter_Ptr pNotificationCenter = pConnection->GetNotificationCenter();

	// Let's listen for notifications in another thread.
	Thread_Simple pNotificationListenerThread;
	pNotificationListenerThread.Create( NotificationListener, pConnection.get() );

	// JOB:
	
	// Subscribes to "channel1"
	pNotificationCenter->Subscribe( "channel1" );
	
	// Notify subscribers of "channel1"
	pNotificationCenter->Notify( "channel1", "message" );
	
	Pause();
	
	// Without this call we will be waiting for thread finish endless.
	pConnection->GetNotificationQueue()->Close();	

	// Waiting for thread finished:
	pNotificationListenerThread.Join();

Notification listener thread:

// This func waits for notifications and print them in dedicated thread until NotificationQueue
// is closed.
//
FBL_THREAD_ROUTINE( NotificationListener, inConnectionPtr )
{
	I_Connection* pConnection = static_cast<I_Connection*>( inConnectionPtr );
	if( pConnection )
	{
		while( Notification_Ptr pEvent = pConnection->GetNotificationQueue()->WaitForNotification() )
		{
			IO_LOCK;
			cout <<	endl;
			cout << "Channel: "		<< pEvent->mChannel.getBufferA()	<< endl;
			cout << "InitiatorClientID: "	<< pEvent->mInitiatorClientID		<< endl;
			cout << "IsSystem: "		<< pEvent->mIsSystem			<< endl;
			cout << "PayLoad: "		<< pEvent->mPayLoad.getBufferA()	<< endl;
		}
	}
	
	return NULL;
}