Skip to content

Instantly share code, notes, and snippets.

@Herzult
Created January 12, 2024 01:37
Show Gist options
  • Save Herzult/d562d974b22e49ec99e528084565d06f to your computer and use it in GitHub Desktop.
Save Herzult/d562d974b22e49ec99e528084565d06f to your computer and use it in GitHub Desktop.
JSON Stream Golang
package jsonstream
import (
"encoding/json"
"fmt"
"io"
"net/http"
"sync"
)
func FromHTTP[T any](client *http.Client, req *http.Request) *Stream[T] {
c := make(chan Result[T])
f := func() { runReq(client, req, c) }
return &Stream[T]{
c: c,
openFn: f,
}
}
type Result[T any] struct {
Val T
Err error
}
type Stream[T any] struct {
c <-chan Result[T]
mux sync.Mutex
openFn func()
isOpen bool
}
func (s *Stream[T]) Chan() <-chan Result[T] {
s.mux.Lock()
defer s.mux.Unlock()
if !s.isOpen {
go s.openFn()
s.isOpen = true
}
return s.c
}
func runReq[T any](h *http.Client, r *http.Request, c chan<- Result[T]) {
defer close(c)
res, err := h.Do(r)
if err != nil {
c <- Result[T]{Err: err}
return
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
c <- Result[T]{Err: fmt.Errorf("unexpected status: %s", res.Status)}
return
}
d := json.NewDecoder(res.Body)
for d.More() {
var val T
if err := d.Decode(&val); err != nil {
c <- Result[T]{Err: err}
return
}
c <- Result[T]{Val: val}
}
if d.Decode(nil) == io.ErrUnexpectedEOF {
c <- Result[T]{Err: io.ErrUnexpectedEOF}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment