Official Go Keybase chat bot SDK

Overview

go-keybase-chat-bot

Travis CI

Write rich bots for Keybase chat in Go.

Installation

Make sure to install Keybase.

go get -u github.com/keybase/go-keybase-chat-bot/...

Hello world

package main

import (
	"flag"
	"fmt"
	"os"

	"github.com/keybase/go-keybase-chat-bot/kbchat"
)

func fail(msg string, args ...interface{}) {
	fmt.Fprintf(os.Stderr, msg+"\n", args...)
	os.Exit(3)
}

func main() {
	var kbLoc string
	var kbc *kbchat.API
	var err error

	flag.StringVar(&kbLoc, "keybase", "keybase", "the location of the Keybase app")
	flag.Parse()

	if kbc, err = kbchat.Start(kbchat.RunOptions{KeybaseLocation: kbLoc}); err != nil {
		fail("Error creating API: %s", err.Error())
	}

	tlfName := fmt.Sprintf("%s,%s", kbc.GetUsername(), "kb_monbot")
	fmt.Printf("saying hello on conversation: %s\n", tlfName)
	if _, err = kbc.SendMessageByTlfName(tlfName, "hello!"); err != nil {
		fail("Error sending message; %s", err.Error())
	}
}

Commands

Start(runOpts RunOptions) (*API, error)

This must be run first in order to start the Keybase JSON API stdin/stdout interactive mode.

API.SendMessage(channel chat1.ChatChannel, body string) (SendResponse, error)

send a new message by specifying a channel

API.SendMessageByConvID(convID chat1.ConvIDStr, body string) (SendResponse, error)

send a new message by specifying a conversation ID

API.SendMessageByTlfName(tlfName string, body string) (SendResponse, error)

send a new message by specifying a TLF name

API.GetConversations(unreadOnly bool) ([]chat1.ConvSummary, error)

get all conversations, optionally filtering for unread status

API.GetTextMessages(channel chat1.ChatChannel, unreadOnly bool) ([]chat1.MsgSummary, error)

get all text messages, optionally filtering for unread status

Reads the messages in a channel. You can read with or without marking as read.

API.ListenForNextTextMessages() NewSubscription

Returns an object that allows for a bot to enter into a loop calling NewSubscription.Read to receive any new message across all conversations (except the bots own messages). See the following example:

API.InChatSend(channel chat1.ChatChannel, body string) (SendResponse, error)

send a new message which can contain in-chat-send payments (i.e. [email protected]) by specifying a channel

API.InChatSendByConvID(convID chat1.ConvIDStr, body string) (SendResponse, error)

send a new message which can contain in-chat-send payments (i.e. [email protected]) by specifying a conversation ID

API.InChatSendByTlfName(tlfName string, body string) (SendResponse, error)

send a new message which can contain in-chat-send payments (i.e. [email protected]) by specifying a TLF name

	sub, err := kbc.ListenForNewTextMessages()
	if err != nil {
		fail("Error listening: %s", err.Error())
	}

	for {
		msg, err := sub.Read()
		if err != nil {
			fail("failed to read message: %s", err.Error())
		}

		if msg.Message.Content.TypeName != "text" {
			continue
		}

		if msg.Message.Sender.Username == kbc.GetUsername() {
			continue
		}

		if _, err = kbc.SendMessage(msg.Message.Channel, msg.Message.Content.Text.Body); err != nil {
			fail("error echo'ing message: %s", err.Error())
		}
	}

API.Listen(kbchat.ListenOptions{Wallet: true}) NewSubscription

