Skip to content

Commit 4c9186b

Browse files
committed
robot: learn message api
Fixes #90.
1 parent d374d93 commit 4c9186b

File tree

1 file changed

+54
-0
lines changed

1 file changed

+54
-0
lines changed

api.go

+54
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"github.com/prometheus/client_golang/prometheus/promhttp"
2222

2323
"github.com/zephyrtronium/robot/brain"
24+
"github.com/zephyrtronium/robot/userhash"
2425
)
2526

2627
func (robo *Robot) api(ctx context.Context, listen string, mux *http.ServeMux, metrics []prometheus.Collector) error {
@@ -44,6 +45,7 @@ func (robo *Robot) api(ctx context.Context, listen string, mux *http.ServeMux, m
4445
mux.HandleFunc("GET /debug/pprof/symbol", pprof.Symbol)
4546
mux.HandleFunc("GET /debug/pprof/trace", pprof.Trace)
4647
mux.HandleFunc("GET /api/message/{tag...}", robo.apiRecall)
48+
mux.HandleFunc("POST /api/message/{tag...}", robo.apiLearn)
4749
mux.HandleFunc("DELETE /api/message/{tag...}", robo.apiForget)
4850
l, err := net.Listen("tcp", listen)
4951
if err != nil {
@@ -149,6 +151,58 @@ func (robo *Robot) apiRecall(w http.ResponseWriter, r *http.Request) {
149151
}
150152
}
151153

154+
func (robo *Robot) apiLearn(w http.ResponseWriter, r *http.Request) {
155+
ctx := r.Context()
156+
log := slog.With(slog.String("api", "recall"), slog.Any("trace", uuid.New()))
157+
log.InfoContext(ctx, "handle", slog.String("route", r.Pattern), slog.String("remote", r.RemoteAddr))
158+
defer log.InfoContext(ctx, "done")
159+
tag := r.PathValue("tag")
160+
d := jsontext.NewDecoder(r.Body)
161+
var all error
162+
var msg apiMessage
163+
for {
164+
err := json.UnmarshalDecode(d, &msg)
165+
switch err {
166+
case nil: // do nothing
167+
case io.EOF:
168+
// Done; transmit any learn errors.
169+
if all != nil {
170+
jsonerror(w, http.StatusInternalServerError, all.Error())
171+
return
172+
}
173+
w.WriteHeader(http.StatusNoContent)
174+
return
175+
default:
176+
log.ErrorContext(ctx, "read message", slog.Any("err", err))
177+
jsonerror(w, http.StatusBadRequest, "message read failed")
178+
return
179+
}
180+
m := brain.Message{
181+
ID: msg.ID,
182+
Sender: userhash.Hash{'A', 'P', 'I'},
183+
Text: msg.Text,
184+
}
185+
if m.ID == "" {
186+
m.ID = "API:" + uuid.NewString()
187+
}
188+
if msg.Time == "" {
189+
m.Timestamp = time.Now().UnixMilli()
190+
} else {
191+
t, err := time.Parse(time.RFC3339, msg.Time)
192+
if err != nil {
193+
all = errors.Join(all, err)
194+
continue
195+
}
196+
m.Timestamp = t.UnixMilli()
197+
}
198+
if err := brain.Learn(ctx, robo.brain, tag, &m); err != nil {
199+
log.ErrorContext(ctx, "learn failed", slog.String("tag", tag), slog.String("id", m.ID), slog.Any("err", err))
200+
all = errors.Join(all, err)
201+
// continue on
202+
}
203+
}
204+
}
205+
152206
func (robo *Robot) apiForget(w http.ResponseWriter, r *http.Request) {
153207
ctx := r.Context()
154208
log := slog.With(slog.String("api", "recall"), slog.Any("trace", uuid.New()))

0 commit comments

Comments
 (0)