mirror of
https://github.com/chai2010/advanced-go-programming-book.git
synced 2025-05-24 04:16:01 +00:00
143 lines
3.0 KiB
Go
143 lines
3.0 KiB
Go
// Copyright 2016 <chaishushan{AT}gmail.com>. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
// +build ignore
|
|
|
|
package main
|
|
|
|
import (
|
|
"flag"
|
|
"log"
|
|
"net"
|
|
"net/http"
|
|
"os/exec"
|
|
"runtime"
|
|
"time"
|
|
)
|
|
|
|
var (
|
|
flagRootDir = flag.String("dir", ".", "root dir")
|
|
flagHttpAddr = flag.String("http", ":8080", "HTTP service address")
|
|
flagNoCache = flag.Bool("no-cache", true, "disable browser cache")
|
|
flagOpenBrowser = flag.Bool("openbrowser", true, "open browser automatically")
|
|
)
|
|
|
|
func main() {
|
|
flag.Parse()
|
|
|
|
host, port, err := net.SplitHostPort(*flagHttpAddr)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
if host == "" {
|
|
host = getLocalIP()
|
|
}
|
|
httpAddr := host + ":" + port
|
|
url := "http://" + httpAddr + "/_book"
|
|
|
|
go func() {
|
|
log.Printf("dir: %s\n", *flagRootDir)
|
|
|
|
if waitServer(url) && *flagOpenBrowser && startBrowser(url) {
|
|
log.Printf("A browser window should open. If not, please visit %s", url)
|
|
} else {
|
|
log.Printf("Please open your web browser and visit %s", url)
|
|
}
|
|
log.Printf("Hit CTRL-C to stop the server\n")
|
|
}()
|
|
|
|
mainHandler := http.FileServer(http.Dir(*flagRootDir))
|
|
if *flagNoCache {
|
|
mainHandler = NoCache(mainHandler)
|
|
}
|
|
log.Fatal(http.ListenAndServe(httpAddr, mainHandler))
|
|
}
|
|
|
|
// waitServer waits some time for the http Server to start
|
|
// serving url. The return value reports whether it starts.
|
|
func waitServer(url string) bool {
|
|
tries := 20
|
|
for tries > 0 {
|
|
resp, err := http.Get(url)
|
|
if err == nil {
|
|
resp.Body.Close()
|
|
return true
|
|
}
|
|
time.Sleep(100 * time.Millisecond)
|
|
tries--
|
|
}
|
|
return false
|
|
}
|
|
|
|
func getLocalIP() string {
|
|
addrs, err := net.InterfaceAddrs()
|
|
if err != nil {
|
|
return "127.0.0.1"
|
|
}
|
|
for _, address := range addrs {
|
|
if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
|
|
if ipnet.IP.To4() != nil {
|
|
return ipnet.IP.String()
|
|
}
|
|
}
|
|
}
|
|
return "127.0.0.1"
|
|
}
|
|
|
|
// startBrowser tries to open the URL in a browser, and returns
|
|
// whether it succeed.
|
|
func startBrowser(url string) bool {
|
|
// try to start the browser
|
|
var args []string
|
|
switch runtime.GOOS {
|
|
case "darwin":
|
|
args = []string{"open"}
|
|
case "windows":
|
|
args = []string{"cmd", "/c", "start"}
|
|
default:
|
|
args = []string{"xdg-open"}
|
|
}
|
|
cmd := exec.Command(args[0], append(args[1:], url)...)
|
|
return cmd.Start() == nil
|
|
}
|
|
|
|
var epoch = time.Unix(0, 0).Format(time.RFC1123)
|
|
|
|
var noCacheHeaders = map[string]string{
|
|
"Expires": epoch,
|
|
"Cache-Control": "no-cache, private, max-age=0",
|
|
"Pragma": "no-cache",
|
|
"X-Accel-Expires": "0",
|
|
}
|
|
|
|
var etagHeaders = []string{
|
|
"ETag",
|
|
"If-Modified-Since",
|
|
"If-Match",
|
|
"If-None-Match",
|
|
"If-Range",
|
|
"If-Unmodified-Since",
|
|
}
|
|
|
|
func NoCache(h http.Handler) http.Handler {
|
|
fn := func(w http.ResponseWriter, r *http.Request) {
|
|
// Delete any ETag headers that may have been set
|
|
for _, v := range etagHeaders {
|
|
if r.Header.Get(v) != "" {
|
|
r.Header.Del(v)
|
|
}
|
|
}
|
|
|
|
// Set our NoCache headers
|
|
for k, v := range noCacheHeaders {
|
|
w.Header().Set(k, v)
|
|
}
|
|
|
|
h.ServeHTTP(w, r)
|
|
}
|
|
|
|
return http.HandlerFunc(fn)
|
|
}
|