func Connect() bool { lock.Lock() defer lock.Unlock() if irc == nil { logging.Fatal("Called Connect() before Init().") } return connectLoop() }
func (m *mongoDatabase) C(name string) Collection { m.Lock() defer m.Unlock() if m.sessions == nil { logging.Fatal("Tried to create MongoDB collection %q when disconnected.", name) } s := m.sessions[0].Copy() m.sessions = append(m.sessions, s) return &mongoCollection{Collection: s.DB(DATABASE).C(name)} }
func (b *boltDatabase) C(name string) Collection { b.Lock() defer b.Unlock() if b.db == nil { logging.Fatal("Tried to create BoltDB bucket %q when disconnected.", name) } err := b.db.Update(func(tx *bolt.Tx) error { if _, err := tx.CreateBucketIfNotExists([]byte(name)); err != nil { return err } return nil }) if err != nil { logging.Fatal("Creating BoltDB bucket failed: %v") } return &boltBucket{name: []byte(name), db: b.db} }
func Shutdown() { lock.Lock() defer lock.Unlock() if bot == nil { logging.Fatal("Called Shutdown() before Init().") } if !bot.connected { logging.Warn("Not connected to servers.") } bot.connected = false bot.servers.Shutdown(false) }
func Connect() chan bool { lock.Lock() defer lock.Unlock() if bot == nil { logging.Fatal("Called Connect() before Init().") } if bot.connected { logging.Warn("Already connected to servers.") } bot.connected = true return bot.servers.Connect() }
// Wraps connecting to mongo and selecting the "sp0rkle" database. func Init() *mgo.Database { lock.Lock() defer lock.Unlock() if db != nil { return db } s, err := mgo.Dial(*database) if err != nil { logging.Fatal("Unable to connect to MongoDB: %s", err) } session, db = s, s.DB(DATABASE) // Let's be explicit about requiring journaling, ehh? session.EnsureSafe(&mgo.Safe{J: true}) return db }
func Client(cfg *Config) *Conn { logging.InitFromFlags() if cfg == nil || cfg.Me == nil || cfg.Me.Nick == "" || cfg.Me.Ident == "" { logging.Fatal("irc.Client(): Both cfg.Nick and cfg.Ident must be non-empty.") } conn := &Conn{ cfg: cfg, in: make(chan *Line, 32), out: make(chan string, 32), handlers: handlerSet(), stRemovers: make([]Remover, 0, len(stHandlers)), lastsent: time.Now(), } conn.addIntHandlers() conn.initialise() return conn }
func (b *boltDatabase) backupLoop() { if err := os.MkdirAll(b.dir, 0700); err != nil { logging.Fatal("Could not create backup dir %q: %v", b.dir, err) } // Do a backup on startup, too. b.doBackup() tick := time.NewTicker(b.every) for { select { case <-tick.C: b.doBackup() case <-b.quit: tick.Stop() return } } }
// Wraps connecting to mongo and selecting the "sp0rkle" database. func Init() *mgo.Database { lock.Lock() defer lock.Unlock() if sessions != nil { // Give each caller a distinct session to avoid contention. s := sessions[0].Copy() sessions = append(sessions, s) return s.DB(DATABASE) } sessions = make([]*mgo.Session, 1) s, err := mgo.Dial(*database) if err != nil { logging.Fatal("Unable to connect to MongoDB: %s", err) } // Let's be explicit about requiring journaling, ehh? s.EnsureSafe(&mgo.Safe{J: true}) sessions[0] = s return s.DB(DATABASE) }
func main() { flag.Parse() logging.InitFromFlags() // Initialise bot state bot.Init() // Connect to mongo db.Init() defer db.Close() // Add drivers calcdriver.Init() decisiondriver.Init() factdriver.Init() karmadriver.Init() markovdriver.Init() quotedriver.Init() reminddriver.Init() seendriver.Init() urldriver.Init() // Start up the HTTP server go http.ListenAndServe(*httpPort, nil) // Connect the bot to IRC and wait; reconnects are handled automatically. // If we get true back from the bot, re-exec the (rebuilt) binary. if bot.Connect() { // Calling syscall.Exec probably means deferred functions won't get // called, so disconnect from mongodb first for politeness' sake. db.Close() // If sp0rkle was run from PATH, we need to do that lookup manually. fq, _ := exec.LookPath(os.Args[0]) logging.Warn("Re-executing sp0rkle with args '%v'.", os.Args) err := syscall.Exec(fq, os.Args, os.Environ()) if err != nil { // hmmmmmm logging.Fatal("Couldn't re-exec sp0rkle: %v", err) } } logging.Info("Shutting down cleanly.") }
func Init() { uc = urls.Init() if err := os.MkdirAll(*urlCacheDir, 0700); err != nil { logging.Fatal("Couldn't create URL cache dir: %v", err) } bot.Handle(urlScan, client.PRIVMSG) bot.Command(find, "urlfind", "urlfind <regex> -- "+ "searches for previously mentioned URLs matching <regex>") bot.Command(find, "url find", "url find <regex> -- "+ "searches for previously mentioned URLs matching <regex>") bot.Command(find, "urlsearch", "urlsearch <regex> -- "+ "searches for previously mentioned URLs matching <regex>") bot.Command(find, "url search", "url search <regex> -- "+ "searches for previously mentioned URLs matching <regex>") bot.Command(find, "randurl", "randurl -- displays a random URL") bot.Command(find, "random url", "random url -- displays a random URL") bot.Command(shorten, "shorten that", "shorten that -- "+ "shortens the last mentioned URL.") bot.Command(shorten, "shorten", "shorten <url> -- shortens <url>") bot.Command(cache, "cache that", "cache that -- "+ "caches the last mentioned URL.") bot.Command(cache, "cache", "cache <url> -- caches <url>") bot.Command(cache, "save that", "save that -- "+ "caches the last mentioned URL.") bot.Command(cache, "save", "save <url> -- caches <url>") // This serves "shortened" urls http.Handle(shortenPath, http.StripPrefix(shortenPath, http.HandlerFunc(shortenedServer))) // This serves "cached" urls http.Handle(cachePath, http.StripPrefix(cachePath, http.FileServer(http.Dir(*urlCacheDir)))) }
func loadModules(conn *irc.Conn) (modules []IModule) { // Load each module in the modules directory scripts, err := ioutil.ReadDir("modules") if err != nil { log.Fatal(err.Error()) } // Read base module script file, err := os.Open("module.js") if err != nil { log.Fatal("Error reading base module script:", err) } defer file.Close() baseScript, err := ioutil.ReadAll(file) if err != nil { log.Fatal("Error reading base module script:", err) } for _, fileInfo := range scripts { if !fileInfo.IsDir() { if !strings.HasSuffix(fileInfo.Name(), "js") { continue } filename := "modules/" + fileInfo.Name() file, err := os.Open(filename) if err != nil { log.Error("Error loading module:", err) continue } defer file.Close() script, err := ioutil.ReadAll(file) if err != nil { log.Error("Error loading module:", err) continue } module := NewModule(fileInfo.Name(), conn) // Init module with base script and its own script ret, err := module.Init(v8.NewContext(), string(baseScript)+string(script)) if err != nil { log.Error("Error loading module: %s\n%s", err, ret) continue } // Create file watcher watcher, err := fsnotify.NewWatcher() if err != nil { log.Error("Error creating file watcher for %s:", fileInfo.Name(), err) } watcher.Watch(filename) go func(filename string) { for { select { case ev := <-watcher.Event: watcher.Watch(filename) // Make sure we continue to watch the file at this location if !ev.IsModify() { // Only reload the module on a modification event continue } case err := <-watcher.Error: log.Error("Error watching file: %s", filename, err) continue } // Reload script log.Info("Reloading %s", filename) file, err := os.Open(filename) if err != nil { log.Error("Error loading module:", err) continue } defer file.Close() script, err := ioutil.ReadAll(file) if err != nil { log.Error("Error loading module:", err) continue } ret, err := module.Init(v8.NewContext(), string(baseScript)+string(script)) if err != nil { log.Error("Error reloading module: %s\n%s", err, ret) } } }(filename) log.Info("Loaded module %s", fileInfo.Name()) modules = append(modules, &module) } } return }
func main() { flag.Parse() logging.InitFromFlags() golog.Init() // Slightly more random than 1. rand.Seed(time.Now().UnixNano() * int64(os.Getpid())) // Initialise bot state bot.Init() // Connect to mongo db.Init() defer db.Close() // Add drivers calcdriver.Init() decisiondriver.Init() factdriver.Init() karmadriver.Init() markovdriver.Init() netdriver.Init() quotedriver.Init() reminddriver.Init() seendriver.Init() statsdriver.Init() urldriver.Init() // Start up the HTTP server go http.ListenAndServe(*httpPort, nil) // Set up a signal handler to shut things down gracefully. // NOTE: net/http doesn't provide for graceful shutdown :-/ go func() { called := new(int32) sigint := make(chan os.Signal, 1) signal.Notify(sigint, syscall.SIGINT) for _ = range sigint { if atomic.AddInt32(called, 1) > 1 { logging.Fatal("Recieved multiple interrupts, dying.") } bot.Shutdown() } }() // Connect the bot to IRC and wait; reconnects are handled automatically. // If we get true back from the bot, re-exec the (rebuilt) binary. if <-bot.Connect() { // Calling syscall.Exec probably means deferred functions won't get // called, so disconnect from mongodb first for politeness' sake. db.Close() // If sp0rkle was run from PATH, we need to do that lookup manually. fq, _ := exec.LookPath(os.Args[0]) logging.Warn("Re-executing sp0rkle with args '%v'.", os.Args) err := syscall.Exec(fq, os.Args, os.Environ()) if err != nil { // hmmmmmm logging.Fatal("Couldn't re-exec sp0rkle: %v", err) } } logging.Info("Shutting down cleanly.") }