Search code examples
kotlinserver-pushcuba-platform

CUBA Platform push messages from backend to UI


i was wondering if it is possible to send messages from the backend (for example a running task that receives information from an external system) to the UI. In my case it needs to be a specific session (no broadcast) and only on a specific screen

plan B would be polling the backend frequently but i was hoping to get something more "realtime"

I was trying to work something out like this, but i keep getting a NotSerializableException.

@Push
class StorageAccess : Screen(), MessageListener {
    @Inject
    private lateinit var stationWSService: StationWebSocketService
    @Inject
    private lateinit var notifications: Notifications

    @Subscribe
    private fun onInit(event: InitEvent) {
    }

    @Subscribe("stationPicker")
    private fun onStationPickerValueChange(event: HasValue.ValueChangeEvent<StorageUnit>) {
        val current = AppUI.getCurrent()
        current.userSession.id ?: return

        val prevValue = event.prevValue
        if (prevValue != null) {
            stationWSService.remove(current.userSession.id)
        }
        val value = event.value ?: return

        stationWSService.listen(current.userSession.id, value, this)
    }

    override fun messageReceived(message: String) {
        val current = AppUI.getCurrent()
        current.access {
            notifications.create().withCaption(message).show()
        }

    }

    @Subscribe
    private fun onAfterDetach(event: AfterDetachEvent) {
        val current = AppUI.getCurrent()
        current.userSession.id ?: return
        stationWSService.remove(current.userSession.id)
    }

}

-- The callback interface

interface MessageListener : Serializable {
    fun messageReceived(message: String);
}

-- The listen method of my backend service

private val listeners: MutableMap<String, MutableMap<UUID, MessageListener>> = HashMap()
override fun listen(id: UUID, storageUnit: StorageUnit, callback: MessageListener) {
    val unitStationIP: String = storageUnit.unitStationIP ?: return

    if (!listeners.containsKey(unitStationIP))
        listeners[unitStationIP] = HashMap()

    listeners[unitStationIP]?.set(id, callback)
}

The Exception i get is NotSerializableException: com.haulmont.cuba.web.sys.WebNotifications which happens during adding the listener to the backend: stationWSService.listen(current.userSession.id, value, this)

as far as i understand this is the place where the UI sends the information to the backend - and with it the entire status of the class StorageAccess, including all its members.

is there an elegant solution to this?

regards


Solution

  • There is an add-on that solves exactly this problem: https://github.com/cuba-platform/global-events-addon