package main import ( "flag" "fmt" "github.com/deckarep/golang-set" "github.com/fsnotify/fsnotify" "github.com/irccloud/irccat/httplistener" "github.com/irccloud/irccat/tcplistener" "github.com/juju/loggo" "github.com/spf13/viper" "github.com/thoj/go-ircevent" "os" "os/signal" "strings" "syscall" ) var log = loggo.GetLogger("main") var branch string var revision string var CONFIG_FILE_LOCATIONS = []string{ "/etc", "/run/secrets", ".", } type IRCCat struct { auth_channel string channels mapset.Set auth_users map[string]bool irc *irc.Connection tcp *tcplistener.TCPListener signals chan os.Signal } func main() { debug := flag.Bool("debug", false, "Print raw IRC lines") configFile := flag.String("config", "", "Path to config file to use") flag.Parse() loggo.ConfigureLoggers("=INFO") log.Infof("IRCCat %s (%s) starting...", branch, revision) if *configFile != "" { viper.SetConfigFile(*configFile) } else { viper.SetConfigName("irccat") for _, p := range CONFIG_FILE_LOCATIONS { viper.AddConfigPath(p) } } var err error err = viper.ReadInConfig() if err != nil { log.Errorf("Error reading config file - exiting. I'm looking for irccat.[json|yaml|toml|hcl] in one of %s", strings.Join(CONFIG_FILE_LOCATIONS, ", ")) return } irccat := IRCCat{auth_users: map[string]bool{}, signals: make(chan os.Signal, 1), channels: mapset.NewSet(), auth_channel: viper.GetString("commands.auth_channel")} viper.WatchConfig() viper.OnConfigChange(irccat.handleConfigChange) signal.Notify(irccat.signals, os.Interrupt, syscall.SIGINT, syscall.SIGTERM) go irccat.signalHandler() err = irccat.connectIRC(*debug) if err != nil { log.Criticalf("Error connecting to IRC server: %s", err) return } if viper.IsSet("tcp.listen") { irccat.tcp, err = tcplistener.New() if err != nil { log.Criticalf("Error starting TCP listener: %s", err) return } irccat.tcp.Run(irccat.irc) } if viper.IsSet("http") { httplistener.New(irccat.irc) } irccat.irc.Loop() } func (i *IRCCat) signalHandler() { sig := <-i.signals log.Infof("Exiting on %s", sig) i.irc.QuitMessage = fmt.Sprintf("Exiting on %s", sig) i.irc.Quit() } func (i *IRCCat) handleConfigChange(e fsnotify.Event) { log.Infof("Reloaded config") new_channels := mapset.NewSet() for _, channel := range viper.GetStringSlice("irc.channels") { new_channels.Add(channel) if !i.channels.Contains(channel) { log.Infof("Joining new channel %s", channel) i.irc.Join(channel) i.channels.Add(channel) } } it := i.channels.Difference(new_channels).Iterator() for channel := range it.C { log.Infof("Leaving channel %s", channel) i.irc.Part(channel.(string)) i.channels.Remove(channel) } }