func init() { runtime.GOMAXPROCS(runtime.NumCPU()) var err error if err = core.Bootstrap(); err != nil { log.Fatalln(err) } core.Version = TmailVersion // Check base path structure requiredPaths := []string{"db", "nsq", "ssl"} for _, p := range requiredPaths { if err = os.MkdirAll(path.Join(core.GetBasePath(), p), 0700); err != nil { log.Fatalln("Unable to create path "+path.Join(core.GetBasePath(), p), " - ", err.Error()) } } // TODO: if clusterMode check if nsqlookupd is available // check DB // TODO: do check in CLI call (raise error & ask for user to run tmail initdb|checkdb) if !core.IsOkDB(core.DB) { var r []byte for { fmt.Printf("Database 'driver: %s, source: %s' misses some tables.\r\nShould i create them ? (y/n):", core.Cfg.GetDbDriver(), core.Cfg.GetDbSource()) r, _, _ = bufio.NewReader(os.Stdin).ReadLine() if r[0] == 110 || r[0] == 121 { break } } if r[0] == 121 { if err = core.InitDB(core.DB); err != nil { log.Fatalln(err) } } else { log.Println("See you soon...") os.Exit(0) } } // sync tables from structs if err := core.AutoMigrateDB(core.DB); err != nil { log.Fatalln(err) } // init rand seed rand.Seed(time.Now().UTC().UnixNano()) // Dovecot support if core.Cfg.GetDovecotSupportEnabled() { _, err := exec.LookPath(core.Cfg.GetDovecotLda()) if err != nil { log.Fatalln("Unable to find Dovecot LDA binary, checks your config poarameter TMAIL_DOVECOT_LDA ", err) } } }
// MAIN func main() { var err error app := cli.NewApp() app.Name = "tmail" app.Usage = "SMTP server" app.Author = "Stéphane Depierrepont aka toorop" app.Email = "*****@*****.**" app.Version = TmailVersion app.Commands = tcli.CliCommands // no know command ? Launch server app.Action = func(c *cli.Context) { if len(c.Args()) != 0 { cli.ShowAppHelp(c) } else { // if there is nothing to do then... do nothing if !core.Cfg.GetLaunchDeliverd() && !core.Cfg.GetLaunchSmtpd() { log.Fatalln("I have nothing to do, so i do nothing. Bye.") } // Init Bolt (used as cache) if err = core.InitBolt(); err != nil { log.Fatalln("Init bolt failed", err) } // Loop sigChan := make(chan os.Signal, 1) signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM) // TODO // Chanel to comunicate between all elements //daChan := make(chan string) // init and launch nsqd opts := nsqd.NewOptions() opts.Logger = log.New(ioutil.Discard, "", 0) if core.Cfg.GetDebugEnabled() { opts.Logger = core.Log } opts.Verbose = core.Cfg.GetDebugEnabled() opts.DataPath = core.GetBasePath() + "/nsq" // if cluster get lookupd addresses if core.Cfg.GetClusterModeEnabled() { opts.NSQLookupdTCPAddresses = core.Cfg.GetNSQLookupdTcpAddresses() } // deflate (compression) opts.DeflateEnabled = true // if a message timeout it returns to the queue: https://groups.google.com/d/msg/nsq-users/xBQF1q4srUM/kX22TIoIs-QJ // msg timeout : base time to wait from consummer before requeuing a message // note: deliverd consumer return immediatly (message is handled in a go routine) // Ce qui est au dessus est faux malgres la go routine il attends toujours a la réponse // et c'est normal car le message est toujours "in flight" // En fait ce timeout c'est le temps durant lequel le message peut rester dans le state "in flight" // autrement dit c'est le temps maxi que peu prendre deliverd.processMsg opts.MsgTimeout = 10 * time.Minute // maximum duration before a message will timeout opts.MaxMsgTimeout = 15 * time.Hour // maximum requeuing timeout for a message // si le client ne demande pas de requeue dans ce delais alors // le message et considéré comme traité opts.MaxReqTimeout = 1 * time.Hour // Number of message in RAM before synching to disk opts.MemQueueSize = 0 nsqd := nsqd.New(opts) nsqd.LoadMetadata() if err = nsqd.PersistMetadata(); err != nil { log.Fatalf("ERROR: failed to persist metadata - %s", err.Error()) } nsqd.Main() // smtpd if core.Cfg.GetLaunchSmtpd() { // clamav ? if core.Cfg.GetSmtpdClamavEnabled() { if err = core.NewClamav().Ping(); err != nil { log.Fatalln("Unable to connect to clamd -", err) } } smtpdDsns, err := core.GetDsnsFromString(core.Cfg.GetSmtpdDsns()) if err != nil { log.Fatalln("unable to parse smtpd dsn -", err) } for _, dsn := range smtpdDsns { go core.NewSmtpd(dsn).ListenAndServe() // TODO at this point we don't know if serveur is launched core.Log.Info("smtpd " + dsn.String() + " launched.") } } // deliverd go core.LaunchDeliverd() // HTTP REST server if core.Cfg.GetRestServerLaunch() { go rest.LaunchServer() } <-sigChan core.Log.Info("Exiting...") // close NsqQueueProducer if exists core.NsqQueueProducer.Stop() // flush nsqd memory to disk nsqd.Exit() // exit os.Exit(0) } } app.Run(os.Args) }