|
6 | 6 | "encoding/json"
|
7 | 7 | "fmt"
|
8 | 8 | "net/http"
|
| 9 | + "time" |
9 | 10 |
|
10 | 11 | "github.com/thenativeweb/goutils/v2/coreutils/contextutils"
|
11 | 12 |
|
@@ -40,6 +41,9 @@ func newObserveEventsValue(item StoreItem) ObserveEventsResult {
|
40 | 41 | func (client *Client) ObserveEvents(ctx context.Context, subject string, recursive ObserveRecursivelyOption, options ...ObserveEventsOption) <-chan ObserveEventsResult {
|
41 | 42 | results := make(chan ObserveEventsResult, 1)
|
42 | 43 |
|
| 44 | + heartbeatInterval := 1 * time.Second |
| 45 | + heartbeatTimeout := heartbeatInterval * 3 |
| 46 | + |
43 | 47 | go func() {
|
44 | 48 | defer close(results)
|
45 | 49 |
|
@@ -94,52 +98,70 @@ func (client *Client) ObserveEvents(ctx context.Context, subject string, recursi
|
94 | 98 | }
|
95 | 99 | defer response.Body.Close()
|
96 | 100 |
|
| 101 | + heartbeatTimer := time.NewTimer(heartbeatTimeout) |
| 102 | + defer heartbeatTimer.Stop() |
| 103 | + |
97 | 104 | unmarshalContext, cancelUnmarshalling := context.WithCancel(ctx)
|
98 | 105 | defer cancelUnmarshalling()
|
99 | 106 |
|
100 | 107 | unmarshalResults := ndjson.UnmarshalStream[ndjson.StreamItem](unmarshalContext, response.Body)
|
101 | 108 | for unmarshalResult := range unmarshalResults {
|
102 |
| - data, err := unmarshalResult.GetData() |
103 |
| - if err != nil { |
104 |
| - if contextutils.IsContextTerminationError(err) { |
105 |
| - results <- newObserveEventsError(err) |
106 |
| - return |
107 |
| - } |
108 |
| - |
| 109 | + select { |
| 110 | + case <-heartbeatTimer.C: |
109 | 111 | results <- newObserveEventsError(
|
110 |
| - customErrors.NewServerError(fmt.Sprintf("unsupported stream item encountered: %s", err.Error())), |
| 112 | + customErrors.NewServerError("heartbeat timeout"), |
111 | 113 | )
|
112 | 114 | return
|
113 |
| - } |
114 | 115 |
|
115 |
| - switch data.Type { |
116 |
| - case "heartbeat": |
117 |
| - continue |
118 |
| - case "error": |
119 |
| - var serverError streamError |
120 |
| - if err := json.Unmarshal(data.Payload, &serverError); err != nil { |
| 116 | + default: |
| 117 | + data, err := unmarshalResult.GetData() |
| 118 | + if err != nil { |
| 119 | + if contextutils.IsContextTerminationError(err) { |
| 120 | + results <- newObserveEventsError(err) |
| 121 | + return |
| 122 | + } |
| 123 | + |
121 | 124 | results <- newObserveEventsError(
|
122 |
| - customErrors.NewServerError(fmt.Sprintf("unsupported stream error encountered: %s", err.Error())), |
| 125 | + customErrors.NewServerError(fmt.Sprintf("unsupported stream item encountered: %s", err.Error())), |
123 | 126 | )
|
124 | 127 | return
|
125 | 128 | }
|
126 | 129 |
|
127 |
| - results <- newObserveEventsError(customErrors.NewServerError(serverError.Error)) |
128 |
| - case "item": |
129 |
| - var storeItem StoreItem |
130 |
| - if err := json.Unmarshal(data.Payload, &storeItem); err != nil { |
| 130 | + switch data.Type { |
| 131 | + case "heartbeat": |
| 132 | + if !heartbeatTimer.Stop() { |
| 133 | + <-heartbeatTimer.C |
| 134 | + } |
| 135 | + heartbeatTimer.Reset(heartbeatTimeout) |
| 136 | + |
| 137 | + case "error": |
| 138 | + var serverError streamError |
| 139 | + if err := json.Unmarshal(data.Payload, &serverError); err != nil { |
| 140 | + results <- newObserveEventsError( |
| 141 | + customErrors.NewServerError(fmt.Sprintf("unsupported stream error encountered: %s", err.Error())), |
| 142 | + ) |
| 143 | + return |
| 144 | + } |
| 145 | + |
| 146 | + results <- newObserveEventsError(customErrors.NewServerError(serverError.Error)) |
| 147 | + |
| 148 | + case "item": |
| 149 | + var storeItem StoreItem |
| 150 | + if err := json.Unmarshal(data.Payload, &storeItem); err != nil { |
| 151 | + results <- newObserveEventsError( |
| 152 | + customErrors.NewServerError(fmt.Sprintf("unsupported stream item encountered: '%s' (trying to unmarshal '%+v')", err.Error(), data)), |
| 153 | + ) |
| 154 | + return |
| 155 | + } |
| 156 | + |
| 157 | + results <- newObserveEventsValue(storeItem) |
| 158 | + |
| 159 | + default: |
131 | 160 | results <- newObserveEventsError(
|
132 |
| - customErrors.NewServerError(fmt.Sprintf("unsupported stream item encountered: '%s' (trying to unmarshal '%+v')", err.Error(), data)), |
| 161 | + customErrors.NewServerError(fmt.Sprintf("unsupported stream item encountered: '%+v' does not have a recognized type", data)), |
133 | 162 | )
|
134 | 163 | return
|
135 | 164 | }
|
136 |
| - |
137 |
| - results <- newObserveEventsValue(storeItem) |
138 |
| - default: |
139 |
| - results <- newObserveEventsError( |
140 |
| - customErrors.NewServerError(fmt.Sprintf("unsupported stream item encountered: '%+v' does not have a recognized type", data)), |
141 |
| - ) |
142 |
| - return |
143 | 165 | }
|
144 | 166 | }
|
145 | 167 | }()
|
|
0 commit comments