Returns the same object as above, but this one will have another channel on it that also gets wallet events. You can get those just like chat messages: NewSubscription.ReadWallet. So if you care about both of these types of events, you might run two loops like this:

	sub, err := kbc.Listen(kbchat.ListenOptions{Wallet: true})
	if err != nil {
		fail("Error listening: %s", err.Error())
	}

	go func() {
		for {
			payment, err := sub.ReadWallet()
			if err != nil {
				fail("failed to read payment event: %s", err.Error())
			}
			tlfName := fmt.Sprintf("%s,%s", payment.Payment.FromUsername, "kb_monbot")
			msg := fmt.Sprintf("thanks for the %s!", payment.Payment.AmountDescription)
			if _, err = kbc.SendMessageByTlfName(tlfName, msg); err != nil {
				fail("error thanking for payment: %s", err.Error())
			}
		}
	}()

	for {
		msg, err := sub.Read()
		if err != nil {
			fail("failed to read message: %s", err.Error())
		}

		if msg.Message.Content.TypeName != "text" {
			continue
		}

		if msg.Message.Sender.Username == kbc.GetUsername() {
			continue
		}

		if _, err = kbc.SendMessage(msg.Message.Channel, msg.Message.Content.Text.Body); err != nil {
			fail("error echo'ing message: %s", err.Error())
		}
	}

TODO:

  • attachment handling (posting/getting)
  • edit/delete
  • many other things!

Contributions

  • welcomed!

Precommit hooks

We check all git commits with pre-commit hooks generated via pre-commit.com pre-commit hooks. To enable use of these pre-commit hooks:

  • Install the pre-commit utility. For some common cases:
    • pip install pre-commit
    • brew install pre-commit
  • Remove any existing pre-commit hooks via rm .git/hooks/pre-commit
  • Configure via pre-commit install

Types

Most of the types the bot uses are generated from definitions defined in the protocol/ directory inside the Keybase client repo. This ensures that the types that the bot uses are consistent across bots and always up to date with the output of the API.

To build the types for the Go bot, you'll need to clone the client repo in the same parent directory that contains go-keybase-chat-bot/.

git clone https://github.com/keybase/client

and install the necessary dependencies for compiling the protocol files. This requires node.js and Yarn.

cd client/protocol
yarn install

Then you can generate the types by using the provided Makefile in this Go bot repo. Note that goimports is required to generate the types.

go get golang.org/x/tools/cmd/goimports # if you don't have goimports installed
cd ../../go-keybase-chat-bot
make

You can optionally specify a directory to the client protocol when making the types if client and go-keybase-chat-bot are not in the same directory.

make PROTOCOL_PATH=path/to/client/protocol

Should you need to remove all the types for some reason, you can run make clean.

Testing

You'll need to have a few demo bot accounts and teams to run the suite of tests. Make a copy of kbchat/test_config.example.yaml, rename it to kbchat/test_config.yaml, and replace the example data with your own. Tests can then be run inside of kbchat/ with go test.

