package main import ( "backend/models" "backend/server" "backend/user" "backend/utils" "flag" "fmt" "log" "net/http" "os" "path/filepath" "strings" "time" dbApi "gitea.tecamino.com/paadi/memberDB/api" "gitea.tecamino.com/paadi/tecamino-logger/logging" "github.com/gin-contrib/cors" "github.com/gin-gonic/gin" ) func main() { var allowOrigins models.StringSlice flag.Var(&allowOrigins, "allowOrigin", "Allowed origin (can repeat this flag)") spa := flag.String("spa", "./dist/spa", "quasar spa files") workingDir := flag.String("workingDirectory", ".", "quasar spa files") ip := flag.String("ip", "0.0.0.0", "server listening ip") port := flag.Uint("port", 9500, "server listening port") debug := flag.Bool("debug", false, "log debug") flag.Parse() //change working directory only if value is given if *workingDir != "." && *workingDir != "" { fmt.Println(1, *workingDir) os.Chdir(*workingDir) } wd, err := os.Getwd() if err != nil { log.Fatalf("Could not get working directory: %v", err) } folderName := filepath.Base(wd) logFileName := folderName + ".log" logger, err := logging.NewLogger(logFileName, &logging.Config{ MaxSize: 1, MaxBackup: 3, MaxAge: 28, Debug: *debug, TerminalOut: true, }) if err != nil { logger.Error("main new logger", err.Error()) panic(err) } //new login manager userManager, err := user.NewUserManager(".") if err != nil { logger.Error("main login manager", err.Error()) panic(err) } // new server s := server.NewServer() // initiate Database handler dbHandler := dbApi.NewAPIHandler() //get local ip allowOrigins = append(allowOrigins, "http://localhost:9000", "http://localhost:9500", "http://127.0.0.1:9500") localIP, err := utils.GetLocalIP() if err != nil { logger.Error("main", fmt.Sprintf("get local ip : %s", err.Error())) } else { allowOrigins = append(allowOrigins, fmt.Sprintf("http://%s:9000", localIP), fmt.Sprintf("http://%s:9500", localIP)) } s.Routes.Use(cors.New(cors.Config{ AllowOrigins: allowOrigins, AllowMethods: []string{"POST", "GET", "DELETE", "OPTIONS"}, AllowHeaders: []string{"Origin", "Content-Type"}, ExposeHeaders: []string{"Content-Length"}, AllowCredentials: true, MaxAge: 12 * time.Hour, })) api := s.Routes.Group("/api") //set routes //public api.GET("/logout", userManager.Logout) api.GET("/login/me", userManager.Me) api.POST("/login", userManager.Login) //private auth := api.Group("/secure", user.AuthMiddleware()) auth.GET("/members", dbHandler.GetMemberById) auth.POST("database/open", dbHandler.OpenDatabase) auth.POST("/members/add", dbHandler.AddNewMember) auth.POST("/members/edit", dbHandler.EditMember) auth.POST("/members/delete", dbHandler.DeleteMember) auth.POST("/members/import/csv", dbHandler.ImportCSV) auth.POST("/settings/update", userManager.UpdateSettings) auth.POST("/user/add", userManager.AddUser) auth.POST("/login/refresh", userManager.Refresh) auth.DELETE("/user", userManager.RemoveUser) // Serve static files s.Routes.StaticFS("/assets", gin.Dir(filepath.Join(*spa, "assets"), true)) s.Routes.NoRoute(func(c *gin.Context) { // Disallow fallback for /api paths if strings.HasPrefix(c.Request.URL.Path, "/api") { c.JSON(http.StatusNotFound, models.NewJsonErrorMessageResponse("API endpoint not found")) return } // Try to serve file from SPA directory filePath := filepath.Join(*spa, c.Request.URL.Path) if _, err := os.Stat(filePath); err == nil { c.File(filePath) return } // Fallback to index.html for SPA routing c.File(filepath.Join(*spa, "index.html")) }) go func() { time.Sleep(500 * time.Millisecond) if err := utils.OpenBrowser(fmt.Sprintf("http://localhost:%d", *port), logger); err != nil { logger.Error("main", fmt.Sprintf("starting browser error : %s", err.Error())) } }() // start http server logger.Info("main", fmt.Sprintf("http listen on ip: %s port: %d", *ip, *port)) if err := s.ServeHttp(*ip, *port); err != nil { logger.Error("main", "error http server "+err.Error()) } }