[Windows] Try Golang 1
Tags: go
Published: 2022-04-23 17:30:26

## Intro
I want to use Pion/WebRtc on Windows, but I've written a little Golang code.

* [Pion](https://pion.ly/?msclkid=2ea93037c24a11ec900c0a19e84e96e3)
* [pion/webrtc - GitHub](https://github.com/pion/webrtc?msclkid=2ea98279c24a11ecbac5c3b3a9b80729)

So I try writing Golang in this time.

### Environments
* Windows 11 insider-preview-build-22598
* Go ver.1.18.1 windows/amd64

## GOPATH
Go installer sets GOPATH environment variable automatically.
But I can't use it like "$GOPATH" on PowerShell.

I have to write like "$ENV:GOPATH".

* [about Environment Variables - PowerShell | Microsoft Docs](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_environment_variables?view=powershell-7.2#:~:text=Environment%20variables%20store%20information%20about%20the%20operating%20system,used%20by%20the%20operating%20system%20and%20other%20programs.?msclkid=994544b1c25511ec835cb6c4118f5571)

## Modules
According to the README, I should execute "GO111MODULE=on go get ~" to run Pion/WebRtc examples.
But if I do that, I will get an error.

```
GO111MODULE=on : The term 'GO111MODULE=on' is not recognized as the name of a cmdlet, function, script file, or operabl
e program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:1
...
```

Because from ver.1.13, GO111MODULE environment variable isn't set.
And I should "go mod init" instead it.

* [How to Write Go Code - The Go Programming Language](https://go.dev/doc/code)

To run Pion/WebRtc examples, I just have to clone Pion/WebRtc and run them.

```
git clone https://github.com/pion/webrtc.git $ENV:GOPATH/src/github.com/pion/webrtc
cd $ENV:GOPATH/src/github.com/pion/webrtc/examples
go run examples.go --address localhost:8080
```

## Try creating a web application
### Create a new project
According to the documents, I should create a new project in GOPATH.

```
mkdir $ENV:GOPATH/src/sample/webappsample
cd $ENV:GOPATH/src/sample/webappsample
go mod init sample/webappsample
```

I create a .gitignore file by [gitignore.io](https://www.toptal.com/developers/gitignore/).

#### main.go
```go
package main

import (
	"fmt"
	"log"
	"net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])
}
func main() {
	http.HandleFunc("/", handler)
	log.Fatal(http.ListenAndServe(":8080", nil))
}
```

* [Writing Web Applications - The Go Programming Language](https://go.dev/doc/articles/wiki/)
* [A Tour of Go - The Go Programming Language](https://go.dev/tour/)

### Firewall
Now I have one problem.
When I execute "go run main.go", firewall security alerts shows every time.
Because the execution file path always be generated as new.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/er35dl8870ds79lbam7z.jpg)

To avoid them, I can change the first "ListenAndServe" argument as "localhost:8080".

#### main.go
```go
...
func main() {
	http.HandleFunc("/", handler)
	log.Fatal(http.ListenAndServe("localhost:8080", nil))
}
```
* [Golang run on Windows without deal with the Firewall - StackOverflow](https://stackoverflow.com/questions/55201561/golang-run-on-windows-without-deal-with-the-firewall)

But if I do that, I can't access by IP address.
So if I change it to something like "0.0.0.0:8080", I get the first problem again :(

Perhaps, when I want to access from other devices, I should build first.

### Show HTML files
#### index.html
```html
<!DOCTYPE html>
<html>
    <head>
        <title>Go Sample</title>
        <meta charset="utf-8">
    </head>
    <body>
        <div>Hello world!</div>
    </body>
</html>
```

#### main.go
```go
package main

import (
	"html/template"
	"log"
	"net/http"
	"path/filepath"
	"sync"
)

type templateHandler struct {
	once     sync.Once
	filename string
	templ    *template.Template
}

func (t *templateHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// "sync.Once" executes only one time.
	t.once.Do(func() {
		// "Must()" wraps "ParseFiles()" results, so I can put it into "templateHandler.templ" directly
		t.templ = template.Must(template.ParseFiles(filepath.Join("templates", t.filename)))
	})
	t.templ.Execute(w, nil)
}

func main() {
	// In this sample, "ServeHTTP()" is called twice.
	// The second time is for loading "favicon.ico"
	http.Handle("/", &templateHandler{filename: "index.html"})
	log.Fatal(http.ListenAndServe("localhost:8080", nil))
}
```

* [Go言語によるWebアプリケーション開発(Go Programming Blueprints)](https://www.oreilly.co.jp/books/9784873117522/?msclkid=04ddcc18c2ac11ecb7675fec5a3cb48d)

### Load static files
How about loading static files like CSS, JavaScript, and so on?

I should add "http.Handle()" again.

#### main.go
```go
...
func main() {
	// load templates/css/*
	http.Handle("/css/", http.FileServer(http.Dir("templates")))
	
	// In this sample, "ServeHTTP()" is called twice.
	// The second time is for loading "favicon.ico"
	http.Handle("/", &templateHandler{filename: "index.html"})
	log.Fatal(http.ListenAndServe("localhost:8080", nil))
}
```