neffos icon indicating copy to clipboard operation
neffos copied to clipboard

[INFO] How to integrate with Echo framework

Open xXLokerXx opened this issue 5 years ago • 5 comments

Hi @kataras, I started to use neffos nearly weak ago and i really like it, where i work we decide to move into real time aplication, and i searched for a good socket package, i already used iris and i really like how it works, i was working with websockets of iris and when i updated iris i see some errors (i was in trubles before because updates of other libraries we use), then i read the documentation and i've changed all.

I also integrate the sockets with echo framework and i wold like to leave here how i made it for anyone who need it and also i think it will be good for this greate library if they have examples of implementatios with other to.

Then here is the code:

package main

import (
	"github.com/labstack/echo"
        "github.com/kataras/neffos"
	"github.com/kataras/neffos/gorilla"
	"github.com/labstack/echo"
)

type serverConn struct {
	*neffos.NSConn
}

func main() {
        router := echo.New()

        controller := new(serverConn)
        events := neffos.NewStruct(controller).
		SetNamespace("default").
		SetEventMatcher(neffos.EventTrimPrefixMatcher("On"))

        websocketServer := neffos.New(
		gorilla.DefaultUpgrader, /* DefaultGobwasUpgrader can be used too. */
		events)

       // Wrap the web socket handler with echo function to be compatible, both use http library to work
       router.Any("/echo", echo.WrapHandler(websocketServer), deleteOrigin)

        if err := router.Start(":8080"); err != nil {
		log.Fatalf("error in ListenAndServe: %s", err)
	}
}

// deleteOrigin allows others origins than local access to sockets
// if we avoid this handler then we can't connect from servers in other ports or routes
// NOTE: This isn't the best way to do it, but i can't found another way to do it.
func deleteOrigin(next echo.HandlerFunc) echo.HandlerFunc {
	return func(c echo.Context) error {
		c.Request().Header.Del("Origin")
		return next(c)
	}
}

func (c *serverConn) OnNamespaceConnected(msg neffos.Message) error {
	log.Printf("[%s] connected to namespace [%s]",
		c.Conn, msg.Namespace)
	return nil
}

func (c *serverConn) OnNamespaceDisconnect(msg neffos.Message) error {
	log.Printf("[%s] disconnected from namespace [%s]", c.Conn, msg.Namespace)
	return nil
}

func (c *serverConn) OnChat(msg neffos.Message) error {
	log.Printf("[%s] sent: %s", c.Conn, string(msg.Body))
	c.Conn.Server().Broadcast(c.Conn, msg)
	return nil
}

This is only for the server file, if anyone want to test it use with the files in the route: _examples/basic/browser

One las thing: I don't know how to acces to the context of the request.

xXLokerXx avatar Aug 09 '19 23:08 xXLokerXx

Looks great @xXLokerXx, thanks, this library is designed for every Gopher.

About your question on

One las thing: I don't know how to acces to the context of the request.

There are many ways but the easiest is to wrap the neffos.Socket with a custom socket structure and create a custom echo Handler which will put the the original Echo Context to that socket wrapper.

You can see how Iris does that at: https://github.com/kataras/iris/blob/4e1c4ac355ad0f0b176ff223ae70e3f32a71bd4a/websocket/websocket.go#L151-L192

An alternative way would be to use the Request().WithContext and provide a key and a value which will be the echo Context but I really don't recommend that one.

kataras avatar Aug 10 '19 15:08 kataras

I just did a change: from this: router.GET("/echo", echo.WrapHandler(websocketServer), deleteOrigin) to this: router.Any("/echo", echo.WrapHandler(websocketServer), deleteOrigin)

xXLokerXx avatar Feb 20 '20 23:02 xXLokerXx

@kataras I have another problem with sockets, the socket is disconnect and reconnect a lot of times and i don't know why

xXLokerXx avatar Feb 20 '20 23:02 xXLokerXx

Hello @xXLokerXx, is this the neffos.js javascript client library? If so please check the reconnect option and try to remove it or increase its value. Neffos is trying to re-connect on networks errors (in browser and nodejs client). Is this a backend (main neffos websocket server) issue? Do you have a code I can take a look of?

Thanks,

kataras avatar Feb 21 '20 07:02 kataras

@kataras yes i've working with neffos.js and nefos (for go), i've got the next error:

goroutine 1272113 [running]:
runtime.throw(0xe3003b, 0x15)
        /usr/local/go/src/runtime/panic.go:774 +0x72 fp=0xc0001a38e8 sp=0xc0001a38b8 pc=0x42f8d2
runtime.mapdelete_faststr(0xd1a2a0, 0xc0001d8120, 0xc0008a02ef, 0x2)
        /usr/local/go/src/runtime/map_faststr.go:306 +0x386 fp=0xc0001a3950 sp=0xc0001a38e8 pc=0x414f36
github.com/server/socket.(*serverConn).OnNamespaceDisconnect(0xc000010148, 0x0, 0x0, 0xc000c401c0, 0x7, 0x0, 0x0, 0xe30ffd, 0x16, 0x0, ...)
        /go/src/github.com/server/socket/socket.go:63 +0xe5 fp=0xc0001a39a8 sp=0xc0001a3950 pc=0x96cc95
