main.go raw
1 // Simple static file server for testing the standalone dashboard
2 package main
3
4 import (
5 "flag"
6 "fmt"
7 "log"
8 "net/http"
9 "os"
10 "path/filepath"
11 )
12
13 func main() {
14 port := flag.Int("port", 8080, "port to listen on")
15 dir := flag.String("dir", "", "directory to serve (default: app/web/dist)")
16 flag.Parse()
17
18 // Find the dist directory
19 serveDir := *dir
20 if serveDir == "" {
21 // Try to find it relative to current directory or executable
22 candidates := []string{
23 "app/web/dist",
24 "../app/web/dist",
25 "../../app/web/dist",
26 }
27
28 // Also check relative to executable
29 if exe, err := os.Executable(); err == nil {
30 exeDir := filepath.Dir(exe)
31 candidates = append(candidates,
32 filepath.Join(exeDir, "app/web/dist"),
33 filepath.Join(exeDir, "../app/web/dist"),
34 )
35 }
36
37 for _, candidate := range candidates {
38 if info, err := os.Stat(candidate); err == nil && info.IsDir() {
39 serveDir = candidate
40 break
41 }
42 }
43
44 if serveDir == "" {
45 log.Fatal("Could not find dist directory. Use -dir flag to specify.")
46 }
47 }
48
49 absDir, _ := filepath.Abs(serveDir)
50 fmt.Printf("Serving %s on http://localhost:%d\n", absDir, *port)
51 fmt.Println("Press Ctrl+C to stop")
52
53 // Create file server with SPA fallback
54 fs := http.FileServer(http.Dir(serveDir))
55 http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
56 // Try to serve the file
57 path := filepath.Join(serveDir, r.URL.Path)
58 if _, err := os.Stat(path); os.IsNotExist(err) {
59 // File doesn't exist, serve index.html for SPA routing
60 http.ServeFile(w, r, filepath.Join(serveDir, "index.html"))
61 return
62 }
63 fs.ServeHTTP(w, r)
64 })
65
66 addr := fmt.Sprintf(":%d", *port)
67 if err := http.ListenAndServe(addr, nil); err != nil {
68 log.Fatal(err)
69 }
70 }
71