Decode reads one SSE stream from body until EOF, context cancellation, or a handler error. Decode closes body only when ctx is canceled so a blocked Read can unblock and observe the cancellation.
(ctx context.Context, body io.ReadCloser, handler Handler)
| 32 | // handler error. Decode closes body only when ctx is canceled so a blocked Read |
| 33 | // can unblock and observe the cancellation. |
| 34 | func Decode(ctx context.Context, body io.ReadCloser, handler Handler) error { |
| 35 | if ctx == nil { |
| 36 | return fmt.Errorf("sse: context is required") |
| 37 | } |
| 38 | if readerIsNil(body) { |
| 39 | return fmt.Errorf("sse: body is required") |
| 40 | } |
| 41 | if handler == nil { |
| 42 | return fmt.Errorf("sse: handler is required") |
| 43 | } |
| 44 | |
| 45 | cancelDone, cancelCloseErr := closeReaderOnCancel(ctx, body) |
| 46 | defer close(cancelDone) |
| 47 | |
| 48 | scanner := bufio.NewScanner(body) |
| 49 | scanner.Buffer(make([]byte, 0, 64*1024), maxLineBytes) |
| 50 | |
| 51 | event := Event{} |
| 52 | dataBuffer := make([]byte, 0, 256) |
| 53 | emit := func() (bool, error) { |
| 54 | if event.ID == "" && event.Event == "" && len(dataBuffer) == 0 { |
| 55 | return false, nil |
| 56 | } |
| 57 | if len(dataBuffer) > 0 { |
| 58 | event.Data = append(json.RawMessage(nil), dataBuffer...) |
| 59 | } |
| 60 | err := handler(event) |
| 61 | event = Event{} |
| 62 | dataBuffer = dataBuffer[:0] |
| 63 | if errors.Is(err, ErrStop) { |
| 64 | return true, nil |
| 65 | } |
| 66 | return false, err |
| 67 | } |
| 68 | |
| 69 | for scanner.Scan() { |
| 70 | if err := ctx.Err(); err != nil { |
| 71 | return decodeContextError(err, cancelCloseErr) |
| 72 | } |
| 73 | |
| 74 | shouldEmit, err := decodeLine(scanner.Text(), &event, &dataBuffer) |
| 75 | if err != nil { |
| 76 | return err |
| 77 | } |
| 78 | if shouldEmit { |
| 79 | stop, err := emit() |
| 80 | if err != nil { |
| 81 | return err |
| 82 | } |
| 83 | if stop { |
| 84 | return nil |
| 85 | } |
| 86 | } |
| 87 | } |
| 88 | |
| 89 | if err := scanner.Err(); err != nil { |
| 90 | if ctxErr := ctx.Err(); ctxErr != nil { |
| 91 | return decodeContextError(ctxErr, cancelCloseErr) |