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