package services import ( "backend/models" "encoding/json" "errors" "fmt" "io" "net/http" "os" "path/filepath" "gitea.tecamino.com/paadi/statusServer" "github.com/gin-gonic/gin" ) type ServicesHandler struct { cfgDir string cfgFile string config models.Configuration statusWs *statusServer.StatusWebsocket } func NewServicesHandler(cfgDir, cfgFile string) *ServicesHandler { return &ServicesHandler{cfgDir: cfgDir, cfgFile: cfgFile} } func (s *ServicesHandler) LinkStatusServer(statusServer *statusServer.StatusWebsocket) { s.statusWs = statusServer } func (s *ServicesHandler) GetAllAvaiableServices(c *gin.Context) { var services []models.Service defaultCfg, err := s.readDefaultConfig() if err != nil { c.JSON(http.StatusBadRequest, models.NewJsonErrorResponse(err)) return } configFile := filepath.Join(s.cfgDir, defaultCfg.CfgFileName) if _, err := os.Stat(configFile); err != nil { c.JSON(http.StatusOK, gin.H{"services": defaultCfg.Services}) return } content, err := os.ReadFile(configFile) if err != nil { c.JSON(http.StatusBadRequest, models.NewJsonErrorResponse(err)) return } var cfg models.Configuration err = json.Unmarshal(content, &cfg) if err != nil { c.JSON(http.StatusBadRequest, models.NewJsonErrorResponse(err)) return } // check wether service was already initiated then skip next: for _, new := range defaultCfg.Services { for _, old := range cfg.Services { if new.Name == old.Name { continue next } } services = append(services, new) } c.JSON(http.StatusOK, gin.H{"services": services}) } func (s *ServicesHandler) LoadAllServices(c *gin.Context) { defaultCfg, err := s.readDefaultConfig() if err != nil { c.JSON(http.StatusBadRequest, models.NewJsonErrorResponse(err)) return } configFile := filepath.Join(s.cfgDir, defaultCfg.CfgFileName) if _, err := os.Stat(configFile); err != nil { c.JSON(http.StatusOK, gin.H{"message": "no services"}) return } content, err := os.ReadFile(configFile) if err != nil { c.JSON(http.StatusBadRequest, models.NewJsonErrorResponse(err)) return } err = json.Unmarshal(content, &s.config) if err != nil { c.JSON(http.StatusBadRequest, models.NewJsonErrorResponse(err)) return } if len(s.config.Services) == 0 { c.JSON(http.StatusOK, gin.H{"message": "no services"}) return } c.JSON(http.StatusOK, gin.H{"services": s.config.Services}) } func (s *ServicesHandler) AddNewService(c *gin.Context) { body, err := io.ReadAll(c.Request.Body) if err != nil { c.JSON(http.StatusBadRequest, models.NewJsonErrorResponse(err)) return } var newService struct { Name string `json:"name"` } err = json.Unmarshal(body, &newService) if err != nil { c.JSON(http.StatusBadRequest, models.NewJsonErrorResponse(err)) return } defaultCfg, err := s.readDefaultConfig() if err != nil { c.JSON(http.StatusBadRequest, models.NewJsonErrorResponse(err)) return } var config models.Configuration if _, err := os.Stat(filepath.Join(s.cfgDir, defaultCfg.CfgFileName)); err == nil { content, err := os.ReadFile(filepath.Join(s.cfgDir, defaultCfg.CfgFileName)) if err != nil { c.JSON(http.StatusBadRequest, models.NewJsonErrorResponse(err)) return } err = json.Unmarshal(content, &config) if err != nil { c.JSON(http.StatusBadRequest, models.NewJsonErrorResponse(err)) return } } for _, service := range defaultCfg.Services { if service.Name == newService.Name { config.Services = append(config.Services, service) f, err := os.OpenFile(filepath.Join(s.cfgDir, defaultCfg.CfgFileName), os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0774) if err != nil { c.JSON(http.StatusBadRequest, models.NewJsonErrorResponse(err)) return } defer f.Close() output, err := json.Marshal(config) if err != nil { c.JSON(http.StatusBadRequest, models.NewJsonErrorResponse(err)) return } _, err = f.Write(output) if err != nil { c.JSON(http.StatusBadRequest, models.NewJsonErrorResponse(err)) return } c.JSON(http.StatusOK, gin.H{"message": "service '" + newService.Name + "' added"}) return } } c.JSON(http.StatusBadRequest, models.NewJsonErrorResponse(errors.New("no service '"+newService.Name+"' found"))) } func (s *ServicesHandler) StartService(c *gin.Context) { service := c.Param("service") s.statusWs.Publish("status/"+service, gin.H{ "state": "Starting", }) for i := range s.config.Services { if s.config.Services[i].Name == service { if err := s.config.Services[i].Start(func(e string) { s.statusWs.Publish("status/"+service, gin.H{"state": "Error", "message": e}) }); err != nil { c.JSON(http.StatusBadRequest, models.NewJsonErrorResponse(err)) s.statusWs.Publish("status/"+service, gin.H{ "state": "Error", "message": err.Error(), }) return } c.JSON(http.StatusOK, gin.H{ "message": fmt.Sprintf("service '%s' started", service), }) s.statusWs.Publish("status/"+service, gin.H{ "state": "Started", }) return } } c.JSON(http.StatusBadRequest, models.NewJsonErrorMessageResponse(fmt.Sprintf("no service '%s' found", service))) s.statusWs.Publish("status/"+service, gin.H{ "state": "Error", "message": fmt.Sprintf("no service '%s' found", service), }) } func (s *ServicesHandler) StopService(c *gin.Context) { service := c.Param("service") s.statusWs.Publish("status/"+service, gin.H{ "state": "Stopping", }) for i := range s.config.Services { if s.config.Services[i].Name == service { if err := s.config.Services[i].Stop(); err != nil { c.JSON(http.StatusBadGateway, gin.H{ "error": true, "message": fmt.Sprintf("service '%s' error; %v", service, err), }) s.statusWs.Publish("status/"+service, gin.H{ "state": "Error", "message": fmt.Sprintf("service '%s' error; %v", service, err), }) return } c.JSON(http.StatusOK, gin.H{ "message": fmt.Sprintf("service '%s' stopped", service), }) s.statusWs.Publish("status/"+service, gin.H{ "state": "Stopped", }) return } } c.JSON(http.StatusBadRequest, gin.H{ "error": true, "message": fmt.Sprintf("no service '%s' found", service), }) s.statusWs.Publish("status/"+service, gin.H{ "state": "Stopped", "message": fmt.Sprintf("no service '%s' found", service), }) } func (s *ServicesHandler) readDefaultConfig() (data models.Configuration, err error) { content, err := os.ReadFile(filepath.Join(s.cfgDir, s.cfgFile)) if err != nil { return } err = json.Unmarshal(content, &data) return }