diff options
| -rw-r--r-- | cmd/gotosocial/main.go | 58 | ||||
| -rw-r--r-- | cmd/server/server.go | 35 | ||||
| -rw-r--r-- | go.mod | 1 | ||||
| -rw-r--r-- | go.sum | 2 | ||||
| -rw-r--r-- | internal/config/config.go | 72 | ||||
| -rw-r--r-- | internal/consts/consts.go | 77 | ||||
| -rw-r--r-- | internal/db/postgres.go | 3 | ||||
| -rw-r--r-- | internal/db/service.go | 15 | ||||
| -rw-r--r-- | internal/log/log.go | 58 | 
9 files changed, 282 insertions, 39 deletions
diff --git a/cmd/gotosocial/main.go b/cmd/gotosocial/main.go index 78c7002a2..ffb7b9b8d 100644 --- a/cmd/gotosocial/main.go +++ b/cmd/gotosocial/main.go @@ -22,23 +22,69 @@ import (  	"os"  	"github.com/gotosocial/gotosocial/cmd/server" +	"github.com/gotosocial/gotosocial/internal/consts"  	"github.com/sirupsen/logrus"  	"github.com/urfave/cli/v2"  )  func main() { +	flagNames := consts.GetFlagNames() +	envNames := consts.GetEnvNames()  	app := &cli.App{  		Flags: []cli.Flag{ +			// GENERAL FLAGS  			&cli.StringFlag{ -				Name:        "config", -				Aliases:     []string{"c"}, -				Usage:       "Load configuration from `FILE`", +				Name:    flagNames.LogLevel, +				Usage:   "Log level to run at: debug, info, warn, fatal", +				Value:   "info", +				EnvVars: []string{"GTS_LOG_LEVEL"},  			},  			&cli.StringFlag{ -				Name:        "log-level", -				Usage:       "Log level to run at: debug, info, warn, fatal", -				Value:       "info", +				Name:    flagNames.ApplicationName, +				Usage:   "Name of the application, used in various places internally", +				Value:   "gotosocial", +				EnvVars: []string{envNames.ApplicationName}, +				Hidden:  true, +			}, + +			// DATABASE FLAGS +			&cli.StringFlag{ +				Name:    flagNames.DbType, +				Usage:   "Database type: eg., postgres", +				Value:   "postgres", +				EnvVars: []string{envNames.DbType}, +			}, +			&cli.StringFlag{ +				Name:    flagNames.DbAddress, +				Usage:   "Database ipv4 address or hostname", +				Value:   "localhost", +				EnvVars: []string{envNames.DbAddress}, +			}, +			&cli.IntFlag{ +				Name:    flagNames.DbPort, +				Usage:   "Database port", +				Value:   5432, +				EnvVars: []string{envNames.DbPort}, +			}, +			&cli.StringFlag{ +				Name:    flagNames.DbUser, +				Usage:   "Database username", +				Value:   "postgres", +				EnvVars: []string{envNames.DbUser}, +			}, +			&cli.StringFlag{ +				Name:     flagNames.DbPassword, +				Usage:    "Database password", +				Value:    "postgres", +				EnvVars:  []string{envNames.DbPassword}, +				FilePath: "./dbpass", +			}, +			&cli.StringFlag{ +				Name:    flagNames.DbDatabase, +				Usage:   "Database name", +				Value:   "postgres", +				EnvVars: []string{envNames.DbDatabase},  			},  		},  		Commands: []*cli.Command{ diff --git a/cmd/server/server.go b/cmd/server/server.go index 4f2969993..bd16e1f84 100644 --- a/cmd/server/server.go +++ b/cmd/server/server.go @@ -25,43 +25,28 @@ import (  	"os/signal"  	"syscall" +	"github.com/gotosocial/gotosocial/internal/config"  	"github.com/gotosocial/gotosocial/internal/db" -	"github.com/sirupsen/logrus" +	"github.com/gotosocial/gotosocial/internal/log"  	"github.com/urfave/cli/v2"  ) -// getLog will try to set the logrus log level to the -// desired level specified by the user with the --log-level flag -func getLog(c *cli.Context) (*logrus.Logger, error) { -	log := logrus.New() -	logLevel, err := logrus.ParseLevel(c.String("log-level")) -	if err != nil { -		return nil, err -	} -	log.SetLevel(logLevel) -	return log, nil -} -  // Run starts the gotosocial server  func Run(c *cli.Context) error { -	log, err := getLog(c) +	log, err := log.New(c.String("log-level"))  	if err != nil {  		return fmt.Errorf("error creating logger: %s", err)  	} -	ctx := context.Background() -	dbConfig := &db.Config{ -		Type:            "POSTGRES", -		Address:         "", -		Port:            5432, -		User:            "", -		Password:        "whatever", -		Database:        "postgres", -		ApplicationName: "gotosocial", +	var gtsConfig *config.Config +	if gtsConfig, err = config.New(c.String("config")); err != nil { +		return fmt.Errorf("error creating config: %s", err)  	} -	dbService, err := db.NewService(ctx, dbConfig, log) + +	ctx := context.Background() +	dbService, err := db.NewService(ctx, gtsConfig.DBConfig, log)  	if err != nil { -		return err +		return fmt.Errorf("error creating dbservice: %s", err)  	}  	// catch shutdown signals from the operating system @@ -9,6 +9,7 @@ require (  	github.com/golang/protobuf v1.4.3 // indirect  	github.com/google/go-cmp v0.5.4 // indirect  	github.com/jinzhu/inflection v1.0.0 // indirect +	github.com/namsral/flag v1.7.4-pre // indirect  	github.com/onsi/ginkgo v1.15.0 // indirect  	github.com/onsi/gomega v1.10.5 // indirect  	github.com/sirupsen/logrus v1.8.0 @@ -77,6 +77,8 @@ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OH  github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=  github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=  github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/namsral/flag v1.7.4-pre h1:b2ScHhoCUkbsq0d2C15Mv+VU8bl8hAXV8arnWiOHNZs= +github.com/namsral/flag v1.7.4-pre/go.mod h1:OXldTctbM6SWH1K899kPZcf65KxJiD7MsceFUpB5yDo=  github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=  github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=  github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= diff --git a/internal/config/config.go b/internal/config/config.go new file mode 100644 index 000000000..9b6935a7c --- /dev/null +++ b/internal/config/config.go @@ -0,0 +1,72 @@ +/* +   GoToSocial +   Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + +   This program is free software: you can redistribute it and/or modify +   it under the terms of the GNU Affero General Public License as published by +   the Free Software Foundation, either version 3 of the License, or +   (at your option) any later version. + +   This program is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +   GNU Affero General Public License for more details. + +   You should have received a copy of the GNU Affero General Public License +   along with this program.  If not, see <http://www.gnu.org/licenses/>. +*/ + +package config + +import ( +	"encoding/json" +	"fmt" +	"os" + +	"github.com/gotosocial/gotosocial/internal/db" +) + +// Config contains all the configuration needed to run gotosocial +type Config struct { +	DBConfig *db.Config `json:"db,omitempty"` +} + +// New returns a new config, or an error if something goes amiss. +// The path parameter is optional, for loading a configuration json from the given path. +func New(path string) (*Config, error) { +	var config *Config +	if path != "" { +		var err error +		if config, err = loadFromFile(path); err != nil { +			return nil, fmt.Errorf("error creating config: %s", err) +		} +	} + +	return config, nil +} + +// loadFromFile takes a path to a .json file and attempts to load a Config object from it +func loadFromFile(path string) (*Config, error) { +	bytes, err := os.ReadFile(path) +	if err != nil { +		return nil, fmt.Errorf("could not read file at path %s: %s", path, err) +	} + +	config := &Config{} +	if err := json.Unmarshal(bytes, config); err != nil { +		return nil, fmt.Errorf("could not unmarshal file at path %s: %s", path, err) +	} + +	return config, nil +} + +// WithFlags returns a copy of this config object with flags set using the provided flags object +func (c *Config) WithFlags(f Flags) *Config { +	return c +} + +// Flags is a wrapper for any type that can store keyed flags and give them back +type Flags interface { +	String(k string) string +	Int(k string) int +} diff --git a/internal/consts/consts.go b/internal/consts/consts.go new file mode 100644 index 000000000..92c574a41 --- /dev/null +++ b/internal/consts/consts.go @@ -0,0 +1,77 @@ +/* +   GoToSocial +   Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + +   This program is free software: you can redistribute it and/or modify +   it under the terms of the GNU Affero General Public License as published by +   the Free Software Foundation, either version 3 of the License, or +   (at your option) any later version. + +   This program is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +   GNU Affero General Public License for more details. + +   You should have received a copy of the GNU Affero General Public License +   along with this program.  If not, see <http://www.gnu.org/licenses/>. +*/ + +// Package consts is where we shove any consts that don't really belong anywhere else in the code. +// Don't judge me. +package consts + +// FlagNames is used for storing the names of the various flags used for +// initializing and storing urfavecli flag variables. +type FlagNames struct { +	LogLevel        string +	ApplicationName string +	DbType          string +	DbAddress       string +	DbPort          string +	DbUser          string +	DbPassword      string +	DbDatabase      string +} + +// GetFlagNames returns a struct containing the names of the various flags used for +// initializing and storing urfavecli flag variables. +func GetFlagNames() FlagNames { +	return FlagNames{ +		LogLevel:        "log-level", +		ApplicationName: "application-name", +		DbType:          "db-type", +		DbAddress:       "db-address", +		DbPort:          "db-port", +		DbUser:          "db-users", +		DbPassword:      "db-password", +		DbDatabase:      "db-database", +	} +} + +// EnvNames is used for storing the environment variable keys used for +// initializing and storing urfavecli flag variables. +type EnvNames struct { +	LogLevel        string +	ApplicationName string +	DbType          string +	DbAddress       string +	DbPort          string +	DbUser          string +	DbPassword      string +	DbDatabase      string +} + +// GetEnvNames returns a struct containing the names of the environment variable keys used for +// initializing and storing urfavecli flag variables. +func GetEnvNames() FlagNames { +	return FlagNames{ +		LogLevel:        "GTS_LOG_LEVEL", +		ApplicationName: "GTS_APPLICATION_NAME", +		DbType:          "GTS_DB_TYPE", +		DbAddress:       "GTS_DB_ADDRESS", +		DbPort:          "GTS_DB_PORT", +		DbUser:          "GTS_DB_USER", +		DbPassword:      "GTS_DB_PASSWORD", +		DbDatabase:      "GTS_DB_DATABASE", +	} +} diff --git a/internal/db/postgres.go b/internal/db/postgres.go index f4cf47406..14c8d3d7b 100644 --- a/internal/db/postgres.go +++ b/internal/db/postgres.go @@ -23,6 +23,7 @@ import (  	"errors"  	"fmt"  	"net/url" +	"strings"  	"time"  	"github.com/go-fed/activity/streams/vocab" @@ -95,7 +96,7 @@ func newPostgresService(ctx context.Context, config *Config, log *logrus.Entry)  // derivePGOptions takes an application config and returns either a ready-to-use *pg.Options  // with sensible defaults, or an error if it's not satisfied by the provided config.  func derivePGOptions(config *Config) (*pg.Options, error) { -	if config.Type != dbTypePostgres { +	if strings.ToUpper(config.Type) != dbTypePostgres {  		return nil, fmt.Errorf("expected db type of %s but got %s", dbTypePostgres, config.Type)  	} diff --git a/internal/db/service.go b/internal/db/service.go index 9a1d3ce2c..6c738606e 100644 --- a/internal/db/service.go +++ b/internal/db/service.go @@ -46,13 +46,14 @@ type Service interface {  // Config provides configuration options for the database connection  type Config struct { -	Type            string -	Address         string -	Port            int -	User            string -	Password        string -	Database        string -	ApplicationName string +	Type            string `json:"type,omitempty"` +	Address         string `json:"address,omitempty"` +	Port            int    `json:"port,omitempty"` +	User            string `json:"user,omitempty"` +	Password        string `json:"password,omitempty"` +	PasswordFile    string `json:"passwordFile,omitempty"` +	Database        string `json:"database,omitempty"` +	ApplicationName string `json:"applicationName,omitempty"`  }  // NewService returns a new database service that satisfies the Service interface and, by extension, diff --git a/internal/log/log.go b/internal/log/log.go new file mode 100644 index 000000000..65b820ce4 --- /dev/null +++ b/internal/log/log.go @@ -0,0 +1,58 @@ +/* +   GoToSocial +   Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + +   This program is free software: you can redistribute it and/or modify +   it under the terms of the GNU Affero General Public License as published by +   the Free Software Foundation, either version 3 of the License, or +   (at your option) any later version. + +   This program is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +   GNU Affero General Public License for more details. + +   You should have received a copy of the GNU Affero General Public License +   along with this program.  If not, see <http://www.gnu.org/licenses/>. +*/ + +package log + +import ( +	"bytes" +	"os" + +	"github.com/sirupsen/logrus" +) + +// New returns a new logrus logger with the specified level, +// or an error if that level can't be parsed +func New(level string) (*logrus.Logger, error) { +	log := logrus.New() +	log.SetOutput(&outputSplitter{}) +	return setLogLevel(level, log) +} + +// outputSplitter implements the io.Writer interface for use with Logrus, and simply +// splits logs between stdout and stderr depending on their severity. +// See: https://github.com/sirupsen/logrus/issues/403#issuecomment-346437512 +type outputSplitter struct{} + +func (splitter *outputSplitter) Write(p []byte) (n int, err error) { +	if bytes.Contains(p, []byte("level=error")) { +		return os.Stderr.Write(p) +	} +	return os.Stdout.Write(p) +} + +// setLogLevel will try to set the logrus log level to the +// desired level specified by the user with the --log-level flag +func setLogLevel(level string, logger *logrus.Logger) (*logrus.Logger, error) { +	log := logrus.New() +	logLevel, err := logrus.ParseLevel(level) +	if err != nil { +		return nil, err +	} +	log.SetLevel(logLevel) +	return log, nil +}  | 
