Skip to content

Commit 753c81d

Browse files
committed
embed and serve a directory of static files in agentapi
1 parent cf52b9c commit 753c81d

File tree

5 files changed

+91
-3
lines changed

5 files changed

+91
-3
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ output-*.log
33
snapshot-*.log
44
snapshot2-*.log
55
.aider*
6-
schema.yaml
6+
schema.yaml
7+
**/.claude/settings.local.json

lib/httpapi/chat/404.html

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>Chat</title>
5+
<p>This is a placeholder for the 404 page.</p>
6+
<p>
7+
Looks like you're running a build without the chat frontend. Use `make
8+
build` to rebuild the binary with the chat frontend embedded.
9+
</p>
10+
</head>
11+
</html>

lib/httpapi/chat/index.html

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>Chat</title>
5+
<p>
6+
Looks like you're running a build without the chat frontend. Use `make
7+
build` to rebuild the binary with the chat frontend embedded.
8+
</p>
9+
</head>
10+
</html>

lib/httpapi/embed.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package httpapi
2+
3+
import (
4+
"embed"
5+
"fmt"
6+
"io/fs"
7+
"net/http"
8+
"os"
9+
"strings"
10+
)
11+
12+
//go:embed chat/*
13+
var chatStaticFiles embed.FS
14+
15+
// FileServerWithIndexFallback creates a file server that serves the given filesystem
16+
// and falls back to index.html for any path that doesn't match a file
17+
func FileServerWithIndexFallback() http.Handler {
18+
// First, try to get the embedded files
19+
subFS, err := fs.Sub(chatStaticFiles, "chat")
20+
if err != nil {
21+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
22+
http.Error(w, fmt.Sprintf("failed to get subfs: %s", err), http.StatusInternalServerError)
23+
})
24+
}
25+
chatFS := http.FS(subFS)
26+
fileServer := http.FileServer(chatFS)
27+
28+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
29+
path := r.URL.Path
30+
trimmedPath := strings.TrimPrefix(path, "/")
31+
fmt.Println("path", trimmedPath)
32+
if trimmedPath == "" {
33+
trimmedPath = "index.html"
34+
}
35+
36+
// Try to serve the file directly
37+
_, err := chatFS.Open(trimmedPath)
38+
if err == nil {
39+
fileServer.ServeHTTP(w, r)
40+
return
41+
}
42+
43+
// If file doesn't exist, serve 404.html for any path
44+
if os.IsNotExist(err) {
45+
r2 := new(http.Request)
46+
*r2 = *r
47+
r2.URL.Path = "/404.html"
48+
fileServer.ServeHTTP(w, r2)
49+
return
50+
}
51+
52+
// For other errors, return the error as is
53+
http.Error(w, fmt.Sprintf("failed to serve file: %s", err), http.StatusInternalServerError)
54+
})
55+
}

lib/httpapi/server.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,7 @@ func NewServer(ctx context.Context, agentType mf.AgentType, process *termexec.Pr
5757
router := chi.NewMux()
5858

5959
corsMiddleware := cors.New(cors.Options{
60-
// coder.github.io hosts the chat demo
61-
AllowedOrigins: []string{"http://localhost:3000", "https://coder.github.io"},
60+
AllowedOrigins: []string{"*"},
6261
AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
6362
AllowedHeaders: []string{"Accept", "Authorization", "Content-Type", "X-CSRF-Token"},
6463
ExposedHeaders: []string{"Link"},
@@ -152,6 +151,9 @@ func (s *Server) registerRoutes() {
152151
}, map[string]any{
153152
"screen": ScreenUpdateBody{},
154153
}, s.subscribeScreen)
154+
155+
// Serve static files for the chat interface under /chat
156+
s.registerStaticFileRoutes()
155157
}
156158

157159
// getStatus handles GET /status
@@ -296,3 +298,12 @@ func (s *Server) Stop(ctx context.Context) error {
296298
}
297299
return nil
298300
}
301+
302+
// registerStaticFileRoutes sets up routes for serving static files
303+
func (s *Server) registerStaticFileRoutes() {
304+
chatHandler := FileServerWithIndexFallback()
305+
306+
// Mount the file server at /chat
307+
s.router.Handle("/chat", http.StripPrefix("/chat", chatHandler))
308+
s.router.Handle("/chat/*", http.StripPrefix("/chat", chatHandler))
309+
}

0 commit comments

Comments
 (0)