Вы находитесь на странице: 1из 385

Go Programming Blueprints

Build real-world, production-ready solutions in Go using cutting-edge technology and techniques
Build real-world, production-ready solutions in Go using
cutting-edge technology and techniques
Go Programming Blueprints Build real-world, production-ready solutions in Go using cutting-edge technology and techniques

Published by Packt Publishing Ltd. Livery Place 35 Livery Street Birmingham B3 2PB, UK.

@dahernan @tylerb @mazondo @golangbridge

Appendix

Chapter 1

Chapter 2

Chapter 3

Chapter 4

Chapter 5

Chapter 6 Chapter 5 http.HandlerFunc

Chapter 7

Chapter 8

Chapter 9

Chapter 10

Chapter 11 Chapter 9

Appendix

Appendix

webApp.war

package meander type Cost int8 const ( _ Cost = iota

Cost1

Cost2

Cost3

Cost4

Cost5

)

net/http

 net/http net/http http.Handler

net/http http.Handler

GOPATH Appendix

main.go chat GOPATH

package main

import (

"log"

"net/http"

)

func main() { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(` <html> <head> <title>Chat</title> </head> <body> Let's chat! </body>

</html>

))

}) // start the web server if err := http.ListenAndServe(":8080", nil); err != nil {

log.Fatal("ListenAndServe:", err)

}

}

net/http :8080 ListenAndServe

http.HandleFunc / http://localhost:8080/ func(w http.ResponseWriter, r *http.Request)

package main

package chat

main.go

go run go build

http://localhost:8080

Hello {{name}}, how are you

{{name}}

Hello Bruce, how are you

html/template html/template

text/template

chat templates chat.html main.go

<html> <head> <title>Chat</title> </head> <body> Let's chat (from template) </body> </html>

struct filename sync.Once text/template path/filepath sync

main.go func main()

// templ represents a single template type templateHandler struct {

sync.Once

filename string templ *template.Template

once

}

// ServeHTTP handles the HTTP request. func (t *templateHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { t.once.Do(func() { t.templ = template.Must(template.ParseFiles(filepath.Join("templates", t.filename)))

}) t.templ.Execute(w, nil)

}

Appendix

templateHandler ServeHTTP http.HandleFunc http.ResponseWriter ServeHTTP http.Handler http.Handle

http.Handler ServeHTTP net/http

NewTemplateHandler main ServeHTTP sync.Once ServeHTTP ServeHTTP

ServeHTTP

templateHandler main

func main() { // root http.Handle("/", &templateHandler{filename: "chat.html"}) // start the web server if err := http.ListenAndServe(":8080", nil); err != nil { log.Fatal("ListenAndServe:", err)

}

}

templateHandler http.Handler http.Handle templateHandler chat.html & http.Handle templateHandler

go run main.go

go build .go -o

room client

client.go main.go chat

package main import ( "github.com/gorilla/websocket"

)

// client represents a single chatting user. type client struct { // socket is the web socket for this client. socket *websocket.Conn // send is a channel on which messages are sent. send chan []byte // room is the room this client is chatting in. room *room

}

socket send room

go get websocket

room room.go

package main type room struct { // forward is a channel that holds incoming messages // that should be forwarded to the other clients. forward chan []byte

}

forward

client.go client read write client

func (c *client) read() { defer c.socket.Close() for { _, msg, err := c.socket.ReadMessage() if err != nil {

return

}

c.room.forward <- msg

}

}

func (c *client) write() { defer c.socket.Close() for msg := range c.send { err := c.socket.WriteMessage(websocket.TextMessage, msg) if err != nil { return

}

}

}

read ReadMessage forward room 'the socket has died' write send WriteMessage for

defer c.socket.Close() return defer defer close

c.room.forward <- msg room.go

package main type room struct { // forward is a channel that holds incoming messages // that should be forwarded to the other clients. forward chan []byte // join is a channel for clients wishing to join the room. join chan *client // leave is a channel for clients wishing to leave the room. leave chan *client // clients holds all current clients in this room. clients map[*client]bool

}

join leave clients

select select

room run select

func (r *room) run() { for { select { case client := <-r.join:

// joining r.clients[client] = true case client := <-r.leave:

// leaving

delete(r.clients, client) close(client.send) case msg := <-r.forward:

// forward message to all clients for client := range r.clients { client.send <- msg

}

}

}

}

for join leave forward select

r.clients

join r.clients true true

leave client send forward send write

room http.Handler ServeHTTP

room.go

const ( socketBufferSize = 1024 messageBufferSize = 256

)

var upgrader = &websocket.Upgrader{ReadBufferSize: socketBufferSize, WriteBufferSize: socketBufferSize} func (r *room) ServeHTTP(w http.ResponseWriter, req *http.Request) { socket, err := upgrader.Upgrade(w, req, nil) if err != nil { log.Fatal("ServeHTTP:", err) return

}

client := &client{

socket: socket,

send:

make(chan []byte, messageBufferSize),

room:

r,

}

r.join <- client defer func() { r.leave <- client }() go client.write() client.read()

}

ServeHTTP

websocket.Upgrader ServeHTTP upgrader.Upgrade join

write go go

read