From 052783db664ab529a52026e5a2bbfa2d5ca427d2 Mon Sep 17 00:00:00 2001 From: tsmethurst Date: Thu, 4 Mar 2021 14:38:18 +0100 Subject: [PATCH] tidying up here and there --- cmd/gotosocial/main.go | 58 ++++++++-- example/config.yaml | 9 +- internal/action/action.go | 31 +++++ internal/ap/{service.go => ap.go} | 0 internal/{client/service.go => api/client.go} | 3 +- internal/{client => api}/route_statuses.go | 2 +- internal/{client => api}/router.go | 2 +- internal/config/config.go | 109 ++++++++++++++++-- internal/config/db.go | 12 ++ internal/consts/consts.go | 72 ------------ internal/db/actions.go | 36 ++++++ internal/db/{service.go => db.go} | 28 ++--- internal/db/postgres.go | 83 ++++++------- internal/log/log.go | 35 +++--- internal/server/actions.go | 54 +++++++++ internal/server/server.go | 47 -------- 16 files changed, 366 insertions(+), 215 deletions(-) create mode 100644 internal/action/action.go rename internal/ap/{service.go => ap.go} (100%) rename internal/{client/service.go => api/client.go} (95%) rename internal/{client => api}/route_statuses.go (98%) rename internal/{client => api}/router.go (98%) create mode 100644 internal/config/db.go delete mode 100644 internal/consts/consts.go create mode 100644 internal/db/actions.go rename internal/db/{service.go => db.go} (54%) create mode 100644 internal/server/actions.go diff --git a/cmd/gotosocial/main.go b/cmd/gotosocial/main.go index 26b9d49..664ed2e 100644 --- a/cmd/gotosocial/main.go +++ b/cmd/gotosocial/main.go @@ -19,18 +19,22 @@ package main import ( + "fmt" "os" + "github.com/gotosocial/gotosocial/internal/action" + "github.com/gotosocial/gotosocial/internal/config" + "github.com/gotosocial/gotosocial/internal/db" + "github.com/gotosocial/gotosocial/internal/log" "github.com/gotosocial/gotosocial/internal/server" - "github.com/gotosocial/gotosocial/internal/consts" "github.com/sirupsen/logrus" "github.com/urfave/cli/v2" ) func main() { - flagNames := consts.GetFlagNames() - envNames := consts.GetEnvNames() + flagNames := config.GetFlagNames() + envNames := config.GetEnvNames() app := &cli.App{ Usage: "a fediverse social media server", Flags: []cli.Flag{ @@ -81,9 +85,9 @@ func main() { EnvVars: []string{envNames.DbUser}, }, &cli.StringFlag{ - Name: flagNames.DbPassword, - Usage: "Database password", - EnvVars: []string{envNames.DbPassword}, + Name: flagNames.DbPassword, + Usage: "Database password", + EnvVars: []string{envNames.DbPassword}, }, &cli.StringFlag{ Name: flagNames.DbDatabase, @@ -98,9 +102,24 @@ func main() { Usage: "gotosocial server-related tasks", Subcommands: []*cli.Command{ { - Name: "start", - Usage: "start the gotosocial server", - Action: server.Run, + Name: "start", + Usage: "start the gotosocial server", + Action: func(c *cli.Context) error { + return runAction(c, server.Run) + }, + }, + }, + }, + { + Name: "db", + Usage: "database-related tasks and utils", + Subcommands: []*cli.Command{ + { + Name: "init", + Usage: "initialize a database with the required schema for gotosocial; has no effect & is safe to run on an already-initialized db", + Action: func(c *cli.Context) error { + return runAction(c, db.Initialize) + }, }, }, }, @@ -112,3 +131,24 @@ func main() { logrus.Fatal(err) } } + +// runAction builds up the config and logger necessary for any +// gotosocial action, and then executes the action. +func runAction(c *cli.Context, a action.GTSAction) error { + + // create a new *config.Config based on the config path provided... + conf, err := config.New(c.String(config.GetFlagNames().ConfigPath)) + if err != nil { + return fmt.Errorf("error creating config: %s", err) + } + // ... and the flags set on the *cli.Context by urfave + conf.ParseFlags(c) + + // create a logger with the log level, formatting, and output splitter already set + log, err := log.New(conf.LogLevel) + if err != nil { + return fmt.Errorf("error creating logger: %s", err) + } + + return a(c.Context, conf, log) +} diff --git a/example/config.yaml b/example/config.yaml index bc87ecd..3fcdc7a 100644 --- a/example/config.yaml +++ b/example/config.yaml @@ -8,7 +8,7 @@ logLevel: "info" # Default: "gotosocial" applicationName: "gotosocial" -# Config pertaining to the Gotosocial database connection +# Config pertaining to the Gotosocial database connection db: # String. Database type. # Options: ["postgres"] @@ -22,7 +22,7 @@ db: # Int. Port for database connection. # Examples: [5432, 1234, 6969] - # Default: 5432 + # Default: 5432 port: 5432 # String. Username for the database connection. @@ -35,3 +35,8 @@ db: # Examples: ["password123","verysafepassword","postgres"] # Default: "" password: "" + + # String. Name of the database to use within the provided database type. + # Examples: ["mydb","postgres","gotosocial"] + # Default: "postgres" + database: "postgres" diff --git a/internal/action/action.go b/internal/action/action.go new file mode 100644 index 0000000..8febed7 --- /dev/null +++ b/internal/action/action.go @@ -0,0 +1,31 @@ +/* + 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 . +*/ + +package action + +import ( + "context" + + "github.com/gotosocial/gotosocial/internal/config" + "github.com/sirupsen/logrus" +) + +// GTSAction defines one *action* that can be taken by the gotosocial cli command. +// This can be either a long-running action (like server start) or something +// shorter like db init or db inspect. +type GTSAction func(context.Context, *config.Config, *logrus.Logger) error diff --git a/internal/ap/service.go b/internal/ap/ap.go similarity index 100% rename from internal/ap/service.go rename to internal/ap/ap.go diff --git a/internal/client/service.go b/internal/api/client.go similarity index 95% rename from internal/client/service.go rename to internal/api/client.go index 4e6bad8..5d8a709 100644 --- a/internal/client/service.go +++ b/internal/api/client.go @@ -16,8 +16,7 @@ along with this program. If not, see . */ -// Package client AAAAAAAAAAAAAAA -package client +package api // API is the client API exposed to the outside world for access by front-ends; this is distinct from the federation API type API interface { diff --git a/internal/client/route_statuses.go b/internal/api/route_statuses.go similarity index 98% rename from internal/client/route_statuses.go rename to internal/api/route_statuses.go index d17a81d..1cdc5f9 100644 --- a/internal/client/route_statuses.go +++ b/internal/api/route_statuses.go @@ -16,7 +16,7 @@ along with this program. If not, see . */ -package client +package api import ( "net/http" diff --git a/internal/client/router.go b/internal/api/router.go similarity index 98% rename from internal/client/router.go rename to internal/api/router.go index 0cedcd0..95e7840 100644 --- a/internal/client/router.go +++ b/internal/api/router.go @@ -16,7 +16,7 @@ along with this program. If not, see . */ -package client +package api import "github.com/gin-gonic/gin" diff --git a/internal/config/config.go b/internal/config/config.go index 1f31eef..5832ed5 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -22,21 +22,22 @@ import ( "fmt" "os" - "github.com/gotosocial/gotosocial/internal/db" "gopkg.in/yaml.v2" ) -// Config contains all the configuration needed to run gotosocial +// Config pulls together all the configuration needed to run gotosocial type Config struct { - LogLevel string `yaml:"logLevel"` - ApplicationName string `yaml:"applicationName,omitempty"` - DBConfig *db.Config `yaml:"db,omitempty"` + LogLevel string `yaml:"logLevel"` + ApplicationName string `yaml:"applicationName"` + DBConfig *DBConfig `yaml:"db"` } // 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) { - config := &Config{} + config := &Config{ + DBConfig: &DBConfig{}, + } if path != "" { var err error if config, err = loadFromFile(path); err != nil { @@ -63,12 +64,102 @@ func loadFromFile(path string) (*Config, error) { } // ParseFlags sets flags on the config using the provided Flags object -func (c *Config) ParseFlags(f Flags) { +func (c *Config) ParseFlags(f KeyedFlags) { + fn := GetFlagNames() + // For all of these flags, we only want to set them on the config if: + // + // a) They haven't been set at all in the config file we already parsed, + // and so we take the default from the flags object. + // + // b) They may have been set in the config, but they've *also* been set explicitly + // as a command-line argument or an env variable, which takes priority. + + // general flags + if c.LogLevel == "" || f.IsSet(fn.LogLevel) { + c.LogLevel = f.String(fn.LogLevel) + } + + if c.ApplicationName == "" || f.IsSet(fn.ApplicationName) { + c.ApplicationName = f.String(fn.ApplicationName) + } + + // db flags + if c.DBConfig.Type == "" || f.IsSet(fn.DbType) { + c.DBConfig.Type = f.String(fn.DbType) + } + + if c.DBConfig.Address == "" || f.IsSet(fn.DbAddress) { + c.DBConfig.Address = f.String(fn.DbAddress) + } + + if c.DBConfig.Port == 0 || f.IsSet(fn.DbPort) { + c.DBConfig.Port = f.Int(fn.DbPort) + } + + if c.DBConfig.User == "" || f.IsSet(fn.DbUser) { + c.DBConfig.User = f.String(fn.DbUser) + } + + if c.DBConfig.Password == "" || f.IsSet(fn.DbPassword) { + c.DBConfig.Password = f.String(fn.DbPassword) + } + + if c.DBConfig.Database == "" || f.IsSet(fn.DbDatabase) { + c.DBConfig.Database = f.String(fn.DbDatabase) + } } -// Flags is a wrapper for any type that can store keyed flags and give them back -type Flags interface { +// KeyedFlags is a wrapper for any type that can store keyed flags and give them back. +// HINT: This works with a urfave cli context struct ;) +type KeyedFlags interface { String(k string) string Int(k string) int + IsSet(k string) bool +} + +// Flags is used for storing the names of the various flags used for +// initializing and storing urfavecli flag variables. +type Flags struct { + LogLevel string + ApplicationName string + ConfigPath 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() Flags { + return Flags{ + LogLevel: "log-level", + ApplicationName: "application-name", + ConfigPath: "config-path", + DbType: "db-type", + DbAddress: "db-address", + DbPort: "db-port", + DbUser: "db-user", + DbPassword: "db-password", + DbDatabase: "db-database", + } +} + +// GetEnvNames returns a struct containing the names of the environment variable keys used for +// initializing and storing urfavecli flag variables. +func GetEnvNames() Flags { + return Flags{ + LogLevel: "GTS_LOG_LEVEL", + ApplicationName: "GTS_APPLICATION_NAME", + ConfigPath: "GTS_CONFIG_PATH", + 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/config/db.go b/internal/config/db.go new file mode 100644 index 0000000..9cbc174 --- /dev/null +++ b/internal/config/db.go @@ -0,0 +1,12 @@ +package config + +// DBConfig provides configuration options for the database connection +type DBConfig struct { + Type string `yaml:"type"` + Address string `yaml:"address"` + Port int `yaml:"port"` + User string `yaml:"user"` + Password string `yaml:"password"` + Database string `yaml:"database"` + ApplicationName string `yaml:"applicationName"` +} diff --git a/internal/consts/consts.go b/internal/consts/consts.go deleted file mode 100644 index 34f8107..0000000 --- a/internal/consts/consts.go +++ /dev/null @@ -1,72 +0,0 @@ -/* - 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 . -*/ - -// Package consts is where we shove any consts that don't really belong anywhere else in the code. -// Don't judge me. -package consts - -import "regexp" - -// Flags is used for storing the names of the various flags used for -// initializing and storing urfavecli flag variables. -type Flags struct { - LogLevel string - ApplicationName string - ConfigPath 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() Flags { - return Flags{ - LogLevel: "log-level", - ApplicationName: "application-name", - ConfigPath: "config-path", - DbType: "db-type", - DbAddress: "db-address", - DbPort: "db-port", - DbUser: "db-user", - DbPassword: "db-password", - DbDatabase: "db-database", - } -} - -// GetEnvNames returns a struct containing the names of the environment variable keys used for -// initializing and storing urfavecli flag variables. -func GetEnvNames() Flags { - return Flags{ - LogLevel: "GTS_LOG_LEVEL", - ApplicationName: "GTS_APPLICATION_NAME", - ConfigPath: "GTS_CONFIG_PATH", - DbType: "GTS_DB_TYPE", - DbAddress: "GTS_DB_ADDRESS", - DbPort: "GTS_DB_PORT", - DbUser: "GTS_DB_USER", - DbPassword: "GTS_DB_PASSWORD", - DbDatabase: "GTS_DB_DATABASE", - } -} - -var IPV4Regex = regexp.MustCompile(`^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$`) -var HostnameRegex = regexp.MustCompile(`^(?:[a-z0-9]+(?:-[a-z0-9]+)*\.)+[a-z]{2,}$`) diff --git a/internal/db/actions.go b/internal/db/actions.go new file mode 100644 index 0000000..ae3d8ca --- /dev/null +++ b/internal/db/actions.go @@ -0,0 +1,36 @@ +/* + 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 . +*/ + +package db + +import ( + "context" + + "github.com/gotosocial/gotosocial/internal/action" + "github.com/gotosocial/gotosocial/internal/config" + "github.com/sirupsen/logrus" +) + +// Initialize will initialize the database given in the config for use with GoToSocial +var Initialize action.GTSAction = func(ctx context.Context, c *config.Config, log *logrus.Logger) error { + _, err := New(ctx, c, log) + if err != nil { + return err + } + return nil +} diff --git a/internal/db/service.go b/internal/db/db.go similarity index 54% rename from internal/db/service.go rename to internal/db/db.go index 4449a98..df38ae1 100644 --- a/internal/db/service.go +++ b/internal/db/db.go @@ -24,15 +24,16 @@ import ( "strings" "github.com/go-fed/activity/pub" + "github.com/gotosocial/gotosocial/internal/config" "github.com/sirupsen/logrus" ) const dbTypePostgres string = "POSTGRES" -// Service provides methods for interacting with an underlying database (for now, just postgres). -// The function mapping lines up with the Database interface described in go-fed. +// DB provides methods for interacting with an underlying database (for now, just postgres). +// The function mapping lines up with the DB interface described in go-fed. // See here: https://github.com/go-fed/activity/blob/master/pub/database.go -type Service interface { +type DB interface { /* GO-FED DATABASE FUNCTIONS */ @@ -44,24 +45,13 @@ type Service interface { Stop(context.Context) error } -// Config provides configuration options for the database connection -type Config struct { - Type string `yaml:"type,omitempty"` - Address string `yaml:"address,omitempty"` - Port int `yaml:"port,omitempty"` - User string `yaml:"user,omitempty"` - Password string `yaml:"password,omitempty"` - Database string `yaml:"database,omitempty"` - ApplicationName string `yaml:"applicationName,omitempty"` -} - -// NewService returns a new database service that satisfies the Service interface and, by extension, +// New returns a new database service that satisfies the Service interface and, by extension, // the go-fed database interface described here: https://github.com/go-fed/activity/blob/master/pub/database.go -func NewService(context context.Context, config *Config, log *logrus.Logger) (Service, error) { - switch strings.ToUpper(config.Type) { +func New(ctx context.Context, c *config.Config, log *logrus.Logger) (DB, error) { + switch strings.ToUpper(c.DBConfig.Type) { case dbTypePostgres: - return newPostgresService(context, config, log.WithField("service", "db")) + return newPostgresService(ctx, c, log.WithField("service", "db")) default: - return nil, fmt.Errorf("database type %s not supported", config.Type) + return nil, fmt.Errorf("database type %s not supported", c.DBConfig.Type) } } diff --git a/internal/db/postgres.go b/internal/db/postgres.go index 1eb3eb4..2982596 100644 --- a/internal/db/postgres.go +++ b/internal/db/postgres.go @@ -23,17 +23,18 @@ import ( "errors" "fmt" "net/url" + "regexp" "strings" "time" "github.com/go-fed/activity/streams/vocab" "github.com/go-pg/pg" - "github.com/gotosocial/gotosocial/internal/consts" + "github.com/gotosocial/gotosocial/internal/config" "github.com/sirupsen/logrus" ) type postgresService struct { - config *Config + config *config.DBConfig conn *pg.DB log *logrus.Entry cancel context.CancelFunc @@ -41,8 +42,8 @@ type postgresService struct { // newPostgresService returns a postgresService derived from the provided config, which implements the go-fed DB interface. // Under the hood, it uses https://github.com/go-pg/pg to create and maintain a database connection. -func newPostgresService(ctx context.Context, config *Config, log *logrus.Entry) (*postgresService, error) { - opts, err := derivePGOptions(config) +func newPostgresService(ctx context.Context, c *config.Config, log *logrus.Entry) (*postgresService, error) { + opts, err := derivePGOptions(c) if err != nil { return nil, fmt.Errorf("could not create postgres service: %s", err) } @@ -83,7 +84,7 @@ func newPostgresService(ctx context.Context, config *Config, log *logrus.Entry) // we can confidently return this useable postgres service now return &postgresService{ - config: config, + config: c.DBConfig, conn: conn, log: log, cancel: cancel, @@ -96,46 +97,50 @@ 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 strings.ToUpper(config.Type) != dbTypePostgres { - return nil, fmt.Errorf("expected db type of %s but got %s", dbTypePostgres, config.Type) +func derivePGOptions(c *config.Config) (*pg.Options, error) { + if strings.ToUpper(c.DBConfig.Type) != dbTypePostgres { + return nil, fmt.Errorf("expected db type of %s but got %s", dbTypePostgres, c.DBConfig.Type) } // validate port - if config.Port == 0 { + if c.DBConfig.Port == 0 { return nil, errors.New("no port set") } // validate address - if config.Address == "" { + if c.DBConfig.Address == "" { return nil, errors.New("no address set") } - if !consts.HostnameRegex.MatchString(config.Address) && !consts.IPV4Regex.MatchString(config.Address) && config.Address != "localhost" { - return nil, fmt.Errorf("address %s was neither an ipv4 address nor a valid hostname", config.Address) + + ipv4Regex := regexp.MustCompile(`^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$`) + hostnameRegex := regexp.MustCompile(`^(?:[a-z0-9]+(?:-[a-z0-9]+)*\.)+[a-z]{2,}$`) + if !hostnameRegex.MatchString(c.DBConfig.Address) && !ipv4Regex.MatchString(c.DBConfig.Address) && c.DBConfig.Address != "localhost" { + return nil, fmt.Errorf("address %s was neither an ipv4 address nor a valid hostname", c.DBConfig.Address) } // validate username - if config.User == "" { + if c.DBConfig.User == "" { return nil, errors.New("no user set") } // validate that there's a password - if config.Password == "" { + if c.DBConfig.Password == "" { return nil, errors.New("no password set") } // validate database - if config.Database == "" { + if c.DBConfig.Database == "" { return nil, errors.New("no database set") } // We can rely on the pg library we're using to set // sensible defaults for everything we don't set here. options := &pg.Options{ - Addr: fmt.Sprintf("%s:%d", config.Address, config.Port), - User: config.User, - Password: config.Password, - Database: config.Database, + Addr: fmt.Sprintf("%s:%d", c.DBConfig.Address, c.DBConfig.Port), + User: c.DBConfig.User, + Password: c.DBConfig.Password, + Database: c.DBConfig.Database, + ApplicationName: c.ApplicationName, } return options, nil @@ -144,83 +149,83 @@ func derivePGOptions(config *Config) (*pg.Options, error) { /* GO-FED DB INTERFACE-IMPLEMENTING FUNCTIONS */ -func (ps *postgresService) Lock(c context.Context, id *url.URL) error { +func (ps *postgresService) Lock(ctx context.Context, id *url.URL) error { return nil } -func (ps *postgresService) Unlock(c context.Context, id *url.URL) error { +func (ps *postgresService) Unlock(ctx context.Context, id *url.URL) error { return nil } -func (ps *postgresService) InboxContains(c context.Context, inbox *url.URL, id *url.URL) (bool, error) { +func (ps *postgresService) InboxContains(ctx context.Context, inbox *url.URL, id *url.URL) (bool, error) { return false, nil } -func (ps *postgresService) GetInbox(c context.Context, inboxIRI *url.URL) (inbox vocab.ActivityStreamsOrderedCollectionPage, err error) { +func (ps *postgresService) GetInbox(ctx context.Context, inboxIRI *url.URL) (inbox vocab.ActivityStreamsOrderedCollectionPage, err error) { return nil, nil } -func (ps *postgresService) SetInbox(c context.Context, inbox vocab.ActivityStreamsOrderedCollectionPage) error { +func (ps *postgresService) SetInbox(ctx context.Context, inbox vocab.ActivityStreamsOrderedCollectionPage) error { return nil } -func (ps *postgresService) Owns(c context.Context, id *url.URL) (owns bool, err error) { +func (ps *postgresService) Owns(ctx context.Context, id *url.URL) (owns bool, err error) { return false, nil } -func (ps *postgresService) ActorForOutbox(c context.Context, outboxIRI *url.URL) (actorIRI *url.URL, err error) { +func (ps *postgresService) ActorForOutbox(ctx context.Context, outboxIRI *url.URL) (actorIRI *url.URL, err error) { return nil, nil } -func (ps *postgresService) ActorForInbox(c context.Context, inboxIRI *url.URL) (actorIRI *url.URL, err error) { +func (ps *postgresService) ActorForInbox(ctx context.Context, inboxIRI *url.URL) (actorIRI *url.URL, err error) { return nil, nil } -func (ps *postgresService) OutboxForInbox(c context.Context, inboxIRI *url.URL) (outboxIRI *url.URL, err error) { +func (ps *postgresService) OutboxForInbox(ctx context.Context, inboxIRI *url.URL) (outboxIRI *url.URL, err error) { return nil, nil } -func (ps *postgresService) Exists(c context.Context, id *url.URL) (exists bool, err error) { +func (ps *postgresService) Exists(ctx context.Context, id *url.URL) (exists bool, err error) { return false, nil } -func (ps *postgresService) Get(c context.Context, id *url.URL) (value vocab.Type, err error) { +func (ps *postgresService) Get(ctx context.Context, id *url.URL) (value vocab.Type, err error) { return nil, nil } -func (ps *postgresService) Create(c context.Context, asType vocab.Type) error { +func (ps *postgresService) Create(ctx context.Context, asType vocab.Type) error { return nil } -func (ps *postgresService) Update(c context.Context, asType vocab.Type) error { +func (ps *postgresService) Update(ctx context.Context, asType vocab.Type) error { return nil } -func (ps *postgresService) Delete(c context.Context, id *url.URL) error { +func (ps *postgresService) Delete(ctx context.Context, id *url.URL) error { return nil } -func (ps *postgresService) GetOutbox(c context.Context, outboxIRI *url.URL) (inbox vocab.ActivityStreamsOrderedCollectionPage, err error) { +func (ps *postgresService) GetOutbox(ctx context.Context, outboxIRI *url.URL) (inbox vocab.ActivityStreamsOrderedCollectionPage, err error) { return nil, nil } -func (ps *postgresService) SetOutbox(c context.Context, outbox vocab.ActivityStreamsOrderedCollectionPage) error { +func (ps *postgresService) SetOutbox(ctx context.Context, outbox vocab.ActivityStreamsOrderedCollectionPage) error { return nil } -func (ps *postgresService) NewID(c context.Context, t vocab.Type) (id *url.URL, err error) { +func (ps *postgresService) NewID(ctx context.Context, t vocab.Type) (id *url.URL, err error) { return nil, nil } -func (ps *postgresService) Followers(c context.Context, actorIRI *url.URL) (followers vocab.ActivityStreamsCollection, err error) { +func (ps *postgresService) Followers(ctx context.Context, actorIRI *url.URL) (followers vocab.ActivityStreamsCollection, err error) { return nil, nil } -func (ps *postgresService) Following(c context.Context, actorIRI *url.URL) (followers vocab.ActivityStreamsCollection, err error) { +func (ps *postgresService) Following(ctx context.Context, actorIRI *url.URL) (followers vocab.ActivityStreamsCollection, err error) { return nil, nil } -func (ps *postgresService) Liked(c context.Context, actorIRI *url.URL) (followers vocab.ActivityStreamsCollection, err error) { +func (ps *postgresService) Liked(ctx context.Context, actorIRI *url.URL) (followers vocab.ActivityStreamsCollection, err error) { return nil, nil } diff --git a/internal/log/log.go b/internal/log/log.go index 65b820c..0355360 100644 --- a/internal/log/log.go +++ b/internal/log/log.go @@ -26,11 +26,30 @@ import ( ) // New returns a new logrus logger with the specified level, -// or an error if that level can't be parsed +// or an error if that level can't be parsed. It also sets +// the output to log.outputSplitter, so you get error logs +// on stderr and normal logs on stdout. func New(level string) (*logrus.Logger, error) { log := logrus.New() + log.SetOutput(&outputSplitter{}) - return setLogLevel(level, log) + + logLevel, err := logrus.ParseLevel(level) + if err != nil { + return nil, err + } + log.SetLevel(logLevel) + + if logLevel == logrus.TraceLevel { + log.SetReportCaller(true) + } + + log.SetFormatter(&logrus.TextFormatter{ + DisableColors: true, + FullTimestamp: true, + }) + + return log, nil } // outputSplitter implements the io.Writer interface for use with Logrus, and simply @@ -44,15 +63,3 @@ func (splitter *outputSplitter) Write(p []byte) (n int, err error) { } 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 -} diff --git a/internal/server/actions.go b/internal/server/actions.go new file mode 100644 index 0000000..b3047c3 --- /dev/null +++ b/internal/server/actions.go @@ -0,0 +1,54 @@ +/* + 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 . +*/ + +package server + +import ( + "context" + "fmt" + "os" + "os/signal" + "syscall" + + "github.com/gotosocial/gotosocial/internal/action" + "github.com/gotosocial/gotosocial/internal/config" + "github.com/gotosocial/gotosocial/internal/db" + "github.com/sirupsen/logrus" +) + +// Run starts the gotosocial server +var Run action.GTSAction = func(ctx context.Context, c *config.Config, log *logrus.Logger) error { + dbService, err := db.New(ctx, c, log) + if err != nil { + return fmt.Errorf("error creating dbservice: %s", err) + } + + // catch shutdown signals from the operating system + sigs := make(chan os.Signal, 1) + signal.Notify(sigs, os.Interrupt, syscall.SIGTERM) + sig := <-sigs + log.Infof("received signal %s, shutting down", sig) + + // close down all running services in order + if err := dbService.Stop(ctx); err != nil { + return fmt.Errorf("error closing dbservice: %s", err) + } + + log.Info("done! exiting...") + return nil +} diff --git a/internal/server/server.go b/internal/server/server.go index 6457f55..5fef839 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -17,50 +17,3 @@ */ package server - -import ( - "context" - "fmt" - "os" - "os/signal" - "syscall" - - "github.com/gotosocial/gotosocial/internal/config" - "github.com/gotosocial/gotosocial/internal/consts" - "github.com/gotosocial/gotosocial/internal/db" - "github.com/gotosocial/gotosocial/internal/log" - "github.com/urfave/cli/v2" -) - -// Run starts the gotosocial server -func Run(c *cli.Context) error { - log, err := log.New(c.String("log-level")) - if err != nil { - return fmt.Errorf("error creating logger: %s", err) - } - - gtsConfig, err := config.New(c.String(consts.GetFlagNames().ConfigPath)) - if err != nil { - return fmt.Errorf("error creating config: %s", err) - } - - ctx := context.Background() - dbService, err := db.NewService(ctx, gtsConfig.DBConfig, log) - if err != nil { - return fmt.Errorf("error creating dbservice: %s", err) - } - - // catch shutdown signals from the operating system - sigs := make(chan os.Signal, 1) - signal.Notify(sigs, os.Interrupt, syscall.SIGTERM) - sig := <-sigs - log.Infof("received signal %s, shutting down", sig) - - // close down all running services in order - if err := dbService.Stop(ctx); err != nil { - return fmt.Errorf("error closing dbservice: %s", err) - } - - log.Info("done! exiting...") - return nil -}