package feta import "os" import "time" import "github.com/jinzhu/gorm" import _ "github.com/jinzhu/gorm/dialects/sqlite" // required for orm import "github.com/rs/zerolog" import "github.com/rs/zerolog/log" import "github.com/mattn/go-isatty" import "github.com/sneak/feta/ingester" // InstanceHostname is a special type for holding the hostname of an // instance (string) type InstanceHostname string // CLIEntry is the main entrypoint for the feta process from the cli func CLIEntry(version string, buildarch string) int { f := new(Process) f.version = version f.buildarch = buildarch f.setupLogging() return f.runForever() } // Process is the main structure/process of this app type Process struct { version string buildarch string locator *InstanceLocator manager *InstanceManager ingester *ingester.TootIngester api *fetaAPIServer db *gorm.DB startup time.Time } func (f *Process) identify() { log.Info(). Str("version", f.version). Str("buildarch", f.buildarch). Msg("starting") } func (f *Process) setupLogging() { log.Logger = log.With().Caller().Logger() tty := isatty.IsTerminal(os.Stdin.Fd()) || isatty.IsCygwinTerminal(os.Stdin.Fd()) if tty { out := zerolog.NewConsoleWriter( func(w *zerolog.ConsoleWriter) { // Customize time format w.TimeFormat = time.RFC3339 }, ) log.Logger = log.Output(out) } // always log in UTC zerolog.TimestampFunc = func() time.Time { return time.Now().UTC() } zerolog.SetGlobalLevel(zerolog.InfoLevel) if os.Getenv("DEBUG") != "" { zerolog.SetGlobalLevel(zerolog.DebugLevel) } f.identify() } func (f *Process) uptime() time.Duration { return time.Since(f.startup) } func (f *Process) setupDatabase() { var err error f.db, err = gorm.Open("sqlite3", "feta.sqlite") if err != nil { panic(err) } f.databaseMigrations() } func (f *Process) runForever() int { f.startup = time.Now() f.setupDatabase() newInstanceHostnameNotifications := make(chan InstanceHostname) f.locator = newInstanceLocator() f.manager = newInstanceManager() f.ingester = ingester.NewTootIngester() f.api = new(fetaAPIServer) f.api.setFeta(f) // api needs to get to us to access data f.locator.setInstanceNotificationChannel(newInstanceHostnameNotifications) f.manager.setInstanceNotificationChannel(newInstanceHostnameNotifications) f.manager.setTootDestination(f.ingester.GetDeliveryChannel()) // ingester goroutine: go f.ingester.Ingest() // locator goroutine: go f.locator.Locate() // manager goroutine: go f.manager.Manage() go f.api.Serve() // this goroutine (main) does nothing until we handle signals // FIXME(sneak) for { time.Sleep(1 * time.Second) } return 0 }