Wednesday, March 15, 2017

Getting Started with Golang Part 4: Your first package

This part of the tutorial covers how to make and document a basic package and put functions on a type.

Every language has some method of implementing libraries. In Go, these are called packages (like they are called in Java), and are mapped based on an internet location (e.g. "github.com/jadr2ddude/go-opencv" is the package path of my fork of the go-opencv package). In this tutorial, we will be creating a very basic package that implements the HTML5 Server Sent Events protocol.

Preparation
For this tutorial, you will need a GitHub account (or any other git hosting system - just change your paths appropriately). Create a repository (preferably called html5sse) and clone it on your computer. Start by creating a .go file to put your code in inside this repository. First, we need to specify our package name:
package html5sse
Note that you have to put this package specification at the top of every line. Now, we need to specify our imports as usual. For this tutorial, we are importing "net/http" and "fmt".
Defining a struct
Instead of using object oriented programming, Go extends the C notion of a struct - a simple group of values. Using structs instead of Objects eliminates dynamic type checking overhead caused by inheritance (which Go structs still have), making code run faster. To define a struct type we do:
type TypeName struct {
      //Struct members
      exampleMember int
}
In Go, capitalization of type/variable names determines whether they are "exported". If something is exported (e.g. TypeName in the example above), that means that it can be accessed by another package. Otherwise, it is only directly accessible in the package it is defined in (such as the exampleMember of the struct defined above). However, you can access unexported things in exported functions - allowing getters and setters for example.
In our code, we will have 2 struct members - one called out that is an http.ResponseWriter, and one called count which is an int. Call the struct type "EventSender".
Creating a constructor function
Constructor functions in Go are essentially just normal functions which return a new instance. We will call out function NewEventSender. We will be doing normal C-like returns for this function (Go also supports named returns which will be discussed later). Our function definition would start like this:
func NewEventSender(w http.ResponseWriter) *EventSender {
Note the * before EventSender. Structs are pass by value by default, and * tells the compiler that we want to pass by reference. Inside this function, we first want to allocate a memory location for the struct using the special function make:
es := make(EventSender)
The variable es now contains a reference to the allocated struct. When we are done with it, Go will automatically delete it (Garbage Collection). Now we want to initialize the out member with the http.ResponseWriter passed in as an argument, and count with 0. This is done just like it is in most programming languages (with the = operator).
Putting a method on the struct
In Go you can put a method on (almost) any type of value - even redefined primitive types (e.g. you could put a .Add method on an int). To do this, you do not need to make any changes to your struct. Instead, you prepend an input to the beginning of the function definition. For our SendEvent method, the declaration would become this:
func (es *EventSender) SendEvent(e string) {
The EventSender this is being called on is now stored in a variable in the SendEvent function called es.
Sending our data
The HTML5 Server Sent Events protocol is extremely simple - you send a string followed by two newline characters and that string is given to a JavaScript function running in the browser. We also have to flush our stream whenever we send the event to force the OS to immediately send the event data without buffering it. First, we need to write data. Use fmt.Fprintf to write the data (use "%s\n\n") to the out http.ResponseWriter. Now, we need to flush the stream - using the .Flush() method of the ResponseWriter. Finally, we must increment the count variable using the ++ operator.
Additional Functions
We also want to implement a getter called GetCount for the EventSender.
Trying your library
Run go build in your repository to check syntax and then commit and push your code. Now run go get github.com/usernamehere/reponamehere. Now you can use this library. Try modifying your code from the previous tutorial to add a handler for "/event" which creates an EventSender and sends an event with example text (e.g. "Hello SSE!"). Add the following code to the page served by your original handler:
<script>
var ev = new EventSource("event");
ev.onmessage = function(event) {alert(event.data);};
</script>
Now, run your code and you should see an alert saying "Hello, SSE!".
Documenting
Now, we want to document the html5sse library. We do this by simply adding a comment before the definition of every exported field. In order to distinguish this from other comments, it must start with the name of the exported field. Once you are done with this, commit & push your changes and go to GoDoc.org. Plug in your package import path, and you should see your documentation pop up!

No comments:

Post a Comment