A very common use-case in Webcom applications is to receive notifications as soon as some data is updated (either by the running client itself or by any other client). This strength of the Webcom back end relies on the real-time feature of its underlying database.
In practice, the idea is to subscribe to a given type of update event on a given data node (or subscriber node). From then on, a callback function registered at subscription will be called for each matching update event on the data at this node. In addition to the data itself, the notified event may contain useful pieces of information such as the acknowledgement status of the data.
Note that the Webcom SDK provides additional subscription channels, namely notifications over a
webhook (mainly for back end clients) or a mobile push messaging system (for mobile clients only).
More experimented developers may also go further and read also Subscribable events in depth.
The callback subscription channel is not available with the lite Serverless Database service (provided by the Webcom SDK for JavaScript) or the REST interface.
In both cases, you can nevertheless subscribe to webhooks.
Subscribable event types
Webcom currently provides 4 types of update events you can subscribe to:
Type of update event | Description |
---|---|
Value Change | The value of the subscriber node has been updated. The raised event includes the new value and its acknowledgement status. |
Child Addition | A new child has been added to the subscriber node. The raised event includes the key of the new child, its value, the key of the preceding child (following the Webcom key ordering), and the acknowledgement status of this child addition. |
Child Change | The value of an existing child of the subscriber node has been updated. The raised event includes the key of the updated child, its value, the key of the preceding child (following the Webcom key ordering), and the acknowledgement status of this child update. |
Child Removal | A child of the subscriber node has been removed. The raised event includes the key of the removed child, the value of the child before its removal, and the acknowledgement status of this child removal. |
While several types of Child related events can be combined and subscribed simultaneously, Value Change and Child related events cannot. For example: Child Addition and Child Removal may be subscribed at the same time, while Child Addition and Value Change cannot.
Once a subscription registered, the associated callback function will be called each time an event of the type that
has been subscribed is raised. The details for each event type are given in the following sections.
In addition, the callback function may also be notified of:
- the acknowledgement event. It is raised in case the node update is acknowledged by the back end without its data having changed themselves. This is useful when you need to check some data have been actually taken into account by the Webcom back end (the notion of "acknowledgement" is described hereafter in this page).
- the revocation event. It is raised by the Webcom back end as soon as: the security rules prevent the subscriber node from being read, or the size of the subscriber node becomes too large. Once raised, the revocation event is passed to the callback function, and the associated subscription is automatically canceled. The callback will never be called any longer from then on.
- the cancelation event. It is raised as soon as the corresponding subscription has been canceled by the client application. Once raised, the cancelation event is passed to the callback function, and of course the callback will never be called any longer from then on.
Subscribing and unsubscribing
In JavaScript, subscribing relies on the subscribe(...)
method. The first parameter expects the subscribed event
type, while the second one expects a notification callback. An optional third parameter makes it possible to specify
a query constraint (see Querying data subsets).
The notified events passed to the callback are instances of the DataSnapshot
class: among the methods common to all
subscribed types of events, the acked
property indicates whether the data update represented by the event is
acknowledged by the back end or local to the client cache, and the event
property returns the type of the actually
raised event (it is useful when the callback is subscribed to several types of event at a time).
By default, revocation events are always notified, but you can explicitly exclude them with by calling
excludeRevocations()
on the passed event descriptor:
// const app = Webcom.App("<your-app>"); // UNCOMMENT if you haven't yet an instance of your app!
const database = app.serverlessDb;
let node = database.rootNode.relativeNode("contacts");
let eventDescriptor = Webcom.Event.Child.Addition.Removal // subscribe to both child added and child removed events
.excludeRevocations() // explicitly ask NOT to be notified of revocation events
node.subscribe(
eventDescriptor,
Webcom.Callback(dataSnapshot => { // the callback to call when an event is raised (except revocation events)
if (dataSnapshot.event.isChildAddition) {
console.log(`The contact ${dataSnapshot.node.key} is added, with value ${JSON.stringify(dataSnapshot.val())}`);
console.log("The data ", dataSnapshot.acked ? "are" : "are not yet", "acknowledged")
} else {
console.log(`The contact ${dataSnapshot.node.key} is removed`);
}
})
);
The Callback
objects may be customized using:
- the
onCanceled()
method to specify a dedicated callback to be called either when the subscription is revoked by the Webcom back end or explicitly canceled by the client application. - the
includeAcknowledgements()
method to call the callback function also when the subscribed data is acknowledged by the Webcom back end without change.
// const app = Webcom.App("<your-app>"); // UNCOMMENT if you haven't yet an instance of your app!
const database = app.serverlessDb;
let node = database.rootNode.relativeNode("contacts");
// build a callback
const callback = Webcom.Callback(dataSnapshot => { // the callback to call when an event is raised
if (dataSnapshot.event.isChildAddition) {
console.log(`The contact ${dataSnapshot.node.key} is added, with value ${JSON.stringify(dataSnapshot.val())}`);
console.log("The data ", dataSnapshot.acked ? "are" : "are not yet", "acknowledged")
} else {
console.log(`The contact ${dataSnapshot.node.key} is removed`);
}
});
callback.includeAcknowledgements(); // notify also acknowledgements
callback.onCanceled(
(error) => { // defines a 'revocation' callback
if (error === null) {console.log("Subscription explicitly canceled by client app");}
else {console.log("Subscription revoked by Webcom back end, with cause: ", error.message);}
}
);
// then subscribe to events
node.subscribe(Webcom.Event.Child.Addition.Removal, callback);
Examples of valid event descriptors:
Webcom.Event.ValueChange
Webcom.Event.ValueChange.WithoutData
Webcom.Event.ValueChange.excludeRevocations()
Webcom.Event.Child.Change.Addition.Removal
Unsubscribing may be done using either the unsubscribe(...)
method on a data node, or the cancel()
method on a
given subscription:
// const app = Webcom.App("<your-app>"); // UNCOMMENT if you haven't yet an instance of your app!
const database = app.serverlessDb;
let node = database.rootNode.relativeNode("contacts");
// first subscribe
let myCallback = Webcom.Callback(/*...*/); // please see code sample above
let mySubscription;
node.subscribe(Webcom.Event.ValueChange, myCallback)
.then((subscription) => mySubscription = subscription) // get the returned subscription when the promise is resolved
// ... do some stuff
// then unsubscribe to one callback (other callbacks may remain for this node)
node.unsubscribe(myCallback) // from the node
// or
mySubscription.cancel() // another way do do the same, from the received subscription
In Kotlin, a subscription is registered using the
subscribe()
method of
DatasyncNode
objects, and is managed by the
DatasyncManager
object that has created this DatasyncNode
instance:
- The first argument of this method represents the subscribed types of event, excluding “Value
Acknowledgement” and “Child Acknowledgement”, which are separately requested using the boolean
property
includesAcknowledgements
of theoptions
parameter. The subscribed types of event are given as their common Kotlin type inheriting theSubscribableEvent
interface:Value.Changed::class
for the “Value Change” event type,Child.Added::class
for the “Child Addition” event type,Child.Changed::class
for the “Child Change” event type, etc... - The last argument of the
subscribe()
method is a callback function, which is called for each raised event, including cancelation and revocation events.
The notifications received by the callback may be either:
- A cancelation or revocation notification (passed as instances of
Notification.ControlNotification
subclasses). In this case, it is the last notification to be received by the callback. - A notification of one of the subscribed events (which are all subclasses of both
Notification.DataNotification
andSubscribableEvent
). Among the properties common to all of these subclasses,isAcknowledgement
indicates whether the event is one of the “Value Acknowledgement” or “Child Acknowledgement” events, andvalue
gives theDatasyncValue
associated to the event (including its acknowledgement status).
import com.orange.webcom.sdk.datasync.subscription.SubscribableEvent.*
val app = WebcomApplication.default
val manager = app.datasyncService.createManager()
val node = manager / "contacts"
val options = SubscriptionOptions(includesAcknowledgements = true)
val subscription = node.subscribe(Value.Changed::class, options = options) { // it: Notification<Value.Changed>
when (it) {
is Notification.DataNotification -> { // it.data: Value.Changed
if (!it.data.isAcknowledgement) println("The data at CONTACTS has changed: ${it.data.value}")
println("The data at CONTACTS ${if (it.data.value.acknowledged) "is" else "is not"} acknowledged")
}
is Notification.ControlNotification ->
println("The subscription on CONTACTS has been canceled or revoked! ${it.error?.message}")
}
}
Unsubscribing is done using the cancel()
method of the
Subscription
object returned by the previous
subscribe()
method:
subscription.cancel()
Note that subscriptions are managed by
DatasyncManager
objects so that each manager automatically cancels its registered subscription when released (ie garbage-collected). A typical use-case is to create a dedicated manager for eachActivity
orFragment
of your Android app and bind their life-cycles. Thus, this avoids managing explicitly the cancelation of subscriptions, which is generally a tedious task.
In Swift, a subscription is registered using the
subscribe()
method of DatasyncNode
objects and is managed by the DatasyncManager
object that has created this DatasyncNode
instance.
A subscription is specified by a callback function that will be called each time the corresponding event is raised.
The subscribed type of event is represented by a value of the dedicated
DatasyncEventType
enum.
The subscription callback receives as parameter a DatasyncEvent
value that provides convenient methods to retrieve the kind of the just raised event, the value of the associated
data node, as well as the corresponding DatasyncSubscription
object (which makes it possible to individually revoke the subscription without waiting for the manager to do it).
let manager = Webcom.defaultApplication.datasyncService.createManager()
let contactsNode = manager / "contacts"
contactsNode?.subscribe(to: .valueChange) { event in
guard let allContacts: [Contact] = event.value.decoded() else {
return
}
print("The 'contacts' node has \(allContacts.count) child nodes")
}
Subscriptions are managed by
DatasyncManager
objects so that each manager automatically cancels its registered subscription when released. The idea is to create a manager for each view controller and bind their life-cycles, in order to avoid explicitly managing the cancelation of subscriptions, which is generally a tedious task.
Value events
Value events are raised as soon as the value of the subscriber node, considered as a whole, changes. Considering the
value of a nonexistent data node is null
, these events are also raised when the subscriber node is deleted (ie its
value becomes null
).
“Value Change” event
This event is raised:
- Initially at subscription registration, with the current known value of the subscriber node,
- Then each time the value of the subscriber node changes, with its new value.
This event also conveys whether the value of the subscriber node has been acknowledged by the Webcom back end or only updated locally within the client cache.
In JavaScript, the “Value Change” event type is represented by the Webcom.Event.ValueChange
constant.
The val()
method of the DataSnapshot
object passed to the callback gets the subscriber node value.
// const app = Webcom.App("<your-app>"); // UNCOMMENT if you haven't yet an instance of your app!
const database = app.serverlessDb;
let contactsNode = database.rootNode.relativeNode("contacts");
// Display the count of contacts in real time
contactsNode.subscribe(Webcom.Event.ValueChange,
Webcom.Callback(dataSnapshot => {
console.log("There are now", Object.keys(dataSnapshot.val()).length, "contacts");
})
);
In Kotlin, there are 2 variants of the “Value Change” event type:
Value.Changed
, which conveys the value of the subscriber node when raised,Value.ChangedHidingData
, which doesn't convey the value of the subscriber node when raised.
import com.orange.webcom.sdk.datasync.subscription.SubscribableEvent.*
val app = WebcomApplication.default
val manager = app.datasyncService.createManager()
val contactsNode = manager / "contacts"
// Display the count of contacts in real time
val subscription = contactsNode.subscribe(Value.Changed::class) { // it: Notification<Value.Changed>
when (it) {
is Notification.DataNotification -> // it.data: Value.Changed
println("There are now ${it.data.value.asMap.size} contacts")
is Notification.ControlNotification -> println("Contact watching revoked: ${it.error?.message}")
}
}
let app = Webcom.defaultApplication
let manager = app.datasyncService.createManager()
let contactsNode = manager / "contacts"
// Display the count of contacts in real time
contactsNode?.subscribe(to: .valueChange) { event in
print("There are now \(event.value.decoded(as: [String: Contact].self)?.count ?? 0) contacts")
} onCompletion: { completion in
if case let .revocation(reason: reason) = completion {
print("Contact watching revoked: \(reason)")
}
}
“Value Acknowledgement” event
That's not an explicit event type as such but, when subscribing to “Value Change”, you can ask to be also notified of data acknowledgments. In other words, it is not possible to subscribe to the “Value Change Acknowledgement” event alone, without subscribing to the “Value Change” event. It is not really a limitation, since this use case is quite useless (see the tip corner below).
An acknowledgment event:
- Is never raised initially at subscription registration,
- Is raised following a “Value Change” event, whose conveyed value of the subscriber node is NOT
acknowledged by the Webcom back end:
- as soon as the value of the subscriber node is acknowledged by the back end,
- AND its value is the same as the one conveyed by the previous “Value Change” event (otherwise a new “Value Change” event is raised).
For convenience, it conveys the acknowledged value of the subscriber node, which is necessarily equal to the value of the previous “Value Change” event, and the acknowledgement status of the value, which is necessarily true.
In JavaScript, you ask receiving acknowledgement events by calling the includeAcknowledgements()
method of the
Callback
object passed to the subscribe()
method.
// const app = Webcom.App("<your-app>"); // UNCOMMENT if you haven't yet an instance of your app!
const database = app.serverlessDb;
let contactsNode = database.rootNode.relativeNode("contacts");
let callback = Webcom.Callback(/*...*/) // define a callback
.includeAcknowledgements() // ask notifications on acknowledgements
// Display a message each time the contact list is acknowledged by the back end
contactsNode.subscribe(
Webcom.Event.ValueChange,
Webcom.Callback(dataSnapshot => {
if (dataSnapshot.event.isAck) { console.log("The contact list has just been acknowledged"); }
/* else the contact list has just been updated (in the acknowledged state or not) */
})
);
In Kotlin, you ask receiving acknowledgement events by passing a
SubscriptionOptions
object with the
includesAcknowledgement
property set to true
to the subscribe()
method.
import com.orange.webcom.sdk.datasync.subscription.SubscribableEvent.*
val app = WebcomApplication.default
val manager = app.datasyncService.createManager()
val contactsNode = manager / "contacts"
// Display a message each time the contact list is acknowledged by the back end
val options = SubscriptionOptions(includesAcknowledgements = true)
contactsNode.subscribe(Value.Changed::class, options = options) { // it: Notification<Value.Changed>
if (it is Notification.DataNotification && it.data.isAcknowledgement)
println("The contact list has just been acknowledged")
/* else the contact list has just been updated (in the acknowledged state or not) */
}
let app = Webcom.defaultApplication
let manager = app.datasyncService.createManager()
let contactsNode = manager / "contacts"
// Display a message each time the contact list is acknowledged by the back end
contactsNode?.subscribe(to: .valueEvent) {
if $0.value.isAcknowledged {
print("The contact list is acknowledged")
}
}
Note that, in practice, in order to watch the acknowledgement of the value of a data node, it is necessary to subscribe to BOTH:
- “Value Change” event, in case the notified value is already acknowledged (typically the value has been updated by another client),
- “Value Acknowledgement” event (by asking to receive additionally acknowledgement notifications), in case the value is first updated locally on the client (raising the previous event in not acknowledged state) and then acknowledged by the back end.
Child events
Child events are raised as soon as a child of the subscriber node is updated. When watching children, it is possible to distinguish between additions, changes (ie updates of existing children) and removals of children. Such raised events additionally convey, with respect to previous Value events, the key of the concerned child and sometimes the key of the child that precedes the concerned child along the Webcom key ordering.
“Child Addition” event
This event is raised:
- Initially at subscription registration, one time for each of the current known children of the subscriber node,
- Then each time a child node is added to the subscriber node, with the key and the value of this child.
This event also conveys the key of the child of the subscriber node that directly precedes (along the Webcom key ordering) the added child, as well as a boolean indicating whether the added child has been acknowledged by the Webcom back end or only updated locally within the client cache.
In JavaScript, the “Child Addition” event type is represented by the Webcom.Event.Child.Addition
constant.
The first argument passed to the callback is a DataSnapshot
object, whose node.key
property gives the key of the
added child, and whose val()
method gets its value. The second argument passed to the callback is a string
representing the key of the child that precedes the added child or null
if it is the first child of the subscriber
node.
// const app = Webcom.App("<your-app>"); // UNCOMMENT if you haven't yet an instance of your app!
const database = app.serverlessDb;
let node = database.rootNode.relativeNode("contacts");
// Update a GUI in real-time each time a new contact is added
node.subscribe(Webcom.Event.Child.Addition,
Webcom.Callback((dataSnapshot, previousChildKey) => {
myView.addItem({name: dataSnapshot.node.key, value: dataSnapshot.val(), after: previousChildKey});
})
);
In Kotlin, the “Child Addition” event type is represented by the
Child.Added
interface:
import com.orange.webcom.sdk.datasync.subscription.SubscribableEvent.*
val app = WebcomApplication.default
val manager = app.datasyncService.createManager()
val contactsNode = manager / "contacts"
// Update a GUI in real-time each time a new contact is added
val subscription = contactsNode.subscribe(Child.Added::class) { // it: Notification<Child.Added>
when (it) {
is Notification.DataNotification -> // it.data: Child.Added
myView.addItem(name = it.data.node.key, value = it.data.value.asA(Contact::class))
is Notification.ControlNotification -> println("Contact watching revoked: ${it.error?.message}")
}
}
If needed, the previousKey
property gives the key of the preceding child node or null
if the subscriber node is in
first position.
let app = Webcom.defaultApplication
let manager = app.datasyncService.createManager()
let contactsNode = manager / "contacts"
// Update a GUI in real-time each time a new contact is added
contactsNode?.subscribe(to: .childAddition) { event in
myView.addItem(name: event.key, value: event.value.decoded())
} onCompletion: { completion in
if case let .revocation(reason: reason) = completion {
print("Contact watching revoked: \(reason)")
}
}
“Child Change” event
This event:
- Is never raised initially at subscription registration,
- Is raised each time the value of an existing child node of the subscriber node changes (except when the new value of
the child is
null
, in this case a Child Removal event is raised), with the new value of this child.
This event also conveys the key of the child of the subscriber node that directly precedes (along the Webcom key ordering) the changed child, as well as a boolean indicating whether the new value of the child has been acknowledged by the Webcom back end or only updated locally within the client cache.
In JavaScript, the “Child Change” event type to is represented by the Webcom.Event.Child.Change
constant.
The first argument passed to the callback is a DataSnapshot
object, whose node.key
property gives the key of
the changed child, and whose val()
method gets its new value. The second argument passed to the callback is a string
representing the key of the child that precedes the changed child or null
if it is the first child of the subscriber
node.
// const app = Webcom.App("<your-app>"); // UNCOMMENT if you haven't yet an instance of your app!
const database = app.serverlessDb;
let node = database.rootNode.relativeNode("contacts");
// Update a GUI in real-time each time a new contact is updated
node.subscribe(Webcom.Event.Child.Change,
Webcom.Callback((dataSnapshot, previousChildKey) => {
myView.updateItem({name: dataSnapshot.node.key, value: dataSnapshot.val(), after: previousChildKey});
})
);
In Kotlin, the “Child Change” event type is represented by the
Child.Changed
interface:
import com.orange.webcom.sdk.datasync.subscription.SubscribableEvent.*
val app = WebcomApplication.default
val manager = app.datasyncService.createManager()
val contactsNode = manager / "contacts"
// Update a GUI in real-time each time a new contact is updated
val subscription = contactsNode.subscribe(Child.Changed::class) { // it: Notification<Child.Changed>
when (it) {
is Notification.DataNotification -> // it.data: Child.Changed
myView.updateItem(name = it.data.node.key, value = it.data.value.asA(Contact::class), after = it.data.previousKey)
is Notification.ControlNotification -> println("Contact watching revoked: ${it.error?.message}")
}
}
As with Child.Added
, the previousKey
property gives the key of the preceding child node or null
if the
subscriber node is in first position.
let app = Webcom.defaultApplication
let manager = app.datasyncService.createManager()
let contactsNode = manager / "contacts"
// Update a GUI in real-time each time a new contact is added
contactsNode?.subscribe(to: .childChange) { event in
myView.updateItem(name: event.key, value: event.value.decoded())
} onCompletion: { completion in
if case let .revocation(reason: reason) = completion {
print("Contact watching revoked: \(reason)")
}
}
“Child Removal” event
This event:
- Is never raised initially at subscription registration,
- Is raised each time an existing child node of the subscriber node is removed (or its value is updated to
null
), with the old value of this child.
This event also conveys whether the removal of the child has been acknowledged by the Webcom back end or only updated locally within the client cache.
In JavaScript, the “Child Removal” event type is represented by the Webcom.Event.Child.Removal
constant. The argument passed to the callback is a DataSnapshot
object, whose node.key
method gives the key of
the removed child, and whose val()
method gets its deleted value.
// const app = Webcom.App("<your-app>"); // UNCOMMENT if you haven't yet an instance of your app!
const database = app.serverlessDb;
let node = database.rootNode.relativeNode("contacts");
// Update a GUI in real-time each time a new contact is deleted
node.subscribe(Webcom.Event.Child.Removal,
Webcom.Callback(dataSnapshot => {
myView.deleteItem({name: dataSnapshot.node.key});
})
);
In Kotlin, the “Child Removal” event type is represented by the
Child.Removed
interface:
import com.orange.webcom.sdk.datasync.subscription.SubscribableEvent.*
val app = WebcomApplication.default
val manager = app.datasyncService.createManager()
val contactsNode = manager / "contacts"
// Update a GUI in real-time each time a new contact is deleted
val subscription = contactsNode.subscribe(Child.Removed::class) { // it: Notification<Child.Removed>
when (it) {
is Notification.DataNotification -> // it.data: Child.Removed
myView.deleteItem(name = it.data.node.key)
is Notification.ControlNotification -> println("Contact watching revoked: ${it.error?.message}")
}
}
let app = Webcom.defaultApplication
let manager = app.datasyncService.createManager()
let contactsNode = manager / "contacts"
// Update a GUI in real-time each time a new contact is added
contactsNode?.subscribe(to: .childRemoval) { event in
myView.deleteItem(name: event.key)
} onCompletion: { completion in
if case let .revocation(reason: reason) = completion {
print("Contact watching revoked: \(reason)")
}
}
“Child Acknowledgement” event
Similarly to the “Value Acknowledgement” event, the “Child Acknowledgement” event is not an explicit event type as such but, when subscribing to a child event, you can ask to be also notified of data acknowledgments. In other words, it is not possible to subscribe to the “Child Acknowledgement” event alone, without subscribing to any of the child events. It is not really a limitation, since this use case is quite useless.
An acknowledgment event:
- Is never raised initially at subscription registration,
- Is necessarily raised following a “Child Addition”, “Child Change” or “Child
Removal” event, whose associated child value is NOT acknowledged by the Webcom back end:
- as soon as the value of the subscriber node child is acknowledged by the back end,
- AND its value is the same as the one conveyed by the previous “Child ...” event (otherwise a new “Child ...” event is raised).
For convenience, it conveys the acknowledged value of the subscriber node child, which is necessarily equal to the
value of the previous “Child ...” event (null
for a removed child), and the acknowledgement status of
the value, which is necessarily true.
WARNING: when asking to be notified of child data acknowledgements, you receive child acknowledgements related to all child event types (i.e. addition, change or removal) event if it follows a child event that is not subscribed. For example, if you subscribe to “Child Addition” events, including acknowledgements, you will also receive acknowledgements for changes and removals of child nodes.
In practice, a callback often subscribes to all the child events. Let's wrap up all together in our contact book example:
As with “Value Acknowledgement” events, you ask receiving acknowledgements by calling the
includeAcknowledgements()
method of the Callback
object passed to the subscribe()
method.
In addition, note how the various child events can be combined:
// const app = Webcom.App("<your-app>"); // UNCOMMENT if you haven't yet an instance of your app!
const database = app.serverlessDb;
let node = database.rootNode.relativeNode("contacts");
// Update a GUI in real-time each time the list of contacts is updated
node.subscribe(
Webcom.Event.Child.Removal.Addition.Change, // subscribe to all child events at the same time
Webcom.Callback((dataSnapshot, previousChildKey) => {
if (dataSnapshot.event.isChildAddition) {
myView.addItem({name: dataSnapshot.node.key, value: dataSnapshot.val(), after: previousChildKey});
} else if (dataSnapshot.event.isChildChange) {
myView.updateItem({name: dataSnapshot.node.key, value: dataSnapshot.val()});
} else if (dataSnapshot.event.isChildRemoval) {
myView.deleteItem({name: dataSnapshot.node.key}); // mark the item removed without deleting it
} else if (dataSnapshot.event.isAck) {
// child acknowledgement events do nothing here
}
// darken, lighten or delete the item depending on its acknowledged and removed statuses
myView.ackItem({name: dataSnapshot.node.key, acknowledged: dataSnapshot.acked});
}).includeAcknowledgements() // ask also notifications on acknowledgements
);
As with “Value Acknowledgement” events, you ask receiving acknowledgements by passing a
SubscriptionOptions
object with the
includesAcknowledgement
property set to true
to the subscribe()
method.
import com.orange.webcom.sdk.datasync.subscription.SubscribableEvent.*
val app = WebcomApplication.default
val manager = app.datasyncService.createManager()
val contactsNode = manager / "contacts"
// Update a GUI in real-time each time a new contact is added
val options = SubscriptionOptions(includesAcknowledgements = true)
val subscription = contactsNode.subscribe(Child.AddedChangedRemoved::class, options = options) { // it: Notification<Child.AddedChangedRemoved>
when (it) {
is Notification.DataNotification -> with(it.data) { // this: Child.AddedChangedRemoved
// this is an instance of either Child.Added, Child.Changed, Child.Removed or Child.Acknowledged
if (!isAcknowledgement) when (this) { // Child.Acknowledged inherits all Child.* interfaces, so it must be checked first
is Child.Added -> myView.addItem(name = node.key, value = value.asA(Contact::class))
is Child.Changed -> myView.updateItem(name = node.key, value = value.asA(Contact::class), after = previousKey)
is Child.Removed -> myView.deleteItem(name = node.key) // mark the item removed without deleting it
}
// darken, lighten or delete the item depending on its acknowledged and removed statuses
myView.markItem(name = node.key, acknowledged = value.acknowledged)
}
is Notification.ControlNotification -> println("Contact watching revoked: ${it.error?.message}")
}
}
The
Child.Acknowledged
interface inherits allChild.Added
,Child.Changed
andChild.Removed
ones. Consequently, you have to check whether an event isChild.Acknowledged
BEFORE performing any pattern matching against one of these interfaces.
To do so, simply test theisAcknowledgement
property.
Note also how you can subscribe to several child events: there is one interface available for each possible combination:
Child.AddedChanged
for subscribing to both “Child Addition” and “Child Change” events,Child.AddedRemoved
for both “Child Addition” and “Child Removal”, etc...
let app = Webcom.defaultApplication
let manager = app.datasyncService.createManager()
let contactsNode = manager / "contacts"
// Update a GUI in real-time each time the list of contacts is updated
contactsNode?.subscribe(to: .childEvent) { event in
switch event.eventType {
case .childAddition:
myView.addItem(name: event.key, value: event.value.decoded())
case .childChange:
myView.updateItem(name: event.key, value: event.value.decoded())
case .childRemoval:
myView.deleteItem(name: event.key) // mark the item removed without deleting it
case .childAcknowledgement:
break // childAcknowledgement vents do nothing here
default:
break // other events are not subscribed
}
// darken, lighten or delete the item depending on its acknowledged and removed statuses
myView.markItem(name: event.key, isAcknowledged: event.value.isAcknowledged)
} onCompletion: { completion in
if case let .revocation(reason: reason) = completion {
print("Contact watching revoked: \(reason)")
}
}