fix callback URL to use configurable public base

Separate callback URL generation from LISTEN_ADDR by introducing CALLBACK_BASE_URL with a localhost default for local development.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-04-27 19:02:31 +07:00
co-authored by Claude Opus 4.7
parent 8815c20c13
commit cc9d54afdc
6 changed files with 113 additions and 2 deletions
+10 -1
View File
@@ -6,6 +6,7 @@ import (
"fmt"
"io"
"net/http"
"strings"
"time"
"thuanle.me/claw-email-bridge/internal/config"
@@ -65,7 +66,7 @@ func (d *Dispatcher) Dispatch(task *database.Task) {
}
// Build callback URL.
callbackURL := fmt.Sprintf("http://%s/callback", d.cfg.ListenAddr)
callbackURL := buildCallbackURL(d.cfg.CallbackBaseURL)
payload := openClawRequest{
Input: task.BodyPlain,
@@ -129,6 +130,14 @@ func (d *Dispatcher) Dispatch(task *database.Task) {
}
}
func buildCallbackURL(base string) string {
trimmed := strings.TrimRight(base, "/")
if trimmed == "" {
trimmed = "http://localhost"
}
return trimmed + "/callback"
}
// callAPI makes a single HTTP POST to OpenClaw.
func (d *Dispatcher) callAPI(payload openClawRequest) error {
body, err := json.Marshal(payload)
+43
View File
@@ -1,6 +1,7 @@
package ai_client_test
import (
"encoding/json"
"net/http"
"net/http/httptest"
"sync/atomic"
@@ -112,3 +113,45 @@ func TestDispatch_AllRetriesFailed(t *testing.T) {
t.Errorf("expected attempt_openclaw = 3, got %d", updated.AttemptOpenClaw)
}
}
func TestDispatch_UsesCallbackBaseURL(t *testing.T) {
tdb := database.NewTestDB(t)
var callbackURL string
mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var payload map[string]any
if err := json.NewDecoder(r.Body).Decode(&payload); err != nil {
t.Fatalf("decode payload: %v", err)
}
val, _ := payload["callback_url"].(string)
callbackURL = val
w.WriteHeader(http.StatusOK)
}))
defer mockServer.Close()
cfg := &config.Config{
OpenClawURL: mockServer.URL,
ListenAddr: ":9999",
CallbackBaseURL: "https://bridge.example.com/",
}
task := &database.Task{
TaskUUID: "uuid-callback-url",
ThreadID: "thread-1",
MessageID: "msg-callback@test.com",
Sender: "user@test.com",
Subject: "Callback test",
BodyPlain: "Hello",
Status: database.StatusReceived,
}
if err := database.CreateTask(tdb.DB, task); err != nil {
t.Fatalf("create task: %v", err)
}
dispatcher := ai_client.NewDispatcher(cfg, tdb.DB)
dispatcher.Dispatch(task)
if callbackURL != "https://bridge.example.com/callback" {
t.Fatalf("expected normalized callback URL, got %q", callbackURL)
}
}