Skip to content

Commit

Permalink
feat: added TUI shortcut to reload the running project
Browse files Browse the repository at this point in the history
  • Loading branch information
F1bonacc1 committed Sep 28, 2024
1 parent d409e61 commit ff0c746
Show file tree
Hide file tree
Showing 18 changed files with 2,118 additions and 81 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ setup:
ci: setup build testrace

swag: swag2op ## Generate docs from swagger attributes in the code
./bin/swag2op init --dir src --output src/docs -g api/pc_api.go --openapiOutputDir src/docs
./bin/swag2op init --dir src --output src/docs -g api/pc_api.go --openapiOutputDir src/docs --parseDependency --parseInternal

build:
CGO_ENABLED=0 go build -o bin/${NAME}${EXT} ${LD_FLAGS} ./src
Expand Down
74 changes: 57 additions & 17 deletions src/api/pc_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@ import (
// @version 1.0
// @description This is a sample server Process Compose server.

// @contact.name Eugene Berger
// @contact.url https://f1bonacc1.github.io/process-compose/
// @contact.name Process Compose Discord Channel
// @contact.url https://discord.gg/S4xgmRSHdC

// @license.name Apache 2.0
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html

// @externalDocs.url https://f1bonacc1.github.io/process-compose/

type PcApi struct {
project app.IProject
}
Expand All @@ -33,7 +35,8 @@ func NewPcApi(project app.IProject) *PcApi {
// @Summary Get process state
// @Produce json
// @Param name path string true "Process Name"
// @Success 200 {object} object "Process State"
// @Success 200 {object} types.ProcessState
// @Failure 400 {object} map[string]string
// @Router /process/{name} [get]
func (api *PcApi) GetProcess(c *gin.Context) {
name := c.Param("name")
Expand All @@ -53,7 +56,8 @@ func (api *PcApi) GetProcess(c *gin.Context) {
// @Summary Get process config
// @Produce json
// @Param name path string true "Process Name"
// @Success 200 {object} object "Process Config"
// @Success 200 {object} types.ProcessConfig
// @Failure 400 {object} map[string]string
// @Router /process/info/{name} [get]
func (api *PcApi) GetProcessInfo(c *gin.Context) {
name := c.Param("name")
Expand All @@ -72,7 +76,8 @@ func (api *PcApi) GetProcessInfo(c *gin.Context) {
// @Tags Process
// @Summary Get all processes
// @Produce json
// @Success 200 {object} object "Processes Status"
// @Success 200 {object} types.ProcessesState "Processes Status"
// @Failure 400 {object} map[string]string
// @Router /processes [get]
func (api *PcApi) GetProcesses(c *gin.Context) {
states, err := api.project.GetProcessesState()
Expand All @@ -92,7 +97,8 @@ func (api *PcApi) GetProcesses(c *gin.Context) {
// @Param name path string true "Process Name"
// @Param endOffset path int true "Offset from the end of the log"
// @Param limit path int true "Limit of lines to get (0 will get all the lines till the end)"
// @Success 200 {object} object "Process Logs"
// @Success 200 {object} map[string][]string "Process Logs"
// @Failure 400 {object} map[string]string
// @Router /process/logs/{name}/{endOffset}/{limit} [get]
func (api *PcApi) GetProcessLogs(c *gin.Context) {
name := c.Param("name")
Expand Down Expand Up @@ -123,7 +129,8 @@ func (api *PcApi) GetProcessLogs(c *gin.Context) {
// @Summary Stop a process
// @Produce json
// @Param name path string true "Process Name"
// @Success 200 {string} string "Stopped Process Name"
// @Success 200 {object} map[string]string "Stopped Process Name"
// @Failure 400 {object} map[string]string
// @Router /process/stop/{name} [patch]
func (api *PcApi) StopProcess(c *gin.Context) {
name := c.Param("name")
Expand All @@ -142,7 +149,9 @@ func (api *PcApi) StopProcess(c *gin.Context) {
// @Summary Stop processes
// @Produce json
// @Param []string body []string true "Processes Names"
// @Success 200 {object} string "Stopped Processes Names"
// @Success 200 {object} map[string]string "Stopped Processes Names"
// @Success 207 {object} map[string]string "Stopped Processes Names"
// @Failure 400 {object} map[string]string
// @Router /processes/stop [patch]
func (api *PcApi) StopProcesses(c *gin.Context) {
var names []string
Expand All @@ -169,7 +178,8 @@ func (api *PcApi) StopProcesses(c *gin.Context) {
// @Summary Start a process
// @Produce json
// @Param name path string true "Process Name"
// @Success 200 {string} string "Started Process Name"
// @Success 200 {object} map[string]string "Started Process Name"
// @Failure 400 {object} map[string]string
// @Router /process/start/{name} [post]
func (api *PcApi) StartProcess(c *gin.Context) {
name := c.Param("name")
Expand All @@ -188,7 +198,8 @@ func (api *PcApi) StartProcess(c *gin.Context) {
// @Summary Restart a process
// @Produce json
// @Param name path string true "Process Name"
// @Success 200 {string} string "Restarted Process Name"
// @Success 200 {object} map[string]string "Restarted Process Name"
// @Failure 400 {object} map[string]string
// @Router /process/restart/{name} [post]
func (api *PcApi) RestartProcess(c *gin.Context) {
name := c.Param("name")
Expand All @@ -208,7 +219,8 @@ func (api *PcApi) RestartProcess(c *gin.Context) {
// @Produce json
// @Param name path string true "Process Name"
// @Param scale path int true "New amount of process replicas"
// @Success 200 {string} string "Scaled Process Name"
// @Success 200 {object} map[string]string "Scaled Process Name"
// @Failure 400 {object} map[string]string
// @Router /process/scale/{name}/{scale} [patch]
func (api *PcApi) ScaleProcess(c *gin.Context) {
name := c.Param("name")
Expand Down Expand Up @@ -242,7 +254,8 @@ func (api *PcApi) IsAlive(c *gin.Context) {
// @Tags Hostname
// @Summary Get Hostname
// @Produce json
// @Success 200
// @Success 200 {object} map[string]string "Hostname"
// @Failure 400 {object} map[string]string
// @Router /hostname [get]
func (api *PcApi) GetHostName(c *gin.Context) {
name, err := api.project.GetHostName()
Expand All @@ -260,7 +273,8 @@ func (api *PcApi) GetHostName(c *gin.Context) {
// @Summary Get process ports
// @Produce json
// @Param name path string true "Process Name"
// @Success 200 {object} object "Process Ports"
// @Success 200 {object} types.ProcessPorts "Process Ports"
// @Failure 400 {object} map[string]string
// @Router /process/ports/{name} [get]
func (api *PcApi) GetProcessPorts(c *gin.Context) {
name := c.Param("name")
Expand All @@ -279,7 +293,7 @@ func (api *PcApi) GetProcessPorts(c *gin.Context) {
// @Tags Project
// @Summary Stops all the processes and the server
// @Produce json
// @Success 200
// @Success 200 {object} map[string]string "Stopped Server"
// @Router /project/stop [post]
func (api *PcApi) ShutDownProject(c *gin.Context) {
api.project.ShutDownProject()
Expand All @@ -291,7 +305,9 @@ func (api *PcApi) ShutDownProject(c *gin.Context) {
// @Tags Project
// @Summary Updates running processes
// @Produce json
// @Success 200
// @Success 200 {object} map[string]string "Update Project Status"
// @Success 207 {object} map[string]string "Update Project Status"
// @Failure 400 {object} map[string]string
// @Router /project [post]
func (api *PcApi) UpdateProject(c *gin.Context) {
var project types.Project
Expand All @@ -316,7 +332,8 @@ func (api *PcApi) UpdateProject(c *gin.Context) {
// @Tags Process
// @Summary Updates process configuration
// @Produce json
// @Success 200
// @Success 200 {object} types.ProcessConfig "Updated Process Config"
// @Failure 400 {object} map[string]string
// @Router /process [post]
func (api *PcApi) UpdateProcess(c *gin.Context) {
var proc types.ProcessConfig
Expand All @@ -337,7 +354,8 @@ func (api *PcApi) UpdateProcess(c *gin.Context) {
// @Tags Project
// @Summary Get project state
// @Produce json
// @Success 200 {object} object "Project State"
// @Success 200 {object} types.ProjectState "Project State"
// @Failure 500 {object} map[string]string
// @Router /project/state [get]
func (api *PcApi) GetProjectState(c *gin.Context) {
withMemory := c.DefaultQuery("withMemory", "false")
Expand All @@ -351,3 +369,25 @@ func (api *PcApi) GetProjectState(c *gin.Context) {

c.JSON(http.StatusOK, state)
}

// @Schemes
// @Description Reload project state from config
// @Tags Project
// @Summary Reload project
// @Produce json
// @Success 200 {object} map[string]string "Update Project Status"
// @Success 207 {object} map[string]string "Update Project Status"
// @Failure 400 {object} map[string]string
// @Router /project/configuration [post]
func (api *PcApi) ReloadProject(c *gin.Context) {
status, err := api.project.ReloadProject()
if err != nil {
if len(status) == 0 {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
} else {
c.JSON(http.StatusMultiStatus, status)
}
return
}
c.JSON(http.StatusOK, status)
}
1 change: 1 addition & 0 deletions src/api/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ func InitRoutes(useLogger bool, handler *PcApi) *gin.Engine {
r.POST("/process/restart/:name", handler.RestartProcess)
r.POST("/project/stop", handler.ShutDownProject)
r.POST("/project", handler.UpdateProject)
r.POST("/project/configuration", handler.ReloadProject)
r.GET("/project/state", handler.GetProjectState)
r.PATCH("/process/scale/:name/:scale", handler.ScaleProcess)

Expand Down
1 change: 1 addition & 0 deletions src/app/project_interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,5 @@ type IProject interface {
SetProcessPassword(name string, password string) error
UpdateProject(project *types.Project) (map[string]string, error)
UpdateProcess(updated *types.ProcessConfig) error
ReloadProject() (map[string]string, error)
}
5 changes: 5 additions & 0 deletions src/app/project_opts.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ type ProjectOpts struct {
mainProcessArgs []string
isTuiOn bool
isOrderedShutDown bool
disableDotenv bool
}

func (p *ProjectOpts) WithProject(project *types.Project) *ProjectOpts {
Expand Down Expand Up @@ -45,3 +46,7 @@ func (p *ProjectOpts) WithOrderedShutDown(isOrderedShutDown bool) *ProjectOpts {
p.isOrderedShutDown = isOrderedShutDown
return p
}

func (o *ProjectOpts) WithDotEnvDisabled(disabled bool) {
o.disableDotenv = disabled
}
22 changes: 22 additions & 0 deletions src/app/project_runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"github.com/f1bonacc1/process-compose/src/config"
"github.com/f1bonacc1/process-compose/src/health"
"github.com/f1bonacc1/process-compose/src/loader"
"github.com/f1bonacc1/process-compose/src/pclog"
"github.com/f1bonacc1/process-compose/src/types"
"os"
Expand Down Expand Up @@ -45,6 +46,7 @@ type ProjectRunner struct {
isOrderedShutDown bool
ctxApp context.Context
cancelAppFn context.CancelFunc
disableDotenv bool
}

func (p *ProjectRunner) GetLexicographicProcessNames() ([]string, error) {
Expand Down Expand Up @@ -833,6 +835,7 @@ func NewProjectRunner(opts *ProjectOpts) (*ProjectRunner, error) {
mainProcessArgs: opts.mainProcessArgs,
isTuiOn: opts.isTuiOn,
isOrderedShutDown: opts.isOrderedShutDown,
disableDotenv: opts.disableDotenv,
projectState: &types.ProjectState{
FileNames: opts.project.FileNames,
StartTime: time.Now(),
Expand Down Expand Up @@ -912,6 +915,25 @@ func (p *ProjectRunner) UpdateProject(project *types.Project) (map[string]string
return status, errors.Join(errs...)
}

func (p *ProjectRunner) ReloadProject() (map[string]string, error) {
opts := &loader.LoaderOptions{
FileNames: p.project.FileNames,
EnvFileNames: p.project.EnvFileNames,
}
opts.WithTuiDisabled(p.disableDotenv)
opts.WithTuiDisabled(p.isTuiOn)
project, err := loader.Load(opts)
if err != nil {
log.Err(err).Msg("Failed to load project")
return nil, err
}
status, err := p.UpdateProject(project)
if err != nil {
log.Err(err).Msg("Failed to update project")
return nil, err
}
return status, nil
}
func (p *ProjectRunner) UpdateProcess(updated *types.ProcessConfig) error {
isScaleChanged := false
validateProbes(updated.LivenessProbe)
Expand Down
4 changes: 4 additions & 0 deletions src/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,3 +171,7 @@ func (p *PcClient) UpdateProject(project *types.Project) (map[string]string, err
func (p *PcClient) UpdateProcess(updated *types.ProcessConfig) error {
return p.updateProcess(updated)
}

func (p *PcClient) ReloadProject() (map[string]string, error) {
return p.reloadProject()
}
26 changes: 26 additions & 0 deletions src/client/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,29 @@ func (p *PcClient) updateProject(project *types.Project) (map[string]string, err
}
return nil, fmt.Errorf(respErr.Error)
}

func (p *PcClient) reloadProject() (map[string]string, error) {
url := fmt.Sprintf("http://%s/project/configuration", p.address)
resp, err := p.client.Post(url, "application/json", nil)
if err != nil {
log.Err(err).Msg("failed to update project")
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode == http.StatusOK || resp.StatusCode == http.StatusMultiStatus {
status := map[string]string{}
if err = json.NewDecoder(resp.Body).Decode(&status); err != nil {
log.Err(err).Msg("failed to decode updated processes")
return status, err
}
log.Info().Msgf("status: %v", status)

return status, nil
}
var respErr pcError
if err = json.NewDecoder(resp.Body).Decode(&respErr); err != nil {
log.Err(err).Msg("failed to decode err update project")
return nil, err
}
return nil, fmt.Errorf(respErr.Error)
}
8 changes: 2 additions & 6 deletions src/cmd/project_runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,8 @@ import (
)

func getProjectRunner(process []string, noDeps bool, mainProcess string, mainProcessArgs []string) *app.ProjectRunner {
if *pcFlags.DisableDotEnv {
opts.DisableDotenv()
}
if !*pcFlags.IsTuiEnabled {
opts.WithTuiDisabled()
}
opts.DisableDotenv(*pcFlags.DisableDotEnv)
opts.WithTuiDisabled(!*pcFlags.IsTuiEnabled)

project, err := loader.Load(opts)
if err != nil {
Expand Down
Loading

0 comments on commit ff0c746

Please sign in to comment.