Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problem getting vcards for all roster entries #6

Closed
arthef opened this issue Oct 5, 2020 · 4 comments
Closed

Problem getting vcards for all roster entries #6

arthef opened this issue Oct 5, 2020 · 4 comments
Assignees

Comments

@arthef
Copy link
Contributor

arthef commented Oct 5, 2020

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.

@arthef
Copy link
Contributor Author

arthef commented Oct 5, 2020

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.

@arthef arthef assigned arthef and unassigned bmalkow Oct 5, 2020
@arthef
Copy link
Contributor Author

arthef commented Oct 5, 2020

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()}")
    }
}

@bmalkow
Copy link
Contributor

bmalkow commented Nov 18, 2020

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()

@bmalkow bmalkow assigned arthef and unassigned bmalkow Nov 18, 2020
@arthef
Copy link
Contributor Author

arthef commented Nov 21, 2020

Thank you, this works for me.

@arthef arthef closed this as completed Nov 21, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants