# HG changeset patch # User Henry Precheur # Date 1378428077 25200 # Thu Sep 05 17:41:17 2013 -0700 # Node ID d0d8570c60ff65a247814afbd1c3c805b733e73d # Parent 875c40bd8d8c3a39a496b019095eb33e0682f070 WIP diff --git a/restlog.go b/restlog.go --- a/restlog.go +++ b/restlog.go @@ -15,17 +15,26 @@ var _ = os.Open -type LogHandler interface { - Writer(log string) (io.WriteCloser, error) - Reader(log string) (io.ReadCloser, error) + +type Logger interface { + Writer(log string) (io.Writer, error) + Reader(log string) (io.ReadSeeker, error) } type HTTPLog struct { - logHandler LogHandler + logger Logger +} + +func NewHTTPLog(logger Logger) HTTPLog { + return HTTPLog{logger: logger} } -func NewHTTPLog(handler LogHandler) HTTPLog { - return HTTPLog{logHandler: handler} +func closeIfNeeded(value interface{}) error { + // switch v := value.(type) { + // case io.Closer: + // return v.Close() + // } + return nil } func validateInput(req *http.Request) ([]byte, error) { @@ -47,30 +56,41 @@ return x, nil } +func addLog(req *http.Request, logger Logger) (string, int, error) { + input, err := validateInput(req) + if err != nil { + return "", 400, err + } + + f, err := logger.Writer(req.URL.Path) + if err != nil { + return "", 500, err + } + + var t = time.Now().Format(time.RFC3339) + var line = fmt.Sprintf("%s %s\n", t, string(input)) + io.WriteString(f, line) + + if err := closeIfNeeded(logger); err != nil { + return line, 500, err + } + + return line, 200, nil +} + func (self HTTPLog) ServeHTTP(w http.ResponseWriter, req *http.Request) { switch req.Method { case "POST": - input, err := validateInput(req) - if err != nil { - http.Error(w, err.Error(), 400) - return - } + line, code, err := addLog(req, self.logger) - f, err := self.logHandler.Writer(req.URL.Path) if err != nil { - http.Error(w, err.Error(), 500) - return + http.Error(w, err.Error(), code) + } else { + io.WriteString(w, line) } - - var t = time.Now().Format(time.RFC3339) - var line = fmt.Sprintf("%s %s\n", t, string(input)) - - io.WriteString(f, line) - f.Close() - io.WriteString(w, line) return case "GET": - var f, err = self.logHandler.Reader(req.URL.Path) + var f, err = self.logger.Reader(req.URL.Path) if err != nil { code := http.StatusInternalServerError http.Error(w, err.Error(), code) @@ -82,7 +102,7 @@ http.Error(w, "Only GET & POST", http.StatusMethodNotAllowed) } -type FileLogHandler struct{} +type FileLogger struct{} func HashPath(path string) string { var hash = sha1.New() @@ -101,46 +121,33 @@ return nil, fmt.Errorf("Invalid mode: %x", mode) } -func (h FileLogHandler) Reader(path string) (io.ReadCloser, error) { +func (h FileLogger) Reader(path string) (io.ReadSeeker, error) { return fileOpenLog(path, os.O_RDONLY) } -func (h FileLogHandler) Writer(path string) (io.WriteCloser, error) { +func (h FileLogger) Writer(path string) (io.Writer, error) { return fileOpenLog(path, os.O_WRONLY) } -type BufferCloser struct { - bytes.Buffer -} +type MemoryLogger map[string][]byte -func (_ BufferCloser) Close() error { - return nil -} - -func NewBufferCloser(buf []byte) *BufferCloser { - return &BufferCloser{*bytes.NewBuffer(buf)} +func (self MemoryLogger) handle(path string) []byte { + if self[path] == nil { + self[path] = make([]byte, 0) + } + return self[path] } -type MemoryLogHandler map[string]*BufferCloser - -func (h MemoryLogHandler) handle(path string) (*BufferCloser, error) { - _, present := h[HashPath(path)] - if !present { - h[HashPath(path)] = new(BufferCloser) - } - return h[HashPath(path)], nil +func (self MemoryLogger) Reader(path string) (io.ReadSeeker, error) { + return bytes.NewReader(self.handle(path)), nil } -func (h MemoryLogHandler) Reader(path string) (io.ReadCloser, error) { - return h[HashPath(path)], nil +func (self MemoryLogger) Writer(path string) (io.Writer, error) { + return bytes.NewBuffer(self.handle(path)), nil } -func (h MemoryLogHandler) Writer(path string) (io.WriteCloser, error) { - return h.handle(path) -} - -func NewMemoryHandler() *MemoryLogHandler { - m := make(MemoryLogHandler) +func NewMemoryLogger() *MemoryLogger { + m := make(MemoryLogger) return &m } @@ -171,7 +178,7 @@ flag.Parse() addr := listenAddress() log.Println("Listening on", addr) - err := http.ListenAndServe(addr, NewHTTPLog(new(FileLogHandler))) + err := http.ListenAndServe(addr, NewHTTPLog(new(FileLogger))) if err != nil { log.Fatal(err) } diff --git a/restlog_test.go b/restlog_test.go --- a/restlog_test.go +++ b/restlog_test.go @@ -33,7 +33,7 @@ } func TestAddLog(t *testing.T) { - memorylog := NewMemoryHandler() + memorylog := NewMemoryLogger() var handler = NewHTTPLog(memorylog) req := postRequest(t, "/log", "foo bar s:+1") @@ -49,8 +49,8 @@ t.Errorf("bad # of logs: %d", len(*memorylog)) } for _, value := range *memorylog { - if value.Len() < 100 { - t.Fatal("The logs look small", value.Len(), "< 100") + if len(value) < 100 { + t.Fatal("The logs look small", len(value), "< 100") } } } diff --git a/rlog b/rlog --- a/rlog +++ b/rlog @@ -1,6 +1,7 @@ #!/bin/sh -readonly url='http://henry.precheur.org/log/rlog' +# readonly url='http://henry.precheur.org/log/rlog' +readonly url='http://localhost:8080/log' if test -z "$*" then