mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-31 00:22:26 -05:00 
			
		
		
		
	tidying up here and there
This commit is contained in:
		
					parent
					
						
							
								baa2cbcca3
							
						
					
				
			
			
				commit
				
					
						052783db66
					
				
			
		
					 16 changed files with 366 additions and 215 deletions
				
			
		|  | @ -19,18 +19,22 @@ | ||||||
| package main | package main | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"fmt" | ||||||
| 	"os" | 	"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/server" | ||||||
| 	"github.com/gotosocial/gotosocial/internal/consts" |  | ||||||
| 	"github.com/sirupsen/logrus" | 	"github.com/sirupsen/logrus" | ||||||
| 
 | 
 | ||||||
| 	"github.com/urfave/cli/v2" | 	"github.com/urfave/cli/v2" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func main() { | func main() { | ||||||
| 	flagNames := consts.GetFlagNames() | 	flagNames := config.GetFlagNames() | ||||||
| 	envNames := consts.GetEnvNames() | 	envNames := config.GetEnvNames() | ||||||
| 	app := &cli.App{ | 	app := &cli.App{ | ||||||
| 		Usage: "a fediverse social media server", | 		Usage: "a fediverse social media server", | ||||||
| 		Flags: []cli.Flag{ | 		Flags: []cli.Flag{ | ||||||
|  | @ -100,7 +104,22 @@ func main() { | ||||||
| 					{ | 					{ | ||||||
| 						Name:  "start", | 						Name:  "start", | ||||||
| 						Usage: "start the gotosocial server", | 						Usage: "start the gotosocial server", | ||||||
| 						Action: server.Run, | 						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) | 		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) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -35,3 +35,8 @@ db: | ||||||
|   # Examples: ["password123","verysafepassword","postgres"] |   # Examples: ["password123","verysafepassword","postgres"] | ||||||
|   # Default: "" |   # Default: "" | ||||||
|   password: "" |   password: "" | ||||||
|  | 
 | ||||||
|  |   # String. Name of the database to use within the provided database type. | ||||||
|  |   # Examples: ["mydb","postgres","gotosocial"] | ||||||
|  |   # Default: "postgres" | ||||||
|  |   database: "postgres" | ||||||
|  |  | ||||||
							
								
								
									
										31
									
								
								internal/action/action.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								internal/action/action.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -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 <http://www.gnu.org/licenses/>. | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | 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 | ||||||
|  | @ -16,8 +16,7 @@ | ||||||
|    along with this program.  If not, see <http://www.gnu.org/licenses/>. |    along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| // Package client AAAAAAAAAAAAAAA | package api | ||||||
| package client |  | ||||||
| 
 | 
 | ||||||
| // API is the client API exposed to the outside world for access by front-ends; this is distinct from the federation 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 { | type API interface { | ||||||
|  | @ -16,7 +16,7 @@ | ||||||
|    along with this program.  If not, see <http://www.gnu.org/licenses/>. |    along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| package client | package api | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"net/http" | 	"net/http" | ||||||
|  | @ -16,7 +16,7 @@ | ||||||
|    along with this program.  If not, see <http://www.gnu.org/licenses/>. |    along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| package client | package api | ||||||
| 
 | 
 | ||||||
| import "github.com/gin-gonic/gin" | import "github.com/gin-gonic/gin" | ||||||
| 
 | 
 | ||||||
|  | @ -22,21 +22,22 @@ import ( | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"os" | 	"os" | ||||||
| 
 | 
 | ||||||
| 	"github.com/gotosocial/gotosocial/internal/db" |  | ||||||
| 	"gopkg.in/yaml.v2" | 	"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 { | type Config struct { | ||||||
| 	LogLevel        string    `yaml:"logLevel"` | 	LogLevel        string    `yaml:"logLevel"` | ||||||
| 	ApplicationName string     `yaml:"applicationName,omitempty"` | 	ApplicationName string    `yaml:"applicationName"` | ||||||
| 	DBConfig        *db.Config `yaml:"db,omitempty"` | 	DBConfig        *DBConfig `yaml:"db"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // New returns a new config, or an error if something goes amiss. | // 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. | // The path parameter is optional, for loading a configuration json from the given path. | ||||||
| func New(path string) (*Config, error) { | func New(path string) (*Config, error) { | ||||||
| 	config := &Config{} | 	config := &Config{ | ||||||
|  | 		DBConfig: &DBConfig{}, | ||||||
|  | 	} | ||||||
| 	if path != "" { | 	if path != "" { | ||||||
| 		var err error | 		var err error | ||||||
| 		if config, err = loadFromFile(path); err != nil { | 		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 | // 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 | // KeyedFlags is a wrapper for any type that can store keyed flags and give them back. | ||||||
| type Flags interface { | // HINT: This works with a urfave cli context struct ;) | ||||||
|  | type KeyedFlags interface { | ||||||
| 	String(k string) string | 	String(k string) string | ||||||
| 	Int(k string) int | 	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", | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
							
								
								
									
										12
									
								
								internal/config/db.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								internal/config/db.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -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"` | ||||||
|  | } | ||||||
|  | @ -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 <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 |  | ||||||
| 
 |  | ||||||
| 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,}$`) |  | ||||||
							
								
								
									
										36
									
								
								internal/db/actions.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								internal/db/actions.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -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 <http://www.gnu.org/licenses/>. | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | 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 | ||||||
|  | } | ||||||
|  | @ -24,15 +24,16 @@ import ( | ||||||
| 	"strings" | 	"strings" | ||||||
| 
 | 
 | ||||||
| 	"github.com/go-fed/activity/pub" | 	"github.com/go-fed/activity/pub" | ||||||
|  | 	"github.com/gotosocial/gotosocial/internal/config" | ||||||
| 	"github.com/sirupsen/logrus" | 	"github.com/sirupsen/logrus" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| const dbTypePostgres string = "POSTGRES" | const dbTypePostgres string = "POSTGRES" | ||||||
| 
 | 
 | ||||||
| // Service provides methods for interacting with an underlying database (for now, just postgres). | // DB 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. | // 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 | // See here: https://github.com/go-fed/activity/blob/master/pub/database.go | ||||||
| type Service interface { | type DB interface { | ||||||
| 	/* | 	/* | ||||||
| 		GO-FED DATABASE FUNCTIONS | 		GO-FED DATABASE FUNCTIONS | ||||||
| 	*/ | 	*/ | ||||||
|  | @ -44,24 +45,13 @@ type Service interface { | ||||||
| 	Stop(context.Context) error | 	Stop(context.Context) error | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Config provides configuration options for the database connection | // New returns a new database service that satisfies the Service interface and, by extension, | ||||||
| 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, |  | ||||||
| // the go-fed database interface described here: https://github.com/go-fed/activity/blob/master/pub/database.go | // 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) { | func New(ctx context.Context, c *config.Config, log *logrus.Logger) (DB, error) { | ||||||
| 	switch strings.ToUpper(config.Type) { | 	switch strings.ToUpper(c.DBConfig.Type) { | ||||||
| 	case dbTypePostgres: | 	case dbTypePostgres: | ||||||
| 		return newPostgresService(context, config, log.WithField("service", "db")) | 		return newPostgresService(ctx, c, log.WithField("service", "db")) | ||||||
| 	default: | 	default: | ||||||
| 		return nil, fmt.Errorf("database type %s not supported", config.Type) | 		return nil, fmt.Errorf("database type %s not supported", c.DBConfig.Type) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | @ -23,17 +23,18 @@ import ( | ||||||
| 	"errors" | 	"errors" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"net/url" | 	"net/url" | ||||||
|  | 	"regexp" | ||||||
| 	"strings" | 	"strings" | ||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
| 	"github.com/go-fed/activity/streams/vocab" | 	"github.com/go-fed/activity/streams/vocab" | ||||||
| 	"github.com/go-pg/pg" | 	"github.com/go-pg/pg" | ||||||
| 	"github.com/gotosocial/gotosocial/internal/consts" | 	"github.com/gotosocial/gotosocial/internal/config" | ||||||
| 	"github.com/sirupsen/logrus" | 	"github.com/sirupsen/logrus" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type postgresService struct { | type postgresService struct { | ||||||
| 	config *Config | 	config *config.DBConfig | ||||||
| 	conn   *pg.DB | 	conn   *pg.DB | ||||||
| 	log    *logrus.Entry | 	log    *logrus.Entry | ||||||
| 	cancel context.CancelFunc | 	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. | // 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. | // 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) { | func newPostgresService(ctx context.Context, c *config.Config, log *logrus.Entry) (*postgresService, error) { | ||||||
| 	opts, err := derivePGOptions(config) | 	opts, err := derivePGOptions(c) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, fmt.Errorf("could not create postgres service: %s", err) | 		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 | 	// we can confidently return this useable postgres service now | ||||||
| 	return &postgresService{ | 	return &postgresService{ | ||||||
| 		config: config, | 		config: c.DBConfig, | ||||||
| 		conn:   conn, | 		conn:   conn, | ||||||
| 		log:    log, | 		log:    log, | ||||||
| 		cancel: cancel, | 		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 | // 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. | // with sensible defaults, or an error if it's not satisfied by the provided config. | ||||||
| func derivePGOptions(config *Config) (*pg.Options, error) { | func derivePGOptions(c *config.Config) (*pg.Options, error) { | ||||||
| 	if strings.ToUpper(config.Type) != dbTypePostgres { | 	if strings.ToUpper(c.DBConfig.Type) != dbTypePostgres { | ||||||
| 		return nil, fmt.Errorf("expected db type of %s but got %s", dbTypePostgres, config.Type) | 		return nil, fmt.Errorf("expected db type of %s but got %s", dbTypePostgres, c.DBConfig.Type) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// validate port | 	// validate port | ||||||
| 	if config.Port == 0 { | 	if c.DBConfig.Port == 0 { | ||||||
| 		return nil, errors.New("no port set") | 		return nil, errors.New("no port set") | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// validate address | 	// validate address | ||||||
| 	if config.Address == "" { | 	if c.DBConfig.Address == "" { | ||||||
| 		return nil, errors.New("no address set") | 		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 | 	// validate username | ||||||
| 	if config.User == "" { | 	if c.DBConfig.User == "" { | ||||||
| 		return nil, errors.New("no user set") | 		return nil, errors.New("no user set") | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// validate that there's a password | 	// validate that there's a password | ||||||
| 	if config.Password == "" { | 	if c.DBConfig.Password == "" { | ||||||
| 		return nil, errors.New("no password set") | 		return nil, errors.New("no password set") | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// validate database | 	// validate database | ||||||
| 	if config.Database == "" { | 	if c.DBConfig.Database == "" { | ||||||
| 		return nil, errors.New("no database set") | 		return nil, errors.New("no database set") | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// We can rely on the pg library we're using to set | 	// We can rely on the pg library we're using to set | ||||||
| 	// sensible defaults for everything we don't set here. | 	// sensible defaults for everything we don't set here. | ||||||
| 	options := &pg.Options{ | 	options := &pg.Options{ | ||||||
| 		Addr:     fmt.Sprintf("%s:%d", config.Address, config.Port), | 		Addr:            fmt.Sprintf("%s:%d", c.DBConfig.Address, c.DBConfig.Port), | ||||||
| 		User:     config.User, | 		User:            c.DBConfig.User, | ||||||
| 		Password: config.Password, | 		Password:        c.DBConfig.Password, | ||||||
| 		Database: config.Database, | 		Database:        c.DBConfig.Database, | ||||||
|  | 		ApplicationName: c.ApplicationName, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return options, nil | 	return options, nil | ||||||
|  | @ -144,83 +149,83 @@ func derivePGOptions(config *Config) (*pg.Options, error) { | ||||||
| /* | /* | ||||||
|    GO-FED DB INTERFACE-IMPLEMENTING FUNCTIONS |    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 | 	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 | 	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 | 	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 | 	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 | 	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 | 	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 | 	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 | 	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 | 	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 | 	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 | 	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 | 	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 | 	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 | 	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 | 	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 | 	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 | 	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 | 	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 | 	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 | 	return nil, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -26,11 +26,30 @@ import ( | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // New returns a new logrus logger with the specified level, | // 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) { | func New(level string) (*logrus.Logger, error) { | ||||||
| 	log := logrus.New() | 	log := logrus.New() | ||||||
|  | 
 | ||||||
| 	log.SetOutput(&outputSplitter{}) | 	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 | // 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) | 	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 |  | ||||||
| } |  | ||||||
|  |  | ||||||
							
								
								
									
										54
									
								
								internal/server/actions.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								internal/server/actions.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -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 <http://www.gnu.org/licenses/>. | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | 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 | ||||||
|  | } | ||||||
|  | @ -17,50 +17,3 @@ | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| package server | 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 |  | ||||||
| } |  | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue