SSE Emitter over Spring MVC and calling it in angular

459 views Asked by At

I have a problem with the implementation of SSE in spring. To be honest, I don't know if I use it correctly for what I want but I give it a try anyway.

What I try to do is a game where a user chooses a nickname and a game code. If then the game code exists he will be redirected to a lobby page.

Code for that: Angular:

this.joinGameService.addUser(nickname).subscribe(userId => { more calls for inserting data in database});
// more code
this.router.navigate(['/lobby']);

Spring boot:

Controller:

@RequestMapping(value = ["/addUser"], method = [RequestMethod.PUT])
    fun addUser(@RequestBody userName: String?): ResponseEntity<String?> {
        if (userName != null) {
            var user_id = usersService.addUser(userName)
            return ResponseEntity(user_id, HttpStatus.OK)
        }

        return ResponseEntity("Username must not be null", HttpStatus.BAD_REQUEST)
    }

Service and JPA:

    override fun addUser(name: String): String? {
        var user = Users(name)
        usersRepository.save(user)
        return user.id
    }

This works fine.

The problem:


What I want to do next, is making a constant call in the lobby component on the client-side, for retrieving users. So in my spring controller, I call every 10 seconds a service for returning data from my users table.

The code for that: Angular: ( I don't know if I did this correctly.. )

  ngOnInit(): void {
    // this.lobbyService.getUsers(this.gameCode).subscribe(a => console.log(a));
    this.connect();
  }

  connect(): void {
    const source = new EventSource('http://localhost:8080/api/users/getUsers?' + 'table_id=' + this.gameCode);
    source.addEventListener('message', message => {
      let n: Notification;
      n = JSON.parse(message.data);
      console.log(message.data);
     // in the future, data will be mapped and pushed to an interface of kind User, to bind it to html file.
    });
  }

I don't get any data written in console.log.

Spring boot:


Controller:
@RequestMapping(value = ["/getUsers"], method = [RequestMethod.GET])
    fun getAllUsers(@RequestParam table_id: String,response: HttpServletResponse?): SseEmitter? {
        var emitter: SseEmitter? = null
        try {
            emitter = SseEmitter()
            while (true) {
                try {
                    print(table_id)
                    val count = usersService.getAllUsers(table_id)
                    print("\n\ncontroller: " + count) // this print the list of all list of users, so it works
                    emitter.send(count)
                    Thread.sleep((10  *  // minutes to sleep
                            1 *  // seconds to a minute
                            1000).toLong()) // milliseconds to a second
                } catch (cae: ClientAbortException) {
                    BytecodeLogger.LOGGER.info("ClientAbortException Breaking the notification stream")
                    break
                }
            }

            //Closes the stream
            emitter.complete()
        } catch (e: java.lang.Exception) {
            //Closes the stream
            emitter!!.complete()
        }
        return emitter // this doesn't return nothing
    }

Service and JPA:

override fun getAllUsers(table_id: String) : List<Users?> {
   val users =  usersRepository.getUsers(table_id)
       return users
}


@Query("SELECT * FROM users x WHERE x.id_game_table = ?1", nativeQuery = true)
    fun getUsers(tableId: String): List<Users?>

The big problem, is that I don't get any response from the controller on the client-side.

PS: I know a better implementation would be to call usersService.getAllUsers only when I call the controller function, addUser, but I don't know how to do that (if you know you are free to help me out). Now I call data from ten to ten seconds and this is not quite a good implementation. I want a real-time application (without using a socket).

0

There are 0 answers