2020年2月11日火曜日

Google App EngineでGoを動かした

Quickstartに続けてBuilding a Go App on App Engineをやってみた。ただ、そのままでは Hello, World! が表示されるだけなので、少し手を加えてみた。具体的には昔のホームページの定番のアクセスカウンターと掲示板を作った。

まずは app.yaml を作った。
runtime: go113
手元のマシンにインストールされているGo 1.13を使いたいgo113を指定した。
プログラムとHTMLテンプレートを分離したいのでGoの html/template というパッケージを使った。テンプレートはこんな感じ。
<html>
<head><title>Zick's Homepage</title></head>
<body>
<h1>Welcome to Zick's Homepage</h1>
<p>
You are the {{.Counter}} guest!
</p>
<form action="/" method="post">
name:
<input type="text" name="name" /><br />
text:
<textarea name="text" row="4" cols="80"></textarea><br />
<input type="submit" value="submit" />
<table border="1">
{{range .Bbs}}
<tr><td>{{.Date}}</td><td>{{.Name}}</td><td>{{.Text}}</td></tr>
{{end}}
</table>
</form>
</body>
</html>
あえて古臭いHTMLにこだわった。 {{.field}} でテンプレートに渡した構造体のフィールドにアクセスできる。 {{range .repeated_field}} で配列をループで回せる。これでカウンタと掲示板へのすべての書き込みが表示できる。
このテンプレートを使うプログラムはこんな感じ。
package main

import (
 "fmt"
 "html/template"
 "log"
 "net/http"
 "os"
 "sync"
 "time"
)

type Kakikomi struct {
 Date string
 Name string
 Text string
}

var count = 0
var kakikomis []Kakikomi
var mutex sync.Mutex

type Bindings struct {
 Counter string
 Bbs     []Kakikomi
}

func updateVars(name string, text string) (int, []Kakikomi) {
 mutex.Lock()
 defer mutex.Unlock()
 count++
 if name != "" && text != "" {
  kakikomis = append(
   kakikomis, Kakikomi{time.Now().Format("2006-01-02 15:04"), name, text})
 }
 return count, kakikomis
}

func indexHandler(w http.ResponseWriter, r *http.Request) {
 if r.URL.Path != "/" {
  http.NotFound(w, r)
  return
 }
 c, k := updateVars(r.FormValue("name"), r.FormValue("text"))
 tpl := template.Must(template.ParseFiles("index.tpl"))
 m := Bindings{
  Counter: fmt.Sprintf("%dth", c),
  Bbs:     k,
 }
 tpl.Execute(w, m)
}

func main() {
 http.HandleFunc("/", indexHandler)
 port := os.Getenv("PORT")
 if port == "" {
  port = "8080"
  log.Printf("Default to port %s", port)
 }
 log.Printf("Listening on port %s", port)
 if err := http.ListenAndServe(":"+port, nil); err != nil {
  log.Fatal(err)
 }
}
カウンタと掲示板の書き込みはグローバル変数として持つ。これだとプログラムが再起動するとデータが消えるし、複数インスタンスが立ち上がると整合性が保てなくなるが、遊びなのでヨシ!
環境変数PORT以外に特にApp Engine特有の機能は使っていないのでローカルマシンで動く。
go run main.go
localhost:8080にアクセスするとテストができるので便利。
ローカルマシンで動くのが確認できたらデプロイする。
 gcloud app deploy
無事、App Engine上で動くのが確認できた。よかった。

0 件のコメント:

コメントを投稿

code-prettify