package setup import ( "fmt" "net" "net/http" "os" "os/signal" "path/filepath" "strings" "syscall" "github.com/fatih/color" "github.com/gin-gonic/gin" "github.com/yaoapp/yao/config" "github.com/yaoapp/yao/data" "github.com/yaoapp/yao/engine" "github.com/yaoapp/yao/share" "github.com/yaoapp/yao/widgets/app" ) // XGenSetupServer XGen Setup var XGenSetupServer http.Handler = http.FileServer(data.Setup()) // Done check done var Done = make(chan bool, 1) // shutdown check done var shutdown = make(chan bool, 1) // Canceled check if setup is canceld var Canceled = make(chan bool, 1) // Start start the studio api server func Start() (err error) { // recive interrupt signal interrupt := make(chan os.Signal, 1) signal.Notify(interrupt, os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT) errCh := make(chan error, 1) // Set router gin.SetMode(gin.ReleaseMode) router := gin.New() if os.Getenv("YAO_SETUP_DEV") != "" { fmt.Println(color.WhiteString("\nSETUP DEV: %s\n", os.Getenv("YAO_SETUP_DEV"))) } router.Use(func(c *gin.Context) { length := len(c.Request.URL.Path) if length >= 5 && c.Request.URL.Path[0:5] == "/api/" { c.Next() return } if os.Getenv("YAO_SETUP_DEV") != "" { root, err := filepath.Abs(os.Getenv("YAO_SETUP_DEV")) if err != nil { printError("%s", err) } static := http.FileServer(http.Dir(root)) static.ServeHTTP(c.Writer, c.Request) return } // Setup Pages XGenSetupServer.ServeHTTP(c.Writer, c.Request) return }, gin.CustomRecovery(recovered)) router.POST("/api/__yao/app/check", runCheck) router.POST("/api/__yao/app/setup", runSetup) // Server setting addr := ":5099" // Listen l, err := net.Listen("tcp4", addr) if err != nil { addr = ":0" l, err = net.Listen("tcp4", addr) if err != nil { return err } } srv := &http.Server{ Addr: addr, Handler: router, } defer func() { // printInfo("[Setup] %s Close Serve", addr) err = srv.Close() if err != nil { printError("[Setup] Error (%v)", err) } }() // start serve go func() { // printInfo("[Setup] Starting: %s", addr) if err := srv.Serve(l); err != nil && err != http.ErrServerClosed { errCh <- err } }() welcome(l) select { case <-shutdown: printInfo("Setup Shutdown") return err case <-interrupt: printInfo("Setup Interrupt") Canceled <- true return err case err := <-errCh: printError("Setup Error: ", err) Canceled <- true return err } } // Complete stop the studio api server func Complete() { Done <- true } // Stop stop the studio api server func Stop() { shutdown <- true } // AdminURL get admin url func AdminURL(cfg config.Config) ([]string, error) { err := engine.Load(cfg) if err != nil { return nil, err } urls, err := URLs(cfg) adminRoot := "yao" if app.Setting.AdminRoot != "" { adminRoot = app.Setting.AdminRoot } adminRoot = strings.Trim(adminRoot, "/") for i := range urls { urls[i] = fmt.Sprintf("%s/%s/", urls[i], adminRoot) } return urls, nil } // URLs get admin url func URLs(cfg config.Config) ([]string, error) { err := engine.Load(cfg) if err != nil { return nil, err } ips, err := Ips() if err != nil { return nil, err } for i := range ips { ips[i] = fmt.Sprintf("http://%s:%d", ips[i], cfg.Port) } return ips, nil } func welcome(l net.Listener) { fmt.Println(color.WhiteString("---------------------------------")) fmt.Println(color.WhiteString("Yao Application Setup v%s", share.VERSION)) fmt.Println(color.WhiteString("---------------------------------")) ips, err := Ips() if err != nil { printError("Error: ", err.Error()) } addr := strings.Split(l.Addr().String(), ":") if len(addr) != 2 { printError("Error: can't get port") } port := addr[1] for _, ip := range ips { fmt.Println(color.WhiteString("\nOpen URL in the browser to continue:\n")) printInfo("http://%s:%s", ip, port) } fmt.Println() } func printError(message string, args ...interface{}) { fmt.Println(color.RedString(message, args...)) os.Exit(1) } func printInfo(message string, args ...interface{}) { fmt.Println(color.GreenString(message, args...)) } // Ips get the local ip list func Ips() ([]string, error) { addrs, err := net.InterfaceAddrs() if err != nil { return nil, err } iplist := []string{} for _, address := range addrs { // check the address type and if it is not a loopback the display it if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() { if ipnet.IP.To4() != nil { iplist = append(iplist, ipnet.IP.String()) } } } return iplist, nil }