diff --git a/api/server_endpoints.go b/api/server_endpoints.go index 6f6f21c..07afadb 100644 --- a/api/server_endpoints.go +++ b/api/server_endpoints.go @@ -33,11 +33,15 @@ type ProcessConfiguration struct { Startup struct { Done string `json:"done"` UserInteraction []string `json:"userInteraction"` + SplitCharacter string `json:"splitCharacter"` + StripAnsi bool `json:"stripAnsi"` } `json:"startup"` + Stop struct { Type string `json:"type"` Value string `json:"value"` } `json:"stop"` + ConfigurationFiles []parser.ConfigurationFile `json:"configs"` } @@ -202,4 +206,4 @@ func (r *PanelRequest) SendTransferSuccess(uuid string) (*RequestError, error) { } return nil, nil -} \ No newline at end of file +} diff --git a/server/listeners.go b/server/listeners.go index ec19243..da3b72d 100644 --- a/server/listeners.go +++ b/server/listeners.go @@ -3,6 +3,7 @@ package server import ( "github.com/apex/log" "github.com/pterodactyl/wings/api" + "regexp" "strings" ) @@ -21,28 +22,54 @@ func (s *Server) AddEventListeners() { }() } +var stripAnsiRegex = regexp.MustCompile("[\u001B\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[a-zA-Z\\d]*)*)?\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PRZcf-ntqry=><~]))") + // Custom listener for console output events that will check if the given line // of output matches one that should mark the server as started or not. func (s *Server) onConsoleOutput(data string) { - // If the specific line of output is one that would mark the server as started, - // set the server to that state. Only do this if the server is not currently stopped - // or stopping. - match := s.ProcessConfiguration().Startup.Done + // Get the server's process configuration. + processConfiguration := s.ProcessConfiguration() - if s.GetState() == ProcessStartingState && strings.Contains(data, match) { - s.Log().WithFields(log.Fields{ - "match": match, - "against": data, - }).Debug("detected server in running state based on console line output") + // Check if the server is currently starting. + if s.GetState() == ProcessStartingState { + // If the specific line of output is one that would mark the server as started, + // set the server to that state. Only do this if the server is not currently stopped + // or stopping. - _ = s.SetState(ProcessRunningState) + var matches []string + if processConfiguration.Startup.SplitCharacter != "" { + matches = strings.Split(processConfiguration.Startup.Done, processConfiguration.Startup.SplitCharacter) + } else { + matches = []string{processConfiguration.Startup.Done} + } + + // Check if we should strip ansi color codes. + if processConfiguration.Startup.StripAnsi { + // Strip ansi color codes from the data string. + data = stripAnsiRegex.ReplaceAllString(data, "") + } + + // Iterate over all the matches. + for _, match := range matches { + if !strings.Contains(data, match) { + continue + } + + s.Log().WithFields(log.Fields{ + "match": match, + "against": data, + }).Debug("detected server in running state based on console line output") + + _ = s.SetState(ProcessRunningState) + break + } } // If the command sent to the server is one that should stop the server we will need to // set the server to be in a stopping state, otherwise crash detection will kick in and // cause the server to unexpectedly restart on the user. if s.IsRunning() { - stop := s.ProcessConfiguration().Stop + stop := processConfiguration.Stop if stop.Type == api.ProcessStopCommand && data == stop.Value { _ = s.SetState(ProcessStoppingState)