Issues
  • Use generated wallet types for wallet functions

    Use generated wallet types for wallet functions

    Replaces our (admittedly small) wallet types used in kbchat/wallet.go with generated types from our AVDL. I generated these files on the branch used in keybase/client#18623.

    Note that chat types, while added in the types/ dir, remain unused by kbchat in favor of its own definitions. I'll change that in a future PR, but figured I'd try to minimize this diff as much as possible.

    opened by nathanmsmith 7
  • Memory leak when `keybase status` times out

    Memory leak when `keybase status` times out

    In my GCP Cloud Run logs I have a string of the following

    2020-02-20 17:00:00.639 PST2020/02/21 01:00:00 Listen: failed to auth: unable to run Keybase command
    2020-02-20 17:00:29.641 PST2020/02/21 01:00:29 Listen: failed to auth: unable to run Keybase command
    2020-02-20 17:01:17.639 PST2020/02/21 01:01:17 Listen: failed to auth: unable to run Keybase command
    2020-02-20 17:02:27.939 PST2020/02/21 01:02:27 Listen: failed to auth: unable to run Keybase command
    2020-02-20 17:02:54.638 PST2020/02/21 01:02:54 Listen: failed to auth: unable to run Keybase command
    2020-02-20 17:03:18.541 PST2020/02/21 01:03:18 Listen: failed to auth: unable to run Keybase command
    2020-02-20 17:03:43.739 PST2020/02/21 01:03:43 Listen: failed to auth: unable to run Keybase command
    2020-02-20 17:04:03.739 PST2020/02/21 01:04:03 Listen: failed to auth: unable to run Keybase command
    2020-02-20 17:04:42.038 PST2020/02/21 01:04:42 Listen: failed to auth: unable to run Keybase command
    2020-02-20 17:05:09.139 PST2020/02/21 01:05:09 Listen: failed to auth: unable to run Keybase command
    2020-02-20 17:05:33.239 PST2020/02/21 01:05:33 Listen: failed to auth: unable to run Keybase command
    2020-02-20 17:06:11.238 PST2020/02/21 01:06:11 Listen: failed to auth: unable to run Keybase command
    2020-02-20 17:07:00.939 PST2020/02/21 01:07:00 Listen: failed to auth: unable to run Keybase command
    

    Which finally ends in a

    2020-02-20 17:18:31.241 PSTMemory limit of 1024M exceeded with 1024M used. Consider increasing the memory limit, see https://cloud.google.com/run/docs/configuring/memory-limits
    

    All of them are Listen: failed to auth: unable to run Keybase command, which comes from https://github.com/keybase/go-keybase-chat-bot/blob/1ce2a64ddf45c8fbdfd5c20a81c584bbdc00652f/kbchat/kbchat.go#L63-L65

    The reason why getUsername() is failing is unclear (and probably unrelated), but it doesn't seem that memory usage should increase as it keeps retrying.

    opened by vladionescu 6
  • update types and kvstore nil entries

    update types and kvstore nil entries

    update kvstore nonexistent entries in get requests to be nil instead of an empty string also update all the types

    depends on https://github.com/keybase/client/pull/23884

    opened by xgess 5
  • 5 secs is too little

    5 secs is too little

    Isn't there a better way than to hardcode timouts amindst the code?

    workaround for: https://github.com/keybase/bot-sshca/issues/91

    My setup:

    • Raspberry Pi B V1.2
    • Location: Colombia
    • Normal internet latency during corona times
    opened by blaggacao 2
  • attempt to fix a race

    attempt to fix a race

    i've been seeing some racey behavior in my bot. sometimes payment events don't get put into the channel if other things are happening at the same time.

    a little bit of research led me to this: https://github.com/golang/go/issues/19685

    @mmaxim what do you think? i was surprised it would help, but it does seem (at least locally) to have improved the situation. hard to know for sure since it's a pretty sporadic problem.

    opened by xgess 2
  • reorg

    reorg

    messy commit history...but all this is doing is

    • moving some tests from kbchat_test.go to chat_test.go, if the function it's testing was moved to chat.go
    • moving structs from types.go that are only used in 1 other go file into that go file

    https://github.com/keybase/go-keybase-chat-bot/pull/39 builds on this PR

    opened by mmou 1
  • Keybase

    Keybase

    Hi, I have installed Keybase today on windows7, but after installation, only a black window is appearing. Nothing else is showing. Please guide what to do? Regards

    opened by oxidil 1
  • Use generated types from AVDL

    Use generated types from AVDL

    Take advantage of node-avdl-compiler 1.4.1 to generate our types.

    Some notes:

    • Since this changes some variable names, this would be a breaking change. I have "Version 2" project to track other changes I think would make sense to go in a 2.0. It seems like the two ways to upgrade version in go is to create a version git tag, separate v2 branch, or v2 subdirectory in the repo. Would love to hear which approach y'all like best, I'm leaning towards tagging.
    • I added a Makefile to generate the types from this repo. The Makefile utilizes the tooling inside the client repo.
    • The README and examples should be updated.
    opened by nathanmsmith 1
  • Use bufio.Reader instead of Scanner for most API calls

    Use bufio.Reader instead of Scanner for most API calls

    For conversations with long histories, bufio.Scanner is not able to parse the entire output in one scan. As per the Go docs' reccomendation:

    Programs that need more control over error handling or large tokens, or must run sequential scans on a reader, should use bufio.Reader instead.

    I opted to use bufio.Reader instead.

    This change only affects functions like GetTextMessages and sends; the listen functionality still uses scanners because bufio.Scanner seems perfectly capable of handling message output from a listen. This could change in the future and may be worth revisiting, but I figured I wouldn't change what isn't broken.

    opened by nathanmsmith 1
  • Support MessageSystemAddedToTeam type

    Support MessageSystemAddedToTeam type

    I only added the one type, but ideally we support all of the system messages. I didn't add all of them because I feel like it would make more sense to include the types from github.com/keybase/client/go

    opened by marceloneil 1
  • Fix README syntax for example code snippets

    Fix README syntax for example code snippets

    This fixes some simple syntax issues with the example code snippets. I updated them based off of the code in the examples/ directory.

    I also got a bit carried away and fixed up some of the "Commands" list. However, I realized that list is kind of incomplete and maybe should be using godoc anyways.

    opened by marceloneil 1
  • Command.stdoutpipe fails on GCP Cloud Run

    Command.stdoutpipe fails on GCP Cloud Run

    Breaking this out from #55

    Google Cloud's serverless container environment is called Cloud Run.

    I'm trying to run a bot here in a container, but it kept crashing on calls to kbc.GetUsername(). Eventually this was tracked down to be a problem with the Command("status") call.

    The issue is that Cloud Run captures STDOUT and STDERR without duplicating the file descriptors, so those original STDOUT/STDERR FDs are no longer doing what we expect. getUsername() expects to shell out to keybase status and read its STDOUT, but since the FDs are being hogged by Cloud Run's logging, the output doesn't come back and it ends up timing out as noted in #55.

    In that issue I recommended 2 potential fixes: using a different FD that we know Cloud Run isn't hogging, or using another API altogether that doesn't involve shelling out to the keybase CLI.

    @malware-unicorn PoC'd the first option successfully.

    opened by vladionescu 4
  • Use GoDoc

    Use GoDoc

    Currently, we document all our functions in the markdown of the README. I think it'd be nice and more idiomatic if we transferred most of this documentation over to GoDoc comments and linked to the godoc.org page for the bot.

    That being said, I think it's still important to describe some basic functionalities and examples in the README, I just think the comprehensive documentation would make more sense in a medium better suited for it.

    opened by nathanmsmith 0
  • Proposal: rename bot package

    Proposal: rename bot package

    Our bot is starting to integrate wallet and team features. If we were to do a major upgrade, I think it'd make sense to rename the package from kbchat to something more general, like kbbot.

    opened by nathanmsmith 0
  • Proposal: Parity between bot functions and Keybase API names

    Proposal: Parity between bot functions and Keybase API names

    Many of the names and functions that the go bot uses are very specific. Examples:

    • GetTextMessages (all other message types are ignored)
    • SendAttachmentByTeam

    Rather than have specific functions for cases like these, I think it'd make more sense to have more general options that map 1-to-1 to the functions exposed to us by the underlying Keybase API. The TypeScript bot is a good example of this; the functionality for the above functions is implemented via read and attach, respectively.

    That being said, I think there are some methods like SendMessageByTlfName that save the creation of a lot of new channel objects. Since the bot types will require a major version upgrade, I'm opening this issue to start a discussion on what function signatures it'd make sense to change in a v2.

    opened by nathanmsmith 0
