Skip to content
Nik Voss edited this page Jun 6, 2013 · 3 revisions

When using golem the most important function is the On-function allowing the server or client to react on incoming messages. To provide more insights than this guide there is a wiki-page about this single function.

Golem's sole purpose is to provide an easy to use and lightweight way to interact with WebSockets. A JSON-based approach for data transmission is provided, but extensibility to use your own methods is provided.

The first thing necessary to handle WebSockets with golem is a Router-Instance dealing with the multiplexing of several events.

myrouter := golem.NewRouter()

To add event handlers the On function accepts functions of the type func(*golem.Connection, *T), where T is any type, that the handler should except, e.g. we want to accept a "Hello"-Message that tells us from whom we were greeted and who was greeted:

type Hello struct {
	To   string `json:"to"`
	From string `json:"from"`
}

func hello(conn *golem.Connection, data *Hello) {
	fmt.Println("Hello from", data.From, "to", data.To)
}

Note: The encoding/json package is used internally, so all tags still work

The On-function uses reflection to unmarshal the incoming data into the required type T. For efficiency a handler function should always accept a pointer to the desired type. To use the just created function we need to register it to an event:

myrouter.On("hello", hello)

This binds the function to an event called "hello", but the router is still not active, because the Handler-Function of the router is not being used by any path or server. The standard http package is used to bind the Handler and create a server and therefore allowing golem to be used with a variety of other packages utilising the http package:

http.HandleFunc("/ws", myrouter.Handler())
if err := http.ListenAndServe(*addr, nil); err != nil {
	log.Fatal("ListenAndServe:", err)
}

Now the server is listening for incoming messages, but we are still missing the client-side. The client library of golem follows the same API design as golem (but follows JavaScript's naming conventions, so method name don't start with a upper case). To connect to our server we would try to connect and if connected try to emit our event with some data:

var conn = new golem.Connection("127.0.0.1:8080/ws", true); // Second argument is debug flag!
conn.on("open", function() {
    conn.emit("hello", { to: "Server", from: "Client" });
});

If we want to receive messages on the client-side we would follow the same patterns as on the server-side:

conn.on("answer", function(data) {
    console.log("Answer: "+data.msg);
});

To send data to the client we need to emit events on the server-side to do this we can create a struct representing the answer:

type Answer struct {
	Msg string `json:"msg"`
}

And emit an answer in our hello-Handler:

func hello(conn *golem.Connection, data *Hello) {
	fmt.Println("Hello from", data.From, "to", data.To)
	conn.Emit("answer", &Answer{"Thanks, client!"})
}

Note: Always emit references/pointers of structures to avoid unnecessary copies and keep the emission lightweight!

We now achieved two way communication by just having to write a few lines of Go and JavaScript. There is a special case that we did not talk about up til now though. What if we want to emit an event and no data is necessary. This is the most lightweight way to communicate, since no parsing of incoming data is necessary. To achieve this we would simply use a Handler accepting no data:

func poke(conn *golem.Connection) {
    fmt.Println("Someone poked me!")
}

On the client-side we would simply emit an event without data:

conn.emit("poke");

You can find the commented source of client and server in the example repository.