spongy/spongy.cgi/spongy.cgi.go

173 lines
3.5 KiB
Go
Raw Normal View History

2014-07-14 19:30:47 -06:00
package main
import (
"fmt"
2014-08-12 22:59:18 -06:00
"github.com/go-fsnotify/fsnotify"
"io/ioutil"
2014-07-14 19:30:47 -06:00
"log"
"os"
"bufio"
"strconv"
"strings"
2014-07-14 19:30:47 -06:00
"net/http"
"net/http/cgi"
"time"
2014-08-05 15:53:03 -06:00
"path"
2014-07-14 19:30:47 -06:00
)
type Handler struct {
cgi.Handler
}
2014-10-24 23:24:49 -06:00
var NetworkDir string
2014-08-05 15:53:03 -06:00
func ReadString(fn string) string {
octets, err := ioutil.ReadFile(fn)
if err != nil {
log.Fatal(err)
}
return strings.TrimSpace(string(octets))
}
2014-07-14 19:30:47 -06:00
2014-10-24 22:21:53 -06:00
func tail(w http.ResponseWriter, filename string, pos int64) {
var err error
2014-08-12 23:21:19 -06:00
2014-10-24 23:24:49 -06:00
currentfn := path.Join(NetworkDir, "current")
2014-10-24 22:21:53 -06:00
if filename == "" {
filename, err = os.Readlink(currentfn)
if err != nil {
log.Fatal(err)
}
}
2014-10-24 23:24:49 -06:00
filepath := path.Join(NetworkDir, filename)
2014-10-24 22:21:53 -06:00
f, err := os.Open(filepath)
2014-07-14 19:30:47 -06:00
if err != nil {
log.Fatal(err)
}
defer f.Close()
2014-08-12 22:59:18 -06:00
watcher, err := fsnotify.NewWatcher()
if err != nil {
log.Fatal(err)
}
defer watcher.Close()
2014-10-24 22:21:53 -06:00
watcher.Add(filepath)
2014-08-12 22:59:18 -06:00
2014-08-05 16:35:51 -06:00
for {
printid := false
2014-08-12 22:59:18 -06:00
newpos, err := f.Seek(pos, 0)
2014-08-05 16:35:51 -06:00
if err != nil {
log.Fatal(err)
}
2014-10-24 22:21:53 -06:00
if newpos != pos {
log.Fatal("Lost my position in the log, somehow (log truncated?)")
2014-08-12 22:59:18 -06:00
}
2014-10-24 22:21:53 -06:00
2014-08-05 16:35:51 -06:00
bf := bufio.NewScanner(f)
for bf.Scan() {
t := bf.Text()
2014-08-12 22:59:18 -06:00
pos += int64(len(t)) + 1 // XXX: this breaks if we ever see \r\n
2014-10-24 22:21:53 -06:00
parts := strings.Split(t, " ")
2014-10-29 17:47:04 -06:00
if (len(parts) >= 4) && (parts[2] == "NEXTLOG") {
2014-10-24 22:21:53 -06:00
watcher.Remove(filepath)
2015-01-29 13:44:28 -07:00
filename = parts[3]
2014-10-24 23:24:49 -06:00
filepath = path.Join(NetworkDir, filename)
2014-10-24 22:21:53 -06:00
f.Close()
2014-10-29 17:47:04 -06:00
f, err = os.Open(filepath)
2014-10-24 22:21:53 -06:00
if err != nil {
log.Fatal(err)
}
2014-10-29 17:47:04 -06:00
watcher.Add(filepath)
2015-01-29 13:44:28 -07:00
pos = 0
2014-10-24 22:21:53 -06:00
}
2014-08-05 16:35:51 -06:00
fmt.Fprintf(w, "data: %s\n", t)
printid = true
}
if printid {
2014-10-24 22:21:53 -06:00
_, err = fmt.Fprintf(w, "id: %s/%d\n\n", filename, pos)
2014-08-05 16:35:51 -06:00
}
if err != nil {
break
}
w.(http.Flusher).Flush()
2014-08-12 22:59:18 -06:00
select {
case _ = <-watcher.Events:
// Somethin' happened!
case err := <-watcher.Errors:
log.Fatal(err)
}
2014-07-14 19:30:47 -06:00
}
}
2014-08-05 15:53:03 -06:00
func handleCommand(w http.ResponseWriter, text string, target string) {
2014-10-24 23:24:49 -06:00
fn := path.Join(NetworkDir, fmt.Sprintf("outq/cgi.%d", time.Now().Unix()))
2014-07-14 19:30:47 -06:00
f, err := os.Create(fn)
if err != nil {
2014-10-24 23:24:49 -06:00
fmt.Fprintln(w, "NO: Cannot create outq file")
2014-07-14 19:30:47 -06:00
fmt.Fprintln(w, err)
return
}
defer f.Close()
2014-08-05 15:53:03 -06:00
switch {
case strings.HasPrefix(text, "/quote "):
fmt.Fprintln(f, text[7:])
case strings.HasPrefix(text, "/me "):
fmt.Fprintf(f, "PRIVMSG %s :\001ACTION %s\001\n", target, text[4:])
default:
fmt.Fprintf(f, "PRIVMSG %s :%s\n", target, text)
}
2014-07-14 19:30:47 -06:00
fmt.Fprintln(w, "OK")
}
func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
2014-10-24 23:24:49 -06:00
BaseDir := "networks"
2014-08-12 22:57:39 -06:00
DefaultDir := path.Join(BaseDir, "default")
2014-10-24 23:24:49 -06:00
NetworkDir = path.Join(BaseDir, r.FormValue("network"))
2014-08-12 21:41:54 -06:00
2014-10-24 23:24:49 -06:00
if path.Dir(DefaultDir) != path.Dir(NetworkDir) {
NetworkDir = DefaultDir
2014-08-12 21:41:54 -06:00
}
2014-10-24 23:24:49 -06:00
authtok := ReadString(path.Join(NetworkDir, "authtok"))
if r.FormValue("auth") != authtok {
w.Header().Set("Content-Type", "text/plain")
2014-10-24 23:24:49 -06:00
fmt.Fprintln(w, "NO: Invalid authtok")
return
}
2014-07-14 19:30:47 -06:00
switch r.FormValue("type") {
case "command":
w.Header().Set("Content-Type", "text/plain")
2014-08-05 15:53:03 -06:00
handleCommand(w, r.Form.Get("text"), r.FormValue("target"))
2014-07-14 19:30:47 -06:00
default:
w.Header().Set("Content-Type", "text/event-stream")
2014-10-24 22:21:53 -06:00
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)
}
2014-07-14 19:30:47 -06:00
}
}
func main() {
2015-02-22 19:44:09 -07:00
log.SetOutput(os.Stdout)
log.SetFlags(0)
log.SetPrefix("Status: 500 CGI Go Boom\nContent-type: text/plain\n\nERROR: ")
2014-07-14 19:30:47 -06:00
h := Handler{}
if err := cgi.Serve(h); err != nil {
log.Fatal(err)
}
}