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" ) type requestParams struct { // Add here the expected request parameters errorList map[string]error requestMessageLen int } 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 (p *requestParams) parseParameters(w http.ResponseWriter, r *http.Request) { err := r.ParseForm() if err != nil { log.Println("error parsing http request", err) } p.errorList = make(map[string]error, 1) p.requestMessageLen, p.errorList["l"] = parseParameterL(r) } func getHTTPHandler(hub circolog.Hub) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { // Looking for known parameter in the request var params requestParams params.parseParameters(w, r) if params.errorList["l"] != nil { log.Println("Request parameter \"l\":", params.errorList["l"]) w.WriteHeader(400) return } client := circolog.Client{ Messages: make(chan format.LogParts, 20), LastMsg: params.requestMessageLen, Nofollow: true} 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)} 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) } }