Add agent => bot
This commit is contained in:
		
							
								
								
									
										7
									
								
								agent/.travis.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								agent/.travis.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | language: go | ||||||
|  | go: | ||||||
|  | - 1.10.x | ||||||
|  | - 1.11.x | ||||||
|  | notifications: | ||||||
|  |   slack: | ||||||
|  |     secure: j+1gw9+LEu6GNisO18UoYOT8x9SGGoy57xJTmSQcWLGmhlcRwdvRzBJTdnZQ/sItokJSufW4K4cVZy4749fq7EaHqMtcuFkwju/i5EVOHliOlTqvo6bZaCThvuSfknBmHK0oU3u0DZBDAqR7BGTRztB+8A4gUNTVYumkP1sVWqoF8lvkM276Il1oprWeRyAdCpBNDuiUlMC0SpJmfUKrqpE64xe1iOCedPTPj7cbgnl35NBll0poXPIp/XNYn4ZsNP100vb5LSyvGHO5Z5XB3LZJit3wNWB3zI9y5Dr4d2EAV/c1VWqalbbT0/CLvSEnP++ubZhnK7sTMhgYxIlMtNTT/81MplVTeKcS+UFBw/aeTzrjhx6g5FNQiN2cnurs/O0Xwoq0Oh01l4uTIU4xUGQFtba/WFPDAO7cEWk8T1Z/fjkD22bDvkm3C2XXsA5nXeIjLhODKRV2fc5/Slxi2p5znhVRFukxnvPh0vVWh8yeukyjYjQXQ2n7Cl+UDBlggWGtRAYOnNo1uhLPShVoJwc/NjnRX5vJPbnjkASkEutqWAw/Rmwh+wx5+WNiYjo/VE8ZJPKyRK+0dQqhOrP73HWJxO9sMFucymeFVcxa4z3B7Nn7TBo1BhCyAdohT9V19gqfRO+TA8kifz8BF8jWBYUBOSQZrg92bYGkia3ROMs= | ||||||
							
								
								
									
										197
									
								
								agent/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										197
									
								
								agent/README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,197 @@ | |||||||
