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
|
||||
}
|
||||
}
|
55
agent/input/input.go
Normal file
55
agent/input/input.go
Normal file
@@ -0,0 +1,55 @@
|
||||
// Package input is an interface for bot inputs
|
||||
package input
|
||||
|
||||
import (
|
||||
"github.com/micro/cli"
|
||||
)
|
||||
|
||||
type EventType string
|
||||
|
||||
const (
|
||||
TextEvent EventType = "text"
|
||||
)
|
||||
|
||||
var (
|
||||
// Inputs keyed by name
|
||||
// Example slack or hipchat
|
||||
Inputs = map[string]Input{}
|
||||
)
|
||||
|
||||
// Event is the unit sent and received
|
||||
type Event struct {
|
||||
Type EventType
|
||||
From string
|
||||
To string
|
||||
Data []byte
|
||||
Meta map[string]interface{}
|
||||
}
|
||||
|
||||
// Input is an interface for sources which
|
||||
// provide a way to communicate with the bot.
|
||||
// Slack, HipChat, XMPP, etc.
|
||||
type Input interface {
|
||||
// Provide cli flags
|
||||
Flags() []cli.Flag
|
||||
// Initialise input using cli context
|
||||
Init(*cli.Context) error
|
||||
// Stream events from the input
|
||||
Stream() (Conn, error)
|
||||
// Start the input
|
||||
Start() error
|
||||
// Stop the input
|
||||
Stop() error
|
||||
// name of the input
|
||||
String() string
|
||||
}
|
||||
|
||||
// Conn interface provides a way to
|
||||
// send and receive events. Send and
|
||||
// Recv both block until succeeding
|
||||
// or failing.
|
||||
type Conn interface {
|
||||
Close() error
|
||||
Recv(*Event) error
|
||||
Send(*Event) error
|
||||
}
|
160
agent/input/slack/conn.go
Normal file
160
agent/input/slack/conn.go
Normal file
@@ -0,0 +1,160 @@
|
||||
package slack
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/micro/go-micro/agent/input"
|
||||
"github.com/nlopes/slack"
|
||||
)
|
||||
|
||||
// Satisfies the input.Conn interface
|
||||
type slackConn struct {
|
||||
auth *slack.AuthTestResponse
|
||||
rtm *slack.RTM
|
||||
exit chan bool
|
||||
|
||||
sync.Mutex
|
||||
names map[string]string
|
||||
}
|
||||
|
||||
func (s *slackConn) run() {
|
||||
// func retrieves user names and maps to IDs
|
||||
setNames := func() {
|
||||
names := make(map[string]string)
|
||||
users, err := s.rtm.Client.GetUsers()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, user := range users {
|
||||
names[user.ID] = user.Name
|
||||
}
|
||||
|
||||
s.Lock()
|
||||
s.names = names
|
||||
s.Unlock()
|
||||
}
|
||||
|
||||
setNames()
|
||||
|
||||
t := time.NewTicker(time.Minute)
|
||||
defer t.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-s.exit:
|
||||
return
|
||||
case <-t.C:
|
||||
setNames()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *slackConn) getName(id string) string {
|
||||
s.Lock()
|
||||
name := s.names[id]
|
||||
s.Unlock()
|
||||
return name
|
||||
}
|
||||
|
||||
func (s *slackConn) Close() error {
|
||||
select {
|
||||
case <-s.exit:
|
||||
return nil
|
||||
default:
|
||||
close(s.exit)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *slackConn) Recv(event *input.Event) error {
|
||||
if event == nil {
|
||||
return errors.New("event cannot be nil")
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-s.exit:
|
||||
return errors.New("connection closed")
|
||||
case e := <-s.rtm.IncomingEvents:
|
||||
switch ev := e.Data.(type) {
|
||||
case *slack.MessageEvent:
|
||||
// only accept type message
|
||||
if ev.Type != "message" {
|
||||
continue
|
||||
}
|
||||
|
||||
// only accept DMs or messages to me
|
||||
switch {
|
||||
case strings.HasPrefix(ev.Channel, "D"):
|
||||
case strings.HasPrefix(ev.Text, s.auth.User):
|
||||
case strings.HasPrefix(ev.Text, fmt.Sprintf("<@%s>", s.auth.UserID)):
|
||||
default:
|
||||
continue
|
||||
}
|
||||
|
||||
// Strip username from text
|
||||
switch {
|
||||
case strings.HasPrefix(ev.Text, s.auth.User):
|
||||
args := strings.Split(ev.Text, " ")[1:]
|
||||
ev.Text = strings.Join(args, " ")
|
||||
event.To = s.auth.User
|
||||
case strings.HasPrefix(ev.Text, fmt.Sprintf("<@%s>", s.auth.UserID)):
|
||||
args := strings.Split(ev.Text, " ")[1:]
|
||||
ev.Text = strings.Join(args, " ")
|
||||
event.To = s.auth.UserID
|
||||
}
|
||||
|
||||
if event.Meta == nil {
|
||||
event.Meta = make(map[string]interface{})
|
||||
}
|
||||
|
||||
// fill in the blanks
|
||||
event.From = ev.Channel + ":" + ev.User
|
||||
event.Type = input.TextEvent
|
||||
event.Data = []byte(ev.Text)
|
||||
event.Meta["reply"] = ev
|
||||
return nil
|
||||
case *slack.InvalidAuthEvent:
|
||||
return errors.New("invalid credentials")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *slackConn) Send(event *input.Event) error {
|
||||
var channel, message, name string
|
||||
|
||||
if len(event.To) == 0 {
|
||||
return errors.New("require Event.To")
|
||||
}
|
||||
|
||||
parts := strings.Split(event.To, ":")
|
||||
|
||||
if len(parts) == 2 {
|
||||
channel = parts[0]
|
||||
name = s.getName(parts[1])
|
||||
// try using reply meta
|
||||
} else if ev, ok := event.Meta["reply"]; ok {
|
||||
channel = ev.(*slack.MessageEvent).Channel
|
||||
name = s.getName(ev.(*slack.MessageEvent).User)
|
||||
}
|
||||
|
||||
// don't know where to send the message
|
||||
if len(channel) == 0 {
|
||||
return errors.New("could not determine who message is to")
|
||||
}
|
||||
|
||||
if len(name) == 0 || strings.HasPrefix(channel, "D") {
|
||||
message = string(event.Data)
|
||||
} else {
|
||||
message = fmt.Sprintf("@%s: %s", name, string(event.Data))
|
||||
}
|
||||
|
||||
s.rtm.SendMessage(s.rtm.NewOutgoingMessage(message, channel))
|
||||
return nil
|
||||
}
|
147
agent/input/slack/slack.go
Normal file
147
agent/input/slack/slack.go
Normal file
@@ -0,0 +1,147 @@
|
||||
package slack
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync"
|
||||
|
||||
"github.com/micro/cli"
|
||||
"github.com/micro/go-micro/agent/input"
|
||||
"github.com/nlopes/slack"
|
||||
)
|
||||
|
||||
type slackInput struct {
|
||||
debug bool
|
||||
token string
|
||||
|
||||
sync.Mutex
|
||||
running bool
|
||||
exit chan bool
|
||||
|
||||
api *slack.Client
|
||||
}
|
||||
|
||||
func init() {
|
||||
input.Inputs["slack"] = NewInput()
|
||||
}
|
||||
|
||||
func (p *slackInput) Flags() []cli.Flag {
|
||||
return []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "slack_debug",
|
||||
Usage: "Slack debug output",
|
||||
EnvVar: "MICRO_SLACK_DEBUG",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "slack_token",
|
||||
Usage: "Slack token",
|
||||
EnvVar: "MICRO_SLACK_TOKEN",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (p *slackInput) Init(ctx *cli.Context) error {
|
||||
debug := ctx.Bool("slack_debug")
|
||||
token := ctx.String("slack_token")
|
||||
|
||||
if len(token) == 0 {
|
||||
return errors.New("missing slack token")
|
||||
}
|
||||
|
||||
p.debug = debug
|
||||
p.token = token
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *slackInput) Stream() (input.Conn, error) {
|
||||
p.Lock()
|
||||
defer p.Unlock()
|
||||
|
||||
if !p.running {
|
||||
return nil, errors.New("not running")
|
||||
}
|
||||
|
||||
// test auth
|
||||
auth, err := p.api.AuthTest()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rtm := p.api.NewRTM()
|
||||
exit := make(chan bool)
|
||||
|
||||
go rtm.ManageConnection()
|
||||
|
||||
go func() {
|
||||
select {
|
||||
case <-p.exit:
|
||||
select {
|
||||
case <-exit:
|
||||
return
|
||||
default:
|
||||
close(exit)
|
||||
}
|
||||
case <-exit:
|
||||
}
|
||||
|
||||
rtm.Disconnect()
|
||||
}()
|
||||
|
||||
conn := &slackConn{
|
||||
auth: auth,
|
||||
rtm: rtm,
|
||||
exit: exit,
|
||||
names: make(map[string]string),
|
||||
}
|
||||
|
||||
go conn.run()
|
||||
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func (p *slackInput) Start() error {
|
||||
if len(p.token) == 0 {
|
||||
return errors.New("missing slack token")
|
||||
}
|
||||
|
||||
p.Lock()
|
||||
defer p.Unlock()
|
||||
|
||||
if p.running {
|
||||
return nil
|
||||
}
|
||||
|
||||
api := slack.New(p.token, slack.OptionDebug(p.debug))
|
||||
|
||||
// test auth
|
||||
_, err := api.AuthTest()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p.api = api
|
||||
p.exit = make(chan bool)
|
||||
p.running = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *slackInput) Stop() error {
|
||||
p.Lock()
|
||||
defer p.Unlock()
|
||||
|
||||
if !p.running {
|
||||
return nil
|
||||
}
|
||||
|
||||
close(p.exit)
|
||||
p.running = false
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *slackInput) String() string {
|
||||
return "slack"
|
||||
}
|
||||
|
||||
func NewInput() input.Input {
|
||||
return &slackInput{}
|
||||
}
|
18
agent/input/telegram/README.md
Normal file
18
agent/input/telegram/README.md
Normal file
@@ -0,0 +1,18 @@
|
||||
# Telegram Messenger input for micro bot
|
||||
[Telegram](https://telegram.org) support for micro bot based on [telegram-bot-api](https://github.com/go-telegram-bot-api/telegram-bot-api).
|
||||
|
||||
## Options
|
||||
### --telegram_token (required)
|
||||
|
||||
Sets bot's token for interacting with API.
|
||||
|
||||
Head over to Telegram's [API documentation](https://core.telegram.org/bots/api)
|
||||
to learn how to create bots and how the API works.
|
||||
|
||||
### --telegram_debug
|
||||
|
||||
Sets the debug flag to make the bot's output verbose.
|
||||
|
||||
### --telegram_whitelist
|
||||
|
||||
Sets a list of comma-separated nicknames (without @ symbol in the beginning) for interacting with bot. Only these users can use the bot.
|
115
agent/input/telegram/conn.go
Normal file
115
agent/input/telegram/conn.go
Normal file
@@ -0,0 +1,115 @@
|
||||
package telegram
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/forestgiant/sliceutil"
|
||||
"github.com/micro/go-micro/agent/input"
|
||||
"github.com/micro/go-log"
|
||||
"gopkg.in/telegram-bot-api.v4"
|
||||
)
|
||||
|
||||
type telegramConn struct {
|
||||
input *telegramInput
|
||||
|
||||
recv <-chan tgbotapi.Update
|
||||
exit chan bool
|
||||
|
||||
syncCond *sync.Cond
|
||||
mutex sync.Mutex
|
||||
}
|
||||
|
||||
func newConn(input *telegramInput) (*telegramConn, error) {
|
||||
conn := &telegramConn{
|
||||
input: input,
|
||||
}
|
||||
|
||||
conn.syncCond = sync.NewCond(&conn.mutex)
|
||||
|
||||
go conn.run()
|
||||
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func (tc *telegramConn) run() {
|
||||
u := tgbotapi.NewUpdate(0)
|
||||
u.Timeout = 60
|
||||
updates, err := tc.input.api.GetUpdatesChan(u)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
tc.recv = updates
|
||||
tc.syncCond.Signal()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-tc.exit:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (tc *telegramConn) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tc *telegramConn) Recv(event *input.Event) error {
|
||||
if event == nil {
|
||||
return errors.New("event cannot be nil")
|
||||
}
|
||||
|
||||
for {
|
||||
if tc.recv == nil {
|
||||
tc.mutex.Lock()
|
||||
tc.syncCond.Wait()
|
||||
}
|
||||
|
||||
update := <-tc.recv
|
||||
|
||||
if update.Message == nil || (len(tc.input.whitelist) > 0 && !sliceutil.Contains(tc.input.whitelist, update.Message.From.UserName)) {
|
||||
continue
|
||||
}
|
||||
|
||||
if event.Meta == nil {
|
||||
event.Meta = make(map[string]interface{})
|
||||
}
|
||||
|
||||
event.Type = input.TextEvent
|
||||
event.From = update.Message.From.UserName
|
||||
event.To = tc.input.api.Self.UserName
|
||||
event.Data = []byte(update.Message.Text)
|
||||
event.Meta["chatId"] = update.Message.Chat.ID
|
||||
event.Meta["chatType"] = update.Message.Chat.Type
|
||||
event.Meta["messageId"] = update.Message.MessageID
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (tc *telegramConn) Send(event *input.Event) error {
|
||||
messageText := strings.TrimSpace(string(event.Data))
|
||||
|
||||
chatId := event.Meta["chatId"].(int64)
|
||||
chatType := ChatType(event.Meta["chatType"].(string))
|
||||
|
||||
msgConfig := tgbotapi.NewMessage(chatId, messageText)
|
||||
msgConfig.ParseMode = tgbotapi.ModeHTML
|
||||
|
||||
if sliceutil.Contains([]ChatType{Group, Supergroup}, chatType) {
|
||||
msgConfig.ReplyToMessageID = event.Meta["messageId"].(int)
|
||||
}
|
||||
|
||||
_, err := tc.input.api.Send(msgConfig)
|
||||
|
||||
if err != nil {
|
||||
// probably it could be because of nested HTML tags -- telegram doesn't allow nested tags
|
||||
log.Log("[telegram][Send] error:", err)
|
||||
msgConfig.Text = "This bot couldn't send the response (Internal error)"
|
||||
tc.input.api.Send(msgConfig)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
101
agent/input/telegram/telegram.go
Normal file
101
agent/input/telegram/telegram.go
Normal file
@@ -0,0 +1,101 @@
|
||||
package telegram
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/micro/cli"
|
||||
"github.com/micro/go-micro/agent/input"
|
||||
"gopkg.in/telegram-bot-api.v4"
|
||||
)
|
||||
|
||||
type telegramInput struct {
|
||||
sync.Mutex
|
||||
|
||||
debug bool
|
||||
token string
|
||||
whitelist []string
|
||||
|
||||
api *tgbotapi.BotAPI
|
||||
}
|
||||
|
||||
type ChatType string
|
||||
|
||||
const (
|
||||
Private ChatType = "private"
|
||||
Group ChatType = "group"
|
||||
Supergroup ChatType = "supergroup"
|
||||
)
|
||||
|
||||
func init() {
|
||||
input.Inputs["telegram"] = &telegramInput{}
|
||||
}
|
||||
|
||||
func (ti *telegramInput) Flags() []cli.Flag {
|
||||
return []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "telegram_debug",
|
||||
EnvVar: "MICRO_TELEGRAM_DEBUG",
|
||||
Usage: "Telegram debug output",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "telegram_token",
|
||||
EnvVar: "MICRO_TELEGRAM_TOKEN",
|
||||
Usage: "Telegram token",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "telegram_whitelist",
|
||||
EnvVar: "MICRO_TELEGRAM_WHITELIST",
|
||||
Usage: "Telegram bot's users (comma-separated values)",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (ti *telegramInput) Init(ctx *cli.Context) error {
|
||||
ti.debug = ctx.Bool("telegram_debug")
|
||||
ti.token = ctx.String("telegram_token")
|
||||
|
||||
whitelist := ctx.String("telegram_whitelist")
|
||||
|
||||
if whitelist != "" {
|
||||
ti.whitelist = strings.Split(whitelist, ",")
|
||||
}
|
||||
|
||||
if len(ti.token) == 0 {
|
||||
return errors.New("missing telegram token")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ti *telegramInput) Stream() (input.Conn, error) {
|
||||
ti.Lock()
|
||||
defer ti.Unlock()
|
||||
|
||||
return newConn(ti)
|
||||
}
|
||||
|
||||
func (ti *telegramInput) Start() error {
|
||||
ti.Lock()
|
||||
defer ti.Unlock()
|
||||
|
||||
api, err := tgbotapi.NewBotAPI(ti.token)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ti.api = api
|
||||
|
||||
api.Debug = ti.debug
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ti *telegramInput) Stop() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *telegramInput) String() string {
|
||||
return "telegram"
|
||||
}
|
Reference in New Issue
Block a user