func (w *StreamWriter) Write(data []byte) (int, error) { var err = sse.Encode(w.writer, sse.Event{ Id: strconv.Itoa(w.count), Event: "message", Data: string(data), }) w.writer.Flush() w.count += len(data) return len(data), err }
func (c *conn) Send(msg common.Message) error { buf := new(bytes.Buffer) err := sse.Encode(buf, sse.Event{ Event: msg.Name(), Id: msg.Id(), Data: msg.Data(), }) if err != nil { return err } return c.socket.WriteMessage(websocket.TextMessage, buf.Bytes()) }
func GetStream(c *gin.Context) { repo := session.Repo(c) buildn, _ := strconv.Atoi(c.Param("build")) jobn, _ := strconv.Atoi(c.Param("number")) c.Writer.Header().Set("Content-Type", "text/event-stream") build, err := store.GetBuildNumber(c, repo, buildn) if err != nil { log.Debugln("stream cannot get build number.", err) c.AbortWithError(404, err) return } job, err := store.GetJobNumber(c, build, jobn) if err != nil { log.Debugln("stream cannot get job number.", err) c.AbortWithError(404, err) return } rc, err := stream.Reader(c, stream.ToKey(job.ID)) if err != nil { c.AbortWithError(404, err) return } go func() { <-c.Writer.CloseNotify() rc.Close() }() var line int var scanner = bufio.NewScanner(rc) for scanner.Scan() { line++ var err = sse.Encode(c.Writer, sse.Event{ Id: strconv.Itoa(line), Event: "message", Data: scanner.Text(), }) if err != nil { break } c.Writer.Flush() } log.Debugf("Closed stream %s#%d", repo.FullName, build.Number) }
// GetRepoEvents will upgrade the connection to a Websocket and will stream // event updates to the browser. func GetRepoEvents(c *gin.Context) { repo := session.Repo(c) c.Writer.Header().Set("Content-Type", "text/event-stream") eventc := make(chan *bus.Event, 1) bus.Subscribe(c, eventc) defer func() { bus.Unsubscribe(c, eventc) close(eventc) log.Infof("closed event stream") }() c.Stream(func(w io.Writer) bool { select { case event := <-eventc: if event == nil { log.Infof("nil event received") return false } // TODO(bradrydzewski) This is a super hacky workaround until we improve // the actual bus. Having a per-call database event is just plain stupid. if event.Repo.FullName == repo.FullName { var payload = struct { model.Build Jobs []*model.Job `json:"jobs"` }{} payload.Build = event.Build payload.Jobs, _ = store.GetJobList(c, &event.Build) data, _ := json.Marshal(&payload) sse.Encode(w, sse.Event{ Event: "message", Data: string(data), }) } case <-c.Writer.CloseNotify(): return false } return true }) }
// GetRepoEvents will upgrade the connection to a Websocket and will stream // event updates to the browser. func GetRepoEvents(c *gin.Context) { engine_ := context.Engine(c) repo := session.Repo(c) c.Writer.Header().Set("Content-Type", "text/event-stream") eventc := make(chan *engine.Event, 1) engine_.Subscribe(eventc) defer func() { engine_.Unsubscribe(eventc) close(eventc) log.Infof("closed event stream") }() c.Stream(func(w io.Writer) bool { select { case event := <-eventc: if event == nil { log.Infof("nil event received") return false } if event.Name == repo.FullName { log.Debugf("received message %s", event.Name) sse.Encode(w, sse.Event{ Event: "message", Data: string(event.Msg), }) } case <-c.Writer.CloseNotify(): return false } return true }) }