Owner
Keybase
Crypto for everyone!
Keybase
Search & watch Youtube videos from a Zoom Meeting chat bot.

Uut Download and search for Youtube videos from a Zoom meeting chatbot. Installation Download Golang and setup your environment Clone this repo Instal

Kevin Roleke 0 Nov 2, 2021
A telegram bot to ban the chat spammers by channel, made with Golang.

ChannelBot A telegram bot to ban channels spamming chat. Vars TOKEN - Your Telegram Bot Token (@BotFather) More Information With the latest update of

Reeshu 5 Apr 16, 2022
ChatRat is a twitch chat bot built in Go that is a dedicated shitpost machine.

ChatRat ChatRat is a twitch chat bot built in Go that is a dedicated shitpost machine. Also does some other things, but for now the main thing is just

Pattycakes 3 Dec 31, 2021
A serverless bot which periodically checks configured BigQuery capacity commitments, reservations and assignments against actual slot consumption of running jobs and reports findings to Slack/Google Chat.

Solution Guide This solution implements a ChatOps-like approach to monitoring slot utilization of Google Cloud BigQuery reservations. As an alternativ

Google Cloud Platform 4 May 2, 2022
A golang sdk for guild bot

botgo a golang sdk for guild bot 设计模式 分为三个主要模块 openapi 用于请求 http 的 openapi websocket 用于监听事件网关,接收事件消息 oauth 用于处理 oauth 的 token 获取 openapi 接口定义:openapi/

