diff --git a/config.go b/config.go index bafbbd3..af77b4e 100644 --- a/config.go +++ b/config.go @@ -1,114 +1,114 @@ package wings import ( - "gopkg.in/yaml.v2" - "io/ioutil" - "os" + "gopkg.in/yaml.v2" + "io/ioutil" + "os" ) type Configuration struct { - // Determines if wings should be running in debug mode. This value is ignored - // if the debug flag is passed through the command line arguments. - Debug bool + // Determines if wings should be running in debug mode. This value is ignored + // if the debug flag is passed through the command line arguments. + Debug bool - // Directory where the server data is stored at. - Data string + // Directory where the server data is stored at. + Data string - Api *ApiConfiguration - Docker *DockerConfiguration + Api *ApiConfiguration + Docker *DockerConfiguration - // Determines if permissions for a server should be set automatically on - // daemon boot. This can take a long time on systems with many servers, or on - // systems with servers containing thousands of files. - SetPermissionsOnBoot bool `yaml:"set_permissions_on_boot"` + // Determines if permissions for a server should be set automatically on + // daemon boot. This can take a long time on systems with many servers, or on + // systems with servers containing thousands of files. + SetPermissionsOnBoot bool `yaml:"set_permissions_on_boot"` - // The amount of time in seconds that should elapse between disk usage checks - // run by the daemon. Setting a higher number can result in better IO performance - // at an increased risk of a malicious user creating a process that goes over - // the assigned disk limits. - DiskCheckTimeout int `yaml:"disk_check_timeout"` + // The amount of time in seconds that should elapse between disk usage checks + // run by the daemon. Setting a higher number can result in better IO performance + // at an increased risk of a malicious user creating a process that goes over + // the assigned disk limits. + DiskCheckTimeout int `yaml:"disk_check_timeout"` - // Defines internal throttling configurations for server processes to prevent - // someone from running an endless loop that spams data to logs. - Throttles struct { - // The number of data overage warnings (inclusive) that can accumulate - // before a process is terminated. - KillAtCount int `yaml:"kill_at_count"` + // Defines internal throttling configurations for server processes to prevent + // someone from running an endless loop that spams data to logs. + Throttles struct { + // The number of data overage warnings (inclusive) that can accumulate + // before a process is terminated. + KillAtCount int `yaml:"kill_at_count"` - // The number of seconds that must elapse before the internal counter - // begins decrementing warnings assigned to a process that is outputting - // too much data. - DecaySeconds int `yaml:"decay"` + // The number of seconds that must elapse before the internal counter + // begins decrementing warnings assigned to a process that is outputting + // too much data. + DecaySeconds int `yaml:"decay"` - // The total number of bytes allowed to be output by a server process - // per interval. - BytesPerInterval int `yaml:"bytes"` + // The total number of bytes allowed to be output by a server process + // per interval. + BytesPerInterval int `yaml:"bytes"` - // The amount of time that should lapse between data output throttle - // checks. This should be defined in milliseconds. - CheckInterval int `yaml:"check_interval"` - } + // The amount of time that should lapse between data output throttle + // checks. This should be defined in milliseconds. + CheckInterval int `yaml:"check_interval"` + } - // The location where the panel is running that this daemon should connect to - // to collect data and send events. - PanelLocation string `yaml:"remote"` + // The location where the panel is running that this daemon should connect to + // to collect data and send events. + PanelLocation string `yaml:"remote"` - // The token used when performing operations. Requests to this instance must - // validate aganist it. - AuthenticationToken string `yaml:"token"` + // The token used when performing operations. Requests to this instance must + // validate aganist it. + AuthenticationToken string `yaml:"token"` } // Defines the configuration for the internal API that is exposed by the // daemon webserver. type ApiConfiguration struct { - // The interface that the internal webserver should bind to. - Host string + // The interface that the internal webserver should bind to. + Host string - // The port that the internal webserver should bind to. - Port int + // The port that the internal webserver should bind to. + Port int - // SSL configuration for the daemon. - Ssl struct { - Enabled bool - CertificateFile string `yaml:"cert"` - KeyFile string `yaml:"key"` - } + // SSL configuration for the daemon. + Ssl struct { + Enabled bool + CertificateFile string `yaml:"cert"` + KeyFile string `yaml:"key"` + } - // The maximum size for files uploaded through the Panel in bytes. - UploadLimit int `yaml:"upload_limit"` + // The maximum size for files uploaded through the Panel in bytes. + UploadLimit int `yaml:"upload_limit"` } // Defines the docker configuration used by the daemon when interacting with // containers and networks on the system. type DockerConfiguration struct { - Container struct { - User string - } + Container struct { + User string + } - // Network configuration that should be used when creating a new network - // for containers run through the daemon. - Network struct { - // The interface that should be used to create the network. Must not conflict - // with any other interfaces in use by Docker or on the system. - Interface string + // Network configuration that should be used when creating a new network + // for containers run through the daemon. + Network struct { + // The interface that should be used to create the network. Must not conflict + // with any other interfaces in use by Docker or on the system. + Interface string - // The name of the network to use. If this network already exists it will not - // be created. If it is not found, a new network will be created using the interface - // defined. - Name string - } + // The name of the network to use. If this network already exists it will not + // be created. If it is not found, a new network will be created using the interface + // defined. + Name string + } - // If true, container images will be updated when a server starts if there - // is an update available. If false the daemon will not attempt updates and will - // defer to the host system to manage image updates. - UpdateImages bool `yaml:"update_images"` + // If true, container images will be updated when a server starts if there + // is an update available. If false the daemon will not attempt updates and will + // defer to the host system to manage image updates. + UpdateImages bool `yaml:"update_images"` - // The location of the Docker socket. - Socket string + // The location of the Docker socket. + Socket string - // Defines the location of the timezone file on the host system that should - // be mounted into the created containers so that they all use the same time. - TimezonePath string `yaml:"timezone_path"` + // Defines the location of the timezone file on the host system that should + // be mounted into the created containers so that they all use the same time. + TimezonePath string `yaml:"timezone_path"` } // Configures the default values for many of the configuration options present @@ -117,60 +117,60 @@ type DockerConfiguration struct { // of the places in the code using them will need to be doing checks, which is // a tedious thing to have to do. func (c *Configuration) SetDefaults() { - // Set the default data directory. - c.Data = "/srv/daemon-data" + // Set the default data directory. + c.Data = "/srv/daemon-data" - // By default the internal webserver should bind to all interfaces and - // be served on port 8080. - c.Api = &ApiConfiguration{ - Host: "0.0.0.0", - Port: 8080, - } + // By default the internal webserver should bind to all interfaces and + // be served on port 8080. + c.Api = &ApiConfiguration{ + Host: "0.0.0.0", + Port: 8080, + } - // Setting this to true by default helps us avoid a lot of support requests - // from people that keep trying to move files around as a root user leading - // to server permission issues. - // - // In production and heavy use environments where boot speed is essential, - // this should be set to false as servers will self-correct permissions on - // boot anyways. - c.SetPermissionsOnBoot = true + // Setting this to true by default helps us avoid a lot of support requests + // from people that keep trying to move files around as a root user leading + // to server permission issues. + // + // In production and heavy use environments where boot speed is essential, + // this should be set to false as servers will self-correct permissions on + // boot anyways. + c.SetPermissionsOnBoot = true - // Configure the default throttler implementation. This should work fine - // for 99% of people running servers on the platform. The occasional host - // might need to tweak them to be less restrictive depending on their hardware - // and target audience. - c.Throttles.KillAtCount = 5 - c.Throttles.DecaySeconds = 10 - c.Throttles.BytesPerInterval = 4096 - c.Throttles.CheckInterval = 100 + // Configure the default throttler implementation. This should work fine + // for 99% of people running servers on the platform. The occasional host + // might need to tweak them to be less restrictive depending on their hardware + // and target audience. + c.Throttles.KillAtCount = 5 + c.Throttles.DecaySeconds = 10 + c.Throttles.BytesPerInterval = 4096 + c.Throttles.CheckInterval = 100 - // Configure the defaults for Docker connection and networks. - c.Docker = &DockerConfiguration{} - c.Docker.UpdateImages = true - c.Docker.Socket = "/var/run/docker.sock" - c.Docker.Network.Name = "pterodactyl_nw" - c.Docker.Network.Interface = "172.18.0.1" + // Configure the defaults for Docker connection and networks. + c.Docker = &DockerConfiguration{} + c.Docker.UpdateImages = true + c.Docker.Socket = "/var/run/docker.sock" + c.Docker.Network.Name = "pterodactyl_nw" + c.Docker.Network.Interface = "172.18.0.1" } // Reads the configuration from the provided file and returns the configuration // object that can then be used. func ReadConfiguration(path string) (*Configuration, error) { - b, err := ioutil.ReadFile(path) - if err != nil { - return nil, err - } + b, err := ioutil.ReadFile(path) + if err != nil { + return nil, err + } - c := &Configuration{} - c.SetDefaults() + c := &Configuration{} + c.SetDefaults() - // Replace environment variables within the configuration file with their - // values from the host system. - b = []byte(os.ExpandEnv(string(b))) + // Replace environment variables within the configuration file with their + // values from the host system. + b = []byte(os.ExpandEnv(string(b))) - if err := yaml.Unmarshal(b, c); err != nil { - return nil, err - } + if err := yaml.Unmarshal(b, c); err != nil { + return nil, err + } - return c, nil + return c, nil } diff --git a/const.go b/const.go index 557014c..7be1c32 100644 --- a/const.go +++ b/const.go @@ -3,27 +3,27 @@ package wings import "os" const ( - Version = "0.0.1" + Version = "0.0.1" - // DefaultFilePerms are the file perms used for created files. - DefaultFilePerms os.FileMode = 0644 + // DefaultFilePerms are the file perms used for created files. + DefaultFilePerms os.FileMode = 0644 - // DefaultFolderPerms are the file perms used for created folders. - DefaultFolderPerms os.FileMode = 0755 + // DefaultFolderPerms are the file perms used for created folders. + DefaultFolderPerms os.FileMode = 0755 - // ServersPath is the path of the servers within the configured DataPath. - ServersPath = "servers" + // ServersPath is the path of the servers within the configured DataPath. + ServersPath = "servers" - // ServerConfigFile is the filename of the server config file. - ServerConfigFile = "server.json" + // ServerConfigFile is the filename of the server config file. + ServerConfigFile = "server.json" - // ServerDataPath is the path of the data of a single server. - ServerDataPath = "data" + // ServerDataPath is the path of the data of a single server. + ServerDataPath = "data" - // DockerContainerPrefix is the prefix used for naming Docker containers. - // It's also used to prefix the hostnames of the docker containers. - DockerContainerPrefix = "ptdl-" + // DockerContainerPrefix is the prefix used for naming Docker containers. + // It's also used to prefix the hostnames of the docker containers. + DockerContainerPrefix = "ptdl-" - // WSMaxMessages is the maximum number of messages that are sent in one transfer. - WSMaxMessages = 10 + // WSMaxMessages is the maximum number of messages that are sent in one transfer. + WSMaxMessages = 10 ) diff --git a/environment/docker.go b/environment/docker.go index 3dd66e5..a3a3645 100644 --- a/environment/docker.go +++ b/environment/docker.go @@ -1,16 +1,16 @@ package environment import ( - "github.com/pterodactyl/wings" - "os" + "github.com/pterodactyl/wings" + "os" ) type Docker struct { - *Controller + *Controller - // Defines the configuration for the Docker instance that will allow us to connect - // and create and modify containers. - Configuration wings.DockerConfiguration + // Defines the configuration for the Docker instance that will allow us to connect + // and create and modify containers. + Configuration wings.DockerConfiguration } // Ensure that the Docker environment is always implementing all of the methods @@ -18,17 +18,17 @@ type Docker struct { var _ Environment = (*Docker)(nil) func (d *Docker) Exists() bool { - return true + return true } func (d *Docker) Start() error { - return nil + return nil } func (d *Docker) Stop() error { - return nil + return nil } func (d *Docker) Terminate(signal os.Signal) error { - return nil + return nil } diff --git a/environment/environment.go b/environment/environment.go index fd5fb74..c657bd1 100644 --- a/environment/environment.go +++ b/environment/environment.go @@ -1,35 +1,35 @@ package environment import ( - "github.com/pterodactyl/wings/server" - "os" + "github.com/pterodactyl/wings/server" + "os" ) // Defines the basic interface that all environments need to implement so that // a server can be properly controlled. type Environment interface { - // Starts a server instance. If the server instance is not in a state where it - // can be started an error should be returned. - Start() error + // Starts a server instance. If the server instance is not in a state where it + // can be started an error should be returned. + Start() error - // Stops a server instance. If the server is already stopped an error should - // not be returned. - Stop() error + // Stops a server instance. If the server is already stopped an error should + // not be returned. + Stop() error - // Determines if the server instance exists. For example, in a docker environment - // this should confirm that the container is created and in a bootable state. In - // a basic CLI environment this can probably just return true right away. - Exists() bool + // Determines if the server instance exists. For example, in a docker environment + // this should confirm that the container is created and in a bootable state. In + // a basic CLI environment this can probably just return true right away. + Exists() bool - // Terminates a running server instance using the provided signal. If the server - // is not running no error should be returned. - Terminate(signal os.Signal) error + // Terminates a running server instance using the provided signal. If the server + // is not running no error should be returned. + Terminate(signal os.Signal) error } // Defines an environment controller for a server instance. This can either be // a docker environment where the server is running in a container, or a host // CLI environment where it is not running in a container at all (theoretically). type Controller struct { - // The server instance attached to this environment. - Server *server.Server + // The server instance attached to this environment. + Server *server.Server } diff --git a/go.mod b/go.mod index db5e508..23128c6 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/gorilla/websocket v1.2.0 github.com/hashicorp/hcl v0.0.0-20180320202055-f40e974e75af // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect - github.com/lestrrat-go/file-rotatelogs v2.1.0+incompatible + github.com/lestrrat-go/file-rotatelogs v2.1.0+incompatible // indirect github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042 // indirect github.com/magiconair/properties v1.7.6 // indirect github.com/mattn/go-isatty v0.0.3 // indirect @@ -30,12 +30,13 @@ require ( github.com/pelletier/go-toml v1.1.0 // indirect github.com/pkg/errors v0.8.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/rifflock/lfshook v0.0.0-20180227222202-bf539943797a + github.com/remeh/sizedwaitgroup v0.0.0-20180822144253-5e7302b12cce // indirect + github.com/rifflock/lfshook v0.0.0-20180227222202-bf539943797a // indirect github.com/shirou/gopsutil v0.0.0-20180227225847-5776ff9c7c5d github.com/sirupsen/logrus v1.0.5 github.com/spf13/afero v1.0.2 // indirect github.com/spf13/cast v1.2.0 // indirect - github.com/spf13/cobra v0.0.2 + github.com/spf13/cobra v0.0.2 // indirect github.com/spf13/jwalterweatherman v0.0.0-20180109140146-7c0cea34c8ec // indirect github.com/spf13/pflag v1.0.0 // indirect github.com/spf13/viper v1.0.2 diff --git a/go.sum b/go.sum index fd1eaff..ca5ea2b 100644 --- a/go.sum +++ b/go.sum @@ -52,6 +52,8 @@ github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/remeh/sizedwaitgroup v0.0.0-20180822144253-5e7302b12cce h1:aP+C+YbHZfOQlutA4p4soHi7rVUqHQdWEVMSkHfDTqY= +github.com/remeh/sizedwaitgroup v0.0.0-20180822144253-5e7302b12cce/go.mod h1:3j2R4OIe/SeS6YDhICBy22RWjJC5eNCJ1V+9+NVNYlo= github.com/rifflock/lfshook v0.0.0-20180227222202-bf539943797a h1:zOAPcZGA4TZZv8zEI+uqbYXgyjmXtMcRVSnR0T0J2t0= github.com/rifflock/lfshook v0.0.0-20180227222202-bf539943797a/go.mod h1:GEXHk5HgEKCvEIIrSpFI3ozzG5xOKA2DVlEX/gGnewM= github.com/shirou/gopsutil v0.0.0-20180227225847-5776ff9c7c5d h1:TW8oufRzBs0qROjv16ll0N780gaBcgSu1TxKjwJMebM= diff --git a/server/server.go b/server/server.go index 779eb37..c81e6d3 100644 --- a/server/server.go +++ b/server/server.go @@ -1,99 +1,134 @@ package server import ( - "github.com/pterodactyl/wings" - "github.com/pterodactyl/wings/environment" - "gopkg.in/yaml.v2" + "github.com/pterodactyl/wings" + "github.com/pterodactyl/wings/environment" + "github.com/remeh/sizedwaitgroup" + "go.uber.org/zap" + "gopkg.in/yaml.v2" + "io/ioutil" + "os" + "strings" ) // High level definition for a server instance being controlled by Wings. type Server struct { - // The unique identifier for the server that should be used when referencing - // it aganist the Panel API (and internally). This will be used when naming - // docker containers as well as in log output. - Uuid string + // The unique identifier for the server that should be used when referencing + // it aganist the Panel API (and internally). This will be used when naming + // docker containers as well as in log output. + Uuid string - // Wether or not the server is in a suspended state. Suspended servers cannot - // be started or modified except in certain scenarios by an admin user. - Suspended bool + // Wether or not the server is in a suspended state. Suspended servers cannot + // be started or modified except in certain scenarios by an admin user. + Suspended bool - // The power state of the server. - State int + // The power state of the server. + State int - // The command that should be used when booting up the server instance. - Invocation string + // The command that should be used when booting up the server instance. + Invocation string - // An array of environment variables that should be passed along to the running - // server process. - EnvVars map[string]string `yaml:"env"` + // An array of environment variables that should be passed along to the running + // server process. + EnvVars map[string]string `yaml:"env"` - Build *BuildSettings - Allocations *Allocations + Build *BuildSettings + Allocations *Allocations - environment *environment.Environment + environment *environment.Environment } // The build settings for a given server that impact docker container creation and // resource limits for a server instance. type BuildSettings struct { - // The total amount of memory in megabytes that this server is allowed to - // use on the host system. - MemoryLimit int `yaml:"memory"` + // The total amount of memory in megabytes that this server is allowed to + // use on the host system. + MemoryLimit int `yaml:"memory"` - // The amount of additional swap space to be provided to a container instance. - Swap int + // The amount of additional swap space to be provided to a container instance. + Swap int - // The relative weight for IO operations in a container. This is relative to other - // containers on the system and should be a value between 10 and 1000. - IoWeight int `yaml:"io"` + // The relative weight for IO operations in a container. This is relative to other + // containers on the system and should be a value between 10 and 1000. + IoWeight int `yaml:"io"` - // The percentage of CPU that this instance is allowed to consume relative to - // the host. A value of 200% represents complete utilization of two cores. This - // should be a value between 1 and THREAD_COUNT * 100. - CpuLimit int `yaml:"cpu"` + // The percentage of CPU that this instance is allowed to consume relative to + // the host. A value of 200% represents complete utilization of two cores. This + // should be a value between 1 and THREAD_COUNT * 100. + CpuLimit int `yaml:"cpu"` - // The amount of disk space in megabytes that a server is allowed to use. - DiskSpace int `yaml:"disk"` + // The amount of disk space in megabytes that a server is allowed to use. + DiskSpace int `yaml:"disk"` } // Defines the allocations available for a given server. When using the Docker environment // driver these correspond to mappings for the container that allow external connections. type Allocations struct { - // Defines the default allocation that should be used for this server. This is - // what will be used for {SERVER_IP} and {SERVER_PORT} when modifying configuration - // files or the startup arguments for a server. - DefaultMapping struct { - Ip string - Port int - } `yaml:"default"` + // Defines the default allocation that should be used for this server. This is + // what will be used for {SERVER_IP} and {SERVER_PORT} when modifying configuration + // files or the startup arguments for a server. + DefaultMapping struct { + Ip string + Port int + } `yaml:"default"` - // Mappings contains all of the ports that should be assigned to a given server - // attached to the IP they correspond to. - Mappings map[string][]int + // Mappings contains all of the ports that should be assigned to a given server + // attached to the IP they correspond to. + Mappings map[string][]int +} + +// Iterates over a given directory and loads all of the servers listed before returning +// them to the calling function. +func LoadDirectory(dir string) (*[]Server, error) { + wg := sizedwaitgroup.New(5) + + f, err := ioutil.ReadDir(dir) + if err != nil { + return nil, err + } + + zap.S().Debug("starting loop") + for _, file := range f { + if !strings.HasSuffix(file.Name(), ".yml") { + continue + } + + wg.Add() + go func(file os.FileInfo) { + zap.S().Debugw("processing in parallel", zap.String("name", file.Name())) + wg.Done() + }(file) + } + + wg.Wait() + + zap.S().Debug("done processing files") + + return nil, nil } // Initalizes a server using a data byte array. This will be marshaled into the // given struct using a YAML marshaler. This will also configure the given environment // for a server. func FromConfiguration(data []byte, cfg wings.DockerConfiguration) (*Server, error) { - s := &Server{} + s := &Server{} - if err := yaml.Unmarshal(data, s); err != nil { - return nil, err - } + if err := yaml.Unmarshal(data, s); err != nil { + return nil, err + } - // Right now we only support a Docker based environment, so I'm going to hard code - // this logic in. When we're ready to support other environment we'll need to make - // some modifications here obviously. - var env environment.Environment - env = &environment.Docker{ - Controller: &environment.Controller{ - Server: s, - }, - Configuration: cfg, - } + // Right now we only support a Docker based environment, so I'm going to hard code + // this logic in. When we're ready to support other environment we'll need to make + // some modifications here obviously. + var env environment.Environment + env = &environment.Docker{ + Controller: &environment.Controller{ + Server: s, + }, + Configuration: cfg, + } - s.environment = &env + s.environment = &env - return s, nil + return s, nil } diff --git a/wings.go b/wings.go index 3072d20..53c733c 100644 --- a/wings.go +++ b/wings.go @@ -1,74 +1,77 @@ package wings import ( - "flag" - "fmt" - "go.uber.org/zap" + "flag" + "fmt" + "github.com/pterodactyl/wings/server" + "go.uber.org/zap" ) // Entrypoint for the Wings application. Configures the logger and checks any // flags that were passed through in the boot arguments. func main() { - var configPath = *flag.String("config", "config.yml", "set the location for the configuration file") - var debug = *flag.Bool("debug", false, "pass in order to run wings in debug mode") + var configPath = *flag.String("config", "config.yml", "set the location for the configuration file") + var debug = *flag.Bool("debug", false, "pass in order to run wings in debug mode") - flag.Parse() + flag.Parse() - zap.S().Infof("using configuration file: %s", configPath) + zap.S().Infof("using configuration file: %s", configPath) - c, err := ReadConfiguration(configPath) - if err != nil { - panic(err) - return - } + c, err := ReadConfiguration(configPath) + if err != nil { + panic(err) + return + } - if debug { - c.Debug = true - } + if debug { + c.Debug = true + } - printLogo() - if err := configureLogging(c.Debug); err != nil { - panic(err) - } + printLogo() + if err := configureLogging(c.Debug); err != nil { + panic(err) + } - if c.Debug { - zap.S().Debugw("running in debug mode") - } + if c.Debug { + zap.S().Debugw("running in debug mode") + } - zap.S().Infow("configuration initalized", zap.Any("config", c)) + zap.S().Infow("configuration initalized", zap.Any("config", c)) + + server.LoadDirectory("config/servers") } // Configures the global logger for Zap so that we can call it from any location // in the code without having to pass around a logger instance. func configureLogging(debug bool) error { - cfg := zap.NewProductionConfig() - if debug { - cfg = zap.NewDevelopmentConfig() - } + cfg := zap.NewProductionConfig() + if debug { + cfg = zap.NewDevelopmentConfig() + } - cfg.Encoding = "console" - cfg.OutputPaths = []string{ - "stdout", - } + cfg.Encoding = "console" + cfg.OutputPaths = []string{ + "stdout", + } - logger, err := cfg.Build() - if err != nil { - return err - } + logger, err := cfg.Build() + if err != nil { + return err + } - zap.ReplaceGlobals(logger) + zap.ReplaceGlobals(logger) - return nil + return nil } // Prints the wings logo, nothing special here! func printLogo() { - fmt.Println() - fmt.Println(` ____`) - fmt.Println(`__ Pterodactyl _____/___/_______ _______ ______`) - fmt.Println(`\_____\ \/\/ / / / __ / ___/`) - fmt.Println(` \___\ / / / / /_/ /___ /`) - fmt.Println(` \___/\___/___/___/___/___ /______/`) - fmt.Println(` /_______/ v` + Version) - fmt.Println() + fmt.Println() + fmt.Println(` ____`) + fmt.Println(`__ Pterodactyl _____/___/_______ _______ ______`) + fmt.Println(`\_____\ \/\/ / / / __ / ___/`) + fmt.Println(` \___\ / / / / /_/ /___ /`) + fmt.Println(` \___/\___/___/___/___/___ /______/`) + fmt.Println(` /_______/ v` + Version) + fmt.Println() }