@@ -2,7 +2,9 @@ package main
2
2
3
3
import (
4
4
"context"
5
+ "errors"
5
6
"fmt"
7
+ "io"
6
8
"log/slog"
7
9
"net"
8
10
"net/http"
@@ -12,6 +14,7 @@ import (
12
14
"time"
13
15
14
16
"github.com/go-json-experiment/json"
17
+ "github.com/go-json-experiment/json/jsontext"
15
18
"github.com/google/uuid"
16
19
"github.com/prometheus/client_golang/prometheus"
17
20
"github.com/prometheus/client_golang/prometheus/collectors"
@@ -41,6 +44,7 @@ func (robo *Robot) api(ctx context.Context, listen string, mux *http.ServeMux, m
41
44
mux .HandleFunc ("GET /debug/pprof/symbol" , pprof .Symbol )
42
45
mux .HandleFunc ("GET /debug/pprof/trace" , pprof .Trace )
43
46
mux .HandleFunc ("GET /api/message/{tag...}" , robo .apiRecall )
47
+ mux .HandleFunc ("DELETE /api/message/{tag...}" , robo .apiForget )
44
48
l , err := net .Listen ("tcp" , listen )
45
49
if err != nil {
46
50
return fmt .Errorf ("couldn't start API server: %w" , err )
@@ -144,3 +148,42 @@ func (robo *Robot) apiRecall(w http.ResponseWriter, r *http.Request) {
144
148
log .ErrorContext (ctx , "write response failed" , slog .Any ("err" , err ))
145
149
}
146
150
}
151
+
152
+ func (robo * Robot ) apiForget (w http.ResponseWriter , r * http.Request ) {
153
+ ctx := r .Context ()
154
+ log := slog .With (slog .String ("api" , "recall" ), slog .Any ("trace" , uuid .New ()))
155
+ log .InfoContext (ctx , "handle" , slog .String ("route" , r .Pattern ), slog .String ("remote" , r .RemoteAddr ))
156
+ defer log .InfoContext (ctx , "done" )
157
+ tag := r .PathValue ("tag" )
158
+ d := jsontext .NewDecoder (r .Body )
159
+ var all error
160
+ for {
161
+ tok , err := d .ReadToken ()
162
+ switch err {
163
+ case nil : // do nothing
164
+ case io .EOF :
165
+ // Done; transmit any forget errors.
166
+ if all != nil {
167
+ jsonerror (w , http .StatusInternalServerError , all .Error ())
168
+ return
169
+ }
170
+ w .WriteHeader (http .StatusNoContent )
171
+ return
172
+ default :
173
+ log .ErrorContext (ctx , "read token" , slog .Any ("err" , err ))
174
+ jsonerror (w , http .StatusBadRequest , "token read failed" )
175
+ return
176
+ }
177
+ if tok .Kind () != '"' {
178
+ log .WarnContext (ctx , "invalid token" , slog .Any ("kind" , tok .Kind ()))
179
+ jsonerror (w , http .StatusBadRequest , "input not a JSON string" )
180
+ return
181
+ }
182
+ id := tok .String ()
183
+ if err := robo .brain .Forget (ctx , tag , id ); err != nil {
184
+ log .ErrorContext (ctx , "forget failed" , slog .String ("tag" , tag ), slog .String ("id" , id ), slog .Any ("err" , err ))
185
+ all = errors .Join (all , err )
186
+ // continue on
187
+ }
188
+ }
189
+ }
0 commit comments