Wednesday, April 22, 2015

Day 5 - IPC using RPC

As RPC is built into Go, lets give it a try.

Im using the rpcbotinterfaceobjects from Day 4 in
$GOPATH\src\github.com\<yourgithubusername>\rpcbotinterfaceobjects

If you dont have rpcbotinterfaceobjects_input.go and rpcbotinterfaceobjects_output.go please check my Day 4 post.

For RPC we need a new struct which connects the in&output structs to the RPC service:

Create a new file rpcservice.go in $GOPATH\src\github.com\<yourgithubusername>\rpcbotinterfaceobjects and copy into it:

package rpcbotinterfaceobjects

import (
    "strconv"
    "strings"
)

type Bot struct {
    ServiceCallCount int
}

// test ProcessPost function - turn the input to uppercase
func (this *Bot) ProcessPost(in *BotInput, out *BotOutput) error {
    out.SetContent(strings.ToUpper(in.GetContent()) + " = " + strconv.Itoa(this.ServiceCallCount))
    this.ServiceCallCount++
    return nil
}



Next is the server:

In $GOPATH\src\github.com\<yourgithubusername>\testrpc create botserver.go:

 package main

import (
    "fmt"
    "github.com/kimxilxyong/rpcbotinterfaceobjects"
    "log"
    "net"
    "net/rpc"
    "os"
    "os/signal"
    "runtime"
)

func init() {
    runtime.GOMAXPROCS(runtime.NumCPU())
}

func main() {

    InstallCtrlCPanic()
    InstallKillPanic()

    bot := new(rpcbotinterfaceobjects.Bot)
    rpc.Register(bot)

    listener, e := net.Listen("tcp", ":9876")
    if e != nil {
        log.Fatal("listen error:", e)
    }

    fmt.Println("Server listening")

    rpc.Accept(listener)
}

// InstallCtrlCPanic installs a Ctrl-C signal handler that panics
func InstallCtrlCPanic() {
    go func() {
        defer SavePanicTrace()
        ch := make(chan os.Signal, 1)
        signal.Notify(ch, os.Interrupt)
        for _ = range ch {
            panic("ctrl-c")
        }
    }()
}

// InstallKillPanic installs a kill signal handler that panics
// From the command-line, this signal is agitated with kill -ABRT
func InstallKillPanic() {
    go func() {
        //defer SavePanicTrace()
        ch := make(chan os.Signal, 1)
        signal.Notify(ch, os.Kill)
        for _ = range ch {
            panic("sigkill")
        }
    }()
}

func SavePanicTrace() {
    r := recover()
    if r == nil {
        return
    }
    // Redirect stderr
    file, err := os.Create("panic")
    if err != nil {
        panic("dumper (no file) " + r.(fmt.Stringer).String())
    }

    //syscall.Dup2(int(file.Fd()), int(os.Stderr.Fd()))
    defer func() { file.Close() }()
    panic("dumper " + r.(string))
}




Next is the client, in the same folder create: botclient.go

package main

import (
    "fmt"
    "github.com/kimxilxyong/rpcbotinterfaceobjects"
    "log"
    "net/rpc"
)

func main() {

    client, err := rpc.Dial("tcp", "localhost:9876")
    if err != nil {
        log.Fatal("dialing:", err)
    }
    // Synchronous call
    in := rpcbotinterfaceobjects.BotInput{"BotInputTestText"}
    var out rpcbotinterfaceobjects.BotOutput

    err = client.Call("Bot.ProcessPost", in, &out)
    if err != nil {
        log.Fatal("ProcessPost error:", err)
    }
    fmt.Printf("ProcessPost: %s\n", out.GetContent())
}

Now open a Cmd shell and build it:

cd $GOPATH\src\github.com\<yourgithubusername>\testrpc
go build botserver.go
go build botclient.go

First run the server:


Then the client:




Friday, April 17, 2015

Day 4 - Go Packages

Today i want to check if my understandings of Go packages are correct:

(Reference: golang-packages)

1) There is only one package inside a subdirectory under $GOPATH
2) The package name has to be the same as the subdirectory name
3) The package can consist of any number of files
4) The filenames of the *.go files inside one package can be anything you choose


So i created a new directory for my test library package:

$GOPATH\src\github.com\<yourgithubusername>\rpcbotinterfaceobjects
which is in my case:
D:\goworkspace\src\github.com\kimxilxyong\rpcbotinterfaceobjects


Inside that directory i created two files:

1)  rpcbotinterfaceobjects_input.go

package rpcbotinterfaceobjects

type BotInput struct {
    Content string
}

func (this *BotInput) GetContent() string {
    return this.Content
}

func (this *BotInput) SetContent(NewContent string) {
    this.Content = NewContent
}

2)  rpcbotinterfaceobjects_output.go

package rpcbotinterfaceobjects

type BotOutput struct {
    Content string
}

func (this *BotOutput) GetContent() string {
    return this.Content
}

func (this *BotOutput) SetContent(NewContent string) {
    this.Content = NewContent
}

As you can see the package names are both the same, but the filenames can be anything you choose.





Next is to create the executable which uses this package in:

