2019-12-19 14:24:26 +00:00
|
|
|
package process
|
2019-11-05 23:32:09 +00:00
|
|
|
|
2020-03-27 23:02:36 +00:00
|
|
|
import (
|
2020-04-06 05:37:22 +00:00
|
|
|
"fmt"
|
2020-03-27 23:02:36 +00:00
|
|
|
"os"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"git.eeqj.de/sneak/feta/database"
|
|
|
|
"git.eeqj.de/sneak/feta/ingester"
|
|
|
|
"git.eeqj.de/sneak/feta/locator"
|
|
|
|
"git.eeqj.de/sneak/feta/manager"
|
|
|
|
"git.eeqj.de/sneak/feta/storage"
|
2020-04-06 05:37:22 +00:00
|
|
|
_ "github.com/jinzhu/gorm/dialects/postgres"
|
2020-03-27 23:02:36 +00:00
|
|
|
_ "github.com/jinzhu/gorm/dialects/sqlite"
|
|
|
|
"github.com/k0kubun/pp"
|
|
|
|
"github.com/mattn/go-isatty"
|
|
|
|
"github.com/rs/zerolog"
|
|
|
|
"github.com/rs/zerolog/log"
|
|
|
|
"github.com/spf13/viper"
|
|
|
|
)
|
|
|
|
|
|
|
|
// required for orm
|
2019-11-06 01:15:31 +00:00
|
|
|
|
2019-12-14 15:24:42 +00:00
|
|
|
// CLIEntry is the main entrypoint for the feta process from the cli
|
2019-12-19 12:39:42 +00:00
|
|
|
func CLIEntry(version string, buildarch string) int {
|
2019-12-19 14:24:26 +00:00
|
|
|
f := new(Feta)
|
2019-11-05 23:32:09 +00:00
|
|
|
f.version = version
|
|
|
|
f.buildarch = buildarch
|
2020-03-27 23:02:36 +00:00
|
|
|
f.configure()
|
2019-11-05 23:32:09 +00:00
|
|
|
f.setupLogging()
|
2020-03-27 23:02:36 +00:00
|
|
|
f.setupDatabase()
|
2019-12-14 15:24:42 +00:00
|
|
|
return f.runForever()
|
2019-11-05 23:32:09 +00:00
|
|
|
}
|
|
|
|
|
2019-12-19 14:24:26 +00:00
|
|
|
// Feta is the main structure/process of this app
|
|
|
|
type Feta struct {
|
2019-11-05 23:32:09 +00:00
|
|
|
version string
|
|
|
|
buildarch string
|
2019-12-19 14:24:26 +00:00
|
|
|
locator *locator.InstanceLocator
|
|
|
|
manager *manager.InstanceManager
|
2019-12-19 12:39:42 +00:00
|
|
|
ingester *ingester.TootIngester
|
2019-12-19 14:24:26 +00:00
|
|
|
api *Server
|
2020-03-27 23:02:36 +00:00
|
|
|
dbm *database.Manager
|
2019-11-06 07:03:42 +00:00
|
|
|
startup time.Time
|
2019-11-05 23:32:09 +00:00
|
|
|
}
|
|
|
|
|
2020-03-27 23:02:36 +00:00
|
|
|
func (f *Feta) configure() {
|
|
|
|
viper.SetConfigName("feta")
|
|
|
|
viper.SetConfigType("yaml")
|
|
|
|
viper.AddConfigPath("/etc/feta") // path to look for the config file in
|
|
|
|
viper.AddConfigPath("$HOME/.config/feta") // call multiple times to add many search paths
|
|
|
|
|
|
|
|
viper.SetEnvPrefix("FETA")
|
|
|
|
viper.AutomaticEnv()
|
|
|
|
|
|
|
|
viper.SetDefault("Debug", false)
|
2020-03-28 02:57:58 +00:00
|
|
|
viper.SetDefault("TootsToDisk", false)
|
|
|
|
viper.SetDefault("TootsToDB", true)
|
2020-03-27 23:02:36 +00:00
|
|
|
viper.SetDefault("HostDiscoveryParallelism", 5)
|
|
|
|
viper.SetDefault("FSStorageLocation", os.ExpandEnv("$HOME/Library/ApplicationSupport/feta/tootarchive.d"))
|
2020-04-06 05:37:22 +00:00
|
|
|
viper.SetDefault("DBURL", fmt.Sprintf("sqlite://%s", os.ExpandEnv("$HOME/Library/ApplicationSupport/feta/feta.state.db")))
|
2020-03-27 23:02:36 +00:00
|
|
|
viper.SetDefault("LogReportInterval", time.Second*10)
|
|
|
|
|
|
|
|
if err := viper.ReadInConfig(); err != nil {
|
|
|
|
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
|
|
|
|
// Config file not found; ignore error if desired
|
|
|
|
} else {
|
|
|
|
// Config file was found but another error was produced
|
|
|
|
log.Panic().
|
|
|
|
Err(err).
|
|
|
|
Msg("cannot read config file")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if viper.GetBool("debug") {
|
|
|
|
pp.Print(viper.AllSettings())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-19 14:24:26 +00:00
|
|
|
func (f *Feta) identify() {
|
2019-11-05 23:32:09 +00:00
|
|
|
log.Info().
|
|
|
|
Str("version", f.version).
|
|
|
|
Str("buildarch", f.buildarch).
|
|
|
|
Msg("starting")
|
|
|
|
}
|
|
|
|
|
2020-03-27 23:02:36 +00:00
|
|
|
func (f *Feta) setupDatabase() {
|
2020-03-30 23:05:53 +00:00
|
|
|
f.dbm = database.New()
|
2020-03-27 23:02:36 +00:00
|
|
|
}
|
|
|
|
|
2019-12-19 14:24:26 +00:00
|
|
|
func (f *Feta) setupLogging() {
|
2019-11-06 01:15:31 +00:00
|
|
|
|
2019-11-05 23:32:09 +00:00
|
|
|
log.Logger = log.With().Caller().Logger()
|
2019-11-06 01:15:31 +00:00
|
|
|
|
2019-11-06 16:02:55 +00:00
|
|
|
tty := isatty.IsTerminal(os.Stdin.Fd()) || isatty.IsCygwinTerminal(os.Stdin.Fd())
|
|
|
|
|
|
|
|
if tty {
|
2019-11-06 01:15:31 +00:00
|
|
|
out := zerolog.NewConsoleWriter(
|
|
|
|
func(w *zerolog.ConsoleWriter) {
|
|
|
|
// Customize time format
|
|
|
|
w.TimeFormat = time.RFC3339
|
|
|
|
},
|
|
|
|
)
|
|
|
|
log.Logger = log.Output(out)
|
2019-11-05 23:32:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// always log in UTC
|
|
|
|
zerolog.TimestampFunc = func() time.Time {
|
|
|
|
return time.Now().UTC()
|
|
|
|
}
|
|
|
|
|
|
|
|
zerolog.SetGlobalLevel(zerolog.InfoLevel)
|
2020-03-27 23:02:36 +00:00
|
|
|
if viper.GetBool("debug") {
|
2019-11-05 23:32:09 +00:00
|
|
|
zerolog.SetGlobalLevel(zerolog.DebugLevel)
|
|
|
|
}
|
|
|
|
|
|
|
|
f.identify()
|
|
|
|
}
|
|
|
|
|
2019-12-19 14:24:26 +00:00
|
|
|
func (f *Feta) uptime() time.Duration {
|
2019-11-06 07:03:42 +00:00
|
|
|
return time.Since(f.startup)
|
2019-11-06 01:15:31 +00:00
|
|
|
}
|
|
|
|
|
2019-12-19 14:24:26 +00:00
|
|
|
func (f *Feta) runForever() int {
|
2019-11-06 07:03:42 +00:00
|
|
|
f.startup = time.Now()
|
|
|
|
|
2019-12-19 14:24:26 +00:00
|
|
|
// FIXME move this channel creation into the manager's constructor
|
|
|
|
// and add getters/setters on the manager/locator
|
2020-03-28 01:17:52 +00:00
|
|
|
newInstanceHostnameNotifications := make(chan string)
|
|
|
|
|
2019-12-19 14:24:26 +00:00
|
|
|
f.locator = locator.New()
|
2020-03-28 01:17:52 +00:00
|
|
|
|
|
|
|
f.manager = manager.New(f.dbm)
|
|
|
|
|
2019-12-19 12:39:42 +00:00
|
|
|
f.ingester = ingester.NewTootIngester()
|
2019-12-14 15:39:58 +00:00
|
|
|
|
2019-12-19 14:24:26 +00:00
|
|
|
home := os.Getenv("HOME")
|
|
|
|
if home == "" {
|
|
|
|
panic("can't find home directory")
|
|
|
|
}
|
|
|
|
|
2020-03-30 23:05:53 +00:00
|
|
|
// TODO make the ingester support multiple storage backends simultaneously
|
2020-03-28 02:57:58 +00:00
|
|
|
if viper.GetBool("TootsToDB") {
|
|
|
|
f.ingester.SetStorageBackend(f.dbm)
|
|
|
|
} else if viper.GetBool("TootsToDisk") {
|
|
|
|
diskBackend := storage.NewTootFSStorage(viper.GetString("FSStorageLocation"))
|
|
|
|
f.ingester.SetStorageBackend(diskBackend)
|
|
|
|
} else {
|
|
|
|
log.Info().Msg("toots will not be saved to disk")
|
|
|
|
}
|
2019-12-19 14:24:26 +00:00
|
|
|
|
|
|
|
f.api = new(Server)
|
|
|
|
f.api.SetFeta(f) // api needs to get to us to access data
|
2019-11-05 23:32:09 +00:00
|
|
|
|
2019-12-19 14:24:26 +00:00
|
|
|
f.locator.SetInstanceNotificationChannel(newInstanceHostnameNotifications)
|
|
|
|
f.manager.SetInstanceNotificationChannel(newInstanceHostnameNotifications)
|
2019-11-05 23:32:09 +00:00
|
|
|
|
2019-12-19 14:24:26 +00:00
|
|
|
f.manager.SetTootDestination(f.ingester.GetDeliveryChannel())
|
2019-12-14 15:39:58 +00:00
|
|
|
|
|
|
|
// ingester goroutine:
|
2019-12-19 12:39:42 +00:00
|
|
|
go f.ingester.Ingest()
|
2019-12-14 15:39:58 +00:00
|
|
|
|
2019-11-06 01:15:31 +00:00
|
|
|
// locator goroutine:
|
2019-12-19 12:39:42 +00:00
|
|
|
go f.locator.Locate()
|
2019-11-05 23:32:09 +00:00
|
|
|
|
2019-11-06 01:15:31 +00:00
|
|
|
// manager goroutine:
|
2019-12-19 12:39:42 +00:00
|
|
|
go f.manager.Manage()
|
2019-11-06 01:15:31 +00:00
|
|
|
|
2019-12-19 12:39:42 +00:00
|
|
|
go f.api.Serve()
|
2019-11-06 01:15:31 +00:00
|
|
|
|
|
|
|
// this goroutine (main) does nothing until we handle signals
|
|
|
|
// FIXME(sneak)
|
|
|
|
for {
|
|
|
|
time.Sleep(1 * time.Second)
|
|
|
|
}
|
2019-11-05 23:32:09 +00:00
|
|
|
|
|
|
|
return 0
|
|
|
|
}
|