5

I've started learning Golang after writing in Node.js for a long time and I'm a bit curious as to how am I to implement a handler - I've opted to use Gorilla Websocket since I understood it's the most reliable package out there.

In socket.io for example you have the simple socket.on function that allows me to call a function based on the "name" parameter passed in JSON.

Gorilla websocket doesn't implement such a thing, so my question is am I to sort of implement the logic behind socket.io in order to achieve what I want ?

As in do a certain procedure based on the value transferred in the websocket ?

If so - I need to implement it both client (I'm using AngularJS on the front-end) and server side separately by my own - make a switch case statement based on a value I get in JSON both in AngularJS for the front-end and in Go for the back-end, and also - is that the most efficient way ?

Thanks !

Random
  • 431
  • 8
  • 20

2 Answers2

5

If you've been using Javascript for a while it is really easy to implement your own version of socket.on and socket.emit here is one I made for my own projects but you can have it if you need,

// e.g.
// let socket = new Socket("ws://w/e");
// socket.on('connected', () => { console.log('Connected'); });
// socket.emit('lobby join', { data: { username: 'Boo' } });

// Using ES2015 with Babel
import {EventEmitter} from 'events';

class Socket {
    constructor(wsurl, ee = new EventEmitter()) {
        let ws = new WebSocket(wsurl);
        this.ee = ee;
        this.ws = ws;
        ws.onmessage = this.message.bind(this);
        ws.onopen = this.open.bind(this);
        ws.onclose = this.close.bind(this);
    }
    on(name, fn) {
        this.ee.on(name, fn);
    }
    off(name, fn) {
        this.ee.removeListener(name, fn);
    }
    emit(name, data) {
        const message = JSON.stringify({name, data});
        this.ws.send(message);
    }
    message(e) {
        try {
            const msgData = JSON.parse(e.data);
            this.ee.emit(msgData.name, msgData.data);
        }
        catch(err) {
            let error = {
                message: err
            }
            console.log(err)
            this.ee.emit(error.message)
        }
    }
    open() {
        this.ee.emit('connected');
    }
    close() {
        this.ee.emit('disconnected');
    }   
}

export default Socket

This will let you use your common socket.on('event', fn); and what not

As for handling it on the servers end:

For receiving messages, I personally just make a switch statement that will match an incoming string to a function, e.g.:

// readPump pumps messages from the websocket connection to the hub.
func (c *connection) readPump() {
    defer c.ws.Close()
    for {
        _, message, err := c.ws.ReadMessage()
        if err != nil {
            break
        }
        var incMessage interface{}
        err = json.Unmarshal(message, &incMessage)
        if err != nil {
            log.Println(err)
        }
        incMessageMap := incMessage.(map[string]interface{})
        switch incMessageMap["name"] {
        case "lobby join":
             // Do something to handle joining
        case "lobby leave":
             // Do something to handle leaving
        }
    }
}

For sending them I have a send channel on my connections that is stored in a map and when I need to emit I have a simple struct that takes a message name, and data, e.g.:

type wsMsg struct {
    Name string                 `json:"name"`
    Data map[string]interface{} `json:"data"`
}


c.send <- wsMsg{
     "user joined",
     map[string]interface{}{
          "username": "Booh",
     },
}

Then on the client side it would come as

socket.on('user joined', (msg) => {
    console.log(msg) // { username: "Booh" }
});

I suggest looking at the examples on gorillas git: https://github.com/gorilla/websocket/tree/master/examples/chat

Datsik
  • 14,453
  • 14
  • 80
  • 121
  • Great ! Is that also the most efficient way to do it in Go or just a simple go-to solution? – Random Jan 06 '16 at 16:17
  • 1
    @Random I've only been using Go for a few months, so in terms of efficiency I'm not sure, but I've never had a problem with this method and it doesn't seem to be slow by any means. My implementation averages about 5-10k concurrent connections and it never hiccups – Datsik Jan 07 '16 at 01:45
  • It's complicated and annoying. Why not use googollee/go-socket.io Why are there more stars in gorilla/websocket -.- – Nam Lee Sep 30 '19 at 04:42
  • hey can I like send the data as a stringified json and based on the name I will unmarshal the data. – nTheta May 06 '22 at 07:33
1

Here is an working example of golang websocket to stream video https://github.com/interviewparrot/OpenAVStream

Let me know if it is good enough

kvs
  • 11
  • 1
  • When answering an old question, your answer would be much more useful to other StackOverflow users if you included some context to explain how your answer helps, particularly for a question that already has an accepted answer. See: [How do I write a good answer](https://stackoverflow.com/help/how-to-answer). – David Buck Dec 11 '19 at 13:56