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

How to pass values to websocket handler in iris websocket #1090

Open
kickbox opened this Issue Sep 18, 2018 · 6 comments

Comments

Projects
None yet
2 participants
@kickbox

kickbox commented Sep 18, 2018

Thank you for the amazing websocket plugin. Its very simple to use.

Since I would like to avoid global variables, I want to pass a custom struct to the websocket handler. I tried overloading the handler function, but I get "used as value" error.

Here is the calling function and handler

func handleWSconnection(c websocket.Connection, s myStruct) {
//...
}

func main(){
// ...
	var c websocket.Connection
	ws.OnConnection(handleWSconnection(c, myStruct))
// ...
}

This is the error in the command line

# command-line-arguments
./app.go:23:36: handleWSconnection(c, myStruct) used as value

Please suggest how to handle this scenario. Thanks in advance.

@kataras

This comment has been minimized.

Owner

kataras commented Sep 19, 2018

func handleWSconnection(s myStruct) func(websocket.Connection) {

    return func(c websocket.Connection) {
        // ...use of "s" + websocket conn here
    }

)

ws.OnConnection(handleWSconnection(myStructInstance)) 
@kickbox

This comment has been minimized.

kickbox commented Sep 22, 2018

Thank you so much.

@kickbox kickbox closed this Sep 22, 2018

@kataras

This comment has been minimized.

Owner

kataras commented Sep 22, 2018

You are very welcomed!

@kickbox

This comment has been minimized.

kickbox commented Oct 9, 2018

@kataras, Unfortunately there seems to be an issue with this setup. The Websocket handler gets triggered multiple times when additional users trigger the websocket handler. When there is only one user, the websocket gets triggered once. When a second user triggers the same websocket, it gets triggered twice for the second user, 3 times for the 3rd user and so on.

How do I make the handler trigger only once ?
Here is sample code, could you please suggest where things are going wrong here...

func handleWSconnection(s *mySession) func(websocket.Connection) {

    return func(c websocket.Connection) {
   
        c.On("tick", func(str string) {
        // This gets triggered MULTIPLE TIMES
       }
    }
)

func main(){
        //........
     	//........
	ws := websocket.New(websocket.Config{
		ReadBufferSize:    1024,
		WriteBufferSize:   1024,
		EnableCompression: true,
	})

       app.Get("/", func(ctx iris.Context) {
           goSession := sess.Start(ctx)
           userId, err := goSession.GetInt("userId")

            currentSession := &userSession {
				uid:    userId,
	    }
	    ws.OnConnection(handleWSconnection(currentSession))
       }
 
      app.Any("/ws", ws.Handler())
      app.Any("/iris-ws.js", func(ctx iris.Context) {
		ctx.Write(websocket.ClientSource)
       })

}

@kickbox kickbox reopened this Oct 9, 2018

@kataras

This comment has been minimized.

Owner

kataras commented Oct 15, 2018

@kickbox ws.OnConnection is server's event and it should be called before your ws.Handler() as examples explaining, so Handler() uses them. You can't add listeners for each time a handler is executed, the "multi triggers" you explained is the logical behavior for your code, I will explain you now but please read the examples more carefully.

You have two ways to deal context access inside websocket handler or a websocket connection inside a context (the same thing but opossite logical-flow), read below:

If you need access to the ctx iris.Context the websocket.Conn has a Context() function which will give you the Context access you need to initialize the session you need. If you open a code editor and type c. inside your weboskcet connection handler you can see the Context() method.

func handleWSconnection(c websocket.Connection) {
	ctx := c.Context()

	goSession := sess.Start(ctx)
	userId, err := goSession.GetInt("userId")

	currentSession := &userSession{
		uid: userId,
	}

	//
	// register your functions to that conn.
	//
	c.On("tick", func(str string) {
		// use the `currentSession` here.
	})
}


func main(){
        //........
     	//........
	ws := websocket.New(websocket.Config{
		ReadBufferSize:    1024,
		WriteBufferSize:   1024,
		EnableCompression: true,
	})

         // register the listener once, so each connection goes through that
         //  handleWSconnection
         ws.OnConnection(handleWSconnection)
         app.Any("/ws", ws.Handler()) //  use /ws or /, you know.
         app.Any("/iris-ws.js", func(ctx iris.Context) { // or ("/ iris-ws.js", ws.ClientHandler())
		 ctx.Write(websocket.ClientSource)
          })

}

Secondly, If you want to upgrade the http to websocket inside an HTTP handler you can do it by using the ws.Upgrade(ctx) function and remove the ws.Connection and app.Any("/ws", ws.Handler()) because you will handle these by your own now, example:

package main

func handleWSconnectionWithSession(c websocket.Connection, s *mySession) {
	c.On("tick", func(str string) {
		// [...]
	})
}

func main() {
	//........
	//........
	ws := websocket.New(websocket.Config{
		ReadBufferSize:    1024,
		WriteBufferSize:   1024,
		EnableCompression: true,
	})

	app.Any("/ws", func(ctx iris.Context) {
		goSession := sess.Start(ctx)
		userId, err := goSession.GetInt("userId")

		currentSession := &userSession{
			uid: userId,
		}

		c := ws.Upgrade(ctx)
		if c.Err() != nil {
			return
		}

		//
		// start the websocket work here
		//
		handleWSconnectionWithSession(c, currentSession)
		//
		// end your custom websocket work here.
		//

		// call `Wait` in order to block the handler
		// and to 'activate' the connection's events.
		c.Wait()
	})

	app.Any("/iris-ws.js", func(ctx iris.Context) { // or ("/ iris-ws.js", ws.ClientHandler())
		ctx.Write(websocket.ClientSource)
	})
}
@kickbox

This comment has been minimized.

kickbox commented Oct 17, 2018

Thank you so much @kataras. I really appreciate your examples and thank you for taking the time to write two more example here on WebSocket. The ease of use and the abundance of examples in iris is what led me to use your package. Thanks again. I will surely look at examples in more detail.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment