Just a second...

Handling subscriptions to missing topics

A client can handle subscription requests for topics that do not exist and can act on those notifications, for example, by creating a topic on demand that matches the request.

Required permissions: modify_topic, register_handler

The client can register itself as a handler for missing topics for any branch of the topic tree. The client is notified of attempts to subscribe to topics that are subordinate to that topic and that do not exist. This enables the client to create the topics and notify Diffusion™ Cloud that the client operation subscribe can proceed.

Note: The handler will also be called if a fetch request made using the deprecated fetch API matches new topics. Missing topic handlers are not called for the enhanced fetch API introduced in Diffusion Cloud 6.2.
Figure 1. Flow from a subscribing client to the client that handles a missing topic subscription The subscribing client subscribes to topic 'foo/missing' that does not exist. The Diffusion server notifies the handling client that has registered a handler against that branch of the topic tree. The handling client acts on this notification and tells the server when its action is complete by calling proceed or cancel. The Diffusion server responds to the subscribing client.

The missing topic handler is removed when the registering session is closed. If the registering session loses connection, it goes into DISCONNECTED state. When in DISCONNECTED state the handler remains active but cannot pass on the notifications to the client. In this case, cancel or proceed callbacks for these notifications might not function as expected because of timeouts. If the client then closes, these notifications are discarded.

To ensure that missing topic notifications are always received by your solution, you can use multiple clients to register missing topic handlers. Ensure that if any of these clients lose connection they go straight to CLOSED state by setting the reconnection timeout to zero. When the client loses connect it closes straight away, the handler is registered is removed, and further missing topic notifications are routed to a handler registered by another client.

Registering a missing topic notification handler

Register a handler against a branch of the topic tree:

JavaScript
session.topics.addMissingTopicHandler("topic_branch", {
		// Implement handling code
	});
Apple
-(void)registerAsMissingTopicHandlerForSession:(PTDiffusionSession *const)session {
    [session.topicControl addMissingTopicHandler:self
                                    forTopicPath:@"topic_branch"
                               completionHandler:^(PTDiffusionTopicTreeRegistration *const registration, NSError *const error)
    {
        if (registration) {
            NSLog(@"Registered as missing topic handler.");
        } else {
            NSLog(@"Failed to register as missing topic handler. Error: %@", error);
        }
    }];
}
Java and Android
TopicControl topicControl = session.feature(TopicControl.class);

topicControl.addMissingTopicHandler("topic_branch", new MissingTopicNotificationHandler());
.NET
ITopicControl topicControl  = session.TopicControl;
var missingTopicHandler = new MissingTopicHandler();
topicControl.AddMissingTopicHandler( topic_branch, missingTopicHandler );
C
MISSING_TOPIC_PARAMS_T handler = {
        .on_missing_topic = on_missing_topic,
        .topic_path = topic_branch,
        .context = NULL
};

missing_topic_register_handler(session, handler);

Implementing a missing topic handler

The sample registration code shows default or no-op missing topic handlers being registered. To take the required action when a missing topic notification is received, implement a missing topic handler:

JavaScript
session.topics.addMissingTopicHandler("topic_branch", {
		
	onRegister : function(path, close) {
		console.log("Registered missing topic handler on path: " + path);
	},
		
	onClose : function(path) {
		console.log("Missing topic handler on path '" + path + "' has been closed");
	},
		
	onError : function(path, error) {
		console.log("Error on missing topic handler");
	},
		
	onMissingTopic : function(notification) {
		console.log("Received missing topic notification with selector: " + notification.selector);
		
	    // Action to take in response to the notification, for example, creating a topic.
		    
	    // If the action is successful, you can indicate that by calling proceed
	    notification.proceed();
	}
});
Apple
@implementation MissingTopicHandlerExample (PTDiffusionMissingTopicHandler)

-(void)diffusionTopicTreeRegistration:(PTDiffusionTopicTreeRegistration *const)registration
          hadMissingTopicNotification:(PTDiffusionMissingTopicNotification *const)notification {
    NSString *const expression = notification.topicSelectorExpression;
    NSLog(@"Received Missing Topic Notification: %@", expression);

    // Action to take in response to the notification, for example, creating a topic.
    
    // If the action is successful, you can indicate that by calling proceed
    [notification proceed];
}

@end
Java and Android
private final class MissingTopicNotificationHandler implements
        MissingTopicHandler {
    /**
     * @param topicPath
     *            - the path that the handler is active for
     * @param registeredHandler
     *            - allows the handler to be closed
     */
    @Override
    public void onActive(String topicPath, RegisteredHandler registeredHandler) {
    }

    /**
     * @param topicPath
     *            - the branch of the topic tree for which the handler was
     *            registered
     */
    @Override
    public void onClose(String topicPath) {
    }

    /**
     * @param notification
     *            - the missing topic details
     */
    @Override
    public void onMissingTopic(MissingTopicNotification notification) {
        // Action to take in response to the notification, for example, creating a topic.
  
        // If the action is successful, you can indicate that by calling proceed
        notification.proceed();
    }

}
.NET
        private class MissingTopicHandler : IMissingTopicHandler {
            private readonly TaskCompletionSource<IRegisteredHandler> onActive =
                new TaskCompletionSource<IRegisteredHandler>();

            private readonly TaskCompletionSource<IMissingTopicNotification> onMissingTopic =
                new TaskCompletionSource<IMissingTopicNotification>();

            private readonly TaskCompletionSource<bool> onClose = new TaskCompletionSource<bool>();

            public Task<IRegisteredHandler> OnActiveCalled {
                get {
                    return onActive.Task;
                }
            }

            public Task<IMissingTopicNotification> OnMissingTopicCalled {
                get {
                    return onMissingTopic.Task;
                }
            }

            public Task OnCloseCalled {
                get {
                    return onClose.Task;
                }
            }

            void IMissingTopicHandler.OnMissingTopic( IMissingTopicNotification notification ) {
                onMissingTopic.SetResult( notification );
            }

            void ITopicTreeHandler.OnActive( string topicPath, IRegisteredHandler registeredHandler ) {
                onActive.SetResult( registeredHandler );
            }

            void ITopicTreeHandler.OnClose( string topicPath ) {
                onClose.TrySetResult( false );
            }
        }
    }
C
static int
on_missing_topic(SESSION_T *session, const SVC_MISSING_TOPIC_REQUEST_T *request, void *context)
{
        printf("Missing topic: %s\n", request->topic_selector);

        // Action to take in response to the notification, for example, creating a topic.
    
        // If the action is successful, you can indicate that by calling proceed
        missing_topic_proceed(session, (SVC_MISSING_TOPIC_REQUEST_T *) request);

        return HANDLER_SUCCESS;
}