runtime.call256(0xc0008253b0, 0xc0009d41f8, 0xc000930000, 0xb8000000c8)
        /usr/local/go/src/runtime/asm_amd64.s:542 +0x55 fp=0xc0001a3ab8 sp=0xc0001a39a8 pc=0x45a3f5
reflect.callMethod(0xc007754bc0, 0xc0001a3b98, 0xc0001a3b80)
        /usr/local/go/src/reflect/value.go:714 +0x1f0 fp=0xc0001a3b68 sp=0xc0001a3ab8 pc=0x48bf00
reflect.methodValueCall(0x0, 0x0, 0xc000c401c0, 0x7, 0x0, 0x0, 0xe30ffd, 0x16, 0x0, 0x0, ...)
        /usr/local/go/src/reflect/asm_amd64.s:35 +0x42 fp=0xc0001a3b98 sp=0xc0001a3b68 pc=0x4957b2
github.com/kataras/neffos.makeEventFromMethod.func1(0xc0007a80c0, 0x0, 0x0, 0xc000c401c0, 0x7, 0x0, 0x0, 0xe30ffd, 0x16, 0x0, ...)
        /go/src/github.com/kataras/neffos/reflect.go:208 +0xbf fp=0xc0001a3c68 sp=0xc0001a3b98 pc=0x95217f
github.com/kataras/neffos.Events.fireEvent(0xc0001d8180, 0xc0007a80c0, 0x0, 0x0, 0xc000c401c0, 0x7, 0x0, 0x0, 0xe30ffd, 0x16, ...)
        /go/src/github.com/kataras/neffos/conn_handler.go:41 +0x16a fp=0xc0001a3d40 sp=0xc0001a3c68 pc=0x9469da
github.com/kataras/neffos.(*Conn).Close(0xc001394400)
        /go/src/github.com/kataras/neffos/conn.go:1023 +0x1a8 fp=0xc0001a3f50 sp=0xc0001a3d40 pc=0x946658
github.com/kataras/neffos.(*Conn).startReader(0xc001394400)
        /go/src/github.com/kataras/neffos/conn.go:335 +0x169 fp=0xc0001a3fd8 sp=0xc0001a3f50 pc=0x942419
runtime.goexit()
        /usr/local/go/src/runtime/asm_amd64.s:1357 +0x1 fp=0xc0001a3fe0 sp=0xc0001a3fd8 pc=0x45bf41
created by github.com/kataras/neffos.(*Server).Upgrade
        /go/src/github.com/kataras/neffos/server.go:340 +0x6c2

and i use the next code in backend:

package socket

import (
	"fmt"
	"log"
	"net/http"

	"github.com/kataras/neffos"
	"github.com/kataras/neffos/gobwas"
	"github.com/labstack/echo"
)

type serverConn struct {
	*neffos.NSConn
}

var (
	Clients         = make(map[string]*serverConn)
	websocketServer *neffos.Server
)

func init() {
	controller := new(serverConn)
	events := neffos.NewStruct(controller).
		SetNamespace("default").
		// This will convert the "OnChat" method to a "Chat" event instead.
		SetEventMatcher(neffos.EventTrimPrefixMatcher("On"))

	websocketServer = neffos.New(
		gobwas.DefaultUpgrader,
		// gorilla.DefaultUpgrader, /* DefaultGobwasUpgrader can be used too. */
		// gorilla.Upgrader(gorillaWs.Upgrader{CheckOrigin: func(*http.Request) bool { return true }}),
		events)
}

func SocketHandler(router *echo.Echo) {
	websocketServer.IDGenerator = func(w http.ResponseWriter, r *http.Request) string {
		if userID := r.Header.Get("idUser"); userID != "" {
			return userID
		}

		return neffos.DefaultIDGenerator(w, r)
	}
	router.Any("/echo", echo.WrapHandler(websocketServer))
}

func (c *serverConn) OnNamespaceConnected(msg neffos.Message) error {
	// ctx := websocket.GetContext(c.Conn)

	fmt.Printf("%v\n", c.Conn.ID())

	Clients[c.Conn.ID()] = c

	log.Printf("[%s] connected to namespace [%s] with IP [%s]",
		c.Conn, msg.Namespace)
	return nil
}

func (c *serverConn) OnNamespaceDisconnect(msg neffos.Message) error {
	log.Printf("[%s] disconnected from namespace [%s]", c.Conn, msg.Namespace)
	delete(Clients, c.Conn.ID())
	return nil
}

func (c *serverConn) OnRoomJoined(msg neffos.Message) error {
	text := fmt.Sprintf("[%s] joined to room [%s].", c, msg.Room)
	log.Printf("%s", text)

	// notify others.
	c.Conn.Server().Broadcast(c, neffos.Message{
		Namespace: msg.Namespace,
		Room:      msg.Room,
		Event:     "Notify",
		Body:      []byte(text),
	})

	return nil
}

func (c *serverConn) OnChat(msg neffos.Message) error {
	log.Printf("[%s] sent: %s", c.Conn, string(msg.Body))
	c.Conn.Server().Broadcast(c.Conn, msg)
	return nil
}

func (c *serverConn) OnNotification(msg neffos.Message) error {
	log.Printf("[%s] sent: '%s' to Notification", c.Conn, string(msg.Body))
	c.Conn.Server().Broadcast(c.Conn, msg)
	return nil
}

xXLokerXx avatar Mar 09 '20 22:03 xXLokerXx