github.com/turbot/steampipe@v1.7.0-rc.0.0.20240517123944-7cef272d4458/pkg/dashboard/dashboardserver/api.go (about) 1 package dashboardserver 2 3 import ( 4 "context" 5 "fmt" 6 "log" 7 "net/http" 8 "path" 9 "time" 10 11 "github.com/gin-contrib/static" 12 "github.com/gin-gonic/gin" 13 "github.com/spf13/viper" 14 "github.com/turbot/steampipe/pkg/constants" 15 "github.com/turbot/steampipe/pkg/error_helpers" 16 "github.com/turbot/steampipe/pkg/filepaths" 17 "gopkg.in/olahol/melody.v1" 18 ) 19 20 func startAPIAsync(ctx context.Context, webSocket *melody.Melody) chan struct{} { 21 doneChan := make(chan struct{}) 22 23 go func() { 24 gin.SetMode(gin.ReleaseMode) 25 router := gin.New() 26 // only add the Recovery middleware 27 router.Use(gin.Recovery()) 28 29 assetsDirectory := filepaths.EnsureDashboardAssetsDir() 30 31 router.Use(static.Serve("/", static.LocalFile(assetsDirectory, true))) 32 33 router.GET("/ws", func(c *gin.Context) { 34 webSocket.HandleRequest(c.Writer, c.Request) 35 }) 36 37 router.NoRoute(func(c *gin.Context) { 38 // https://stackoverflow.com/questions/49547/how-do-we-control-web-page-caching-across-all-browsers 39 c.Header("Cache-Control", "no-cache, no-store, must-revalidate") // HTTP 1.1. 40 c.Header("Pragma", "no-cache") // HTTP 1.0. 41 c.Header("Expires", "0") // Proxies. 42 c.File(path.Join(assetsDirectory, "index.html")) 43 }) 44 45 dashboardServerPort := viper.GetInt(constants.ArgDashboardPort) 46 dashboardServerListen := "localhost" 47 if viper.GetString(constants.ArgDashboardListen) == string(ListenTypeNetwork) { 48 dashboardServerListen = "" 49 } 50 51 srv := &http.Server{ 52 Addr: fmt.Sprintf("%s:%d", dashboardServerListen, dashboardServerPort), 53 Handler: router, 54 } 55 56 go func() { 57 // service connections 58 if err := srv.ListenAndServe(); err != nil { 59 log.Printf("listen: %s\n", err) 60 } 61 }() 62 63 outputReady(ctx, fmt.Sprintf("Dashboard server started on %d and listening on %s", dashboardServerPort, viper.GetString(constants.ArgDashboardListen))) 64 OutputMessage(ctx, fmt.Sprintf("Visit http://localhost:%d", dashboardServerPort)) 65 OutputMessage(ctx, "Press Ctrl+C to exit") 66 <-ctx.Done() 67 log.Println("Shutdown Server…") 68 69 shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second) 70 defer cancel() 71 72 if err := srv.Shutdown(shutdownCtx); err != nil { 73 error_helpers.ShowErrorWithMessage(ctx, err, "Server shutdown failed") 74 } 75 log.Println("[TRACE] Server exiting") 76 77 // indicate the API server is done 78 doneChan <- struct{}{} 79 }() 80 81 return doneChan 82 }