CSS 390: Notes from Lecture 6 (DRAFT)

Administrivia

The original idea was to spend the bulk of class time discussing core concepts and production systems, with some discussion of implementation in Go. The assignments would cover implementation.

Rebooting the course: focus on implementation of the scale model. We'll still discuss general principles and production systems, but it'll be deemphasized.

Make

Simple build shell script:

  1. put the shell commands that you would type into the command prompt into a text file (convention: use .sh extension.
  2. add #! /bin/bash at beginning of the file to tell the loader that it's a shell script.
  3. make the build script executable using chmod command

Make: original build tool from Bell Labs. Long in the tooth, but still useful

VAR = value

target : dependencies...
tabshell commands using $(VAR) is needed

Assignment 1

Assignment 2

Concurrency

Because the golang web server handles concurrent requests (even if you're not making concurrent requests in your testing), you need to protect shared memory access.

Everything you need to know about concurrency for the purposes of this course

Cookies

I was assuming everone knows what a cookie is. Using a cookie in Go is just a struct and couple of library calls:

  1. get the cookie passed in the request object
  2. set the cookie in response writer object

Artists' studies are used by artists to figure out smaller pieces of larger scenes. By analogy, when there is a library or feature you don't quite understand, write a small, simple program to test it out. Once you undestand it, you can incorporate it into your program.

You don't get credit on the assignment for doing a cookie study, but a study may help you figure out what you're trying to do

package main

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

func handler(resp http.ResponseWriter, req *http.Request) {
	oldCookie, err := req.Cookie("name")
	if err != nil {
		fmt.Printf("error getting old cookie: %v\n", err)
	} else {
		fmt.Printf("old cookie: %v\n", oldCookie)
	}
	newCookie := &http.Cookie{
		Name:    "name", // how original
		Value:   "Aries_was_here",
		Expires: time.Now().Add(3 * time.Minute),
	}
	http.SetCookie(resp, newCookie)
	fmt.Fprintf(resp, "cookie: %v", newCookie)
}

func main() {
	http.HandleFunc("/", handler)
	err := http.ListenAndServe(":9191", nil)
	fmt.Printf("ListenAndServe: %v\n", err)
}

curl

The curl command is a handy tool for testing and debugging web sites. It fetches the data without doing any rendering, so you can figure out what's going on. curl -I just fetches the headers.

Assignment 3

Templates

The format argument in the formatted print commands in the fmt package (which are direct descendants of C) is a kind of template.

The Go language provides two templating packages: text/template and html/template. The latter builds on the former, to provide automagic escaping of template parameters. You need to read both pages.

Templates are fairly powerful, including conditionals and loops, but we only need to use fairly limited functionality.

Example 1

Let's do some artists' studies. Start with turning the first example in the html/template into a working program:

package main

import (
	"fmt"
	"html/template"
	"os"
)

const (
	rawText = `{{define "theTemplate"}}Hello, {{.}}!{{end}}`
)

func main() {
	tmpl := template.New("foo")
	tmpl, err := tmpl.Parse(rawText)
	if err != nil {
		fmt.Printf("parsing template: %s\n", err)
		return
	}
	err = tmpl.ExecuteTemplate(os.Stdout, "theTemplate", "Zeus")
	if err != nil {
		fmt.Printf("executing template: %s\n", err)
		return
	}
	fmt.Println()
}
Hello, Zeus!

Example 2

Figuring out the context argument:

package main

import (
	"fmt"
	"html/template"
	"os"
)

const (
	rawText = `{{define "theTemplate"}}Hello, {{.Nationality}} {{.Kind}}!{{end}}`
)

type Context struct {
	Nationality string
	Kind        string
}

func main() {
	tmpl := template.New("foo")
	tmpl, err := tmpl.Parse(rawText)
	if err != nil {
		fmt.Printf("parsing template: %s\n", err)
		return
	}

	context1 := Context{
		Nationality: "Greek",
		Kind:        "Titans",
	}
	err = tmpl.ExecuteTemplate(os.Stdout, "theTemplate", context1)
	if err != nil {
		fmt.Printf("executing template: %s\n", err)
		return
	}
	fmt.Println()

	context2 := Context{
		Nationality: "Norse",
		Kind:        "Giants",
	}
	err = tmpl.ExecuteTemplate(os.Stdout, "theTemplate", context2)
	if err != nil {
		fmt.Printf("executing template: %s\n", err)
		return
	}
	fmt.Println()
}
Hello, Greek Titans!
Hello, Norse Giants!

Example 3

Read the template from a file using the ParseFiles method:

package main

import (
	"fmt"
	"html/template"
	"os"
)

const (
	TemplateFileName = "templates/example03.tmpl"
)

type Context struct {
	Nationality string
	Kind        string
}

func main() {
	tmpl := template.New("foo")
	tmpl, err := tmpl.ParseFiles(TemplateFileName)
	if err != nil {
		fmt.Printf("parsing template: %s\n", err)
		return
	}

	context1 := Context{
		Nationality: "Roman",
		Kind:        "Gods",
	}
	err = tmpl.ExecuteTemplate(os.Stdout, "theTemplate", context1)
	if err != nil {
		fmt.Printf("executing template: %s\n", err)
		return
	}
	fmt.Println()
}
{{define "theTemplate"}}Hello, {{.Nationality}} {{.Kind}}!{{end}}
Hello, Roman Gods!

Example 4

Read from multiple template files. Note ... turns a slice into a sequence of arguments:

package main

import (
	"fmt"
	"html/template"
	"os"
)

var (
	TemplateFiles = []string{
		"templates/example04.tmpl",
		"templates/example04-body.tmpl",
	}
)

type Context struct {
	Name string
}

func main() {
	tmpl := template.New("foo")
	tmpl, err := tmpl.ParseFiles(TemplateFiles...)
	if err != nil {
		fmt.Printf("parsing template: %s\n", err)
		return
	}

	context1 := Context{
		Name: "Hephaestus",
	}
	err = tmpl.ExecuteTemplate(os.Stdout, "page", context1)
	if err != nil {
		fmt.Printf("executing template: %s\n", err)
		return
	}
	fmt.Println()
}

templates/example04.tmpl:

{{define "page"}}
<html>
<body>
<p>
{{template "body" .}}
</p>
{{end}}

templates/example04-body.tmpl:

{{define "body"}}Hello, {{.Name}}!{{end}}`

Output:

<html>
<body>
<p>
Hello, Hephaestus!
</p>

Looping

This is overkill for the assignment, but to get carried away:

package main

import (
	"fmt"
	"html/template"
	"os"
)

var (
	TemplateFiles = []string{
		"templates/example05.tmpl",
	}
)

type Context struct {
	Nationality string
	Kind        string
	Names       []string
}

func main() {
	tmpl := template.New("foo")
	tmpl, err := tmpl.ParseFiles(TemplateFiles...)
	if err != nil {
		fmt.Printf("parsing template: %s\n", err)
		return
	}

	context1 := Context{
		Nationality: "Greek",
		Kind:        "Gods",
		Names: []string{
			"Zeus",
			"Ares",
			"Apollo",
			"Hera",
			"Aphordite",
			"Athena",
		},
	}
	err = tmpl.ExecuteTemplate(os.Stdout, "page", context1)
	if err != nil {
		fmt.Printf("executing template: %s\n", err)
		return
	}
	fmt.Println()

	err = tmpl.ExecuteTemplate(os.Stdout, "name", "Loki")
	if err != nil {
		fmt.Printf("executing template: %s\n", err)
		return
	}
	fmt.Println()
}

templates/example05.tmpl:

{{define "page"}}
<html>
<body>
{{template "body" .}}
</body>
{{end}}

{{define "body"}}
<h1>{{.Nationality}} {{.Kind}}</h1>
<ul>
{{range .Names}}{{template "name" .}}{{end}}
</ul>
{{end}}

{{define "name"}}
  <li>{{.}}</li>
{{end}}

Output:

./bin/template05 

<html>
<body>

<h1>Greek Gods</h1>
<ul>

  <li>Zeus</li>

  <li>Ares</li>

  <li>Apollo</li>

  <li>Hera</li>

  <li>Aphordite</li>

  <li>Athena</li>

</ul>

</body>


  <li>Loki</li>