diff --git a/spongy.cgi/config.go b/spongy.cgi/config.go new file mode 100644 index 0000000..7120ea9 --- /dev/null +++ b/spongy.cgi/config.go @@ -0,0 +1,37 @@ +package main + +import ( + "io/ioutil" + "path" + "strings" +) + +type Config struct { + BaseDir string +} + +func readString(filename string) (string, error) { + octets, err := ioutil.ReadFile(filename) + if err != nil { + return "", err + } + return strings.TrimSpace(string(octets)), nil +} + + +func ReadConfig(cgiDir string) (*Config, error) { + cfgfn := path.Join(cgiDir, "spongy.cfg") + basePath, err := readString(cfgfn) + if err != nil { + return nil, err + } + + return &Config{basePath}, nil +} + +func (c *Config) Get(name string) (string, error) { + path := path.Join(c.BaseDir, name) + val, err := readString(path) + return val, err +} + diff --git a/spongy.cgi/network.go b/spongy.cgi/network.go index fab3083..8598cb8 100644 --- a/spongy.cgi/network.go +++ b/spongy.cgi/network.go @@ -66,6 +66,7 @@ func (nw *Network) Tail(out chan<- *Update) error { watcher.Add(filepath) + // XXX: some way to stop this? for { lines := make([]string, 0) bf := bufio.NewScanner(f) @@ -77,7 +78,7 @@ func (nw *Network) Tail(out chan<- *Update) error { if (len(parts) >= 4) && (parts[2] == "NEXTLOG") { watcher.Remove(filepath) filename := parts[3] - filepath = path.Join(NetworkDir, filename) + filepath = path.Join(nw.basePath, "log", filename) f.Close() f, err = os.Open(filepath) if err != nil { @@ -116,3 +117,30 @@ func (nw *Network) Write(data []byte) { ioutil.WriteFile(filepath, data, 0750) nw.seq += 1 } + + +func Networks(basePath string) (found []*Network) { + + dir, err := os.Open(basePath) + if err != nil { + return + } + defer dir.Close() + + + entities, _ := dir.Readdirnames(0) + for _, fn := range entities { + netdir := path.Join(basePath, fn) + + _, err = os.Stat(path.Join(netdir, "nick")) + if err != nil { + continue + } + + nw := NewNetwork(netdir) + found = append(found, nw) + } + + return +} + \ No newline at end of file diff --git a/spongy.cgi/spongy.cgi b/spongy.cgi/spongy.cgi index 753eafa..a70c528 100755 Binary files a/spongy.cgi/spongy.cgi and b/spongy.cgi/spongy.cgi differ diff --git a/spongy.cgi/spongy.cgi.go b/spongy.cgi/spongy.cgi.go index 580a51e..3c1bf29 100644 --- a/spongy.cgi/spongy.cgi.go +++ b/spongy.cgi/spongy.cgi.go @@ -2,16 +2,10 @@ package main import ( "fmt" - "github.com/go-fsnotify/fsnotify" - "io/ioutil" "log" - "os" - "bufio" - "strconv" "strings" "net/http" "net/http/cgi" - "time" "path" ) @@ -19,144 +13,58 @@ type Handler struct { cgi.Handler } -var NetworkDir string - -func ReadString(fn string) string { - octets, err := ioutil.ReadFile(fn) - if err != nil { - log.Fatal(err) - } - return strings.TrimSpace(string(octets)) -} - -func tail(w http.ResponseWriter, filename string, pos int64) { - var err error - - currentfn := path.Join(NetworkDir, "current") - if filename == "" { - filename, err = os.Readlink(currentfn) - if err != nil { - log.Fatal(err) - } - } +func (h Handler) handleCommand(cfg *Config, w http.ResponseWriter, r *http.Request) { + network := r.FormValue("network") + text := r.FormValue("text") + target := r.FormValue("target") - filepath := path.Join(NetworkDir, filename) - - f, err := os.Open(filepath) - if err != nil { - log.Fatal(err) - } - defer f.Close() - - watcher, err := fsnotify.NewWatcher() - if err != nil { - log.Fatal(err) - } - defer watcher.Close() - watcher.Add(filepath) - - for { - printid := false - - newpos, err := f.Seek(pos, 0) - if err != nil { - log.Fatal(err) - } - - if newpos != pos { - log.Fatal("Lost my position in the log, somehow (log truncated?)") - } - - bf := bufio.NewScanner(f) - for bf.Scan() { - t := bf.Text() - pos += int64(len(t)) + 1 // XXX: this breaks if we ever see \r\n - - parts := strings.Split(t, " ") - if (len(parts) >= 4) && (parts[2] == "NEXTLOG") { - watcher.Remove(filepath) - filename = parts[3] - filepath = path.Join(NetworkDir, filename) - f.Close() - f, err = os.Open(filepath) - if err != nil { - log.Fatal(err) - } - watcher.Add(filepath) - pos = 0 - } - fmt.Fprintf(w, "data: %s\n", t) - printid = true - } - if printid { - _, err = fmt.Fprintf(w, "id: %s/%d\n\n", filename, pos) - } - if err != nil { - break - } - w.(http.Flusher).Flush() - - select { - case _ = <-watcher.Events: - // Somethin' happened! - case err := <-watcher.Errors: - log.Fatal(err) - } - } -} - -func handleCommand(w http.ResponseWriter, text string, target string) { - fn := path.Join(NetworkDir, fmt.Sprintf("outq/cgi.%d", time.Now().Unix())) - f, err := os.Create(fn) - if err != nil { - fmt.Fprintln(w, "NO: Cannot create outq file") - fmt.Fprintln(w, err) - return - } - defer f.Close() + nw := NewNetwork(path.Join(cfg.BaseDir, network)) + var out string switch { case strings.HasPrefix(text, "/quote "): - fmt.Fprintln(f, text[7:]) + out = text[7:] case strings.HasPrefix(text, "/me "): - fmt.Fprintf(f, "PRIVMSG %s :\001ACTION %s\001\n", target, text[4:]) + out = fmt.Sprintf("PRIVMSG %s :\001ACTION %s\001", target, text[4:]) default: - fmt.Fprintf(f, "PRIVMSG %s :%s\n", target, text) + out = fmt.Sprintf("PRIVMSG %s :%s", target, text) } + nw.Write([]byte(out)) fmt.Fprintln(w, "OK") } +func (h Handler) handleTail(cfg *Config, w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "text/plain") + nws := Networks(cfg.BaseDir) + for _, nw := range nws { + fmt.Fprintf(w, "%v\n", nw) + } +} func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - BaseDir := "networks" - DefaultDir := path.Join(BaseDir, "default") - NetworkDir = path.Join(BaseDir, r.FormValue("network")) - - if path.Dir(DefaultDir) != path.Dir(NetworkDir) { - NetworkDir = DefaultDir + cfg, err := ReadConfig(h.Dir) + if err != nil { + http.Error(w, err.Error(), 500) } - authtok := ReadString(path.Join(NetworkDir, "authtok")) + // Validate authtok + authtok, err := cfg.Get("authtok") + if err != nil { + http.Error(w, err.Error(), 500) + } if r.FormValue("auth") != authtok { w.Header().Set("Content-Type", "text/plain") fmt.Fprintln(w, "NO: Invalid authtok") return } + + // Switch based on type switch r.FormValue("type") { case "command": - w.Header().Set("Content-Type", "text/plain") - handleCommand(w, r.Form.Get("text"), r.FormValue("target")) + h.handleCommand(cfg, w, r) default: - w.Header().Set("Content-Type", "text/event-stream") - parts := strings.Split(os.Getenv("HTTP_LAST_EVENT_ID"), "/") - if len(parts) == 2 { - filename := path.Base(parts[0]) - pos, _ := strconv.ParseInt(parts[1], 0, 64) - tail(w, filename, pos) - } else { - tail(w, "", 0) - } + h.handleTail(cfg, w, r) } }