Add agent => bot
This commit is contained in:
22
agent/input/discord/README.md
Normal file
22
agent/input/discord/README.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# Discord input for micro-bot
|
||||
[Discord](https://discordapp.com) support for micro bot based on [discordgo](github.com/bwmarrin/discordgo).
|
||||
|
||||
This was originally written by Aleksandr Tihomirov (@zet4) and can be found at https://github.com/zet4/micro-misc/.
|
||||
|
||||
## Options
|
||||
### discord_token
|
||||
|
||||
You have to supply an application token via `--discord_token`.
|
||||
|
||||
Head over to Discord's [developer introduction](https://discordapp.com/developers/docs/intro)
|
||||
to learn how to create applications and how the API works.
|
||||
|
||||
### discord_prefix
|
||||
|
||||
Set a command prefix with `--discord_prefix`. The default prefix is `Micro `.
|
||||
You can mention the bot or use the prefix to run a command.
|
||||
|
||||
### discord_whitelist
|
||||
|
||||
Pass a list of comma-separated user IDs with `--discord_whitelist`. Only allow
|
||||
these users to use the bot.
|
94
agent/input/discord/conn.go
Normal file
94
agent/input/discord/conn.go
Normal file
@@ -0,0 +1,94 @@
|
||||
package discord
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/bwmarrin/discordgo"
|
||||
"github.com/micro/go-micro/agent/input"
|
||||
"github.com/micro/go-log"
|
||||
)
|
||||
|
||||
type discordConn struct {
|
||||
master *discordInput
|
||||
exit chan struct{}
|
||||
recv chan *discordgo.Message
|
||||
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
func newConn(master *discordInput) *discordConn {
|
||||
conn := &discordConn{
|
||||
master: master,
|
||||
exit: make(chan struct{}),
|
||||
recv: make(chan *discordgo.Message),
|
||||
}
|
||||
|
||||
conn.master.session.AddHandler(func(s *discordgo.Session, m *discordgo.MessageCreate) {
|
||||
if m.Author.ID == master.botID {
|
||||
return
|
||||
}
|
||||
|
||||
whitelisted := false
|
||||
for _, ID := range conn.master.whitelist {
|
||||
if m.Author.ID == ID {
|
||||
whitelisted = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if len(master.whitelist) > 0 && !whitelisted {
|
||||
return
|
||||
}
|
||||
|
||||
var valid bool
|
||||
m.Message.Content, valid = conn.master.prefixfn(m.Message.Content)
|
||||
if !valid {
|
||||
return
|
||||
}
|
||||
|
||||
conn.recv <- m.Message
|
||||
})
|
||||
|
||||
return conn
|
||||
}
|
||||
|
||||
func (dc *discordConn) Recv(event *input.Event) error {
|
||||
for {
|
||||
select {
|
||||
case <-dc.exit:
|
||||
return errors.New("connection closed")
|
||||
case msg := <-dc.recv:
|
||||
|
||||
event.From = msg.ChannelID + ":" + msg.Author.ID
|
||||
event.To = dc.master.botID
|
||||
event.Type = input.TextEvent
|
||||
event.Data = []byte(msg.Content)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (dc *discordConn) Send(e *input.Event) error {
|
||||
fields := strings.Split(e.To, ":")
|
||||
_, err := dc.master.session.ChannelMessageSend(fields[0], string(e.Data))
|
||||
if err != nil {
|
||||
log.Log("[bot][loop][send]", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dc *discordConn) Close() error {
|
||||
if err := dc.master.session.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
select {
|
||||
case <-dc.exit:
|
||||
return nil
|
||||
default:
|
||||
close(dc.exit)
|
||||
}
|
||||
return nil
|
||||
}
|
153
agent/input/discord/discord.go
Normal file
153
agent/input/discord/discord.go
Normal file
@@ -0,0 +1,153 @@
|
||||
package discord
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"github.com/bwmarrin/discordgo"
|
||||
"github.com/micro/cli"
|
||||
"github.com/micro/go-micro/agent/input"
|
||||
)
|
||||
|
||||
func init() {
|
||||
input.Inputs["discord"] = newInput()
|
||||
}
|
||||
|
||||
func newInput() *discordInput {
|
||||
return &discordInput{}
|
||||
}
|
||||
|
||||
type discordInput struct {
|
||||
token string
|
||||
whitelist []string
|
||||
prefix string
|
||||
prefixfn func(string) (string, bool)
|
||||
botID string
|
||||
|
||||
session *discordgo.Session
|
||||
|
||||
sync.Mutex
|
||||
running bool
|
||||
exit chan struct{}
|
||||
}
|
||||
|
||||
func (d *discordInput) Flags() []cli.Flag {
|
||||
return []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "discord_token",
|
||||
EnvVar: "MICRO_DISCORD_TOKEN",
|
||||
Usage: "Discord token (prefix with Bot if it's for bot account)",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "discord_whitelist",
|
||||
EnvVar: "MICRO_DISCORD_WHITELIST",
|
||||
Usage: "Discord Whitelist (seperated by ,)",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "discord_prefix",
|
||||
Usage: "Discord Prefix",
|
||||
EnvVar: "MICRO_DISCORD_PREFIX",
|
||||
Value: "Micro ",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (d *discordInput) Init(ctx *cli.Context) error {
|
||||
token := ctx.String("discord_token")
|
||||
whitelist := ctx.String("discord_whitelist")
|
||||
prefix := ctx.String("discord_prefix")
|
||||
|
||||
if len(token) == 0 {
|
||||
return errors.New("require token")
|
||||
}
|
||||
|
||||
d.token = token
|
||||
d.prefix = prefix
|
||||
|
||||
if len(whitelist) > 0 {
|
||||
d.whitelist = strings.Split(whitelist, ",")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *discordInput) Start() error {
|
||||
if len(d.token) == 0 {
|
||||
return errors.New("missing discord configuration")
|
||||
}
|
||||
|
||||
d.Lock()
|
||||
defer d.Unlock()
|
||||
|
||||
if d.running {
|
||||
return nil
|
||||
}
|
||||
|
||||
var err error
|
||||
d.session, err = discordgo.New(d.token)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
u, err := d.session.User("@me")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
d.botID = u.ID
|
||||
d.prefixfn = CheckPrefixFactory(fmt.Sprintf("<@%s> ", d.botID), fmt.Sprintf("<@!%s> ", d.botID), d.prefix)
|
||||
|
||||
d.exit = make(chan struct{})
|
||||
d.running = true
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *discordInput) Stream() (input.Conn, error) {
|
||||
d.Lock()
|
||||
defer d.Unlock()
|
||||
if !d.running {
|
||||
return nil, errors.New("not running")
|
||||
}
|
||||
|
||||
//Fire-n-forget close just in case...
|
||||
d.session.Close()
|
||||
|
||||
conn := newConn(d)
|
||||
if err := d.session.Open(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func (d *discordInput) Stop() error {
|
||||
d.Lock()
|
||||
defer d.Unlock()
|
||||
|
||||
if !d.running {
|
||||
return nil
|
||||
}
|
||||
|
||||
close(d.exit)
|
||||
d.running = false
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *discordInput) String() string {
|
||||
return "discord"
|
||||
}
|
||||
|
||||
// CheckPrefixFactory Creates a prefix checking function and stuff.
|
||||
func CheckPrefixFactory(prefixes ...string) func(string) (string, bool) {
|
||||
return func(content string) (string, bool) {
|
||||
for _, prefix := range prefixes {
|
||||
if strings.HasPrefix(content, prefix) {
|
||||
return strings.TrimPrefix(content, prefix), true
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user