marvin

A simple and modular IRC bot

git clone https://git.8pit.net/marvin.git

  1// This program is free software: you can redistribute it and/or modify
  2// it under the terms of the GNU Affero General Public License as
  3// published by the Free Software Foundation, either version 3 of the
  4// License, or (at your option) any later version.
  5//
  6// This program is distributed in the hope that it will be useful, but
  7// WITHOUT ANY WARRANTY; without even the implied warranty of
  8// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  9// Affero General Public License for more details.
 10//
 11// You should have received a copy of the GNU Affero General Public
 12// License along with this program. If not, see <http://www.gnu.org/licenses/>.
 13
 14package modules
 15
 16import (
 17	"encoding/json"
 18	"fmt"
 19	"github.com/nmeum/marvin/irc"
 20	"io/ioutil"
 21	"os"
 22	"path/filepath"
 23	"strings"
 24)
 25
 26type Module interface {
 27	Name() string
 28	Help() string
 29	Load(*irc.Client) error
 30	Defaults()
 31}
 32
 33type ModuleSet struct {
 34	client  *irc.Client
 35	modules []Module
 36	configs string
 37}
 38
 39func NewModuleSet(client *irc.Client, configs string) *ModuleSet {
 40	return &ModuleSet{client: client, configs: configs}
 41}
 42
 43func (m *ModuleSet) Register(module Module) {
 44	m.modules = append(m.modules, module)
 45}
 46
 47func (m *ModuleSet) LoadAll() error {
 48	if err := os.MkdirAll(m.configs, 0755); err != nil {
 49		return err
 50	}
 51
 52	for _, module := range m.modules {
 53		fn := fmt.Sprintf("%s.json", module.Name())
 54		fp := filepath.Join(m.configs, fn)
 55
 56		module.Defaults()
 57		data, err := ioutil.ReadFile(fp)
 58		if err == nil {
 59			if err := json.Unmarshal(data, &module); err != nil {
 60				return err
 61			}
 62		} else if !os.IsNotExist(err) {
 63			return err
 64		}
 65
 66		if err := module.Load(m.client); err != nil {
 67			return err
 68		}
 69	}
 70
 71	m.client.CmdHook("privmsg", m.helpCmd)
 72	m.client.CmdHook("privmsg", m.moduleCmd)
 73	m.client.CmdHook("privmsg", m.modulesCmd)
 74
 75	return nil
 76}
 77
 78func (m *ModuleSet) findModule(name string) Module {
 79	for _, module := range m.modules {
 80		if module.Name() == name {
 81			return module
 82		}
 83	}
 84
 85	return nil
 86}
 87
 88func (m *ModuleSet) helpCmd(client *irc.Client, msg irc.Message) error {
 89	if msg.Data != "!help" {
 90		return nil
 91	}
 92
 93	return client.Write("NOTICE %s :%s", msg.Receiver,
 94		"Use !help MODULE to see the help message for the given module, use !modules to list all modules.")
 95}
 96
 97func (m *ModuleSet) modulesCmd(client *irc.Client, msg irc.Message) error {
 98	if msg.Data != "!modules" || len(m.modules) <= 0 {
 99		return nil
100	}
101
102	var names []string
103	for _, module := range m.modules {
104		names = append(names, module.Name())
105	}
106
107	help := fmt.Sprintf("The following modules are available: %s",
108		strings.Join(names, ", "))
109
110	return client.Write("NOTICE %s :%s", msg.Receiver, help)
111}
112
113func (m *ModuleSet) moduleCmd(client *irc.Client, msg irc.Message) error {
114	splited := strings.Fields(msg.Data)
115	if len(splited) < 2 || splited[0] != "!help" {
116		return nil
117	}
118
119	name := strings.ToLower(splited[1])
120	module := m.findModule(name)
121	if module == nil {
122		return client.Write("NOTICE %s :Module %q isn't installed",
123			msg.Receiver, name)
124	}
125
126	return client.Write("NOTICE %s :%s: %s",
127		msg.Receiver, module.Name(), module.Help())
128}