2

I have a uses case in which I need to send push notifications to the Android or IOS client. The notification event should be unicast. Each message is relevant for a single client only.

How can I achieve that? I have previously broadcast events to multiple clients using code like below. I want to send a notification to an event particular subscriber for which event belongs over SSE.


@GetMapping("/sse-emitter")
public SseEmitter sseEmitter() {
   SseEmitter emitter = new SseEmitter();
   Executors.newSingleThreadExecutor().execute(() -> {
       try {
           for (int i = 0; true; i++) {
               SseEmitter.SseEventBuilder event = SseEmitter.event()
                       .id(String.valueOf(i))
                       .name("SSE_EMITTER_EVENT")
                       .data("SSE EMITTER - " + LocalTime.now().toString());
               emitter.send(event);
               Thread.sleep(1000);
           }
       } catch (Exception ex) {
           emitter.completeWithError(ex);
       }
   });
   return emitter;
}

P.S I am using this approach to keep map of SSEEmitters.

SSE Emitter : Manage timeouts and complete()

I will test it properly and update here

Zakir saifi
  • 406
  • 4
  • 23
  • If you need to send push notifications, you generally should be using the native push systems such as GCM or APNS. – chrylis -cautiouslyoptimistic- Nov 03 '21 at 17:07
  • Yeah, my use case is slightly different I need to inform the front-end that a particular event on the back-end server is completed so that it can refresh. FCM would also have a cost factor. – Zakir saifi Nov 03 '21 at 17:23
  • 1
    To me, your use case doesn't sound very different to many similar ones… AFAIK there are no costs for FCM alone (see [Is Firebase Cloud Messaging free?](https://stackoverflow.com/questions/37887066/is-firebase-cloud-messaging-free)). When implementing this yourself you will likely run into problems when the OS puts your app asleep… – slauth Nov 04 '21 at 11:03
  • the message is relevant for a small fraction of time. Suppose users buy something we mark the product as a purchase but not avail. In the background, we run some processing, and then we can inform the specific client over SSE. The client then so does some action to refresh the screen. – Zakir saifi Nov 04 '21 at 11:34
  • something like this but for SSE, not web socket https://github.com/pusher/pusher-websocket-java – Zakir saifi Nov 04 '21 at 11:36
  • Please check the below article https://golb.hplar.ch/2017/03/Server-Sent-Events-with-Spring.html @EnableSseEventBus in this article could be the answer to your problem. https://golb.hplar.ch/2017/03/Server-Sent-Events-with-Spring.html#keeping-track – Pankaj Chimbalkar Jun 16 '22 at 11:24
  • I am already using @EnableSseEventBus. I will post the solution here soon. – Zakir saifi Jun 16 '22 at 17:00

1 Answers1

0

You could leverage Spring compatible SSE event bus lib to have your clients mapped to a unique id. So that you could later distinguish them.

A part of the nice article @Pankaj Chimbalkar left in comments

... The library creates a bean of type SseEventBus that an application can inject into any Spring-managed bean.

@Controller
public class SseController {
  private final SseEventBus eventBus;
  public SseController(SseEventBus eventBus) {
    this.eventBus = eventBus;
  }

  @GetMapping("/register/{id}")
  public SseEmitter register(@PathVariable("id") String id) {
    return this.eventBus.createSseEmitter(id, SseEvent.DEFAULT_EVENT)
  }
}

The library expects each client sends a unique id. An application can create such an id with a UUID library like https://github.com/uuidjs/uuid. For starting the SSE connection, the client calls the endpoint with the createSseEmitter method and sends the id and optionally the names of the events he is interested in.

const uuid = uuid();
const eventSource = new EventSource(`/register/${uuid}`);
eventSource.addEventListener('message', response => {
    //handle the response from the server
    //response.data contains the data line 
}, false);
Vladyslav Nikolaiev
  • 1,819
  • 3
  • 20
  • 39