$GOPATH\src\github.com\<yourgithubusername>\packagetest
or in my case:
D:\goworkspace\src\github.com\kimxilxyong\packagetest

Create a file named test_my_package.go (or actually any name you want) and insert the following code into it:

package main

import (
    "fmt"
    // use the rpcbotinterfaceobjects package
    "github.com/kimxilxyong/rpcbotinterfaceobjects"
)

func main() {

    // Variable declaration for in and output objects
    var input rpcbotinterfaceobjects.BotInput
    var output rpcbotinterfaceobjects.BotOutput

    // Write test strings to the objects
    input.SetContent("rpcbotinterfaceobjects.Input_Content.test_my_package")
    output.SetContent("rpcbotinterfaceobjects.Output_Content.test_my_package")

    // Show the content of the objects
    fmt.Println(input.GetContent())
    fmt.Println(output.GetContent())
}

Open a cmd shell and cd into the packagetest directory.

Run  go install to build the executable, it will be put into your $GOPATH\bin folder.

Note: The bin will be named after your folder, not your *.go file!

Run packagetest




So far my assumptions 1-4 have been confirmed and additionally my tests seem to indicate that if you compile a file with func main() in it, the resulting exe is named like the directory your main comes from.

Maybe some of you may ask why I used this in the struct methods. Thats because I come from a Java and Delphi background and as this or self is not a  keyword in Go I just used it for better readability.

Quote:
Golang does not have a self or this keyword to reference to the current instance. In the method example of func (c *Circle) area() float64 the receiver struct is named "c". Use that variable name, rather than this to refer to the current instance.
oo-example-in-golang
 

Thursday, April 16, 2015

Day 3 - The famous Hello

Today I want to test if all my previous preperations where correct and create my first runnable Go programm.


Create a new directory for the hello world test code inside your workspace:

$GOPATH\src\github.com\<yourgithubusername>\hello
In my case this is:
D:\goworkspace\src\github.com\kimxilxyong\hello

Inside the hello directory create a file named hello.go and copy the following code into it:

package main

import "fmt"

func main() {
    fmt.Printf("Hello, world. Heureka!\n")
}

One important point here is that the opening curly brace MUST be on the same line as func main! (Thats some Go specific syntax, see: Curly brace in Go)

You can edit the code with any editor you like, i am using LiteIDE which is a "simple, open source, cross-platform Go IDE".
http://sourceforge.net/projects/liteide

Next open a cmd prompt and cd into 
$GOPATH\src\github.com\<yourgithubusername>\hello

Run "go install" to compile, this will put the runable hello binary into  $GOPATH\bin
(no output is good, means no error occured)

Run "hello" and hope ...






Aaaand ... it worked, Heureka !!





Wednesday, April 15, 2015

Day 2 - Creating a Go workspace

Creating a Go workspace was much more "head scratching" for me than I thought it would be.


There is this github folder thing in your workspace and the enviroment variables to set which I did not understand at the first glance. So here is what I googled and did to set up a workspace:

Create a simple empty Directory which is NOT the same as $GOROOT and point $GOPATH to it:



(How to set Environment variables in Windows: http://www.computerhope.com/issues/ch000549.htm) Type "set" in a cmd window to show them.

Create a subdirectory "src" in $GOPATH ( D:\goworkspace in my case )

Create the following path: $GOPATH\src\github.com\<yourgithubusername>

The github subdirectory is not mandatory but is considered best practice and will make things easier for you in the future if you want to store your source on github. You dont need to have a github account at this time, just use a username that you would be using later on.

Reference: http://golang.org/doc/code.html#Workspaces


The source directory for all my Go code is now:

D:\goworkspace\src\github.com\kimxilxyong

There are different opinions out there on the interwebs, but as far as I have googled it, it is recommended that you have only ONE workspace. That means all your own source and 3rd party source is all together in one workspace. I will adhere to this recommendation for now, but would be glad to read your opinions and/or arguments about this question.


Tuesday, April 14, 2015

Day 1 - Installing the Go runtime on Windows

This is the first day of my journey into the programming language Go from Google (golang).


I have choosen Go to be the next language im going to learn because it is the best of two worlds: It is as fast as a compiled language, but feels like an interpreted one.
https://golang.org/doc/faq

How to getting started with GoLang on Windows7 64bit:

Go to http://golang.org/dl and download the msi, then install it



Check if it has been installed correctly by starting a cmd shell and enter "go version", it should show something like this:

C:\>go version
go version go1.4.2 windows/amd64




The environment variable $GOROOT should have been created and $PATH should include $GOROOT\bin.

Type "set" to check if these variables are correct if "go version" gives you an error.

To display only one environment variable:

C:\>echo %GOROOT%
C:\Go\


and/or

C:\>echo %PATH%
<some_path_list>;C:\Go\bin;<some_other_pathes>


How to set Environment variables in Windows: http://www.computerhope.com/issues/ch000549.htm


Im sure you already know him but im posting him nevertheless because he is the cutest mascot since Tux.

Please meet Gopher, the GoLang mascot:

 (Downloaded the png from qiita.com)