Merge pull request #47 from pterodactyl/issue/2219-2220
TLS changes, Fix Marked as Stopping, Improvements to Egg Startup Configuration
This commit is contained in:
commit
1a4c6726c5
|
@ -31,13 +31,16 @@ type ServerConfigurationResponse struct {
|
||||||
// and what changes to make to the configuration file for a server.
|
// and what changes to make to the configuration file for a server.
|
||||||
type ProcessConfiguration struct {
|
type ProcessConfiguration struct {
|
||||||
Startup struct {
|
Startup struct {
|
||||||
Done string `json:"done"`
|
Done []string `json:"done"`
|
||||||
UserInteraction []string `json:"userInteraction"`
|
UserInteraction []string `json:"user_interaction"`
|
||||||
|
StripAnsi bool `json:"strip_ansi"`
|
||||||
} `json:"startup"`
|
} `json:"startup"`
|
||||||
|
|
||||||
Stop struct {
|
Stop struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Value string `json:"value"`
|
Value string `json:"value"`
|
||||||
} `json:"stop"`
|
} `json:"stop"`
|
||||||
|
|
||||||
ConfigurationFiles []parser.ConfigurationFile `json:"configs"`
|
ConfigurationFiles []parser.ConfigurationFile `json:"configs"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
96
cmd/root.go
96
cmd/root.go
|
@ -6,6 +6,7 @@ import (
|
||||||
"github.com/NYTimes/logrotate"
|
"github.com/NYTimes/logrotate"
|
||||||
"github.com/apex/log/handlers/multi"
|
"github.com/apex/log/handlers/multi"
|
||||||
"github.com/gammazero/workerpool"
|
"github.com/gammazero/workerpool"
|
||||||
|
"golang.org/x/crypto/acme"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
@ -132,14 +133,15 @@ func rootCmdRun(*cobra.Command, []string) {
|
||||||
config.SetDebugViaFlag(debug)
|
config.SetDebugViaFlag(debug)
|
||||||
|
|
||||||
if err := c.System.ConfigureDirectories(); err != nil {
|
if err := c.System.ConfigureDirectories(); err != nil {
|
||||||
log.Fatal("failed to configure system directories for pterodactyl")
|
log.WithError(err).Fatal("failed to configure system directories for pterodactyl")
|
||||||
panic(err)
|
os.Exit(1)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log.WithField("username", c.System.Username).Info("checking for pterodactyl system user")
|
log.WithField("username", c.System.Username).Info("checking for pterodactyl system user")
|
||||||
if su, err := c.EnsurePterodactylUser(); err != nil {
|
if su, err := c.EnsurePterodactylUser(); err != nil {
|
||||||
log.Error("failed to create pterodactyl system user")
|
log.WithError(err).Error("failed to create pterodactyl system user")
|
||||||
panic(err)
|
os.Exit(1)
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
log.WithFields(log.Fields{
|
log.WithFields(log.Fields{
|
||||||
|
@ -217,15 +219,19 @@ func rootCmdRun(*cobra.Command, []string) {
|
||||||
|
|
||||||
// Addresses potentially invalid data in the stored file that can cause Wings to lose
|
// Addresses potentially invalid data in the stored file that can cause Wings to lose
|
||||||
// track of what the actual server state is.
|
// track of what the actual server state is.
|
||||||
s.SetState(server.ProcessOfflineState)
|
_ = s.SetState(server.ProcessOfflineState)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait until all of the servers are ready to go before we fire up the HTTP server.
|
// Wait until all of the servers are ready to go before we fire up the SFTP and HTTP servers.
|
||||||
pool.StopWait()
|
pool.StopWait()
|
||||||
|
|
||||||
// Initalize SFTP.
|
// Initialize the SFTP server.
|
||||||
sftp.Initialize(c)
|
if err := sftp.Initialize(c); err != nil {
|
||||||
|
log.WithError(err).Error("failed to initialize the sftp server")
|
||||||
|
os.Exit(1)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Ensure the archive directory exists.
|
// Ensure the archive directory exists.
|
||||||
if err := os.MkdirAll(c.System.ArchiveDirectory, 0755); err != nil {
|
if err := os.MkdirAll(c.System.ArchiveDirectory, 0755); err != nil {
|
||||||
|
@ -244,9 +250,46 @@ func rootCmdRun(*cobra.Command, []string) {
|
||||||
"host_port": c.Api.Port,
|
"host_port": c.Api.Port,
|
||||||
}).Info("configuring internal webserver")
|
}).Info("configuring internal webserver")
|
||||||
|
|
||||||
|
// Configure the router.
|
||||||
r := router.Configure()
|
r := router.Configure()
|
||||||
addr := fmt.Sprintf("%s:%d", c.Api.Host, c.Api.Port)
|
|
||||||
|
|
||||||
|
s := &http.Server{
|
||||||
|
Addr: fmt.Sprintf("%s:%d", c.Api.Host, c.Api.Port),
|
||||||
|
Handler: r,
|
||||||
|
|
||||||
|
TLSConfig: &tls.Config{
|
||||||
|
NextProtos: []string{
|
||||||
|
"h2", // enable HTTP/2
|
||||||
|
"http/1.1",
|
||||||
|
},
|
||||||
|
|
||||||
|
// https://blog.cloudflare.com/exposing-go-on-the-internet
|
||||||
|
CipherSuites: []uint16{
|
||||||
|
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||||
|
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
|
||||||
|
|
||||||
|
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||||
|
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
|
||||||
|
|
||||||
|
tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
|
||||||
|
|
||||||
|
tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
|
||||||
|
},
|
||||||
|
|
||||||
|
PreferServerCipherSuites: true,
|
||||||
|
|
||||||
|
MinVersion: tls.VersionTLS12,
|
||||||
|
MaxVersion: tls.VersionTLS13,
|
||||||
|
|
||||||
|
CurvePreferences: []tls.CurveID{
|
||||||
|
tls.X25519,
|
||||||
|
tls.CurveP256,
|
||||||
|
},
|
||||||
|
// END https://blog.cloudflare.com/exposing-go-on-the-internet
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the server should run with TLS but using autocert.
|
||||||
if useAutomaticTls && len(tlsHostname) > 0 {
|
if useAutomaticTls && len(tlsHostname) > 0 {
|
||||||
m := autocert.Manager{
|
m := autocert.Manager{
|
||||||
Prompt: autocert.AcceptTOS,
|
Prompt: autocert.AcceptTOS,
|
||||||
|
@ -255,30 +298,45 @@ func rootCmdRun(*cobra.Command, []string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
log.WithField("hostname", tlsHostname).
|
log.WithField("hostname", tlsHostname).
|
||||||
Info("webserver is now listening with auto-TLS enabled; certifcates will be automatically generated by Let's Encrypt")
|
Info("webserver is now listening with auto-TLS enabled; certificates will be automatically generated by Let's Encrypt")
|
||||||
|
|
||||||
// We don't use the autotls runner here since we need to specify a port other than 443
|
// Hook autocert into the main http server.
|
||||||
// to be using for SSL connections for Wings.
|
s.TLSConfig.GetCertificate = m.GetCertificate
|
||||||
s := &http.Server{Addr: addr, TLSConfig: m.TLSConfig(), Handler: r}
|
s.TLSConfig.NextProtos = append(s.TLSConfig.NextProtos, acme.ALPNProto) // enable tls-alpn ACME challenges
|
||||||
|
|
||||||
go http.ListenAndServe(":http", m.HTTPHandler(nil))
|
// Start the autocert server.
|
||||||
|
go func() {
|
||||||
|
if err := http.ListenAndServe(":http", m.HTTPHandler(nil)); err != nil {
|
||||||
|
log.WithError(err).Error("failed to serve autocert http server")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Start the main http server with TLS using autocert.
|
||||||
if err := s.ListenAndServeTLS("", ""); err != nil {
|
if err := s.ListenAndServeTLS("", ""); err != nil {
|
||||||
log.WithFields(log.Fields{"auto_tls": true, "tls_hostname": tlsHostname, "error": err}).
|
log.WithFields(log.Fields{"auto_tls": true, "tls_hostname": tlsHostname, "error": err}).
|
||||||
Fatal("failed to configure HTTP server using auto-tls")
|
Fatal("failed to configure HTTP server using auto-tls")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
} else if c.Api.Ssl.Enabled {
|
|
||||||
if err := r.RunTLS(addr, c.Api.Ssl.CertificateFile, c.Api.Ssl.KeyFile); err != nil {
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if main http server should run with TLS.
|
||||||
|
if c.Api.Ssl.Enabled {
|
||||||
|
if err := s.ListenAndServeTLS(c.Api.Ssl.CertificateFile, c.Api.Ssl.KeyFile); err != nil {
|
||||||
log.WithFields(log.Fields{"auto_tls": false, "error": err}).Fatal("failed to configure HTTPS server")
|
log.WithFields(log.Fields{"auto_tls": false, "error": err}).Fatal("failed to configure HTTPS server")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
} else {
|
return
|
||||||
if err := r.Run(addr); err != nil {
|
}
|
||||||
|
|
||||||
|
// Run the main http server without TLS.
|
||||||
|
s.TLSConfig = nil
|
||||||
|
if err := s.ListenAndServe(); err != nil {
|
||||||
log.WithField("error", err).Fatal("failed to configure HTTP server")
|
log.WithField("error", err).Fatal("failed to configure HTTP server")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Execute calls cobra to handle cli commands
|
// Execute calls cobra to handle cli commands
|
||||||
func Execute() error {
|
func Execute() error {
|
||||||
|
|
|
@ -201,8 +201,8 @@ func (d *DockerEnvironment) Start() error {
|
||||||
// If we don't set it to stopping first, you'll trigger crash detection which
|
// If we don't set it to stopping first, you'll trigger crash detection which
|
||||||
// we don't want to do at this point since it'll just immediately try to do the
|
// we don't want to do at this point since it'll just immediately try to do the
|
||||||
// exact same action that lead to it crashing in the first place...
|
// exact same action that lead to it crashing in the first place...
|
||||||
d.Server.SetState(ProcessStoppingState)
|
_ = d.Server.SetState(ProcessStoppingState)
|
||||||
d.Server.SetState(ProcessOfflineState)
|
_ = d.Server.SetState(ProcessOfflineState)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -228,7 +228,7 @@ func (d *DockerEnvironment) Start() error {
|
||||||
} else {
|
} else {
|
||||||
// If the server is running update our internal state and continue on with the attach.
|
// If the server is running update our internal state and continue on with the attach.
|
||||||
if c.State.Running {
|
if c.State.Running {
|
||||||
d.Server.SetState(ProcessRunningState)
|
_ = d.Server.SetState(ProcessRunningState)
|
||||||
|
|
||||||
return d.Attach()
|
return d.Attach()
|
||||||
}
|
}
|
||||||
|
@ -243,7 +243,8 @@ func (d *DockerEnvironment) Start() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
d.Server.SetState(ProcessStartingState)
|
_ = d.Server.SetState(ProcessStartingState)
|
||||||
|
|
||||||
// Set this to true for now, we will set it to false once we reach the
|
// Set this to true for now, we will set it to false once we reach the
|
||||||
// end of this chain.
|
// end of this chain.
|
||||||
sawError = true
|
sawError = true
|
||||||
|
@ -289,7 +290,8 @@ func (d *DockerEnvironment) Stop() error {
|
||||||
return d.Terminate(os.Kill)
|
return d.Terminate(os.Kill)
|
||||||
}
|
}
|
||||||
|
|
||||||
d.Server.SetState(ProcessStoppingState)
|
_ = d.Server.SetState(ProcessStoppingState)
|
||||||
|
|
||||||
// Only attempt to send the stop command to the instance if we are actually attached to
|
// Only attempt to send the stop command to the instance if we are actually attached to
|
||||||
// the instance. If we are not for some reason, just send the container stop event.
|
// the instance. If we are not for some reason, just send the container stop event.
|
||||||
if d.IsAttached() && stop.Type == api.ProcessStopCommand {
|
if d.IsAttached() && stop.Type == api.ProcessStopCommand {
|
||||||
|
@ -304,7 +306,7 @@ func (d *DockerEnvironment) Stop() error {
|
||||||
// an error.
|
// an error.
|
||||||
if client.IsErrNotFound(err) {
|
if client.IsErrNotFound(err) {
|
||||||
d.SetStream(nil)
|
d.SetStream(nil)
|
||||||
d.Server.SetState(ProcessOfflineState)
|
_ = d.Server.SetState(ProcessOfflineState)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -333,8 +335,10 @@ func (d *DockerEnvironment) Restart() error {
|
||||||
// will be terminated forcefully depending on the value of the second argument.
|
// will be terminated forcefully depending on the value of the second argument.
|
||||||
func (d *DockerEnvironment) WaitForStop(seconds int, terminate bool) error {
|
func (d *DockerEnvironment) WaitForStop(seconds int, terminate bool) error {
|
||||||
if d.Server.GetState() == ProcessOfflineState {
|
if d.Server.GetState() == ProcessOfflineState {
|
||||||
|
log.WithField("server", d.Server.Id()).Debug("server is already offline, not waiting for stop.")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
log.WithField("server", d.Server.Id()).Debug("waiting for server to stop")
|
||||||
|
|
||||||
if err := d.Stop(); err != nil {
|
if err := d.Stop(); err != nil {
|
||||||
return errors.WithStack(err)
|
return errors.WithStack(err)
|
||||||
|
@ -377,7 +381,9 @@ func (d *DockerEnvironment) Terminate(signal os.Signal) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
d.Server.SetState(ProcessStoppingState)
|
// We set it to stopping than offline to prevent crash detection from being triggered.
|
||||||
|
_ = d.Server.SetState(ProcessStoppingState)
|
||||||
|
_ = d.Server.SetState(ProcessOfflineState)
|
||||||
|
|
||||||
return d.Client.ContainerKill(
|
return d.Client.ContainerKill(
|
||||||
context.Background(), d.Server.Id(), strings.TrimSuffix(strings.TrimPrefix(signal.String(), "signal "), "ed"),
|
context.Background(), d.Server.Id(), strings.TrimSuffix(strings.TrimPrefix(signal.String(), "signal "), "ed"),
|
||||||
|
@ -387,8 +393,9 @@ func (d *DockerEnvironment) Terminate(signal os.Signal) error {
|
||||||
// Remove the Docker container from the machine. If the container is currently running
|
// Remove the Docker container from the machine. If the container is currently running
|
||||||
// it will be forcibly stopped by Docker.
|
// it will be forcibly stopped by Docker.
|
||||||
func (d *DockerEnvironment) Destroy() error {
|
func (d *DockerEnvironment) Destroy() error {
|
||||||
// Avoid crash detection firing off.
|
// We set it to stopping than offline to prevent crash detection from being triggered.
|
||||||
d.Server.SetState(ProcessStoppingState)
|
_ = d.Server.SetState(ProcessStoppingState)
|
||||||
|
_ = d.Server.SetState(ProcessOfflineState)
|
||||||
|
|
||||||
err := d.Client.ContainerRemove(context.Background(), d.Server.Id(), types.ContainerRemoveOptions{
|
err := d.Client.ContainerRemove(context.Background(), d.Server.Id(), types.ContainerRemoveOptions{
|
||||||
RemoveVolumes: true,
|
RemoveVolumes: true,
|
||||||
|
@ -471,11 +478,11 @@ func (d *DockerEnvironment) Attach() error {
|
||||||
go func() {
|
go func() {
|
||||||
defer d.stream.Close()
|
defer d.stream.Close()
|
||||||
defer func() {
|
defer func() {
|
||||||
d.Server.SetState(ProcessOfflineState)
|
_ = d.Server.SetState(ProcessOfflineState)
|
||||||
d.SetStream(nil)
|
d.SetStream(nil)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
io.Copy(console, d.stream.Reader)
|
_, _ = io.Copy(console, d.stream.Reader)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -542,14 +549,14 @@ func (d *DockerEnvironment) EnableResourcePolling() error {
|
||||||
d.Server.Log().WithField("error", err).Warn("encountered error processing server stats, stopping collection")
|
d.Server.Log().WithField("error", err).Warn("encountered error processing server stats, stopping collection")
|
||||||
}
|
}
|
||||||
|
|
||||||
d.DisableResourcePolling()
|
_ = d.DisableResourcePolling()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disable collection if the server is in an offline state and this process is
|
// Disable collection if the server is in an offline state and this process is
|
||||||
// still running.
|
// still running.
|
||||||
if s.GetState() == ProcessOfflineState {
|
if s.GetState() == ProcessOfflineState {
|
||||||
d.DisableResourcePolling()
|
_ = d.DisableResourcePolling()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -613,7 +620,7 @@ func (d *DockerEnvironment) ensureImageExists() error {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
log.WithField("registry", registry).Debug("using authentication for repository")
|
log.WithField("registry", registry).Debug("using authentication for registry")
|
||||||
registryAuth = &c
|
registryAuth = &c
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,12 @@ func (s *Server) Install(sync bool) error {
|
||||||
l.Warn("failed to notify panel of server install state")
|
l.Warn("failed to notify panel of server install state")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Some how these publish events are sent to clients in reverse order,
|
||||||
|
// this is probably due to channels having the most recently sent item first.
|
||||||
|
|
||||||
|
// Ensure that the server is marked as offline.
|
||||||
|
s.Events().Publish(StatusEvent, ProcessOfflineState)
|
||||||
|
|
||||||
// Push an event to the websocket so we can auto-refresh the information in the panel once
|
// Push an event to the websocket so we can auto-refresh the information in the panel once
|
||||||
// the install is completed.
|
// the install is completed.
|
||||||
s.Events().Publish(InstallCompletedEvent, "")
|
s.Events().Publish(InstallCompletedEvent, "")
|
||||||
|
|
|
@ -3,7 +3,9 @@ package server
|
||||||
import (
|
import (
|
||||||
"github.com/apex/log"
|
"github.com/apex/log"
|
||||||
"github.com/pterodactyl/wings/api"
|
"github.com/pterodactyl/wings/api"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Adds all of the internal event listeners we want to use for a server.
|
// Adds all of the internal event listeners we want to use for a server.
|
||||||
|
@ -21,30 +23,79 @@ 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=><~]))")
|
||||||
|
|
||||||
|
regexpCacheMx sync.RWMutex
|
||||||
|
regexpCache map[string]*regexp.Regexp
|
||||||
|
)
|
||||||
|
|
||||||
// Custom listener for console output events that will check if the given line
|
// 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.
|
// of output matches one that should mark the server as started or not.
|
||||||
func (s *Server) onConsoleOutput(data string) {
|
func (s *Server) onConsoleOutput(data string) {
|
||||||
|
// Get the server's process configuration.
|
||||||
|
processConfiguration := s.ProcessConfiguration()
|
||||||
|
|
||||||
|
// 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,
|
// 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
|
// set the server to that state. Only do this if the server is not currently stopped
|
||||||
// or stopping.
|
// or stopping.
|
||||||
match := s.ProcessConfiguration().Startup.Done
|
|
||||||
|
|
||||||
if s.GetState() == ProcessStartingState && strings.Contains(data, match) {
|
// 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 done lines.
|
||||||
|
for _, match := range processConfiguration.Startup.Done {
|
||||||
|
if strings.HasPrefix(match, "regex:") && len(match) > 6 {
|
||||||
|
match = match[6:]
|
||||||
|
|
||||||
|
regexpCacheMx.RLock()
|
||||||
|
rxp, ok := regexpCache[match]
|
||||||
|
regexpCacheMx.RUnlock()
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
rxp, err = regexp.Compile(match)
|
||||||
|
if err != nil {
|
||||||
|
log.WithError(err).Warn("failed to compile regexp")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
regexpCacheMx.Lock()
|
||||||
|
regexpCache[match] = rxp
|
||||||
|
regexpCacheMx.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
if !rxp.MatchString(data) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else if !strings.Contains(data, match) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
s.Log().WithFields(log.Fields{
|
s.Log().WithFields(log.Fields{
|
||||||
"match": match,
|
"match": match,
|
||||||
"against": data,
|
"against": data,
|
||||||
}).Debug("detected server in running state based on console line output")
|
}).Debug("detected server in running state based on console line output")
|
||||||
|
|
||||||
s.SetState(ProcessRunningState)
|
_ = s.SetState(ProcessRunningState)
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the command sent to the server is one that should stop the server we will need to
|
// 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
|
// 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.
|
// cause the server to unexpectedly restart on the user.
|
||||||
if s.IsRunning() {
|
if s.IsRunning() {
|
||||||
stop := s.ProcessConfiguration().Stop
|
stop := processConfiguration.Stop
|
||||||
|
|
||||||
if stop.Type == api.ProcessStopCommand && data == stop.Value {
|
if stop.Type == api.ProcessStopCommand && data == stop.Value {
|
||||||
s.SetState(ProcessStoppingState)
|
_ = s.SetState(ProcessStoppingState)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user