示例#1
0
func TestMain(m *testing.M) {
	err := os.Setenv("ABOT_ENV", "test")
	if err != nil {
		log.Fatal("failed to set ABOT_ENV.", err)
	}
	r, err = core.NewServer()
	if err != nil {
		log.Fatal("failed to start abot server.", err)
	}
	p, err = plugin.New("testplugin")
	if err != nil {
		log.Fatal("failed to build test plugin.", err)
	}
	p.Config.Name = "testplugin"
	p.Trigger = &dt.StructuredInput{
		Commands: []string{"get"},
		Objects:  []string{"result"},
	}
	plugin.SetStates(p, [][]dt.State{
		[]dt.State{
			{
				OnEntry: func(in *dt.Msg) string {
					return "entered first"
				},
				OnInput: func(in *dt.Msg) {},
				Complete: func(in *dt.Msg) (bool, string) {
					return true, ""
				},
			},
		},
		Iterate(p, "", OptsIterate{
			IterableMemKey:  keyMem,
			ResultMemKeyIdx: keyRes,
		}),
		[]dt.State{
			{
				OnEntry: func(in *dt.Msg) string {
					return "Great!"
				},
				OnInput: func(in *dt.Msg) {},
				Complete: func(in *dt.Msg) (bool, string) {
					return true, ""
				},
			},
		},
	})
	p.SM.SetOnReset(func(in *dt.Msg) {
		p.DeleteMemory(in, keyMem)
		p.DeleteMemory(in, keyRes)
		ResetIterate(p, in)
	})
	if err = plugin.Register(p); err != nil {
		log.Fatal("failed to register test plugin.", err)
	}
	cleanup()
	exitVal := m.Run()
	cleanup()
	os.Exit(exitVal)
}
示例#2
0
func TestMain(m *testing.M) {
	if err := LoadEnvVars(); err != nil {
		log.Info("failed to load env vars", err)
	}
	if err := os.Setenv("ABOT_ENV", "test"); err != nil {
		log.Fatal("failed to set ABOT_ENV", err)
	}
	var err error
	router, err = NewServer()
	if err != nil {
		log.Fatal("failed to start server", err)
	}
	os.Exit(m.Run())
}
示例#3
0
func TestMain(m *testing.M) {
	log.SetDebug(true)
	if err := os.Setenv("ABOT_DEBUG", "true"); err != nil {
		log.Fatal(err)
	}
	os.Exit(m.Run())
}
示例#4
0
文件: abot_test.go 项目: itsabot/abot
func TestMain(m *testing.M) {
	if err := core.LoadEnvVars(); err != nil {
		log.Info("failed to load env vars", err)
	}
	if err := os.Setenv("ABOT_ENV", "test"); err != nil {
		log.Fatal(err)
	}
	os.Exit(m.Run())
}
示例#5
0
文件: plugin.go 项目: itsabot/abot
// GetSetting retrieves a specific setting's value. It throws a fatal error if
// the setting has not been declared in the plugin's plugin.json file.
func (p *Plugin) GetSetting(name string) string {
	if p.Config.Settings[name] == nil {
		pluginName := p.Config.Name
		if len(pluginName) == 0 {
			pluginName = "plugin"
		}
		m := fmt.Sprintf(
			"missing setting %s. please declare it in the %s's plugin.json",
			name, pluginName)
		log.Fatal(m)
	}
	var val string
	q := `SELECT value FROM settings WHERE name=$1 AND pluginname=$2`
	err := p.DB.Get(&val, q, name, p.Config.Name)
	if err == sql.ErrNoRows {
		return p.Config.Settings[name].Default
	}
	if err != nil {
		log.Info("failed to get plugin setting.", err)
		return ""
	}
	return val
}
示例#6
0
文件: abot.go 项目: itsabot/abot
func publishPlugin(c *cli.Context) error {
	p := filepath.Join(os.Getenv("HOME"), ".abot.conf")
	fi, err := os.Open(p)
	if err != nil {
		if err.Error() == fmt.Sprintf("open %s: no such file or directory", p) {
			login()
			publishPlugin(c)
			return nil
		}
		log.Fatal(err)
	}
	defer func() {
		if err = fi.Close(); err != nil {
			log.Fatal(err)
		}
	}()

	// Prepare request
	if len(c.Args().First()) == 0 {
		log.Fatal("missing plugin's `go get` path")
	}
	reqData := struct {
		Path   string
		Secret string
	}{
		Path:   c.Args().First(),
		Secret: core.RandSeq(24),
	}
	byt, err := json.Marshal(reqData)
	if err != nil {
		log.Fatal(err)
	}
	u := os.Getenv("ITSABOT_URL") + "/api/plugins.json"
	req, err := http.NewRequest("POST", u, bytes.NewBuffer(byt))
	if err != nil {
		log.Fatal(err)
	}

	// Populate req with login credentials from ~/.abot.conf
	scn := bufio.NewScanner(fi)
	var lineNum int
	for scn.Scan() {
		line := scn.Text()
		cookie := &http.Cookie{}
		switch lineNum {
		case 0:
			cookie.Name = "iaID"
		case 1:
			cookie.Name = "iaEmail"
		case 2:
			req.Header.Set("Authorization", "Bearer "+line)
		case 3:
			cookie.Name = "iaIssuedAt"
		default:
			log.Fatal("unknown line in abot.conf")
		}
		if lineNum != 2 {
			cookie.Value = url.QueryEscape(line)
			req.AddCookie(cookie)
		}
		lineNum++
	}
	if err = scn.Err(); err != nil {
		log.Fatal(err)
	}
	cookie := &http.Cookie{}
	cookie.Name = "iaScopes"
	req.AddCookie(cookie)

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		log.Fatal(err)
	}
	defer func() {
		if err = resp.Body.Close(); err != nil {
			log.Fatal(err)
		}
	}()
	if resp.StatusCode == 401 {
		login()
		publishPlugin(c)
	} else if resp.StatusCode != 202 {
		log.Info("something went wrong. status code", resp.StatusCode)
		var msg string
		if err = json.NewDecoder(resp.Body).Decode(&msg); err != nil {
			log.Fatal(err)
		}
		log.Fatal(msg)
	}

	// Make a websocket request to get updates about the publishing process
	uri, err := url.Parse(os.Getenv("ITSABOT_URL"))
	if err != nil {
		log.Fatal(err)
	}
	ws, err := websocket.Dial("ws://"+uri.Host+"/api/ws", "",
		os.Getenv("ABOT_URL"))
	if err != nil {
		log.Fatal(err)
	}
	if err = websocket.Message.Send(ws, reqData.Secret); err != nil {
		log.Fatal(err)
	}
	var msg socket.Msg
	l := log.New("")
	l.SetFlags(0)
	l.Info("> Establishing connection with server...")
	var established bool
	var lastMsg string
	for {
		websocket.JSON.Receive(ws, &msg)
		if !established {
			l.Info("OK")
			established = true
		}
		if msg.Content == lastMsg {
			log.Info("server hung up. please try again")
			if err = ws.Close(); err != nil {
				log.Info("failed to close socket.", err)
			}
			return nil
		}
		lastMsg = msg.Content
		if msg.Type == socket.MsgTypeFinishedSuccess ||
			msg.Type == socket.MsgTypeFinishedFailed {
			if err = ws.Close(); err != nil {
				log.Info("failed to close socket.", err)
			}
			return nil
		}
		if len(msg.Content) < 2 {
			l.Info(msg.Content)
			continue
		}
		tmp := msg.Content[0:2]
		if tmp == "> " || tmp == "==" {
			l.Info("")
		}
		l.Info(msg.Content)
	}
}
示例#7
0
文件: abot.go 项目: itsabot/abot
func login() {
	reader := bufio.NewReader(os.Stdin)
	fmt.Print("Email: ")
	email, err := reader.ReadString('\n')
	if err != nil {
		log.Fatal(err)
	}
	fmt.Print("Password: "******"ITSABOT_URL") + "/api/users/login.json"
	resp, err := http.Post(u, "application/json", bytes.NewBuffer(byt))
	if err != nil {
		log.Fatal(err)
	}
	defer func() {
		if err = resp.Body.Close(); err != nil {
			log.Fatal(err)
		}
	}()
	var data struct {
		ID        uint64
		Email     string
		Scopes    []string
		AuthToken string
		IssuedAt  uint64
	}
	if err = json.NewDecoder(resp.Body).Decode(&data); err != nil {
		log.Fatal(err)
	}
	if resp.StatusCode == 401 {
		log.Fatal(errors.New("invalid email/password combination"))
	}

	// Create abot.conf file, truncate if exists
	fi, err := os.Create(filepath.Join(os.Getenv("HOME"), ".abot.conf"))
	if err != nil {
		log.Fatal(err)
	}
	defer func() {
		if err = fi.Close(); err != nil {
			log.Fatal(err)
		}
	}()

	// Insert auth data
	s := fmt.Sprintf("%d\n%s\n%s\n%d", data.ID, data.Email, data.AuthToken,
		data.IssuedAt)
	_, err = fi.WriteString(s)
	if err != nil {
		log.Fatal(err)
	}
	log.Info("Success!")
}
示例#8
0
文件: abot.go 项目: itsabot/abot
func main() {
	rand.Seed(time.Now().UnixNano())
	log.SetDebug(os.Getenv("ABOT_DEBUG") == "true")
	if err := core.LoadEnvVars(); err != nil {
		log.Fatal(err)
	}
	app := cli.NewApp()
	app.Commands = []cli.Command{
		{
			Name:  "new",
			Usage: "generate a new abot",
			Action: func(c *cli.Context) error {
				l := log.New("")
				l.SetFlags(0)
				if len(c.Args()) != 1 {
					l.Fatal("usage: abot new {name}")
				}
				if strings.Contains(c.Args().First(), " ") {
					l.Fatal("name cannot include a space. use camelCase")
				}
				err := newAbot(l, c.Args().First(), c.Args().Get(1))
				if err != nil {
					l.Fatalf("could not build new abot. %s", err)
				}
				l.Info("Success. Created " + c.Args().First())
				return nil
			},
		},
		{
			Name:    "server",
			Aliases: []string{"s"},
			Usage:   "run server",
			Action: func(c *cli.Context) error {
				l := log.New("")
				l.SetFlags(0)
				cmd := exec.Command("/bin/sh", "-c", "go build")
				out, err := cmd.CombinedOutput()
				if err != nil {
					l.Info(string(out))
					return err
				}
				dir, err := os.Getwd()
				if err != nil {
					return err
				}
				_, file := filepath.Split(dir)
				cmd = exec.Command("/bin/sh", "-c", "./"+file)
				cmd.Stdout = os.Stdout
				cmd.Stderr = os.Stderr
				if err = cmd.Start(); err != nil {
					return err
				}
				return cmd.Wait()
			},
		},
		{
			Name:    "install",
			Aliases: []string{"i"},
			Usage:   "download and install plugins listed in plugins.json",
			Action: func(c *cli.Context) error {
				errChan := make(chan errMsg)
				l := log.New("")
				l.SetFlags(0)
				l.SetDebug(os.Getenv("ABOT_DEBUG") == "true")
				go func() {
					select {
					case errC := <-errChan:
						if errC.err == nil {
							// Success
							l.Info(errC.msg)
							os.Exit(0)
						}

						// Plugins install failed, so remove incomplete plugins.go file
						errR := os.Remove("plugins.go")
						if errR != nil && !os.IsNotExist(errR) {
							l.Info("could not remove plugins.go file.", errR)
						}
						if len(errC.msg) > 0 {
							l.Fatalf("could not install plugins.\n%s\n%s", errC.msg, errC.err)
						}
						l.Fatalf("could not install plugins.\n%s", errC.err)
					}
				}()
				installPlugins(l, errChan)
				for {
					// Keep process running until a message is received
				}
			},
		},
		{
			Name:  "search",
			Usage: "search plugins indexed on itsabot.org",
			Action: func(c *cli.Context) error {
				l := log.New("")
				l.SetFlags(0)
				args := c.Args()
				if len(args) == 0 || len(args) > 2 {
					l.Fatal(errors.New(`usage: abot plugin search {term}`))
				}
				if err := searchPlugins(args.First()); err != nil {
					l.Fatalf("could not start console\n%s", err)
				}
				return nil
			},
		},
		{
			Name:    "update",
			Aliases: []string{"u", "upgrade"},
			Usage:   "update and install plugins listed in plugins.json",
			Action: func(c *cli.Context) error {
				updatePlugins()
				return nil
			},
		},
		{
			Name:    "publish",
			Aliases: []string{"p"},
			Usage:   "publish a plugin to itsabot.org",
			Action: func(c *cli.Context) error {
				publishPlugin(c)
				return nil
			},
		},
		{
			Name:    "test",
			Aliases: []string{"t"},
			Usage:   "tests plugins",
			Action: func(c *cli.Context) error {
				lg.SetFlags(0)
				count, err := testPlugin()
				if err != nil {
					return err
				}
				if count == 0 {
					lg.Println("No tests found. Did you run \"abot install\"?")
					return nil
				}
				lg.Printf("Success (%d tests).\n", count)
				return nil
			},
		},
		{
			Name:    "generate",
			Aliases: []string{"g"},
			Usage:   "generate plugin scaffolding",
			Action: func(c *cli.Context) error {
				l := log.New("")
				l.SetFlags(0)
				args := c.Args()
				if len(args) != 1 {
					l.Fatal(errors.New(`usage: abot generate {name}`))
				}
				generatePlugin(l, args.First())
				l.Info("Created", args.First(), "in",
					filepath.Join(os.Getenv("PWD"), args.First()))
				return nil
			},
		},
		{
			Name:    "login",
			Aliases: []string{"l"},
			Usage:   "log into itsabot.org to enable publishing plugins",
			Action: func(c *cli.Context) error {
				login()
				return nil
			},
		},
		{
			Name:    "console",
			Aliases: []string{"c"},
			Usage:   "communicate with a running abot server",
			Action: func(c *cli.Context) error {
				if err := startConsole(c); err != nil {
					l := log.New("")
					l.SetFlags(0)
					l.Fatalf("could not start console\n%s", err)
				}
				return nil
			},
		},
		{
			Name:    "dbconsole",
			Aliases: []string{"dbc"},
			Usage:   "communicate with a running abot server",
			Action: func(c *cli.Context) error {
				cmd := exec.Command("/bin/sh", "-c", "psql "+os.Getenv("ABOT_DATABASE_URL"))
				cmd.Stdout = os.Stdout
				cmd.Stdin = os.Stdin
				if err := cmd.Start(); err != nil {
					return err
				}
				return cmd.Wait()
			},
		},
	}
	app.Action = func(c *cli.Context) error {
		cli.ShowAppHelp(c)
		return nil
	}
	if err := app.Run(os.Args); err != nil {
		log.Fatal(err)
	}
}
示例#9
0
文件: plugin.go 项目: itsabot/abot
// New builds a Plugin with its trigger, RPC, and configuration settings from
// its plugin.json.
func New(url string) (*dt.Plugin, error) {
	if err := core.LoadEnvVars(); err != nil {
		log.Fatal(err)
	}
	db, err := core.ConnectDB("")
	if err != nil {
		return nil, err
	}

	// Read plugin.json data from within plugins.go, unmarshal into struct
	c := dt.PluginConfig{}
	if len(os.Getenv("ABOT_PATH")) > 0 {
		p := filepath.Join(os.Getenv("ABOT_PATH"), "plugins.go")
		var scn *bufio.Scanner
		fi, err := os.OpenFile(p, os.O_RDONLY, 0666)
		if os.IsNotExist(err) {
			goto makePlugin
		}
		if err != nil {
			return nil, err
		}
		defer func() {
			if err = fi.Close(); err != nil {
				log.Info("failed to close file", fi.Name())
				return
			}
		}()
		var found bool
		var data string
		scn = bufio.NewScanner(fi)
		for scn.Scan() {
			t := scn.Text()
			if !found && t != url {
				continue
			} else if t == url {
				found = true
				continue
			} else if len(t) >= 1 && t[0] == '}' {
				data += t
				break
			}
			data += t
		}
		if err = scn.Err(); err != nil {
			return nil, err
		}
		if len(data) > 0 {
			if err = json.Unmarshal([]byte(data), &c); err != nil {
				return nil, err
			}
			if len(c.Name) == 0 {
				return nil, ErrMissingPluginName
			}
		}
	}
makePlugin:
	l := log.New(c.Name)
	l.SetDebug(os.Getenv("ABOT_DEBUG") == "true")
	plg := &dt.Plugin{
		Trigger:     &dt.StructuredInput{},
		SetBranches: func(in *dt.Msg) [][]dt.State { return nil },
		Events: &dt.PluginEvents{
			PostReceive:    func(cmd *string) {},
			PreProcessing:  func(cmd *string, u *dt.User) {},
			PostProcessing: func(in *dt.Msg) {},
			PreResponse:    func(in *dt.Msg, resp *string) {},
		},
		Config: c,
		DB:     db,
		Log:    l,
	}
	plg.SM = dt.NewStateMachine(plg)
	return plg, nil
}