all repos — paprika @ 3adf7461370de0257a5e26992348586815ceca07

go rewrite of taigabot

version command
Anthony DeDominic adedomin@gmail.com
Sun, 16 Jan 2022 07:35:19 -0500
commit

3adf7461370de0257a5e26992348586815ceca07

parent

2e70eabfec188c44b6aba9721df4331a513d06f8

4 files changed, 173 insertions(+), 2 deletions(-)

jump to
M database/db.godatabase/db.go

@@ -56,6 +56,17 @@

return err } +// Wrapper function to simplify setting a key/val with a duration. +// see Set +func (d *database) SetWithTTL(key, val []byte, duration time.Duration) error { + err := d.Update(func(txn *badger.Txn) error { + err := txn.SetEntry(badger.NewEntry(key, val).WithTTL(duration)) + return err + }) + + return err +} + // Wrapper function to simplify getting a key from badger. func (d *database) Get(key []byte) ([]byte, error) { var val []byte

@@ -66,8 +77,8 @@ return err

} err = item.Value(func(v []byte) error { - val, err = item.ValueCopy(nil) - return err + val = v + return nil }) return err })

@@ -75,6 +86,60 @@ if err != nil {

return nil, err } return val, nil +} + +type KVPair struct { + a, b []byte +} + +// Wrapper function to simplify getting a range of keys with a given prefix. +func (d *database) GetRange(prefix []byte) ([]KVPair, error) { + var vals []KVPair + err := d.View(func(txn *badger.Txn) error { + iter := txn.NewIterator(badger.DefaultIteratorOptions) + defer iter.Close() + + for iter.Seek(prefix); iter.ValidForPrefix(prefix); iter.Next() { + item := iter.Item() + + var pair KVPair + key := item.Key() + pair.a = key + err := item.Value(func(val []byte) error { + pair.b = val + return nil + }) + + if err != nil { + return err + } + + vals = append(vals, pair) + } + + return nil + }) + if err != nil { + return nil, err + } + return vals, nil +} + +// Key delete wrapper. Returns deleted Value +func (d *database) Delete(key []byte) ([]byte, error) { + var val []byte + err := d.DB.Update(func(txn *badger.Txn) error { + item, err := txn.Get(key) + if err != nil { + return err + } + err = item.Value(func(v []byte) error { + val = v + return nil + }) + return txn.Delete(key) + }) + return val, err } var NumTooBig = errors.New("Number Too Big")
M main.gomain.go

@@ -56,14 +56,23 @@ func ircHandler(c *irc.Client, m *irc.Message) {

switch m.Command { case "001": c.Write(config.SplitChannelList(config.C.Channels)) + // TODO: Generalize this case "JOIN": response, err := plugins.GetIntro(m) + handleChatMessage(c, m, response, err) + // TODO: Generalize this + case "NOTICE": + response, err := plugins.CTCPReply(m) handleChatMessage(c, m, response, err) case "PRIVMSG": // Trim leading and trailing spaces to not trip up our // plugins. m.Params[1] = strings.TrimSpace(m.Params[1]) response, err := plugins.ProcessTrigger(m) + handleChatMessage(c, m, response, err) + // TODO: Generalize this + case "401": + response, err := plugins.NoSuchUser(m) handleChatMessage(c, m, response, err) } }
M plugins/plugins.goplugins/plugins.go

@@ -79,6 +79,15 @@ sym > 58 /* : */ && sym < 65 /* A */ ||

sym == 126 /* ~ */ } +func likelyInvalidNick(nick string) bool { + for i := 0; i < len(nick); i++ { + if likelyInvalidNickChr(nick[i]) { + return true + } + } + return false +} + // Checks for triggers in a message and executes its // corresponding plugin, returning the response/error. func ProcessTrigger(m *irc.Message) (string, error) {
A plugins/version.go

@@ -0,0 +1,88 @@

+package plugins + +import ( + "fmt" + "strings" + "time" + + "git.icyphox.sh/paprika/database" + "github.com/dgraph-io/badger/v3" + "gopkg.in/irc.v3" +) + +func init() { + Register(Version{}) +} + +type Version struct{} + +func (Version) Triggers() []string { + return []string{".v", ".version"} +} + +func (Version) Execute(m *irc.Message) (string, error) { + params := strings.SplitN(m.Trailing(), " ", 3) + if len(params) != 2 { + return fmt.Sprintf("Usage: %s <nick>", params[0]), nil + } + + nickTarget := params[1] + if likelyInvalidNick(nickTarget) { + return fmt.Sprintf("%s does not look like an IRC Nick", nickTarget), nil + } + + replyTarget := m.Params[0] + err := database.DB.SetWithTTL( + []byte(nickTarget), + []byte(replyTarget), + 2 * time.Minute, + ) + if err != nil { + return "", err + } + + m.Params[0] = nickTarget + return "\x01VERSION\x01", nil +} + +func CTCPReply(m *irc.Message) (string, error) { + msg := m.Trailing() + if !strings.HasPrefix(msg, "\x01VERSION") { + return "", NoReply + } + + params := strings.SplitN(msg, " ", 2) + if len(params) != 2 { + return "", NoReply + } + if len(params[1]) == 0 { + return "", NoReply + } + + ver := params[1][:len(params[1])-1] + from := m.Name + + newTarget, err := database.DB.Delete([]byte(from)) + if err != nil { + return "", err + } + + m.Params[0] = string(newTarget) + m.Command = "PRIVMSG" + return fmt.Sprintf("%s VERSION: %s", from, ver), nil +} + +func NoSuchUser(m *irc.Message) (string, error) { + invalidNick := m.Params[1] + newTarget, err := database.DB.Delete([]byte(invalidNick)) + if err == badger.ErrKeyNotFound { + return "", NoReply + } else if err != nil { + return "", err + } + + m.Command = "PRIVMSG" + m.Params[0] = string(newTarget) + m.Params = m.Params[:1] + return fmt.Sprintf("No such nickname: %s", invalidNick), nil +}