...
Run Format

Source file doc/articles/wiki/final.go

     1	// Copyright 2010 The Go Authors. All rights reserved.
     2	// Use of this source code is governed by a BSD-style
     3	// license that can be found in the LICENSE file.
     4	
     5	package main
     6	
     7	import (
     8		"flag"
     9		"html/template"
    10		"io/ioutil"
    11		"log"
    12		"net"
    13		"net/http"
    14		"regexp"
    15	)
    16	
    17	var (
    18		addr = flag.Bool("addr", false, "find open address and print to final-port.txt")
    19	)
    20	
    21	type Page struct {
    22		Title string
    23		Body  []byte
    24	}
    25	
    26	func (p *Page) save() error {
    27		filename := p.Title + ".txt"
    28		return ioutil.WriteFile(filename, p.Body, 0600)
    29	}
    30	
    31	func loadPage(title string) (*Page, error) {
    32		filename := title + ".txt"
    33		body, err := ioutil.ReadFile(filename)
    34		if err != nil {
    35			return nil, err
    36		}
    37		return &Page{Title: title, Body: body}, nil
    38	}
    39	
    40	func viewHandler(w http.ResponseWriter, r *http.Request, title string) {
    41		p, err := loadPage(title)
    42		if err != nil {
    43			http.Redirect(w, r, "/edit/"+title, http.StatusFound)
    44			return
    45		}
    46		renderTemplate(w, "view", p)
    47	}
    48	
    49	func editHandler(w http.ResponseWriter, r *http.Request, title string) {
    50		p, err := loadPage(title)
    51		if err != nil {
    52			p = &Page{Title: title}
    53		}
    54		renderTemplate(w, "edit", p)
    55	}
    56	
    57	func saveHandler(w http.ResponseWriter, r *http.Request, title string) {
    58		body := r.FormValue("body")
    59		p := &Page{Title: title, Body: []byte(body)}
    60		err := p.save()
    61		if err != nil {
    62			http.Error(w, err.Error(), http.StatusInternalServerError)
    63			return
    64		}
    65		http.Redirect(w, r, "/view/"+title, http.StatusFound)
    66	}
    67	
    68	var templates = template.Must(template.ParseFiles("edit.html", "view.html"))
    69	
    70	func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
    71		err := templates.ExecuteTemplate(w, tmpl+".html", p)
    72		if err != nil {
    73			http.Error(w, err.Error(), http.StatusInternalServerError)
    74		}
    75	}
    76	
    77	var validPath = regexp.MustCompile("^/(edit|save|view)/([a-zA-Z0-9]+)$")
    78	
    79	func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
    80		return func(w http.ResponseWriter, r *http.Request) {
    81			m := validPath.FindStringSubmatch(r.URL.Path)
    82			if m == nil {
    83				http.NotFound(w, r)
    84				return
    85			}
    86			fn(w, r, m[2])
    87		}
    88	}
    89	
    90	func main() {
    91		flag.Parse()
    92		http.HandleFunc("/view/", makeHandler(viewHandler))
    93		http.HandleFunc("/edit/", makeHandler(editHandler))
    94		http.HandleFunc("/save/", makeHandler(saveHandler))
    95	
    96		if *addr {
    97			l, err := net.Listen("tcp", "127.0.0.1:0")
    98			if err != nil {
    99				log.Fatal(err)
   100			}
   101			err = ioutil.WriteFile("final-port.txt", []byte(l.Addr().String()), 0644)
   102			if err != nil {
   103				log.Fatal(err)
   104			}
   105			s := &http.Server{}
   106			s.Serve(l)
   107			return
   108		}
   109	
   110		http.ListenAndServe(":8080", nil)
   111	}
   112	

View as plain text