Websockets & group of connections

Just gonna keep it simple for now. I’m currently converting a project from php and a RESTful API to Go and web sockets to keep it fast and real time. I’ve been working with Go for about 3 months now so I feel confident enough to do this. Im using the gorilla toolkit web socket package which is making the process a ton less difficult except web sockets is still a relatively new technology to me so I am having some trouble.

Here is my problem…

Im creating an app which you connect to by a unique key in the url which will enter you into a group with other people which have also connected to that group via the unique key in the url. This isn’t a chat app but it follows the same concept in my opinion. If someone goes to a unique url then they’ll get access to that group of connections and get all the info from those connections which are sent from other connections in that group.

I’ve thought of different ways of doing this like making a struct hub and then adding a slice of pointer to websocket.Conn I’ve got this working except it only works with one group or i have to hard code all the groups which i don’t want since i want to keep it dynamic. The unique keys will be stored in a db along with the stats that go with that group and key. I’ve thought of using the db to store the connections with the key but i don’t think i can store them because when query the connections associated with each key it will be a string and not a pointer to a websocket.Conn which won’t work

That is my issue i’ve ran into. I would much appreciate and pointers to tips on how i should do this or how i should go about it. Let me know if theres more info you need and ill gladly update the original post.

Thank you

Luis R

1 Like

Something like this should be the nicest way to implement this: https://play.golang.org/p/uUC9RDT0tN Note: code untested, and remember to run with race detector.

There are alternative approaches with channels, but I’ve found them to be harder to maintain. Of course, this approach involves locking, which means there are easy ways to create hard-to-debug problems.

PS: Anytime you iterate over users, you need to lock them (RWMutex and using RLock is a good idea). Also, avoid blocking the main list for long; otherwise one problematic connection can bring down the channel.

Thanks! I’m trying to write some code that works like the example i’ll defiantly let you know how it goes!

I think the best approach here is a lock-free one- “don’t communicate by sharing memory.”

This code example models something quite similar to what you’re doing, hope you can get some ideas from this!

https://golang.org/doc/codewalk/sharemem/

So far my experiments with using channels ended up in bad code in this particular situation. Ensuring that “everything happens at the right time” and “everything gets updated properly” get’s more problematic. i.e. this, will be quite common

func (client *Client) Send(msg *Message) {
	select {
	case client.send <- msg:
	default:
		client.Disconnect()
	}
} 

Also when you need to request from the main server, you need to often send either a result channel to get the result. With a lots of channels going several directions.

Something from a simple application:

func (b *Board) run() {
	for {
		select {
		case c := <-b.register:
			b.connections[c] = true
			b.sendState(c)
		case c := <-b.unregister:
			delete(b.connections, c)
			close(c.send)
			if b.shouldTerminate() {
				b.list.remove(b)
				return
			}
		case m := <-b.update:
			go b.handleUpdate(m)
		case m := <-b.broadcast:
			for c := range b.connections {
				select {
				case c.send <- m:
				default:
					delete(b.connections, c)
					close(c.send)
					go c.ws.Close()
				}
			}
		}
	}
}

That is somewhat still manageable, once you add timeouts, failures, priorities, external processes - things start to get unwieldy quickly.

I’ve attempted several designs (can’t remember exactly how many, but definitely more than 4), the one using mutexes was the best. Sure, I would love a version that didn’t use them, but I couldn’t find good one after several tries. If anyone has a good design for it, I would love to see it.

Note: reaction to try and use channels first is the correct one and I use the mutexes only in the “core”, there might be channels elsewhere, e.g. the “client.Send” internally might use a channel to avoid blocking.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.