github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/talks/2013/highperf/mart/2/mart.go (about)

     1  // +build OMIT
     2  
     3  package mart
     4  
     5  import (
     6  	"bytes"
     7  	"fmt"
     8  	"math/rand"
     9  	"net/http"
    10  	"strconv"
    11  	"strings"
    12  
    13  	"appengine"
    14  	"appengine/datastore"
    15  	"appengine/delay"
    16  	"appengine/mail"
    17  	"appengine/user"
    18  
    19  	"github.com/mjibson/appstats"
    20  )
    21  
    22  func init() {
    23  	http.HandleFunc("/", front)
    24  	http.Handle("/checkout", appstats.NewHandler(checkout))
    25  	http.HandleFunc("/admin/populate", adminPopulate)
    26  }
    27  
    28  func front(w http.ResponseWriter, r *http.Request) {
    29  	if r.URL.Path != "/" {
    30  		http.NotFound(w, r)
    31  		return
    32  	}
    33  	fmt.Fprintf(w, "Hello, welcome to Gopher Mart!")
    34  }
    35  
    36  const (
    37  	numItems = 100 // number of different items for sale
    38  
    39  	appAdmin = "noreply@google.com" // an admin of this app, for sending mail
    40  )
    41  
    42  // Item represents an item for sale in Gopher Mart.
    43  type Item struct {
    44  	Name  string
    45  	Price float64
    46  }
    47  
    48  func itemKey(c appengine.Context, i int) *datastore.Key {
    49  	return datastore.NewKey(c, "Item", fmt.Sprintf("item%04d", i), 0, nil)
    50  }
    51  
    52  func checkout(c appengine.Context, w http.ResponseWriter, r *http.Request) {
    53  	w.Header().Set("Content-Type", "text/plain; charset=utf-8")
    54  	num, err := strconv.Atoi(r.FormValue("num"))
    55  	if err == nil && (num < 1 || num > 30) {
    56  		err = fmt.Errorf("%d out of range [1,30]", num)
    57  	}
    58  	if err != nil {
    59  		http.Error(w, fmt.Sprintf("bad number of items: %v", err), http.StatusBadRequest)
    60  		return
    61  	}
    62  
    63  	// Pick random items.
    64  	keys := make([]*datastore.Key, num)
    65  	for i := range keys {
    66  		keys[i] = itemKey(c, rand.Intn(numItems))
    67  	}
    68  
    69  	// Dumb load.
    70  	var items []*Item
    71  	for _, key := range keys {
    72  		item := new(Item)
    73  		if err := datastore.Get(c, key, item); err != nil {
    74  			// ...
    75  			http.Error(w, fmt.Sprintf("datastore.Get: %v", err), http.StatusBadRequest) // OMIT
    76  			return                                                                      // OMIT
    77  		}
    78  		items = append(items, item)
    79  	}
    80  
    81  	// Print items.
    82  	var b bytes.Buffer
    83  	fmt.Fprintf(&b, "Here's what you bought:\n")
    84  	var sum float64
    85  	for _, item := range items {
    86  		fmt.Fprintf(&b, "\t%s", item.Name)
    87  		fmt.Fprint(&b, strings.Repeat("\t", (40-len(item.Name)+7)/8))
    88  		fmt.Fprintf(&b, "$%5.2f\n", item.Price)
    89  		sum += item.Price
    90  	}
    91  	fmt.Fprintln(&b, strings.Repeat("-", 55))
    92  	fmt.Fprintf(&b, "\tTotal:\t\t\t\t\t$%.2f\n", sum)
    93  
    94  	w.Write(b.Bytes())
    95  
    96  	sendReceipt.Call(c, user.Current(c).Email, b.String())
    97  }
    98  
    99  var sendReceipt = delay.Func("send-receipt", func(c appengine.Context, dst, body string) {
   100  	msg := &mail.Message{
   101  		Sender:  appAdmin,
   102  		To:      []string{dst},
   103  		Subject: "Your Gopher Mart receipt",
   104  		Body:    body,
   105  	}
   106  	if err := mail.Send(c, msg); err != nil {
   107  		c.Errorf("mail.Send: %v", err)
   108  	}
   109  })
   110  
   111  func adminPopulate(w http.ResponseWriter, r *http.Request) {
   112  	c := appengine.NewContext(r)
   113  	for i := range [numItems]struct{}{} { // r hates this. tee hee.
   114  		key := itemKey(c, i)
   115  		good := goods[rand.Intn(len(goods))]
   116  		item := &Item{
   117  			// TODO: vary names more
   118  			Name:  fmt.Sprintf("%s %dg", good.name, i+1),
   119  			Price: float64(rand.Intn(1999)+1) / 100,
   120  		}
   121  		if _, err := datastore.Put(c, key, item); err != nil {
   122  			http.Error(w, err.Error(), 500)
   123  			return
   124  		}
   125  	}
   126  	fmt.Fprintf(w, "ok. %d items populated.", numItems)
   127  }
   128  
   129  var goods = [...]struct {
   130  	name string
   131  }{
   132  	{"Gopher Bran"},
   133  	{"Gopher Flakes"},
   134  	{"Gopher Grease"},
   135  	{"Gopher Litter"},
   136  }