diff --git a/cmd/ysvd/main.go b/cmd/ysvd/main.go index 8c8c403..720d087 100644 --- a/cmd/ysvd/main.go +++ b/cmd/ysvd/main.go @@ -21,15 +21,18 @@ const usage = `ysvd environment vars: YSV_PORT: tcp listen port +YSV_HOST: hostname to use ` type config struct { Port int + Host string } func main() { c := &config{ Port: 4040, + Host: "localhost", } if err := envconfig.Process("ysv", c); err != nil { fmt.Fprintf(os.Stderr, "problem processing environment: %v", err) @@ -50,7 +53,8 @@ func main() { } log.Printf("serving at: http://%s:%d/", hostname, c.Port) sm := http.NewServeMux() - vain.NewServer(sm) + ms := vain.NewMemStore() + vain.NewServer(sm, ms, c.Host) addr := fmt.Sprintf(":%d", c.Port) if err := http.ListenAndServe(addr, sm); err != nil { log.Printf("problem with http server: %v", err) diff --git a/doc.go b/doc.go index 3bdc744..dd79820 100644 --- a/doc.go +++ b/doc.go @@ -19,10 +19,9 @@ A sample json object: { "vcs": "mercurial", - "path": "mcquay.me/vain", "repo": "https://s.mcquay.me/sm/vain" } -"path" and "repo" are required; leaving off the "vcs" member defaults to "git". +"repo" is required; leaving off the "vcs" member defaults to "git". */ package vain diff --git a/server.go b/server.go index 76f52d2..b88b833 100644 --- a/server.go +++ b/server.go @@ -1,25 +1,48 @@ package vain import ( + "encoding/json" "fmt" "net/http" + "strings" ) type Server struct { + hostname string + storage *MemStore } func (s *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) { switch req.Method { case "GET": + fmt.Fprintf(w, "\n\n") + for _, p := range s.storage.All() { + fmt.Fprintf(w, "%s\n", p) + } + fmt.Fprintf(w, "\n\n") case "POST": + if req.URL.Path == "/" { + http.Error(w, fmt.Sprintf("invalid path %q", req.URL.Path), http.StatusBadRequest) + return + } + p := Package{} + if err := json.NewDecoder(req.Body).Decode(&p); err != nil { + http.Error(w, fmt.Sprintf("unable to parse json from body: %v", err), http.StatusInternalServerError) + return + } + p.Path = fmt.Sprintf("%s/%s", s.hostname, strings.Trim(req.URL.Path, "/")) + s.storage.Add(p) case "PATCH": default: http.Error(w, fmt.Sprintf("unsupported method %q; accepted: POST, GET, PATCH", req.Method), http.StatusMethodNotAllowed) } } -func NewServer(sm *http.ServeMux) *Server { - s := &Server{} +func NewServer(sm *http.ServeMux, ms *MemStore, hostname string) *Server { + s := &Server{ + storage: ms, + hostname: hostname, + } sm.Handle("/", s) return s } diff --git a/storage.go b/storage.go new file mode 100644 index 0000000..698b6c5 --- /dev/null +++ b/storage.go @@ -0,0 +1,45 @@ +package vain + +import ( + "errors" + "sync" +) + +type MemStore struct { + l sync.RWMutex + p map[string]Package +} + +func NewMemStore() *MemStore { + return &MemStore{ + p: make(map[string]Package), + } +} + +func (ms MemStore) Add(p Package) error { + ms.l.Lock() + ms.p[p.Path] = p + ms.l.Unlock() + return nil +} + +func (ms MemStore) Remove(path string) error { + ms.l.Lock() + delete(ms.p, path) + ms.l.Unlock() + return nil +} + +func (ms MemStore) Save() error { + return errors.New("save is not implemented") +} + +func (ms MemStore) All() []Package { + r := []Package{} + ms.l.RLock() + for _, p := range ms.p { + r = append(r, p) + } + ms.l.RUnlock() + return r +}