Merge pull request #2 from haukened/kvstore
merging kvstore into new dev branch
This commit is contained in:
7
args.go
7
args.go
@ -20,6 +20,7 @@ func (b *bot) parseArgs(args []string) error {
|
||||
flags.StringVar(&cliConfig.LogConvIDStr, "log-convid", "", "sets the keybase chat1.ConvIDStr to log debugging to keybase chat.")
|
||||
flags.StringVar(&cliConfig.FeedbackConvIDStr, "feedback-convid", "", "sets the keybase chat1.ConvIDStr to send feedback to.")
|
||||
flags.StringVar(&cliConfig.FeedbackTeamAdvert, "feedback-team-advert", "", "sets the keybase team/channel to advertise feedback. @team#channel")
|
||||
flags.StringVar(&cliConfig.KVStoreTeam, "kvstore-team", "", "sets the keybase team where kvstore values are stored")
|
||||
if err := flags.Parse(args[1:]); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -38,6 +39,9 @@ func (b *bot) parseArgs(args []string) error {
|
||||
if cliConfig.FeedbackTeamAdvert != "" {
|
||||
b.config.FeedbackTeamAdvert = cliConfig.FeedbackTeamAdvert
|
||||
}
|
||||
if cliConfig.KVStoreTeam != "" {
|
||||
b.config.KVStoreTeam = cliConfig.KVStoreTeam
|
||||
}
|
||||
}
|
||||
|
||||
// then print the running options
|
||||
@ -48,6 +52,9 @@ func (b *bot) parseArgs(args []string) error {
|
||||
if b.config.FeedbackConvIDStr != "" {
|
||||
b.debug("Feedback enabled to %s and advertising %s", b.config.FeedbackConvIDStr, b.config.FeedbackTeamAdvert)
|
||||
}
|
||||
if b.config.KVStoreTeam != "" {
|
||||
b.debug("keybase kvstore enabled in @%s", b.config.KVStoreTeam)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
54
commands.go
54
commands.go
@ -3,6 +3,7 @@ package main
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"samhofi.us/x/keybase/types/chat1"
|
||||
@ -40,3 +41,56 @@ func (b *bot) sendFeedback(convid chat1.ConvIDStr, mesgID chat1.MessageID, sende
|
||||
func (b *bot) sendWelcome(convid chat1.ConvIDStr) {
|
||||
b.k.SendMessageByConvID(convid, "Hello there!! I'm the Jitsi meeting bot, made by @haukened\nI can start Jitsi meetings right here in this chat!\nI can be activated in 2 ways:\n 1. `@jitsibot`\n 2.`!jitsi`\nYou can provide feedback to my humans using:\n 1. `@jitsibot feedback <type anything>`\n 2. `!jitsibot feedback <type anything>`\nYou can also join @jitsi_meet to talk about features, enhancements, or talk to live humans! Everyone is welcome!\nI also accept donations to offset hosting costs, just send some XLM to my wallet if you feel like it by typing `+5XLM@jitsibot`\nIf you ever need to see this message again, ask me for help or say hello to me!")
|
||||
}
|
||||
|
||||
func (b *bot) setKValue(convid chat1.ConvIDStr, msgID chat1.MessageID, args []string) {
|
||||
if args[0] != "set" {
|
||||
return
|
||||
}
|
||||
switch len(args) {
|
||||
case 3:
|
||||
if args[1] == "url" {
|
||||
// first validate the URL
|
||||
u, err := url.ParseRequestURI(args[2])
|
||||
if err != nil {
|
||||
b.k.ReplyByConvID(convid, msgID, "ERROR - `%s`", err)
|
||||
return
|
||||
}
|
||||
// then make sure its HTTPS
|
||||
if u.Scheme != "https" {
|
||||
b.k.ReplyByConvID(convid, msgID, "ERROR - HTTPS Required")
|
||||
return
|
||||
}
|
||||
// then get the current options
|
||||
var opts ConvOptions
|
||||
err = b.KVStoreGetStruct(convid, &opts)
|
||||
if err != nil {
|
||||
eid := b.logError(err)
|
||||
b.k.ReactByConvID(convid, msgID, "Error %s", eid)
|
||||
return
|
||||
}
|
||||
// then update the struct using only the scheme and hostname:port
|
||||
if u.Port() != "" {
|
||||
opts.CustomURL = fmt.Sprintf("%s://%s:%s/", u.Scheme, u.Hostname(), u.Port())
|
||||
} else {
|
||||
opts.CustomURL = fmt.Sprintf("%s://%s/", u.Scheme, u.Hostname())
|
||||
}
|
||||
// then write that back to kvstore, with revision
|
||||
err = b.KVStorePutStruct(convid, opts)
|
||||
if err != nil {
|
||||
eid := b.logError(err)
|
||||
b.k.ReactByConvID(convid, msgID, "ERROR %s", eid)
|
||||
return
|
||||
}
|
||||
b.k.ReactByConvID(convid, msgID, "OK!")
|
||||
return
|
||||
}
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (b *bot) listKValue(convid chat1.ConvIDStr, msgID chat1.MessageID, args []string) {
|
||||
if args[0] != "list" {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
7
go.mod
7
go.mod
@ -4,8 +4,13 @@ go 1.13
|
||||
|
||||
require (
|
||||
github.com/caarlos0/env v3.5.0+incompatible
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/kr/pretty v0.1.0 // indirect
|
||||
github.com/sethvargo/go-diceware v0.2.0
|
||||
github.com/stretchr/testify v1.5.1 // indirect
|
||||
github.com/teris-io/shortid v0.0.0-20171029131806-771a37caa5cf
|
||||
github.com/ugorji/go/codec v1.1.7
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
|
||||
gopkg.in/yaml.v2 v2.2.4 // indirect
|
||||
samhofi.us/x/keybase v0.0.0-20200312153536-07f5168a6a29
|
||||
samhofi.us/x/keybase v0.0.0-20200315012740-74fb4a152b35
|
||||
)
|
||||
|
||||
23
go.sum
23
go.sum
@ -2,10 +2,13 @@ github.com/caarlos0/env v3.5.0+incompatible h1:Yy0UN8o9Wtr/jGHZDpCBLpNrzcFLLM2yi
|
||||
github.com/caarlos0/env v3.5.0+incompatible/go.mod h1:tdCsowwCzMLdkqRYDlHpZCp2UooDD3MspDBjZ2AD02Y=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/lithammer/shortuuid/v3 v3.0.4 h1:uj4xhotfY92Y1Oa6n6HUiFn87CdoEHYUlTy0+IgbLrs=
|
||||
github.com/lithammer/shortuuid/v3 v3.0.4/go.mod h1:RviRjexKqIzx/7r1peoAITm6m7gnif/h+0zmolKJjzw=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/sethvargo/go-diceware v0.2.0 h1:3QzXGqUe0UR9y1XYSz1dxGS+fKtXOxRqqKjy+cG1yTI=
|
||||
@ -13,10 +16,18 @@ github.com/sethvargo/go-diceware v0.2.0/go.mod h1:II+37A5sTGAtg3zd/JqyVQ8qqAjSm/
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/teris-io/shortid v0.0.0-20171029131806-771a37caa5cf h1:Z2X3Os7oRzpdJ75iPqWZc0HeJWFYNCvKsfpQwFpRNTA=
|
||||
github.com/teris-io/shortid v0.0.0-20171029131806-771a37caa5cf/go.mod h1:M8agBzgqHIhgj7wEn9/0hJUZcrvt9VY+Ln+S1I5Mha0=
|
||||
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
samhofi.us/x/keybase v0.0.0-20200312153536-07f5168a6a29 h1:+yj8+O6C56QM8WGZYtDwBFxkdPT4UgVU+O9W+6N85kk=
|
||||
samhofi.us/x/keybase v0.0.0-20200312153536-07f5168a6a29/go.mod h1:fcva80IUFyWcHtV4bBSzgKg07K6Rvuvi3GtGCLNGkyE=
|
||||
samhofi.us/x/keybase v0.0.0-20200315012740-74fb4a152b35 h1:pnpx+34wna1ML9JxHEChf3lDSBOOEh91B5IDuNFUZYk=
|
||||
samhofi.us/x/keybase v0.0.0-20200315012740-74fb4a152b35/go.mod h1:fcva80IUFyWcHtV4bBSzgKg07K6Rvuvi3GtGCLNGkyE=
|
||||
|
||||
12
handlers.go
12
handlers.go
@ -49,7 +49,8 @@ func (b *bot) chatHandler(m chat1.MsgSummary) {
|
||||
// Determine first if this is a command
|
||||
if strings.HasPrefix(m.Content.Text.Body, "!") || strings.HasPrefix(m.Content.Text.Body, "@") {
|
||||
// determine the root command
|
||||
words := strings.Fields(m.Content.Text.Body)
|
||||
body := strings.ToLower(m.Content.Text.Body)
|
||||
words := strings.Fields(body)
|
||||
command := strings.Replace(words[0], "@", "", 1)
|
||||
command = strings.Replace(command, "!", "", 1)
|
||||
command = strings.ToLower(command)
|
||||
@ -58,7 +59,14 @@ func (b *bot) chatHandler(m chat1.MsgSummary) {
|
||||
nargs := len(args)
|
||||
switch command {
|
||||
case b.k.Username:
|
||||
fallthrough
|
||||
if nargs > 0 {
|
||||
switch args[0] {
|
||||
case "set":
|
||||
b.setKValue(m.ConvID, m.Id, args)
|
||||
case "list":
|
||||
b.listKValue(m.ConvID, m.Id, args)
|
||||
}
|
||||
}
|
||||
case "jitsi":
|
||||
if nargs == 0 {
|
||||
b.setupMeeting(m.ConvID, m.Sender.Username, args, m.Channel.MembersType)
|
||||
|
||||
91
kvstore.go
Normal file
91
kvstore.go
Normal file
@ -0,0 +1,91 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/ugorji/go/codec"
|
||||
"samhofi.us/x/keybase/types/chat1"
|
||||
)
|
||||
|
||||
// KvStorePutStruct marshals an interface to JSON and sends to kvstore
|
||||
func (b *bot) KVStorePutStruct(convIDstr chat1.ConvIDStr, v interface{}) error {
|
||||
// marshal the struct to JSON
|
||||
kvstoreDataString, err := encodeStructToJSONString(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// put the string in kvstore
|
||||
err = b.KVStorePut(string(convIDstr), getTypeName(v), kvstoreDataString)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// KVStoreGetStruct gets a string from kvstore and unmarshals the JSON to a struct
|
||||
func (b *bot) KVStoreGetStruct(convIDstr chat1.ConvIDStr, v interface{}) error {
|
||||
// get the string from kvstore
|
||||
result, err := b.KVStoreGet(string(convIDstr), getTypeName(v))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// if there was no result just return and the struct is unmodified
|
||||
if result == "" {
|
||||
return nil
|
||||
}
|
||||
// unmarshal the string into JSON
|
||||
err = decodeJSONStringToStruct(v, result)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// KVStorePut puts a string into kvstore given a key and namespace
|
||||
func (b *bot) KVStorePut(namespace string, key string, value string) error {
|
||||
_, err := b.k.KVPut(&b.config.KVStoreTeam, namespace, key, value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// KVStoreGet gets a string from kvstore given a key and namespace
|
||||
func (b *bot) KVStoreGet(namespace string, key string) (string, error) {
|
||||
kvResult, err := b.k.KVGet(&b.config.KVStoreTeam, namespace, key)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return kvResult.EntryValue, nil
|
||||
}
|
||||
|
||||
// getTypeName returns the name of a type, regardless of if its a pointer or not
|
||||
func getTypeName(v interface{}) string {
|
||||
t := reflect.TypeOf(v)
|
||||
if t.Kind() == reflect.Ptr {
|
||||
return t.Elem().Name()
|
||||
}
|
||||
return t.Name()
|
||||
}
|
||||
|
||||
func encodeStructToJSONString(v interface{}) (string, error) {
|
||||
jh := codecHandle()
|
||||
var bytes []byte
|
||||
err := codec.NewEncoderBytes(&bytes, jh).Encode(v)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
result := string(bytes)
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func decodeJSONStringToStruct(v interface{}, src string) error {
|
||||
bytes := []byte(src)
|
||||
jh := codecHandle()
|
||||
return codec.NewDecoderBytes(bytes, jh).Decode(v)
|
||||
}
|
||||
|
||||
func codecHandle() *codec.JsonHandle {
|
||||
var jh codec.JsonHandle
|
||||
return &jh
|
||||
}
|
||||
17
main.go
17
main.go
@ -29,6 +29,7 @@ type botConfig struct {
|
||||
LogConvIDStr string `env:"BOT_LOG_CONVID" envDefault:""`
|
||||
FeedbackConvIDStr string `env:"BOT_FEEDBACK_CONVID" envDefault:""`
|
||||
FeedbackTeamAdvert string `env:"BOT_FEEDBACK_TEAM_ADVERT" envDefault:""`
|
||||
KVStoreTeam string `env:"BOT_KVSTORE_TEAM" envDefault:""`
|
||||
}
|
||||
|
||||
// hold reply information when needed
|
||||
@ -110,6 +111,22 @@ func (b *bot) run(args []string) error {
|
||||
b.k.ClearCommands()
|
||||
b.registerCommands()
|
||||
|
||||
// this is just for testing, and doesn't work yet
|
||||
if err := b.KVStorePutStruct("test", &ConvOptions{ConvID: "test", CustomURL: "https://te.st:888"}); err != nil {
|
||||
log.Printf("KV: %+v", err)
|
||||
}
|
||||
var vRes1 ConvOptions
|
||||
if err := b.KVStoreGetStruct("test", &vRes1); err != nil {
|
||||
log.Printf("KV: %+v", err)
|
||||
} else {
|
||||
fmt.Printf("VR: %+v\n", vRes1)
|
||||
}
|
||||
var vRes2 ConvOptions
|
||||
if err := b.KVStoreGetStruct("test1", &vRes2); err != nil {
|
||||
log.Printf("KV: %+v", err)
|
||||
} else {
|
||||
fmt.Printf("VR: %+v\n", vRes2)
|
||||
}
|
||||
log.Println("Starting...")
|
||||
b.k.Run(b.handlers, &b.opts)
|
||||
return nil
|
||||
|
||||
8
types.go
Normal file
8
types.go
Normal file
@ -0,0 +1,8 @@
|
||||
package main
|
||||
|
||||
// ConvOptions stores team specific options like custom servers
|
||||
type ConvOptions struct {
|
||||
ConvID string `json:"converation_id,omitempty"`
|
||||
NotificationsEnabled bool `json:"notifications_enabled,omitempty"`
|
||||
CustomURL string `json:"custom_url,omitempty"`
|
||||
}
|
||||
10
utils.go
10
utils.go
@ -4,6 +4,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/teris-io/shortid"
|
||||
"samhofi.us/x/keybase/types/chat1"
|
||||
)
|
||||
|
||||
@ -27,3 +28,12 @@ func getFeedbackExtendedDescription(bc botConfig) *chat1.UserBotExtendedDescript
|
||||
MobileBody: "Please note: Your feedback will be public!",
|
||||
}
|
||||
}
|
||||
|
||||
func (b *bot) logError(err error) string {
|
||||
// generate the error id
|
||||
eid := shortid.MustGenerate()
|
||||
// send the error to the log
|
||||
b.debug("`%s` - %s", eid, err)
|
||||
// then return the error id for use
|
||||
return eid
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user