Code Monkey home page Code Monkey logo

melody's People

Contributors

dependabot[bot] avatar fink-al avatar huljas avatar idc77 avatar lesismal avatar olahol avatar park3r2hu avatar piglig avatar robbiet480 avatar saulshanabrook avatar shiwano avatar silverwind avatar testwill avatar yoki123 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

melody's Issues

Check returned errors before deferring Close()

This pattern is repeated several times in melody_test.go:

conn, err := NewDialer(server.URL)
defer conn.Close()
if err != nil {
	t.Error(err)
	return false
}

However, if there is an error, this is liable to cause a null reference panic.

How to use Gin?

Server how to use Gin c *gin.Conext
name := c.PostForm("name")
then calc the result by name

end c.Json(200, gin.H{"name": calcAfter})
to send client

Allow for synchronous broadcasts.

It looks like all broadcasts so far comprise of wrapping a specified byte slice into an envelope and sending it over the channel *Melody.hub.broadcast.

For performance reasons, I'm looking to minimize the number of allocations by using sync.Pool and need to know when a broadcast has been done synchronously.

Would you be open to a PR for this?

Session Keys and access methods Get and Set is not concurrency safe

Hi,

We just received the following error in our server:

fatal error: concurrent map read and map write

goroutine 900594 [running]:
runtime.throw(0xff43c6, 0x21)
	/usr/local/go/src/runtime/panic.go:1116 +0x72 fp=0xc0050ad860 sp=0xc0050ad830 pc=0x437c52
runtime.mapaccess2_faststr(0xe996c0, 0xc005367290, 0xfd8f40, 0x5, 0x0, 0x0)
	/usr/local/go/src/runtime/map_faststr.go:116 +0x4a5 fp=0xc0050ad8d0 sp=0xc0050ad860 pc=0x415de5
gopkg.in/olahol/melody%2ev1.(*Session).Get(...)
	/home/erdem/Documents/gopath/code/pkg/mod/gopkg.in/olahol/[email protected]/session.go:201

When we checked it seems like the rwmutex in the session struct is not used to protect the Keys map inside it but only used to set and get the closed state. I couldn't figure out if this is deliberate and the consumer of the package is supposed to protect the Keys access with their own mutex. If it is then maybe a two new access methods can be added like SafeGet and SafeSet that uses the session rw mutex to protect access.

I can submit a pull request if you like for this issue.

Make melody.hub public

Hey,
I need a way to figure out if a there are active sessions because I only want to do work if there are any.
I almost implemented something like the melody.hub myself, but I think that it would be better to make this public or provide some kind of API.
Thanks

Tagging a release as v1

With my recent changes (even before them honestly) I think melody is at a good spot for a tagging a v1 release, which would allow users to use gopkg.in to do stable imports of the package. What do you think @olahol?

Proper way

Hi guys,

love your API compared with gorilla/websockets. Also loved that you guys built on top of that solid base instead of doing everything from scratch.