null 171 Jun 16, 2022
A bot based on Telegram Bot API written in Golang allows users to download public Instagram photos, videos, and albums without receiving the user's credentials.

InstagramRobot InstagramRobot is a bot based on Telegram Bot API written in Golang that allows users to download public Instagram photos, videos, and

FTC Team 8 Dec 16, 2021
Dlercloud-telegram-bot - A Telegram bot for managing your Dler Cloud account

Dler Cloud Telegram Bot A Telegram bot for managing your Dler Cloud account. Usa

Beta Kuang 1 Dec 30, 2021
Quote-bot - Un bot utilisant l'API Twitter pour tweeter une citation par jour sur la programmation et les mathématiques.

Description Ceci est un simple bot programmé en Golang qui tweet une citation sur la programmation tout les jours. Ce bot est host sur le compte Twitt

Liam Cornu 0 Jan 1, 2022
Discord-bot - A Discord bot with golang

JS discord bots Install Clone repo git clone https://github.com/fu-js/discord-bo

JS Club 2 Mar 7, 2022
Bot - Telegram Music Bot in Go

Telegram Music Bot in Go An example bot using gotgcalls. Setup Install the serve

null 8 Feb 20, 2022
Pro-bot - A telegram bot to play around with the community telegram channels

pro-bot ?? Pro Bot A Telegram Bot to Play Around With The Community Telegram Cha

TechProber 1 Jan 24, 2022
Slack-emoji-bot - This Slack bot will post the newly created custom Slack emojis to the channel of your choice

Slack Emoji Bot This Slack bot will post the newly created custom Slack emojis t

Ryan Hollis 6 Jun 17, 2022
Sex-bot - The sex bot and its uncreative responses

Sex Bot The sex bot, made with golang! The sex bot can't hear the word "sexo" he

Marcos Vas 2 May 26, 2022
Feline-bot - Feline Bot for Discord using Golang

Feline Bot for Discord Development This bot is implemented using Golang. Feature

null 0 Feb 10, 2022
Zuri Chat Repo

zurichat Zuri Chat Repo To setup To get the Go server running go to the terminal and enter the zc_core type "go run ." Open the url http://127.0.0.1:8

null 18 Nov 8, 2021
A fast responsive, machine learning, conversational dialog engine for creating chat bots, written in Go.

chatbot English | 简体中文 项目说明 chatbot 是一个通过已知对话数据集快速生成回答的 Go 问答引擎。比 ChatterBot 快非常多,我们在1.2亿对话上的对比结果是:ChatterBot 回答需要21秒,chatbot 只需要18毫秒。 bot 问答引擎 cli tr

Kevin Wan 310 Jun 23, 2022
DiscordGo: a Go package that provides low level bindings to the Discord chat client API

DiscordGo DiscordGo is a Go package that provides low level bindings to the Discord chat client API. DiscordGo has nearly complete support for all of

Владислав Черников 1 Dec 14, 2021
This utility allows you to execute Minecraft server commands through the RCON protocol via Telegram chat.

Minecraft RCON by Telegram This utility allows you to execute Minecraft server commands through the RCON protocol via Telegram chat. FAQ When you run

Alexander Pers0na2 4 Apr 24, 2022
This repo is some SDK of Binance

Binance API Go Language SDK This is a Binance Go language sdk that uses a method similar to HuobiRDCenter/huobi_Golang Official Documents Please make

Mickey (Ah !) 131 Jun 10, 2022