|  | # Agent  | ||||||
|  |  | ||||||
|  | Agent is a library used to create commands, inputs and robot services | ||||||
|  |  | ||||||
|  | ## Getting Started | ||||||
|  |  | ||||||
|  | - [Commands](#commands) - Commands are functions executed by the bot based on text based pattern matching. | ||||||
|  | - [Inputs](#inputs) - Inputs are plugins for communication e.g Slack, Telegram, IRC, etc. | ||||||
|  | - [Services](#services) - Write bots as micro services | ||||||
|  |  | ||||||
|  | ## Commands | ||||||
|  |  | ||||||
|  | Commands are functions executed by the bot based on text based pattern matching. | ||||||
|  |  | ||||||
|  | ### Write a Command | ||||||
|  |  | ||||||
|  | ```go | ||||||
|  | import "github.com/micro/go-bot/command" | ||||||
|  |  | ||||||
|  | func Ping() command.Command { | ||||||
|  | 	usage := "ping" | ||||||
|  | 	description := "Returns pong" | ||||||
|  |  | ||||||
|  | 	return command.NewCommand("ping", usage, desc, func(args ...string) ([]byte, error) { | ||||||
|  | 		return []byte("pong"), nil | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ### Register the command | ||||||
|  |  | ||||||
|  | Add the command to the Commands map with a pattern key that can be matched by golang/regexp.Match | ||||||
|  |  | ||||||
|  | ```go | ||||||
|  | import "github.com/micro/go-bot/command" | ||||||
|  |  | ||||||
|  | func init() { | ||||||
|  | 	command.Commands["^ping$"] = Ping() | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ### Rebuild Micro | ||||||
|  |  | ||||||
|  | Build binary | ||||||
|  | ```shell | ||||||
|  | cd github.com/micro/micro | ||||||
|  |  | ||||||
|  | // For local use | ||||||
|  | go build -i -o micro ./main.go | ||||||
|  |  | ||||||
|  | // For docker image | ||||||
|  | CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -ldflags '-w' -i -o micro ./main.go | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ## Inputs | ||||||
|  |  | ||||||
|  | Inputs are plugins for communication e.g Slack, HipChat, XMPP, IRC, SMTP, etc, etc.  | ||||||
|  |  | ||||||
|  | New inputs can be added in the following way. | ||||||
|  |  | ||||||
|  | ### Write an Input | ||||||
|  |  | ||||||
|  | Write an input that satisfies the Input interface. | ||||||
|  |  | ||||||
|  | ```go | ||||||
|  | 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 | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ### Register the input | ||||||
|  |  | ||||||
|  | Add the input to the Inputs map. | ||||||
|  |  | ||||||
|  | ```go | ||||||
|  | import "github.com/micro/micro/bot/input" | ||||||
|  |  | ||||||
|  | func init() { | ||||||
|  | 	input.Inputs["name"] = MyInput | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ### Rebuild Micro | ||||||
|  |  | ||||||
|  | Build binary | ||||||
|  | ```shell | ||||||
|  | cd github.com/micro/micro | ||||||
|  |  | ||||||
|  | // For local use | ||||||
|  | go build -i -o micro ./main.go | ||||||
|  |  | ||||||
|  | // For docker image | ||||||
|  | CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -ldflags '-w' -i -o micro ./main.go | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ## Services | ||||||
|  |  | ||||||
|  | The micro bot supports the ability to create commands as micro services.  | ||||||
|  |  | ||||||
|  | ### How does it work? | ||||||
|  |  | ||||||
|  | The bot watches the service registry for services with it's namespace. The default namespace is `go.micro.bot`.  | ||||||
|  | Any service within this namespace will automatically be added to the list of available commands. When a command  | ||||||
|  | is executed, the bot will call the service with method `Command.Exec`. It also expects the method `Command.Help`  | ||||||
|  | to exist for usage info. | ||||||
|  |  | ||||||
|  |  | ||||||
|  | The service interface is as follows and can be found at [go-bot/proto](https://github.com/micro/go-bot/blob/master/proto/bot.proto) | ||||||
|  |  | ||||||
|  | ``` | ||||||
|  | syntax = "proto3"; | ||||||
|  |  | ||||||
|  | package go.micro.bot; | ||||||
|  |  | ||||||
|  | service Command { | ||||||
|  | 	rpc Help(HelpRequest) returns (HelpResponse) {}; | ||||||
|  | 	rpc Exec(ExecRequest) returns (ExecResponse) {}; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | message HelpRequest { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | message HelpResponse { | ||||||
|  | 	string usage = 1; | ||||||
|  | 	string description = 2; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | message ExecRequest { | ||||||
|  | 	repeated string args = 1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | message ExecResponse { | ||||||
|  | 	bytes result = 1; | ||||||
|  | 	string error = 2; | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ### Example | ||||||
|  |  | ||||||
|  | Here's an example echo command as a microservice | ||||||
|  |  | ||||||
|  | ```go | ||||||
|  | package main | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"strings" | ||||||
|  |  | ||||||
|  | 	"github.com/micro/go-micro" | ||||||
|  | 	"golang.org/x/net/context" | ||||||
|  |  | ||||||
|  | 	proto "github.com/micro/go-bot/proto" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type Command struct{} | ||||||
|  |  | ||||||
|  | // Help returns the command usage | ||||||
|  | func (c *Command) Help(ctx context.Context, req *proto.HelpRequest, rsp *proto.HelpResponse) error { | ||||||
|  | 	// Usage should include the name of the command | ||||||
|  | 	rsp.Usage = "echo" | ||||||
|  | 	rsp.Description = "This is an example bot command as a micro service which echos the message" | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Exec executes the command | ||||||
|  | func (c *Command) Exec(ctx context.Context, req *proto.ExecRequest, rsp *proto.ExecResponse) error { | ||||||
|  | 	rsp.Result = []byte(strings.Join(req.Args, " ")) | ||||||
|  | 	// rsp.Error could be set to return an error instead | ||||||
|  | 	// the function error would only be used for service level issues | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func main() { | ||||||
|  | 	service := micro.NewService( | ||||||
|  | 		micro.Name("go.micro.bot.echo"), | ||||||
|  | 	) | ||||||
|  |  | ||||||
|  | 	service.Init() | ||||||
|  |  | ||||||
|  | 	proto.RegisterCommandHandler(service.Server(), new(Command)) | ||||||
|  |  | ||||||
|  | 	if err := service.Run(); err != nil { | ||||||
|  | 		fmt.Println(err) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | ``` | ||||||
							
								
								
									
										2
									
								
								agent/agent.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								agent/agent.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | |||||||
|  | // Package agent provides an interface for building robots | ||||||
|  | package agent | ||||||
							
								
								
									
										54
									
								
								agent/command/command.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								agent/command/command.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,54 @@ | |||||||
|  | // Package command is an interface for defining bot commands | ||||||
|  | package command | ||||||
|  |  | ||||||
|  | var ( | ||||||
|  | 	// Commmands keyed by golang/regexp patterns | ||||||
|  | 	// regexp.Match(key, input) is used to match | ||||||
|  | 	Commands = map[string]Command{} | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // Command is the interface for specific named | ||||||
|  | // commands executed via plugins or the bot. | ||||||
|  | type Command interface { | ||||||
|  | 	// Executes the command with args passed in | ||||||
|  | 	Exec(args ...string) ([]byte, error) | ||||||
|  | 	// Usage of the command | ||||||
|  | 	Usage() string | ||||||
|  | 	// Description of the command | ||||||
|  | 	Description() string | ||||||
|  | 	// Name of the command | ||||||
|  | 	String() string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type cmd struct { | ||||||
|  | 	name        string | ||||||
|  | 	usage       string | ||||||
|  | 	description string | ||||||
|  | 	exec        func(args ...string) ([]byte, error) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *cmd) Description() string { | ||||||
|  | 	return c.description | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *cmd) Exec(args ...string) ([]byte, error) { | ||||||
|  | 	return c.exec(args...) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *cmd) Usage() string { | ||||||
|  | 	return c.usage | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *cmd) String() string { | ||||||
|  | 	return c.name | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NewCommand helps quickly create a new command | ||||||
|  | func NewCommand(name, usage, description string, exec func(args ...string) ([]byte, error)) Command { | ||||||
|  | 	return &cmd{ | ||||||
|  | 		name:        name, | ||||||
|  | 		usage:       usage, | ||||||
|  | 		description: description, | ||||||
|  | 		exec:        exec, | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										65
									
								
								agent/command/command_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								agent/command/command_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,65 @@ | |||||||
|  | package command | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"testing" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func TestCommand(t *testing.T) { | ||||||
|  | 	c := &cmd{ | ||||||
|  | 		name:        "test", | ||||||
|  | 		usage:       "test usage", | ||||||
|  | 		description: "test description", | ||||||
|  | 		exec: func(args ...string) ([]byte, error) { | ||||||
|  | 			return []byte("test"), nil | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if c.String() != c.name { | ||||||
|  | 		t.Fatalf("expected name %s got %s", c.name, c.String()) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if c.Usage() != c.usage { | ||||||
|  | 		t.Fatalf("expected usage %s got %s", c.usage, c.Usage()) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if c.Description() != c.description { | ||||||
|  | 		t.Fatalf("expected description %s got %s", c.description, c.Description()) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if r, err := c.Exec(); err != nil { | ||||||
|  | 		t.Fatal(err) | ||||||
|  | 	} else if string(r) != "test" { | ||||||
|  | 		t.Fatalf("expected exec result test got %s", string(r)) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestNewCommand(t *testing.T) { | ||||||
|  | 	c := &cmd{ | ||||||
|  | 		name:        "test", | ||||||
|  | 		usage:       "test usage", | ||||||
|  | 		description: "test description", | ||||||
|  | 		exec: func(args ...string) ([]byte, error) { | ||||||
|  | 			return []byte("test"), nil | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	nc := NewCommand(c.name, c.usage, c.description, c.exec) | ||||||
|  |  | ||||||
|  | 	if nc.String() != c.name { | ||||||
|  | 		t.Fatalf("expected name %s got %s", c.name, nc.String()) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if nc.Usage() != c.usage { | ||||||
|  | 		t.Fatalf("expected usage %s got %s", c.usage, nc.Usage()) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if nc.Description() != c.description { | ||||||
|  | 		t.Fatalf("expected description %s got %s", c.description, nc.Description()) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if r, err := nc.Exec(); err != nil { | ||||||
|  | 		t.Fatal(err) | ||||||
|  | 	} else if string(r) != "test" { | ||||||
|  | 		t.Fatalf("expected exec result test got %s", string(r)) | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										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" | ||||||
|  | } | ||||||
							
								
								
									
										118
									
								
								agent/proto/bot.micro.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								agent/proto/bot.micro.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,118 @@ | |||||||
|  | // Code generated by protoc-gen-micro. DO NOT EDIT. | ||||||
|  | // source: github.com/micro/go-bot/proto/bot.proto | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | Package go_micro_bot is a generated protocol buffer package. | ||||||
|  |  | ||||||
|  | It is generated from these files: | ||||||
|  | 	github.com/micro/go-bot/proto/bot.proto | ||||||
|  |  | ||||||
|  | It has these top-level messages: | ||||||
|  | 	HelpRequest | ||||||
|  | 	HelpResponse | ||||||
|  | 	ExecRequest | ||||||
|  | 	ExecResponse | ||||||
|  | */ | ||||||
|  | package go_micro_bot | ||||||
|  |  | ||||||
|  | import proto "github.com/golang/protobuf/proto" | ||||||
|  | import fmt "fmt" | ||||||
|  | import math "math" | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	client "github.com/micro/go-micro/client" | ||||||
|  | 	server "github.com/micro/go-micro/server" | ||||||
|  | 	context "context" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // Reference imports to suppress errors if they are not otherwise used. | ||||||
|  | var _ = proto.Marshal | ||||||
|  | var _ = fmt.Errorf | ||||||
|  | var _ = math.Inf | ||||||
|  |  | ||||||
|  | // This is a compile-time assertion to ensure that this generated file | ||||||
|  | // is compatible with the proto package it is being compiled against. | ||||||
|  | // A compilation error at this line likely means your copy of the | ||||||
|  | // proto package needs to be updated. | ||||||
|  | const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package | ||||||
|  |  | ||||||
|  | // Reference imports to suppress errors if they are not otherwise used. | ||||||
|  | var _ context.Context | ||||||
|  | var _ client.Option | ||||||
|  | var _ server.Option | ||||||
|  |  | ||||||
|  | // Client API for Command service | ||||||
|  |  | ||||||
|  | type CommandService interface { | ||||||
|  | 	Help(ctx context.Context, in *HelpRequest, opts ...client.CallOption) (*HelpResponse, error) | ||||||
|  | 	Exec(ctx context.Context, in *ExecRequest, opts ...client.CallOption) (*ExecResponse, error) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type commandService struct { | ||||||
|  | 	c    client.Client | ||||||
|  | 	name string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func NewCommandService(name string, c client.Client) CommandService { | ||||||
|  | 	if c == nil { | ||||||
|  | 		c = client.NewClient() | ||||||
|  | 	} | ||||||
|  | 	if len(name) == 0 { | ||||||
|  | 		name = "go.micro.bot" | ||||||
|  | 	} | ||||||
|  | 	return &commandService{ | ||||||
|  | 		c:    c, | ||||||
|  | 		name: name, | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *commandService) Help(ctx context.Context, in *HelpRequest, opts ...client.CallOption) (*HelpResponse, error) { | ||||||
|  | 	req := c.c.NewRequest(c.name, "Command.Help", in) | ||||||
|  | 	out := new(HelpResponse) | ||||||
|  | 	err := c.c.Call(ctx, req, out, opts...) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return out, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *commandService) Exec(ctx context.Context, in *ExecRequest, opts ...client.CallOption) (*ExecResponse, error) { | ||||||
|  | 	req := c.c.NewRequest(c.name, "Command.Exec", in) | ||||||
|  | 	out := new(ExecResponse) | ||||||
|  | 	err := c.c.Call(ctx, req, out, opts...) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return out, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Server API for Command service | ||||||
|  |  | ||||||
|  | type CommandHandler interface { | ||||||
|  | 	Help(context.Context, *HelpRequest, *HelpResponse) error | ||||||
|  | 	Exec(context.Context, *ExecRequest, *ExecResponse) error | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func RegisterCommandHandler(s server.Server, hdlr CommandHandler, opts ...server.HandlerOption) error { | ||||||
|  | 	type _command interface { | ||||||
|  | 		Help(ctx context.Context, in *HelpRequest, out *HelpResponse) error | ||||||
|  | 		Exec(ctx context.Context, in *ExecRequest, out *ExecResponse) error | ||||||
|  | 	} | ||||||
|  | 	type Command struct { | ||||||
|  | 		_command | ||||||
|  | 	} | ||||||
|  | 	h := &commandHandler{hdlr} | ||||||
|  | 	return s.Handle(s.NewHandler(&Command{h}, opts...)) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type commandHandler struct { | ||||||
|  | 	CommandHandler | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (h *commandHandler) Help(ctx context.Context, in *HelpRequest, out *HelpResponse) error { | ||||||
|  | 	return h.CommandHandler.Help(ctx, in, out) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (h *commandHandler) Exec(ctx context.Context, in *ExecRequest, out *ExecResponse) error { | ||||||
|  | 	return h.CommandHandler.Exec(ctx, in, out) | ||||||
|  | } | ||||||
							
								
								
									
										210
									
								
								agent/proto/bot.pb.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										210
									
								
								agent/proto/bot.pb.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,210 @@ | |||||||
|  | // Code generated by protoc-gen-go. DO NOT EDIT. | ||||||
|  | // source: github.com/micro/go-bot/proto/bot.proto | ||||||
|  |  | ||||||
|  | package go_micro_bot | ||||||
|  |  | ||||||
|  | import proto "github.com/golang/protobuf/proto" | ||||||
|  | import fmt "fmt" | ||||||
|  | import math "math" | ||||||
|  |  | ||||||
|  | // Reference imports to suppress errors if they are not otherwise used. | ||||||
|  | var _ = proto.Marshal | ||||||
|  | var _ = fmt.Errorf | ||||||
|  | var _ = math.Inf | ||||||
|  |  | ||||||
|  | // This is a compile-time assertion to ensure that this generated file | ||||||
|  | // is compatible with the proto package it is being compiled against. | ||||||
|  | // A compilation error at this line likely means your copy of the | ||||||
|  | // proto package needs to be updated. | ||||||
|  | const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package | ||||||
|  |  | ||||||
|  | type HelpRequest struct { | ||||||
|  | 	XXX_NoUnkeyedLiteral struct{} `json:"-"` | ||||||
|  | 	XXX_unrecognized     []byte   `json:"-"` | ||||||
|  | 	XXX_sizecache        int32    `json:"-"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (m *HelpRequest) Reset()         { *m = HelpRequest{} } | ||||||
|  | func (m *HelpRequest) String() string { return proto.CompactTextString(m) } | ||||||
|  | func (*HelpRequest) ProtoMessage()    {} | ||||||
|  | func (*HelpRequest) Descriptor() ([]byte, []int) { | ||||||
|  | 	return fileDescriptor_bot_654832eab83ed4b5, []int{0} | ||||||
|  | } | ||||||
|  | func (m *HelpRequest) XXX_Unmarshal(b []byte) error { | ||||||
|  | 	return xxx_messageInfo_HelpRequest.Unmarshal(m, b) | ||||||
|  | } | ||||||
|  | func (m *HelpRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { | ||||||
|  | 	return xxx_messageInfo_HelpRequest.Marshal(b, m, deterministic) | ||||||
|  | } | ||||||
|  | func (dst *HelpRequest) XXX_Merge(src proto.Message) { | ||||||
|  | 	xxx_messageInfo_HelpRequest.Merge(dst, src) | ||||||
|  | } | ||||||
|  | func (m *HelpRequest) XXX_Size() int { | ||||||
|  | 	return xxx_messageInfo_HelpRequest.Size(m) | ||||||
|  | } | ||||||
|  | func (m *HelpRequest) XXX_DiscardUnknown() { | ||||||
|  | 	xxx_messageInfo_HelpRequest.DiscardUnknown(m) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | var xxx_messageInfo_HelpRequest proto.InternalMessageInfo | ||||||
|  |  | ||||||
|  | type HelpResponse struct { | ||||||
|  | 	Usage                string   `protobuf:"bytes,1,opt,name=usage,proto3" json:"usage,omitempty"` | ||||||
|  | 	Description          string   `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` | ||||||
|  | 	XXX_NoUnkeyedLiteral struct{} `json:"-"` | ||||||
|  | 	XXX_unrecognized     []byte   `json:"-"` | ||||||
|  | 	XXX_sizecache        int32    `json:"-"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (m *HelpResponse) Reset()         { *m = HelpResponse{} } | ||||||
|  | func (m *HelpResponse) String() string { return proto.CompactTextString(m) } | ||||||
|  | func (*HelpResponse) ProtoMessage()    {} | ||||||
|  | func (*HelpResponse) Descriptor() ([]byte, []int) { | ||||||
|  | 	return fileDescriptor_bot_654832eab83ed4b5, []int{1} | ||||||
|  | } | ||||||
|  | func (m *HelpResponse) XXX_Unmarshal(b []byte) error { | ||||||
|  | 	return xxx_messageInfo_HelpResponse.Unmarshal(m, b) | ||||||
|  | } | ||||||
|  | func (m *HelpResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { | ||||||
|  | 	return xxx_messageInfo_HelpResponse.Marshal(b, m, deterministic) | ||||||
|  | } | ||||||
|  | func (dst *HelpResponse) XXX_Merge(src proto.Message) { | ||||||
|  | 	xxx_messageInfo_HelpResponse.Merge(dst, src) | ||||||
|  | } | ||||||
|  | func (m *HelpResponse) XXX_Size() int { | ||||||
|  | 	return xxx_messageInfo_HelpResponse.Size(m) | ||||||
|  | } | ||||||
|  | func (m *HelpResponse) XXX_DiscardUnknown() { | ||||||
|  | 	xxx_messageInfo_HelpResponse.DiscardUnknown(m) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | var xxx_messageInfo_HelpResponse proto.InternalMessageInfo | ||||||
|  |  | ||||||
|  | func (m *HelpResponse) GetUsage() string { | ||||||
|  | 	if m != nil { | ||||||
|  | 		return m.Usage | ||||||
|  | 	} | ||||||
|  | 	return "" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (m *HelpResponse) GetDescription() string { | ||||||
|  | 	if m != nil { | ||||||
|  | 		return m.Description | ||||||
|  | 	} | ||||||
|  | 	return "" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type ExecRequest struct { | ||||||
|  | 	Args                 []string `protobuf:"bytes,1,rep,name=args,proto3" json:"args,omitempty"` | ||||||
|  | 	XXX_NoUnkeyedLiteral struct{} `json:"-"` | ||||||
|  | 	XXX_unrecognized     []byte   `json:"-"` | ||||||
|  | 	XXX_sizecache        int32    `json:"-"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (m *ExecRequest) Reset()         { *m = ExecRequest{} } | ||||||
|  | func (m *ExecRequest) String() string { return proto.CompactTextString(m) } | ||||||
|  | func (*ExecRequest) ProtoMessage()    {} | ||||||
|  | func (*ExecRequest) Descriptor() ([]byte, []int) { | ||||||
|  | 	return fileDescriptor_bot_654832eab83ed4b5, []int{2} | ||||||
|  | } | ||||||
|  | func (m *ExecRequest) XXX_Unmarshal(b []byte) error { | ||||||
|  | 	return xxx_messageInfo_ExecRequest.Unmarshal(m, b) | ||||||
|  | } | ||||||
|  | func (m *ExecRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { | ||||||
|  | 	return xxx_messageInfo_ExecRequest.Marshal(b, m, deterministic) | ||||||
|  | } | ||||||
|  | func (dst *ExecRequest) XXX_Merge(src proto.Message) { | ||||||
|  | 	xxx_messageInfo_ExecRequest.Merge(dst, src) | ||||||
|  | } | ||||||
|  | func (m *ExecRequest) XXX_Size() int { | ||||||
|  | 	return xxx_messageInfo_ExecRequest.Size(m) | ||||||
|  | } | ||||||
|  | func (m *ExecRequest) XXX_DiscardUnknown() { | ||||||
|  | 	xxx_messageInfo_ExecRequest.DiscardUnknown(m) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | var xxx_messageInfo_ExecRequest proto.InternalMessageInfo | ||||||
|  |  | ||||||
|  | func (m *ExecRequest) GetArgs() []string { | ||||||
|  | 	if m != nil { | ||||||
|  | 		return m.Args | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type ExecResponse struct { | ||||||
|  | 	Result               []byte   `protobuf:"bytes,1,opt,name=result,proto3" json:"result,omitempty"` | ||||||
|  | 	Error                string   `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"` | ||||||
|  | 	XXX_NoUnkeyedLiteral struct{} `json:"-"` | ||||||
|  | 	XXX_unrecognized     []byte   `json:"-"` | ||||||
|  | 	XXX_sizecache        int32    `json:"-"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (m *ExecResponse) Reset()         { *m = ExecResponse{} } | ||||||
|  | func (m *ExecResponse) String() string { return proto.CompactTextString(m) } | ||||||
|  | func (*ExecResponse) ProtoMessage()    {} | ||||||
|  | func (*ExecResponse) Descriptor() ([]byte, []int) { | ||||||
|  | 	return fileDescriptor_bot_654832eab83ed4b5, []int{3} | ||||||
|  | } | ||||||
|  | func (m *ExecResponse) XXX_Unmarshal(b []byte) error { | ||||||
|  | 	return xxx_messageInfo_ExecResponse.Unmarshal(m, b) | ||||||
|  | } | ||||||
|  | func (m *ExecResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { | ||||||
|  | 	return xxx_messageInfo_ExecResponse.Marshal(b, m, deterministic) | ||||||
|  | } | ||||||
|  | func (dst *ExecResponse) XXX_Merge(src proto.Message) { | ||||||
|  | 	xxx_messageInfo_ExecResponse.Merge(dst, src) | ||||||
|  | } | ||||||
|  | func (m *ExecResponse) XXX_Size() int { | ||||||
|  | 	return xxx_messageInfo_ExecResponse.Size(m) | ||||||
|  | } | ||||||
|  | func (m *ExecResponse) XXX_DiscardUnknown() { | ||||||
|  | 	xxx_messageInfo_ExecResponse.DiscardUnknown(m) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | var xxx_messageInfo_ExecResponse proto.InternalMessageInfo | ||||||
|  |  | ||||||
|  | func (m *ExecResponse) GetResult() []byte { | ||||||
|  | 	if m != nil { | ||||||
|  | 		return m.Result | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (m *ExecResponse) GetError() string { | ||||||
|  | 	if m != nil { | ||||||
|  | 		return m.Error | ||||||
|  | 	} | ||||||
|  | 	return "" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func init() { | ||||||
|  | 	proto.RegisterType((*HelpRequest)(nil), "go.micro.bot.HelpRequest") | ||||||
|  | 	proto.RegisterType((*HelpResponse)(nil), "go.micro.bot.HelpResponse") | ||||||
|  | 	proto.RegisterType((*ExecRequest)(nil), "go.micro.bot.ExecRequest") | ||||||
|  | 	proto.RegisterType((*ExecResponse)(nil), "go.micro.bot.ExecResponse") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func init() { | ||||||
|  | 	proto.RegisterFile("github.com/micro/go-bot/proto/bot.proto", fileDescriptor_bot_654832eab83ed4b5) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | var fileDescriptor_bot_654832eab83ed4b5 = []byte{ | ||||||
|  | 	// 246 bytes of a gzipped FileDescriptorProto | ||||||
|  | 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x90, 0x41, 0x4b, 0xc4, 0x30, | ||||||
|  | 	0x10, 0x85, 0xb7, 0xba, 0xae, 0xec, 0xb4, 0x5e, 0x82, 0x48, 0xdd, 0x53, 0xcd, 0xc5, 0xbd, 0x98, | ||||||
|  | 	0x82, 0x5e, 0x05, 0x0f, 0xa2, 0x78, 0xee, 0x3f, 0x68, 0xba, 0x43, 0x2c, 0x6c, 0x3b, 0x35, 0x99, | ||||||
|  | 	0x82, 0xff, 0xc1, 0x3f, 0x2d, 0x4d, 0x72, 0x08, 0xcb, 0xde, 0xe6, 0x65, 0x86, 0xf7, 0xbe, 0x17, | ||||||
|  | 	0x78, 0x34, 0x3d, 0x7f, 0xcf, 0x5a, 0x75, 0x34, 0xd4, 0x43, 0xdf, 0x59, 0xaa, 0x0d, 0x3d, 0x69, | ||||||
|  | 	0xe2, 0x7a, 0xb2, 0xc4, 0x54, 0x6b, 0x62, 0xe5, 0x27, 0x51, 0x18, 0x52, 0xfe, 0x40, 0x69, 0x62, | ||||||
|  | 	0x79, 0x03, 0xf9, 0x17, 0x1e, 0xa7, 0x06, 0x7f, 0x66, 0x74, 0x2c, 0x3f, 0xa1, 0x08, 0xd2, 0x4d, | ||||||
|  | 	0x34, 0x3a, 0x14, 0xb7, 0x70, 0x35, 0xbb, 0xd6, 0x60, 0x99, 0x55, 0xd9, 0x7e, 0xdb, 0x04, 0x21, | ||||||
|  | 	0x2a, 0xc8, 0x0f, 0xe8, 0x3a, 0xdb, 0x4f, 0xdc, 0xd3, 0x58, 0x5e, 0xf8, 0x5d, 0xfa, 0x24, 0x1f, | ||||||
|  | 	0x20, 0xff, 0xf8, 0xc5, 0x2e, 0xda, 0x0a, 0x01, 0xeb, 0xd6, 0x1a, 0x57, 0x66, 0xd5, 0xe5, 0x7e, | ||||||
|  | 	0xdb, 0xf8, 0x59, 0xbe, 0x42, 0x11, 0x4e, 0x62, 0xd4, 0x1d, 0x6c, 0x2c, 0xba, 0xf9, 0xc8, 0x3e, | ||||||
|  | 	0xab, 0x68, 0xa2, 0x5a, 0x10, 0xd0, 0x5a, 0xb2, 0x31, 0x26, 0x88, 0xe7, 0xbf, 0x0c, 0xae, 0xdf, | ||||||
|  | 	0x69, 0x18, 0xda, 0xf1, 0x20, 0xde, 0x60, 0xbd, 0x40, 0x8b, 0x7b, 0x95, 0x56, 0x53, 0x49, 0xaf, | ||||||
|  | 	0xdd, 0xee, 0xdc, 0x2a, 0x04, 0xcb, 0xd5, 0x62, 0xb0, 0xa0, 0x9c, 0x1a, 0x24, 0x0d, 0x4e, 0x0d, | ||||||
|  | 	0x52, 0x72, 0xb9, 0xd2, 0x1b, 0xff, 0xb5, 0x2f, 0xff, 0x01, 0x00, 0x00, 0xff, 0xff, 0xcb, 0x77, | ||||||
|  | 	0xdf, 0x28, 0x85, 0x01, 0x00, 0x00, | ||||||
|  | } | ||||||
							
								
								
									
										25
									
								
								agent/proto/bot.proto
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								agent/proto/bot.proto
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | |||||||
|  | syntax = "proto3"; | ||||||
|  |  | ||||||
|  | package go.micro.bot; | ||||||
|  |  | ||||||
|  | service Command { | ||||||
|  | 	rpc Help(HelpRequest) returns (HelpResponse) {}; | ||||||
|  | 	rpc Exec(ExecRequest) returns (ExecResponse) {}; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | message HelpRequest { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | message HelpResponse { | ||||||
|  | 	string usage = 1; | ||||||
|  | 	string description = 2; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | message ExecRequest { | ||||||
|  | 	repeated string args = 1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | message ExecResponse { | ||||||
|  | 	bytes result = 1; | ||||||
|  | 	string error = 2; | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user