Let me ask: is there a proper way to "deny" the upgrade? I will only allow authenticated users to open a websocket connection:

	r.Get("/ws", func(w http.ResponseWriter, r *http.Request) {
		var input struct {
			Token string `json:"token"`
		}

		if err := render.Bind(r, &input); err != nil {
			http.Error(w, http.StatusText(401), 401)
			return
		}
               ...

Again, thanks for the sweet project.

Return Session from HandleRequest

I am looking for some way to pass the Context I already have into a Session context. Currently I don't think there is any way to do this.

Is HandleRequest returning the Session it creates something that would be worthwhile?

authorized.GET("/ws", func(c *gin.Context) {
    session := m.HandleRequest(c.Writer, c.Request)

    session.Keys = c.Keys
})

Or possibly injecting Keys directly?

authorized.GET("/ws", func(c *gin.Context) {
    m.HandleRequestWithContext(c.Writer, c.Request, c.Keys)
})

writeMessage could panic.

func (s *Session) writeMessage(message *envelope) {
select {
case s.output <- message:
default:
s.melody.errorHandler(s, errors.New("Message buffer full"))
}
}

Here s.output <- message could panic if s.output is already closed, which causes the whole application to exit.

It looks like the problem is:

panic:
[stderr] send on closed channel
[stderr] goroutine 72 [running]:
[stderr] ....melody.(_Session).writeMessage(0xc8203c6f60, 0xc820342000)
.... melody.(_Session).ping

func (s *Session) ping() {
s.writeMessage(&envelope{t: websocket.PingMessage, msg: []byte{}})
}

We should use s.writeRaw instead of s.writeMessage in ping().

session.Write(message) panics

the session.Write func does not return an error and just panics if for example the underlying connection is closed. I think there should be an error returned as well.

Long incoming messages result in connection close

Looks like maximum length is 513 symbols. You can just send any 514 symbol long string to verify.

I serve http with gin-gonic, here's the WS part:

mrouter.HandleMessage(func(s *melody.Session, bytes []byte) {
    log.Printf("WS message: %s\n", bytes)

Log message is never printed in case of socket close.

Wrong data in Gin log

Hello!

This is a bit cosmetic, but when trying out the basic example I've found that when you close the page (the ws connection) Gin is giving a log message with 200 code routing to /ws, with the amount of time the connection was alive. You can try it out. Is this intended or can be fixed?

It actually also gives a 304 for a root route: https://s.vadimyer.com/1632849b-d353-4882-bee1-72bf006e645c.png

Session.Set, Session.Get isn't concurrent safe?

 func (s *Session) Set(key string, value interface{}) {
   	if s.Keys == nil {
   		s.Keys = make(map[string]interface{})
  	 }
  	 s.Keys[key] = value
   }
  
   // Get returns the value for the given key, ie: (value, true).
   // If the value does not exists it returns (nil, false)
   func (s *Session) Get(key string) (value interface{}, exists bool) {
  	 if s.Keys != nil {
  		 value, exists = s.Keys[key]
  	 }
  	 return
  }

I think session must have concurrent safe map.
https://golang.org/pkg/sync/#Map
Or just locks.

Examples don't build

examples/filewatch/main.go imports "github.com/go-fsnotify/fsnotify". However, this import path is deprecated and deleted. This makes the Go tool error out because the package contains no source code.

Update the import path to "github.com/fsnotify/fsnotify".

Question: Handle error in HandleMessage

I sent a token a long with the message to websocket. I want to check if the token valid or not. So how to return error when the server recieve invalid token in HandleMessage function

When is HandleDisconnect called?

I couldn't find anywhere in the code a line where *Melody.disconnectHandler is called.
That function isn't exported, so it is not being called by another package, right?

Tutorial for implementing rooms

Hello!

I understand why you prefer to keep melody as much simple as possible. However, I'm not really sure what is the recommended way to implement rooms. May I ask for the example or short tutorial?

I would like to see that broadcasting happens for the related room's clients only, without the need to filter all existing server clients.

My first thought was to call m := melody.New() multiple times, for every room, but this is confusing me:

r.GET("/ws", func(c *gin.Context) {
	m.HandleRequest(c.Writer, c.Request)
})

... handler is created only once.

Could you please show how would you implement rooms? Performance among one room's users broadcasting is most important.

Sending message in its own goroutine can result in wrong message order.

Hello! It seems that sending message in its own goroutine:

        case m := <-h.broadcast:
            for s := range h.sessions {
                if m.filter != nil {
                    if m.filter(s) {
                        go s.writeMessage(m)
                    }
                } else {
                    go s.writeMessage(m)
                }
            }

can theoretically result in wrong message order when message rate is high as code relies on the order of goroutine execution.

Maybe I miss something or it's not an issue for melody – just noticed and decided to ask.

Ability to close hub

It looks like once you start a melody server, that hub.run() goroutine will continue forever. This usually makes sense, but in my tests I often want to start up a hub, through some websocket connections at it, then tair it down at the end of the test.

What do you think about adding the ability to call Run with some sort of cancellation? Maybe either a context or just a chan struct{} that you would close to stop the run?

json render

hello, How I can return as json instead of servefile. I want to get as json to socket and I will make client with js completely. do you have any example about this?

support session.UnSet or delete

In a fork of this when it was essentially abandoned someone contributed concurrency safety in a PR.
This also had the session.UnSet() function

// UnSet will delete the key and has no return value
func (s *Session) UnSet(key string) {
	s.rwmutex.Lock()
	defer s.rwmutex.Unlock()
	if s.keys != nil {
		_, exists := s.keys[key]
		if exists {
			delete(s.keys, key)
		}
	}
}

Would you be willing to add this?

Because if you set e.g. a string to "" it's still set, the value is "" but when it's not in the keys, you get what I mean.
p.s. correction, it was me who added that :D so, no copyright issue there.

Altough this is probably better

// UnSet will delete the key and has no return value
func (s *Session) UnSet(key string) {
	s.rwmutex.Lock()
	defer s.rwmutex.Unlock()
	if s.Keys != nil {
		_, exists := s.Keys[key]
		if exists {
			delete(s.Keys, key)
		}
	}
}

(Keys is pubic now)

Support for rooms

Has support for rooms been considered?

As of now it seems the way to do rooms is to set keys on a Session and use BroadcastFilter to broadcast to a room. Perhaps this is unfounded, but it seems like this could lead to poor performance since every Session is iterated over to check the filter.

Suggestions:
The list of rooms could look like map[string]map[*Session]bool
Thus broadcasting to a room would only have to iterate over those actually in the room.

However, disconnecting would require iterating over all rooms to check for the Session OR each Session would also have to maintain a list of rooms they are in. I think the second option may be favourable if people would be interesting in seeing what room a Session is in easily.

Thoughts?

Ping msg timeout detection

Hi,

Melody has a ping-pong functionality to keep the connection open and there is a config option PongWait. But how can I detect timeouts? For example, if client's network connection is or becomes too slow - how can I detect it with Melody?

Question: With gorilla/websocket archived, does melody plan to move to nbio or some other plan?

Hi,

Thanks for putting effort into melody. It's the most straight forward Websocket library I've used.

I was hoping to know if melody maintainers plan to move to nbio, else or have some other plans.. now that gorilla/websocket has been archived for about a month.

Things are good at the moment, but some protocol/security issues might come up in recent future. If there is a plan going ahead.

Example for implementing idle session timeout

Hi,

Thank you for a great package, it is much cleaner and simpler to use compared to gorilla/websocket library.

I am developing a game server and need to implement an idle timeout, I've set PingPeriod and PongWait values however it doesn't timeout the session or close the connection. In the readme feature list it looks like this is included "Automatic handling of ping/pong and session timeouts" however I can't seem to get it to work. Can you add an example that includes a simple implementation.

Is the hub mutex really needed?

Hey, thanks for making this library, it's great!

I was wondering: is the mutex here really necessary? It seems the sessions map will never be written to by more than one goroutine and there would probably be some perf gains by removing the lock.

Example for adding option to setup websocket upgrader when creating melody instantce

Hi,
When I want to use the great package melody to refactor the code that using gorilla/websocket directly in the project, I have encountered a problem that I can setup any field of the websocket.Upgrader if it is needed, but in melody library, when creating a melody instance using melody.New(), the websocket.Upgrader is created by default options and there is no exported method to alternate or add other option.

Now, I come up with a idea to bring the functionality to it without changing the code style of the melody.
The code looks like below. You can also reference the code in the pull request.

Thank you for your time to review it.

options.go
`
type Option func(*websocket.Upgrader)

func WithReadBufferSize(size int) Option {
return func(u *websocket.Upgrader) {
u.ReadBufferSize = size
}
}

func WithWriteBufferSize(size int) Option {
return func(u *websocket.Upgrader) {
u.WriteBufferSize = size
}
}

func WithHandshakeTimeout(d time.Duration) Option {
return func(u *websocket.Upgrader) {
u.HandshakeTimeout = d
}
}

func WithEnableCompression() Option {
return func(u *websocket.Upgrader) {
u.EnableCompression = true
}
}

func WithSubprotocols(protocols []string) Option {
return func(u *websocket.Upgrader) {
u.Subprotocols = protocols
}
}
`

melody.go
`
func New(opts ...Option) *Melody {
upgrader := &websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
CheckOrigin: func(r *http.Request) bool { return true },
}

for _, opt := range opts {
	opt(upgrader)
}

   ...

}
`

why the comunication chan is sync, not async

In your code:
func newHub() *hub {
return &hub{
sessions: make(map[*Session]bool),
broadcast: make(chan *envelope),
register: make(chan *Session),
unregister: make(chan *Session),
exit: make(chan *envelope),
open: true,
rwmutex: &sync.RWMutex{},
}
}

But I thank " broadcast: make(chan *envelope, 1024) " is better, or I misunderstand something.
Thanks for your project.

HandleSentMessageBinary func set error

func (m *Melody) HandleSentMessageBinary(fn func(*Session, []byte)) {
m.messageSentHandler = fn
}
should be
func (m *Melody) HandleSentMessageBinary(fn func(*Session, []byte)) {
m.messageSentHandlerBinary = fn
}

Active Management?

There seems to be no active maintenance of this repo, but quite a few active forks. Can we transfer ownership of this repo to someone that is currently working on keeping it current?

Thanks!

SSL support?

Hi, I run a melody server on EC2 which uses websockets and I was wondering how I would add SSL support. Is it the same way you would SSL like in a golang http server like so:

http.ListenAndServeTLS(":8081", "cert.pem", "key.pem", nil)

Or do you use something different?

Any chance for a client?

Heya,

I have been looking for something that would provide a clean wrapper around the x/net/websocket or gorilla websocket, but I have not found any good solution yet.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.