// moduleExited is called when a module process has exited. If an error was returned when exiting // it will be logged. The output (Stdout and Stderr) is also logged. If the module exists in the // handler it will be removed. The module is also unregistered from the bot. func (b *Bot) moduleExited(name string, result *Result) { b.Mu.Lock() defer b.Mu.Unlock() if result.Err != nil { rlog.Error("Bot", name+" [Module Process] has exited with: "+result.Err.Error()) } else { rlog.Info("Bot", "Module "+name+" [Module Process] has exited") } if result.Output != "" { rlog.Info(name, "Process output:"+"\n ----\n"+result.Output+"\n ----\n") } if b.Handler.ModuleExists(name) { // If the module process is dead we can rest assured signalling it to clean up will fail // so we won't even try. It's the sanest thing to do! b.Handler.RemoveModule(ModuleName(name)) } if !b.Modules[name].Registered { rlog.Error("Bot", name+" [Module Client] did not manage to register") } else { b.Modules[name].Registered = false rlog.Info("Bot", name+" [Module Client] has been unregistered from the bot") } }
func (c CliClient) Listen() { var err error rl, err = readline.New(" » ") if err != nil { panic(err) } defer rl.Close() rlog.SetOutput(rl.Stdout()) for { line, err := rl.Readline() if len(line) == 0 { continue } if err != nil { break } raw := ":RainBot " + irc.PRIVMSG + " #cli :" + line msg := irc.ParseMessage(raw) if err != nil { rlog.Error("cli", err.Error()) } c.Emit(irc.PRIVMSG, msg) } }
// ModuleReload will reload a module by telling the handler to signal a kill cleanup to the module // being reloaded. If the module refuses to be killed for whatever reason, reloading of the module // will be aborted. If the module complies, the module's corresponding process will be killed. The // module will then be recompiled if need be and will be restarted after. func (b *Bot) ModuleReload(name string) (err error) { module, ok := b.Modules[strings.ToLower(name)] if !ok { return errors.New("Module is unknown to the bot") } if module.PM.IsRunning() { err = b.Handler.SignalCleanup(ModuleName(name)) if err != nil { rlog.Error("Bot", "Error while cleaning up module "+name+": "+err.Error()) return errors.New("Module did not cleanup, aborting reload") } module.PM.Kill() <-module.PM.Wait() } res := module.PM.Recompile() if res != nil && res.Err != nil { rlog.Errorf("Bot", "Could not recompile module %s\n ----\n%s\n ----\n\n", module.Name, res.Output) return errors.New("Could not recompile module") } b.moduleStart(name) return nil }
// startRPCServer registers the master consumer for plugins. The master consumer allows plugins to // communicate with the bot, allowing access to connected channels, users and registered modules. // Conventionally, it uses a json codec to serve. func (b *Bot) startRPCServer() { rpc.RegisterName("Master", BotAPI{b}) master, err := net.Listen("tcp", ":0") b.ListenPort = strconv.Itoa(master.Addr().(*net.TCPAddr).Port) rlog.Info("Bot", "Listening on port: "+b.ListenPort) if err != nil { rlog.Error("Bot", err.Error()) } // Start accepting connections go func() { for { conn, _ := master.Accept() go rpc.ServeCodec(RpcCodecServer(conn)) } }() }
// Register registers a module with the bot. With the given port number in the Ticket, the bot // creates a new rpc provider client connection to the module. The module is kept in the handler // for event dispatching and module management. func (b BotAPI) Register(t Ticket, result *string) error { rlog.Debug("Bot", "Starting registration for "+t.ModuleName+" [Module Client]") client, err := RpcCodecClientWithPort(t.Port) if err != nil { rlog.Error("Bot", "Could not establish an RPC client: "+err.Error()) return err } module := rpc.NewClientWithCodec(client) if module == nil { rlog.Warn("Bot", "Could not register:"+t.ModuleName) return errors.New("Failed to regsiter module") } b.bot.Handler.AddModule(ModuleName(strings.ToLower(t.ModuleName)), module) b.bot.Modules[strings.ToLower(t.ModuleName)].Registered = true rlog.Debug("Bot", "Registered "+t.ModuleName+" on port "+t.Port) return nil }
func check(err error) { if err != nil { rlog.Error("Config", "Could not correctly parse the configuration, check your syntax :::") panic(err) } }