package main import ( "html/template" "net/http" "log" "os" "strconv" "fmt" ) type Results struct { Title string // Indicates success or failure Message string // the result message Details string // the details of the message } const ( DEFAULT_PORT = "4001" primesHeader = ` Go Sample App - {{.Title}}

{{.Title}}

{{.Message}}

` primesFooter = `

Back home

` ) var resultsTemplate = template.Must(template.ParseFiles("templates/results.html")) var primesHeaderTemplate = template.Must(template.New("header").Parse(primesHeader)) var primesFooterTemplate = template.Must(template.New("footer").Parse(primesFooter)) // Display the index html page // func publicHandler(w http.ResponseWriter, r *http.Request) { log.Println(">> publicHandler") defer log.Println("<< publicHandler") if r.Method != "GET" { w.WriteHeader(http.StatusMethodNotAllowed) return } path := "public" + r.URL.Path if path == "public/" { path = "public/index.html" } log.Printf("Serving file: %+v\n", path) http.ServeFile(w, r, path) } // Put in another file and make it a library // type InvalidArgument uint func (n InvalidArgument) Error() string { return fmt.Sprintf("Invalid argument number %d", n) } type Factor struct { Num uint64 Pow uint } // Return a sorted array of Factor, where each element is the // prime factor with the associated power // func PrimeFactors(n uint64) ([]Factor, error) { if n < 2 { return nil, InvalidArgument(n) } factors := make([]Factor, 0) var i uint for i=0; n%2 == 0; i++ { n /= 2 } if i > 0 { factors = append(factors, Factor{Num: 2, Pow:i}) } for p:=uint64(3); (p*p) <= n; p+=2 { for i=0; n%p == 0; i++ { n /= p } if i > 0 { factors = append(factors, Factor{Num: p, Pow:i}) } } if n > 1 { factors = append(factors, Factor{Num: n, Pow:1}) } return factors, nil } // Calculate first n prime numbers and send them // over a channel // func FirstNPrimeNumbers(n uint, ch chan uint64) (error) { log.Println(">> FirstNPrimeNumbers") defer log.Println("<< FirstNPrimeNumbers") if n < 3 { return InvalidArgument(n) } primes := make([]uint64, n) primes[0] = 2 primes[1] = 3 primes[2] = 5 cprime := uint64(7) ch <- primes[0] ch <- primes[1] ch <- primes[2] for i:=uint(3); i> primeFactorsHandler") defer log.Println("<< primeFactorsHandler") if r.Method != "POST" { w.WriteHeader(http.StatusMethodNotAllowed) return } num_s := r.FormValue("number") log.Printf("Got number from input form: %+v\n", num_s) var results *Results if num, err := strconv.Atoi(num_s); err==nil { // calculate prime factors if num > 0 { if factors, err := PrimeFactors(uint64(num)); err == nil { ss := prettyPrintPrimeFactors(uint64(num), factors) results = &Results{Title: "Success", Message: ss} } else { results = &Results{Title: "Error", Message: fmt.Sprintf("Cannot calculate prime factors of %+v", num), Details: err.Error()} } } else { results = &Results{Title: "Error", Message: fmt.Sprintf("Cannot calculate prime factors of %+v", num), Details: "It must be greather than zero."} } } else { results = &Results{Title: "Error", Message: "Invalid number", Details: err.Error()} } renderResults(w, results) } func primeNumbersHandler(w http.ResponseWriter, r *http.Request) { log.Println(">> primeNumbersHandler") defer log.Println("<< primeNumbersHandler") if r.Method != "POST" { w.WriteHeader(http.StatusMethodNotAllowed) return } num_s := r.FormValue("limit") log.Printf("Got limit from input form: %+v\n", num_s) var results *Results if num, err := strconv.Atoi(num_s); err==nil { // calculate first limit prime numbers if num > 0 { ch := make(chan uint64, 1) quit := make(chan *Results, 1) go func() { if err := FirstNPrimeNumbers(uint(num), ch); err != nil { results = &Results{Title: "Error", Message: fmt.Sprintf("Cannot calculate first %+v prime numbers", num), Details: err.Error()} } // signal the normal end of calculation quit <- results }() writeHead := true tab := 0 for { select { case v := <- ch: if writeHead { // do write header primesHeaderTemplate.Execute(w, &Results{Title: "Success", Message: fmt.Sprintf("First %+v prime numbers:\n", num)}) writeHead = false } fmt.Fprintf(w, "%+v ", v) if tab++; tab > 14 { fmt.Fprintf(w, "
") tab = 0 } case res := <- quit: if res == nil { primesFooterTemplate.Execute(w, nil) } else { renderResults(w, results) } return } } } else { results = &Results{Title: "Error", Message: fmt.Sprintf("Cannot calculate first %+v prime numbers", num), Details: "Limit must be greather than zero."} } } else { results = &Results{Title: "Error", Message: "Invalid number", Details: err.Error()} } if results != nil { log.Printf("Renedring results %+v\n", results) // debug only renderResults(w, results) } } func renderResults(w http.ResponseWriter, results *Results) { log.Println(">> renderResults") defer log.Println("<< renderResults") if err := resultsTemplate.ExecuteTemplate(w, "results.html", results); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } } func main() { // Configure the standard logger log.SetFlags(log.Lmicroseconds|log.Ldate|log.Lshortfile) log.Println(">> GoWeb") defer log.Println("<< GoWeb") var port string if port = os.Getenv("VCAP_APP_PORT"); len(port)==0 { log.Printf("Warning, VCAP_APP_PORT not set. Defaulting to %+v\n", DEFAULT_PORT) port = DEFAULT_PORT } http.HandleFunc("/primefactors", primeFactorsHandler) http.HandleFunc("/primenumbers", primeNumbersHandler) http.HandleFunc("/", publicHandler) log.Printf("Starting GoWeb on port %+v\n", port) http.ListenAndServe(":" + port, nil) }