I am using CometD Java client on Android.
compile group: 'org.cometd.java', name: 'cometd-java-client', version: '2.9.1'
I need to subscribe to a channel on a CometD server. But there is a problem - the server requires a custom subscribe message (this is the expected subscribe message payload from the server docs):
[
{
"user": "xyz-WQUAq3shWho1ZcJHaibQYzCh2ILMMX1o-gA6NuehTFYMhvViv6Ow3dvPbyt8Zwg10-bd8bd779f107615b1c5a1470706e4050e5389ddc",
"domain": "xyz",
"pid": "gA6NuehTFYMhvViv6Ow3dvPbyt8Zwg10",
"sid": "85f103a2",
"gid": "WQUAq3shWho1ZcJHaibQYzCh2ILMMX1o",
"pageId": "6ea23e",
"entityId": "xyz",
"triggeringGoal": "3E955818355C44E2479B2A26629E69566C8C6376",
"chatSearchPattern": "ua.domain=xyz",
"startTime": 1482931626853,
"metadata": "{}",
"chatMetadata": "{}",
"language": "en",
"id": "3",
"channel": "\/meta\/subscribe",
"subscription": "\/chat\/xyz-WQUAq3shWho1ZcJHaibQYzCh2ILMMX1o-gA6NuehTFYMhvViv6Ow3dvPbyt8Zwg10-bd8bd779f107615b1c5a1470706e4050e5389ddc",
"clientId": "26l1v2ngpdcwdtno1wu30rk92dur4",
"ext": {
}
}
]
So my question is how do I add custom fields to the subscribe message (user
, domain
, pid
, sid
etc)? Currently I am subscribing to channels like this:
cometdClient.getChannel("/chat/" + clientID).subscribe(new ChannelListener("/chat/ messages"), new ChannelListener("/chat/ progress"));
But it is failing as expected.
By the way I am using org.eclipse.jetty.client.HttpClient
as the HttpClient.
First of all, you should really upgrade as CometD 2.9.1 is really old now, and JDK 7 is supported on Android.
The design of the server requiring all those fields in a /meta/subscribe
message is really wrong.
Most of that information is static (e.g. user
and various "cookies" such as pid
etc.) and can be determined at the time of the CometD handshake, so there is no need to send it over during a subscription.
Also, sending it during a /meta/subscribe
message makes it subject to attacks (an attacker can forge a message with a different user
field, for example). You want to read the security section of the CometD documentation.
Furthermore, using a channel per user (as it appears that the channel name is a concatenation of /chat/
and the user
field) is not a recommended approach, since it will create possibly a lot of channels, while the same functionality can be achieved much more efficiently with a single service channel (and the user
as a field of the messages being sent).
If you really have to add those fields to the /meta/subscribe
message, the way to do it is to use a custom extension, along these lines:
class SubscribeExtension extends ClientSession.Extension.Adapter {
@Override
public boolean sendMeta(ClientSession session, Message.Mutable message) {
if (Channel.META_SUBSCRIBE.equals(message.getChannel())) {
String subscription = (String)message.get(Message.SUBSCRIPTION_FIELD);
if (subscription.startsWith("/chat/") {
// Add fields.
}
}
return true;
}
}
Finally, if you really need to add extra fields to a /meta/subscribe
message, you want to do it inside the ext
field, with proper namespacing:
{
"id": "3",
"channel": "/meta/subscribe",
"subscription": "/chat/xyz-WQUAq3shWho1ZcJHaibQYzCh2ILMMX1o-gA6NuehTFYMhvViv6Ow3dvPbyt8Zwg10-bd8bd779f107615b1c5a1470706e4050e5389ddc",
"clientId": "26l1v2ngpdcwdtno1wu30rk92dur4",
"ext": {
"com.acme.myapp": {
"time": 1234567890,
"pageId": "6ea23e",
...
}
}
}
Note how the extra fields do no pollute the message itself, but are grouped in the ext
field under namespace com.acme.app
which would represent your company and application.