ソースを参照

Merge pull request #1

Kelly Norton 9 年 前
コミット
15addfb4bc
5 ファイル変更144 行追加4 行削除
  1. 73 0
      cmd/dump-loader/main.go
  2. 20 0
      context/context.go
  3. 3 1
      main.go
  4. 39 0
      web/admin.go
  5. 9 3
      web/web.go

+ 73 - 0
cmd/dump-loader/main.go

@@ -0,0 +1,73 @@
+package main
+
+import (
+	"bytes"
+	"encoding/json"
+	"flag"
+	"fmt"
+	"io/ioutil"
+	"log"
+	"net/http"
+	"time"
+)
+
+const (
+	apiPath = "http://%s:%s/api/url/%s"
+)
+
+type config struct {
+	host     string
+	port     string
+	dumpFile string
+}
+
+type goData struct {
+	url string
+	ts  time.Time
+}
+
+func main() {
+	c := config{}
+	flag.StringVar(&c.host, "host", "localhost", "host to post data to")
+	flag.StringVar(&c.port, "port", "8067", "port on host to talk to")
+	flag.StringVar(&c.dumpFile, "file", "", "dump file to load from")
+	flag.Parse()
+
+	if c.dumpFile == "" {
+		log.Fatal("dump file must be specified with -file argument")
+	}
+
+	var d interface{}
+
+	f, err := ioutil.ReadFile(c.dumpFile)
+
+	if err != nil {
+		log.Printf("error reading dump file : %s\n", c.dumpFile)
+		log.Fatal(err)
+	}
+
+	err = json.Unmarshal(f, &d)
+
+	if err != nil {
+		log.Printf("error parsing dump file : %s\n", c.dumpFile)
+		log.Fatal(err)
+	}
+
+	links := d.(map[string]interface{})
+
+	for k, v := range links {
+		req := fmt.Sprintf(apiPath, c.host, c.port, k)
+		p, err := json.Marshal(&v)
+		if err != nil {
+			log.Printf("error marshalling data for link : %s\n", k)
+			log.Println(err)
+			continue
+		}
+		resp, err := http.Post(req, "application/json", bytes.NewReader(p))
+		if err != nil {
+			log.Printf("error POSTing link : %s\n", k)
+		} else {
+			log.Printf("POSTed short link (%s) : %s\n", resp.Status, k)
+		}
+	}
+}

+ 20 - 0
context/context.go

@@ -159,6 +159,26 @@ func (c *Context) Del(key string) error {
 	return c.db.Delete([]byte(key), &opt.WriteOptions{Sync: true})
 }
 
+// get everything in the db to dump it out for backup purposes
+func (c *Context) GetAll() (map [string]Route, error) {
+	golinks := map[string]Route{}
+	iter := c.db.NewIterator(nil, nil)
+
+	for iter.Next() {
+		key := iter.Key()
+		val := iter.Value()
+		rt := &Route{}
+		if err := rt.read(bytes.NewBuffer(val)); err != nil {
+			return nil, err
+		}
+		golinks[string(key[:])] = *rt
+	}
+	iter.Release()
+	err := iter.Error()
+
+	return golinks, err
+}
+
 func (c *Context) commit(id uint64) error {
 	w, err := os.Create(filepath.Join(c.path, idLogFilename))
 	if err != nil {

+ 3 - 1
main.go

@@ -22,6 +22,8 @@ func main() {
 		"The location to use for the data store")
 	flagAddr := flag.String("addr", ":8067",
 		"The address that the HTTP server will bind")
+	flagAdmin := flag.Bool("admin", false,
+		"If allowing admin level requests")
 	flag.Parse()
 
 	ctx, err := context.Open(*flagData)
@@ -30,5 +32,5 @@ func main() {
 	}
 	defer ctx.Close()
 
-	log.Panic(web.ListenAndServe(*flagAddr, getVersion(), ctx))
+	log.Panic(web.ListenAndServe(*flagAddr, *flagAdmin, getVersion(), ctx))
 }

+ 39 - 0
web/admin.go

@@ -0,0 +1,39 @@
+package web
+
+import (
+	"net/http"
+
+	"github.com/kellegous/go/context"
+)
+
+type adminHandler struct {
+	ctx *context.Context
+}
+
+func adminGet(ctx *context.Context, w http.ResponseWriter, r *http.Request) {
+	p := parseName("/admin/", r.URL.Path)
+
+	if p == "" {
+		writeJSONOk(w)
+		return
+	}
+
+	if p == "dumps" {
+		if golinks, err := ctx.GetAll(); err != nil {
+			writeJSONBackendError(w, err)
+			return
+		} else {
+			writeJSON(w, golinks, http.StatusOK)
+		}
+	}
+
+}
+
+func (h *adminHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	switch r.Method {
+	case "GET":
+		adminGet(h.ctx, w, r)
+	default:
+		writeJSONError(w, http.StatusText(http.StatusMethodNotAllowed))
+	}
+}

+ 9 - 3
web/web.go

@@ -279,7 +279,7 @@ func (h *defaultHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 }
 
 // Setup a Mux with all web routes.
-func allRoutes(ctx *context.Context, version string) *http.ServeMux {
+func allRoutes(ctx *context.Context, admin bool, version string) *http.ServeMux {
 	mux := http.NewServeMux()
 	mux.Handle("/", &defaultHandler{ctx})
 	mux.Handle("/api/url/", &apiHandler{ctx})
@@ -292,11 +292,17 @@ func allRoutes(ctx *context.Context, version string) *http.ServeMux {
 	mux.HandleFunc("/:version", func(w http.ResponseWriter, r *http.Request) {
 		fmt.Fprintln(w, version)
 	})
+	mux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
+		fmt.Fprintln(w, "OK")
+	})
+	if admin {
+		mux.Handle("/admin/", &adminHandler{ctx})
+	}
 	return mux
 }
 
 // ListenAndServe sets up all web routes, binds the port and handles incoming
 // web requests.
-func ListenAndServe(addr, version string, ctx *context.Context) error {
-	return http.ListenAndServe(addr, allRoutes(ctx, version))
+func ListenAndServe(addr string, admin bool, version string, ctx *context.Context) error {
+	return http.ListenAndServe(addr, allRoutes(ctx, admin, version))
 }