Problem getting vcards for all roster entries (#74)
Unknown opened 4 years ago

First I am logging into the XMPP service.

halcyon.connect()

Then, in the SASL event handler, after successful login I am registering handler for RosterEvent and requesting roster entries:

var rosterModule = halcyon.getModule<RosterModule>(RosterModule.TYPE)!!
halcyon.eventBus.register<RosterEvent>(RosterEvent.TYPE) {
    handleRosterEvent(it)
}
rosterModule.rosterGet()

Then, again, in the roter event handler I am attempting to request vCard for each roster item:

fun handleRosterEvent(ev: RosterEvent) {
    var nick = if(ev.item.name == null || ev.item.name == "") ev.item.jid.localpart else ev.item.name
    if (nick == null || nick == "") nick = ev.item.jid.toString()
    val contact = Contact(ev.item.jid.toString(), true, nick)

    println("RosterItem added: ${contact.jid}, nickname: '${contact.nickname}'")

    // Requesting VCard for the roster item
    halcyon.eventBus.register<VCardUpdatedEvent>(VCardUpdatedEvent.TYPE) {
        handleVCardEvent(it)
    }

    var vcardModule = halcyon.getModule<VCardModule>(VCardModule.TYPE)!!
    vcardModule.autoRetrieve = true
    println("Requesting VCard for ${ev.item.jid}")
    vcardModule.retrieveVCard(ev.item.jid)
}

And here is the vCard event handler code:

fun handleVCardEvent(ev: VCardUpdatedEvent) {
    println("Received VCard: ${ev.jid.toString()}")
    var vCard = ev.vcard
    println("VCard: ${vCard.toString()}")
    println("VCard nickname: ${vCard?.nickname}")
    println("VCard formattedName: ${vCard?.formattedName}")
}

I have about 100 items in the roster which all are received using rosterModule.rosterGet() method call.

Now, the problem is that I request a vCard for each roster item in the roster event handler but I only receive vcard for the last roster item and I receive this vCard for the last roster item 100 times.

It looks like vCard module sends 100 requests but the argument for all these 100 request is set to the last JID requested.

Unknown commented 4 years ago

I can no longer replicate the issue. I did make some changes to the code, nothing too significant though but now I just receive vcard from 1 or 2 roster items out of 100.

Please hold on with investigating this. I am analyzing data and further investigate the problem to provide more reliable description.

Unknown commented 4 years ago

I was able to receive vcards for all roster items but the resulting code I use seems not right.

First I removed eventBus.register call from the handleRosterEvent and moved it to the connection initialization section. This seems be responsible for receiving 100 times call for a single roster item vcard request.

I looked inside the VCardModule to see how to request the vcard and ended up with something like this:

        vcardModule.retrieveVCard(ev.item.jid).response {
            handleVCardEvent(VCardUpdatedEvent(ev.item.jid, it.get()))
        }.send()

This works but it does not seem right as I do here part of the job which should be done by the library itself. I am creating VCardUpdatedEvent object myself and then pass it to the handler. There is no event firing call which does not follow the library intended API.

Please suggest a better way to request roster item's vcard.

Here is a complete code of the roster item handler.

private fun handleRosterEvent(ev: RosterEvent) {
    if (ev is RosterEvent.ItemAdded) {
        var nick = if (ev.item.name == null || ev.item.name == "") ev.item.jid.localpart else ev.item.name
        if (nick == null || nick == "") nick = ev.item.jid.toString()
        val contact = Contact(ev.item.jid.toString(), true, nick)

        println("\n\nRosterItem added: ${contact.jid}, nickname: '${contact.nickname}'")

        var vcardModule = halcyon.getModule<VCardModule>(VCardModule.TYPE)!!
        //vcardModule.autoRetrieve = true
        println("Requesting VCard for ${ev.item.jid}")
        vcardModule.retrieveVCard(ev.item.jid).response {
            handleVCardEvent(VCardUpdatedEvent(ev.item.jid, it.get()))
        }.send()
    } else {
        println("\n\n RosterEvent: ${ev.toString()}")
    }
}
Unknown commented 4 years ago

This is correct way to obtain vcard for contact added to roster. The only modification I suggest is better response handling:

vcardModule.retrieveVCard(ev.item.jid).response {
    it.onSuccess { vcard ->
        handleVCardEvent(VCardUpdatedEvent(ev.item.jid, vcard))
    }
}.send()
Unknown commented 4 years ago

Thank you, this works for me.

issue 1 of 1
Issue Votes (0)
Watchers (0)
Reference
tigase/_libraries/halcyon#74
Please wait...
Page is in error, reload to recover