package main import ( "errors" "log" "net/http" "strconv" "time" "git.lattuga.net/boyska/circolog" "github.com/gorilla/websocket" "gopkg.in/mcuadros/go-syslog.v2/format" ) func setupHTTP(hub circolog.Hub) { http.HandleFunc("/", getHTTPHandler(hub)) http.HandleFunc("/ws", getWSHandler(hub)) } func parseParameterL(r *http.Request) (int, error) { var requestMessageLen int var err error if reqL, ok := r.Form["l"]; ok { if len(reqL) == 1 { requestMessageLen, err = strconv.Atoi(reqL[0]) if err != nil { return 0, err } if requestMessageLen <= 0 { return 0, errors.New("malformed request") } } else { return 0, errors.New("malformed request") } } return requestMessageLen, nil } func parseParameters(w http.ResponseWriter, r *http.Request) (circolog.ClientOptions, error) { var opts circolog.ClientOptions opts.BacklogLength = 10 // default err := r.ParseForm() if err != nil { log.Println("error parsing http request", err) return opts, err } l, err := parseParameterL(r) if err != nil { return opts, err } opts.BacklogLength = l return opts, err } func getHTTPHandler(hub circolog.Hub) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { // Looking for known parameter in the request opts, err := parseParameters(w, r) if err != nil { log.Println("Error on request parameter \"l\":", err) w.WriteHeader(400) return } opts.Nofollow = true client := circolog.Client{ Messages: make(chan format.LogParts, 20), Options: opts, } hub.Register <- client for x := range client.Messages { w.Write([]byte(circolog.FormatSyslog(x))) w.Write([]byte("\n")) } } } func getWSHandler(hub circolog.Hub) http.HandlerFunc { var upgrader = websocket.Upgrader{ ReadBufferSize: 1024, WriteBufferSize: 1024, } return func(w http.ResponseWriter, r *http.Request) { conn, err := upgrader.Upgrade(w, r, nil) if err != nil { return } client := circolog.Client{Messages: make(chan format.LogParts, 20), Options: circolog.ClientOptions{BacklogLength: -1}, } hub.Register <- client // Allow collection of memory referenced by the caller by doing all work in // new goroutines. go func(conn *websocket.Conn, c circolog.Client) { defer func() { hub.Unregister <- c conn.Close() }() for { select { case message, ok := <-c.Messages: conn.SetWriteDeadline(time.Now().Add(10 * time.Second)) if !ok { // The hub closed the channel. conn.WriteMessage(websocket.CloseMessage, []byte{}) return } w, err := conn.NextWriter(websocket.TextMessage) if err != nil { return } w.Write([]byte(circolog.FormatSyslog(message))) if err := w.Close(); err != nil { return } // TODO: ticker/ping } } }(conn, client) } }