205 lines
4.8 KiB
Go
205 lines
4.8 KiB
Go
package main
|
|
|
|
import (
|
|
"database/sql"
|
|
"io"
|
|
"os"
|
|
"os/signal"
|
|
"strings"
|
|
"syscall"
|
|
"time"
|
|
|
|
zlogsentry "github.com/archdx/zerolog-sentry"
|
|
"github.com/getsentry/sentry-go"
|
|
_ "github.com/lib/pq"
|
|
_ "github.com/mattn/go-sqlite3"
|
|
"github.com/mileusna/crontab"
|
|
"github.com/rs/zerolog"
|
|
"gitlab.com/etke.cc/go/healthchecks"
|
|
"gitlab.com/etke.cc/linkpearl"
|
|
|
|
"gitlab.com/etke.cc/postmoogle/bot"
|
|
mxconfig "gitlab.com/etke.cc/postmoogle/bot/config"
|
|
"gitlab.com/etke.cc/postmoogle/bot/queue"
|
|
"gitlab.com/etke.cc/postmoogle/config"
|
|
"gitlab.com/etke.cc/postmoogle/smtp"
|
|
"gitlab.com/etke.cc/postmoogle/utils"
|
|
)
|
|
|
|
var (
|
|
q *queue.Queue
|
|
hc *healthchecks.Client
|
|
mxc *mxconfig.Manager
|
|
mxb *bot.Bot
|
|
cron *crontab.Crontab
|
|
smtpm *smtp.Manager
|
|
log zerolog.Logger
|
|
)
|
|
|
|
func main() {
|
|
quit := make(chan struct{})
|
|
|
|
cfg := config.New()
|
|
initLog(cfg)
|
|
utils.SetLogger(&log)
|
|
utils.SetDomains(cfg.Domains)
|
|
|
|
log.Info().Msg("#############################")
|
|
log.Info().Msg("Postmoogle")
|
|
log.Info().Msg("Matrix: true")
|
|
log.Info().Msg("#############################")
|
|
|
|
log.Debug().Msg("starting internal components...")
|
|
initHealthchecks(cfg)
|
|
initMatrix(cfg)
|
|
initSMTP(cfg)
|
|
initCron()
|
|
initShutdown(quit)
|
|
defer recovery()
|
|
|
|
go startBot(cfg.StatusMsg)
|
|
|
|
if err := smtpm.Start(); err != nil {
|
|
//nolint:gocritic
|
|
log.Fatal().Err(err).Msg("SMTP server crashed")
|
|
}
|
|
|
|
<-quit
|
|
}
|
|
|
|
func initLog(cfg *config.Config) {
|
|
loglevel, err := zerolog.ParseLevel(cfg.LogLevel)
|
|
if err != nil {
|
|
loglevel = zerolog.InfoLevel
|
|
}
|
|
zerolog.SetGlobalLevel(loglevel)
|
|
var w io.Writer
|
|
consoleWriter := zerolog.ConsoleWriter{Out: os.Stdout, PartsExclude: []string{zerolog.TimestampFieldName}}
|
|
sentryWriter, err := zlogsentry.New(cfg.Monitoring.SentryDSN)
|
|
if err == nil {
|
|
w = io.MultiWriter(sentryWriter, consoleWriter)
|
|
} else {
|
|
w = consoleWriter
|
|
}
|
|
log = zerolog.New(w).With().Timestamp().Caller().Logger()
|
|
}
|
|
|
|
func initHealthchecks(cfg *config.Config) {
|
|
if cfg.Monitoring.HealchecksUUID == "" {
|
|
return
|
|
}
|
|
hc = healthchecks.New(cfg.Monitoring.HealchecksUUID, func(operation string, err error) {
|
|
log.Error().Err(err).Str("operation", operation).Msg("healthchecks operation failed")
|
|
})
|
|
hc.Start(strings.NewReader("starting postmoogle"))
|
|
go hc.Auto(cfg.Monitoring.HealthechsDuration)
|
|
}
|
|
|
|
func initMatrix(cfg *config.Config) {
|
|
db, err := sql.Open(cfg.DB.Dialect, cfg.DB.DSN)
|
|
if err != nil {
|
|
log.Fatal().Err(err).Msg("cannot initialize SQL database")
|
|
}
|
|
|
|
lp, err := linkpearl.New(&linkpearl.Config{
|
|
Homeserver: cfg.Homeserver,
|
|
Login: cfg.Login,
|
|
Password: cfg.Password,
|
|
DB: db,
|
|
Dialect: cfg.DB.Dialect,
|
|
AccountDataSecret: cfg.DataSecret,
|
|
Logger: log,
|
|
})
|
|
if err != nil {
|
|
// nolint // Fatal = panic, not os.Exit()
|
|
log.Fatal().Err(err).Msg("cannot initialize matrix bot")
|
|
}
|
|
|
|
mxc = mxconfig.New(lp, &log)
|
|
q = queue.New(lp, mxc, &log)
|
|
mxb, err = bot.New(q, lp, &log, mxc, cfg.Proxies, cfg.Prefix, cfg.Domains, cfg.Admins, bot.MBXConfig(cfg.Mailboxes))
|
|
if err != nil {
|
|
log.Panic().Err(err).Msg("cannot start matrix bot")
|
|
}
|
|
log.Debug().Msg("bot has been created")
|
|
}
|
|
|
|
func initSMTP(cfg *config.Config) {
|
|
smtpm = smtp.NewManager(&smtp.Config{
|
|
Domains: cfg.Domains,
|
|
Port: cfg.Port,
|
|
TLSCerts: cfg.TLS.Certs,
|
|
TLSKeys: cfg.TLS.Keys,
|
|
TLSPort: cfg.TLS.Port,
|
|
TLSRequired: cfg.TLS.Required,
|
|
Logger: &log,
|
|
MaxSize: cfg.MaxSize,
|
|
Bot: mxb,
|
|
Callers: []smtp.Caller{mxb, q},
|
|
Relay: &smtp.RelayConfig{
|
|
Host: cfg.Relay.Host,
|
|
Port: cfg.Relay.Port,
|
|
Usename: cfg.Relay.Username,
|
|
Password: cfg.Relay.Password,
|
|
},
|
|
})
|
|
}
|
|
|
|
func initCron() {
|
|
cron = crontab.New()
|
|
|
|
err := cron.AddJob("* * * * *", q.Process)
|
|
if err != nil {
|
|
log.Error().Err(err).Msg("cannot start queue processing cronjob")
|
|
}
|
|
|
|
err = cron.AddJob("*/5 * * * *", mxb.SyncRooms)
|
|
if err != nil {
|
|
log.Error().Err(err).Msg("cannot start sync rooms cronjob")
|
|
}
|
|
}
|
|
|
|
func initShutdown(quit chan struct{}) {
|
|
listener := make(chan os.Signal, 1)
|
|
signal.Notify(listener, os.Interrupt, syscall.SIGABRT, syscall.SIGHUP, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM)
|
|
|
|
go func() {
|
|
<-listener
|
|
defer close(quit)
|
|
|
|
shutdown()
|
|
}()
|
|
}
|
|
|
|
func startBot(statusMsg string) {
|
|
log.Debug().Str("status message", statusMsg).Msg("starting matrix bot...")
|
|
err := mxb.Start(statusMsg)
|
|
if err != nil {
|
|
//nolint:gocritic
|
|
log.Panic().Err(err).Msg("cannot start the bot")
|
|
}
|
|
}
|
|
|
|
func shutdown() {
|
|
log.Info().Msg("Shutting down...")
|
|
cron.Shutdown()
|
|
smtpm.Stop()
|
|
mxb.Stop()
|
|
if hc != nil {
|
|
hc.Shutdown()
|
|
hc.ExitStatus(0, strings.NewReader("shutting down postmoogle"))
|
|
}
|
|
|
|
sentry.Flush(5 * time.Second)
|
|
log.Info().Msg("Postmoogle has been stopped")
|
|
os.Exit(0)
|
|
}
|
|
|
|
func recovery() {
|
|
defer shutdown()
|
|
err := recover()
|
|
if err != nil {
|
|
sentry.CurrentHub().Recover(err)
|
|
}
|
|
}
|