commit
8879a32137
11 changed files with 449 additions and 0 deletions
@ -0,0 +1,7 @@ |
|||||||
|
Copyright 2020 David Haukeness |
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: |
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. |
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
@ -0,0 +1,35 @@ |
|||||||
|
package main |
||||||
|
|
||||||
|
import ( |
||||||
|
"flag" |
||||||
|
|
||||||
|
"github.com/caarlos0/env" |
||||||
|
) |
||||||
|
|
||||||
|
// parseArgs parses command line and environment args and sets globals
|
||||||
|
func (b *bot) parseArgs(args []string) error { |
||||||
|
// parse the env variables into the bot config
|
||||||
|
if err := env.Parse(&b.config); err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
|
||||||
|
// then parse CLI args as overrides
|
||||||
|
flags := flag.NewFlagSet(args[0], flag.ExitOnError) |
||||||
|
cliConfig := botConfig{} |
||||||
|
flags.BoolVar(&cliConfig.Debug, "debug", false, "enables command debugging") |
||||||
|
if err := flags.Parse(args[1:]); err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
|
||||||
|
// then override the environment vars if there were cli args
|
||||||
|
if flags.NFlag() > 0 { |
||||||
|
if cliConfig.Debug == true { |
||||||
|
b.config.Debug = true |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// then print the running options
|
||||||
|
b.debug("Debug Enabled") |
||||||
|
|
||||||
|
return nil |
||||||
|
} |
@ -0,0 +1,33 @@ |
|||||||
|
package main |
||||||
|
|
||||||
|
import ( |
||||||
|
"bytes" |
||||||
|
"fmt" |
||||||
|
"log" |
||||||
|
"text/tabwriter" |
||||||
|
|
||||||
|
"samhofi.us/x/keybase/types/chat1" |
||||||
|
) |
||||||
|
|
||||||
|
func (b *bot) setupMeeting(convid chat1.ConvIDStr, msgid chat1.MessageID, words []string, membersType string) { |
||||||
|
b.debug("command recieved in conversation %s", convid) |
||||||
|
meeting, err := newJitsiMeeting() |
||||||
|
if err != nil { |
||||||
|
log.Println(err) |
||||||
|
b.k.SendMessageByConvID(convid, "I'm sorry, i'm not sure what happened... I was unable to set up a new meeting.\nI've written the appropriate logs and notified my humans.") |
||||||
|
return |
||||||
|
} |
||||||
|
var buf bytes.Buffer |
||||||
|
w := tabwriter.NewWriter(&buf, 0, 4, 3, ' ', 0) |
||||||
|
fmt.Fprintln(w, "Here's your meeting:") |
||||||
|
fmt.Fprintf(w, "URL:\t%s\n", meeting.getURL()) |
||||||
|
fmt.Fprintf(w, "PIN:\t%s\n", meeting.getPIN()) |
||||||
|
fmt.Fprintln(w, "Dial In:\t") |
||||||
|
fmt.Fprintln(w, "```") |
||||||
|
for _, phone := range meeting.Phone { |
||||||
|
fmt.Fprintf(w, " %s\t%s\t\n", phone.Country, phone.Number) |
||||||
|
} |
||||||
|
fmt.Fprintln(w, "```") |
||||||
|
w.Flush() |
||||||
|
b.k.SendMessageByConvID(convid, buf.String()) |
||||||
|
} |
@ -0,0 +1,12 @@ |
|||||||
|
module jitsy-bot |
||||||
|
|
||||||
|
go 1.13 |
||||||
|
|
||||||
|
require ( |
||||||
|
github.com/caarlos0/env v3.5.0+incompatible |
||||||
|
github.com/lithammer/shortuuid/v3 v3.0.4 |
||||||
|
github.com/onsi/ginkgo v1.12.0 // indirect |
||||||
|
github.com/onsi/gomega v1.9.0 // indirect |
||||||
|
github.com/tjarratt/babble v0.0.0-20191209142150-eecdf8c2339d |
||||||
|
samhofi.us/x/keybase v0.0.0-20200312153536-07f5168a6a29 |
||||||
|
) |
@ -0,0 +1,38 @@ |
|||||||
|
github.com/caarlos0/env v3.5.0+incompatible h1:Yy0UN8o9Wtr/jGHZDpCBLpNrzcFLLM2yixi/rBrKyJs= |
||||||
|
github.com/caarlos0/env v3.5.0+incompatible/go.mod h1:tdCsowwCzMLdkqRYDlHpZCp2UooDD3MspDBjZ2AD02Y= |
||||||
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= |
||||||
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= |
||||||
|
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/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= |
||||||
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= |
||||||
|
github.com/lithammer/shortuuid v3.0.0+incompatible h1:NcD0xWW/MZYXEHa6ITy6kaXN5nwm/V115vj2YXfhS0w= |
||||||
|
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/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= |
||||||
|
github.com/onsi/ginkgo v1.12.0 h1:Iw5WCbBcaAAd0fpRb1c9r5YCylv4XDoCSigm1zLevwU= |
||||||
|
github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= |
||||||
|
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= |
||||||
|
github.com/onsi/gomega v1.9.0 h1:R1uwffexN6Pr340GtYRIdZmAiN4J+iw6WG4wog1DUXg= |
||||||
|
github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= |
||||||
|
github.com/tjarratt/babble v0.0.0-20191209142150-eecdf8c2339d h1:b7oHBI6TgTdCDuqTijsVldzlh+6cfQpdYLz1EKtCAoY= |
||||||
|
github.com/tjarratt/babble v0.0.0-20191209142150-eecdf8c2339d/go.mod h1:O5hBrCGqzfb+8WyY8ico2AyQau7XQwAfEQeEQ5/5V9E= |
||||||
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA= |
||||||
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
||||||
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
||||||
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
||||||
|
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e h1:N7DeIrjYszNmSW409R3frPPwglRwMkXSBzwVbkOjLLA= |
||||||
|
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
||||||
|
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= |
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= |
||||||
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc= |
||||||
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |
||||||
|
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= |
||||||
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= |
||||||
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= |
||||||
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= |
||||||
|
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= |
@ -0,0 +1,103 @@ |
|||||||
|
package main |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
"log" |
||||||
|
"strings" |
||||||
|
|
||||||
|
"samhofi.us/x/keybase" |
||||||
|
"samhofi.us/x/keybase/types/chat1" |
||||||
|
"samhofi.us/x/keybase/types/stellar1" |
||||||
|
) |
||||||
|
|
||||||
|
// RegisterHandlers is called by main to map these handler funcs to events
|
||||||
|
func (b *bot) registerHandlers() { |
||||||
|
chat := b.chatHandler |
||||||
|
conv := b.convHandler |
||||||
|
wallet := b.walletHandler |
||||||
|
err := b.errHandler |
||||||
|
|
||||||
|
b.handlers = keybase.Handlers{ |
||||||
|
ChatHandler: &chat, |
||||||
|
ConversationHandler: &conv, |
||||||
|
WalletHandler: &wallet, |
||||||
|
ErrorHandler: &err, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// chatHandler should handle all messages coming from the chat
|
||||||
|
func (b *bot) chatHandler(m chat1.MsgSummary) { |
||||||
|
// only handle text, we don't really care about attachments
|
||||||
|
if m.Content.TypeName != "text" { |
||||||
|
return |
||||||
|
} |
||||||
|
// if this chat message is a payment, add it to the bot payments
|
||||||
|
if m.Content.Text.Payments != nil { |
||||||
|
// there can be multiple payments on each message, iterate them
|
||||||
|
for _, payment := range m.Content.Text.Payments { |
||||||
|
if strings.Contains(payment.PaymentText, b.k.Username) { |
||||||
|
// if the payment is successful put log the payment for wallet closure
|
||||||
|
if payment.Result.ResultTyp__ == 0 && payment.Result.Error__ == nil { |
||||||
|
var replyInfo = botReply{convID: m.ConvID, msgID: m.Id} |
||||||
|
b.payments[*payment.Result.Sent__] = replyInfo |
||||||
|
} else { |
||||||
|
// if the payment fails, be sad
|
||||||
|
b.k.ReactByConvID(m.ConvID, m.Id, ":cry:") |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
// if the message is @myusername just perform the default function
|
||||||
|
if strings.HasPrefix(m.Content.Text.Body, fmt.Sprintf("@%s", b.k.Username)) { |
||||||
|
words := strings.Fields(m.Content.Text.Body) |
||||||
|
b.setupMeeting(m.ConvID, m.Id, words, m.Channel.MembersType) |
||||||
|
} |
||||||
|
// its a command for me, iterate through extended commands
|
||||||
|
if strings.HasPrefix(m.Content.Text.Body, "!") { |
||||||
|
// break up the message into words
|
||||||
|
words := strings.Fields(m.Content.Text.Body) |
||||||
|
// strip the ! from the first word, and lowercase to derive the command
|
||||||
|
thisCommand := strings.ToLower(strings.Replace(words[0], "!", "", 1)) |
||||||
|
// decide if this is askind for extended commands
|
||||||
|
switch thisCommand { |
||||||
|
case "meeting": |
||||||
|
fallthrough |
||||||
|
case "jitsi": |
||||||
|
b.setupMeeting(m.ConvID, m.Id, words, m.Channel.MembersType) |
||||||
|
default: |
||||||
|
return |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// handle conversations (this fires when a new conversation is initiated)
|
||||||
|
// i.e. when someone opens a conversation to you but hasn't sent a message yet
|
||||||
|
func (b *bot) convHandler(m chat1.ConvSummary) { |
||||||
|
switch m.Channel.MembersType { |
||||||
|
case "team": |
||||||
|
b.debug("Added to new team: @%s (%s) Sending welcome message", m.Channel.Name, m.Id) |
||||||
|
case "impteamnative": |
||||||
|
b.debug("New conversation found %s (%s) Sending welcome message", m.Channel.Name, m.Id) |
||||||
|
default: |
||||||
|
b.debug("New convID found %s, sending welcome message.", m.Id) |
||||||
|
} |
||||||
|
b.k.SendMessageByConvID(m.Id, "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`\nI also accept donations to offset hosting costs,\njust send some XLM to my wallet if you feel like it by typing `+5XLM@urbandictionary`") |
||||||
|
} |
||||||
|
|
||||||
|
// this handles wallet events, like when someone send you money in chat
|
||||||
|
func (b *bot) walletHandler(m stellar1.PaymentDetailsLocal) { |
||||||
|
// if the payment is successful
|
||||||
|
if m.Summary.StatusSimplified == 3 { |
||||||
|
// get the reply info and see if it exists
|
||||||
|
replyInfo := b.payments[m.Summary.Id] |
||||||
|
if replyInfo.convID != "" { |
||||||
|
b.k.ReplyByConvID(replyInfo.convID, replyInfo.msgID, "Thank you so much! I'll use this to offset my hosting costs!") |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// this handles all errors returned from the keybase binary
|
||||||
|
func (b *bot) errHandler(m error) { |
||||||
|
log.Println("---[ error ]---") |
||||||
|
log.Println(p(m)) |
||||||
|
} |
@ -0,0 +1,107 @@ |
|||||||
|
package main |
||||||
|
|
||||||
|
import ( |
||||||
|
"encoding/json" |
||||||
|
"fmt" |
||||||
|
"io/ioutil" |
||||||
|
"net/http" |
||||||
|
"net/url" |
||||||
|
"sort" |
||||||
|
"strconv" |
||||||
|
|
||||||
|
"github.com/lithammer/shortuuid/v3" |
||||||
|
) |
||||||
|
|
||||||
|
type phoneNumber struct { |
||||||
|
Country string |
||||||
|
Number string |
||||||
|
} |
||||||
|
|
||||||
|
type jitsiMeeting struct { |
||||||
|
Name string |
||||||
|
ID string |
||||||
|
Phone []phoneNumber |
||||||
|
} |
||||||
|
|
||||||
|
func (j *jitsiMeeting) getJitsiName() { |
||||||
|
j.Name = shortuuid.New() |
||||||
|
} |
||||||
|
|
||||||
|
func (j *jitsiMeeting) getURL() string { |
||||||
|
return fmt.Sprintf("https://meet.jit.si/%s", j.Name) |
||||||
|
} |
||||||
|
|
||||||
|
func (j *jitsiMeeting) getPIN() string { |
||||||
|
if len(j.ID) == 10 { |
||||||
|
return fmt.Sprintf("%s %s %s#", j.ID[0:4], j.ID[4:8], j.ID[8:10]) |
||||||
|
} |
||||||
|
return fmt.Sprintf("%s#", j.ID) |
||||||
|
} |
||||||
|
|
||||||
|
func (j *jitsiMeeting) getJitsiID() error { |
||||||
|
type jitsiMeetingHTTPResponse struct { |
||||||
|
Message string `json:"message,omitempty"` |
||||||
|
ID int64 `json:"id,omitempty"` |
||||||
|
Conference string `json:"conference,omitempty"` |
||||||
|
} |
||||||
|
|
||||||
|
queryURL := fmt.Sprintf("https://api.jitsi.net/conferenceMapper?conference=%s@conference.meet.jit.si", url.QueryEscape(j.Name)) |
||||||
|
resp, err := http.Get(queryURL) |
||||||
|
if err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
defer resp.Body.Close() |
||||||
|
respBody, err := ioutil.ReadAll(resp.Body) |
||||||
|
if err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
var jR jitsiMeetingHTTPResponse |
||||||
|
if err := json.Unmarshal(respBody, &jR); err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
j.ID = strconv.FormatInt(jR.ID, 10) |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
func (j *jitsiMeeting) getJitsiNumbers() error { |
||||||
|
type jitsiPhoneHTTPResponse struct { |
||||||
|
Message string `json:"message,omitempty"` |
||||||
|
Numbers map[string][]string `json:"numbers,omitempty"` |
||||||
|
Enabled bool `json:"numbersEnabled,omitempty"` |
||||||
|
} |
||||||
|
queryURL := fmt.Sprintf("https://api.jitsi.net/phoneNumberList?conference=%s@conference.meet.jit.si", url.QueryEscape(j.Name)) |
||||||
|
resp, err := http.Get(queryURL) |
||||||
|
if err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
defer resp.Body.Close() |
||||||
|
respBody, err := ioutil.ReadAll(resp.Body) |
||||||
|
if err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
var jR jitsiPhoneHTTPResponse |
||||||
|
if err := json.Unmarshal(respBody, &jR); err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
for key, value := range jR.Numbers { |
||||||
|
j.Phone = append(j.Phone, phoneNumber{ |
||||||
|
Country: key, |
||||||
|
Number: value[0], |
||||||
|
}) |
||||||
|
} |
||||||
|
// then sort them alphabetically
|
||||||
|
sort.Slice(j.Phone, func(a, b int) bool { return j.Phone[a].Country < j.Phone[b].Country }) |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
func newJitsiMeeting() (jitsiMeeting, error) { |
||||||
|
result := jitsiMeeting{} |
||||||
|
result.getJitsiName() |
||||||
|
if err := result.getJitsiID(); err != nil { |
||||||
|
return result, err |
||||||
|
} |
||||||
|
if err := result.getJitsiNumbers(); err != nil { |
||||||
|
return result, err |
||||||
|
} |
||||||
|
return result, nil |
||||||
|
} |
Binary file not shown.
@ -0,0 +1,100 @@ |
|||||||
|
package main |
||||||
|
|
||||||
|
import ( |
||||||
|
"log" |
||||||
|
"os" |
||||||
|
|
||||||
|
"samhofi.us/x/keybase" |
||||||
|
"samhofi.us/x/keybase/types/chat1" |
||||||
|
"samhofi.us/x/keybase/types/stellar1" |
||||||
|
) |
||||||
|
|
||||||
|
// this global controls debug printing
|
||||||
|
var debug bool |
||||||
|
|
||||||
|
// Bot holds the necessary information for the bot to work.
|
||||||
|
type bot struct { |
||||||
|
k *keybase.Keybase |
||||||
|
handlers keybase.Handlers |
||||||
|
opts keybase.RunOptions |
||||||
|
payments map[stellar1.PaymentID]botReply |
||||||
|
config botConfig |
||||||
|
} |
||||||
|
|
||||||
|
// botConfig hold env and cli flags and options
|
||||||
|
// fields must be exported for package env (reflect) to work
|
||||||
|
type botConfig struct { |
||||||
|
Debug bool `env:"BOT_DEBUG" envDefault:"false"` |
||||||
|
} |
||||||
|
|
||||||
|
// hold reply information when needed
|
||||||
|
type botReply struct { |
||||||
|
convID chat1.ConvIDStr |
||||||
|
msgID chat1.MessageID |
||||||
|
} |
||||||
|
|
||||||
|
// Debug provides printing only when --debug flag is set or BOT_DEBUG env var is set
|
||||||
|
func (b *bot) debug(s string, a ...interface{}) { |
||||||
|
if b.config.Debug { |
||||||
|
log.Printf(s, a...) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// newBot returns a new empty bot
|
||||||
|
func newBot() *bot { |
||||||
|
var b bot |
||||||
|
b.k = keybase.NewKeybase() |
||||||
|
b.handlers = keybase.Handlers{} |
||||||
|
b.opts = keybase.RunOptions{} |
||||||
|
b.payments = make(map[stellar1.PaymentID]botReply) |
||||||
|
return &b |
||||||
|
} |
||||||
|
|
||||||
|
// this handles setting up command advertisements and aliases
|
||||||
|
func (b *bot) registerCommands() { |
||||||
|
opts := keybase.AdvertiseCommandsOptions{ |
||||||
|
Advertisements: []chat1.AdvertiseCommandAPIParam{ |
||||||
|
{ |
||||||
|
Typ: "public", |
||||||
|
Commands: []chat1.UserBotCommandInput{ |
||||||
|
{ |
||||||
|
Name: "jitsi", |
||||||
|
Description: "Starts a meet.jit.si meeting", |
||||||
|
Usage: "", |
||||||
|
}, |
||||||
|
{ |
||||||
|
Name: "meeting", |
||||||
|
Description: "Starts a meet.jit.si meeting", |
||||||
|
Usage: "", |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
} |
||||||
|
b.k.AdvertiseCommands(opts) |
||||||
|
} |
||||||
|
|
||||||
|
// run performs a proxy main function
|
||||||
|
func (b *bot) run(args []string) error { |
||||||
|
// parse the arguments
|
||||||
|
err := b.parseArgs(args) |
||||||
|
if err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
|
||||||
|
b.registerHandlers() |
||||||
|
b.registerCommands() |
||||||
|
|
||||||
|
log.Println("Starting...") |
||||||
|
b.k.Run(b.handlers, &b.opts) |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
// main is a thin skeleton, proxied to Bot.Run()
|
||||||
|
func main() { |
||||||
|
b := newBot() |
||||||
|
if err := b.run(os.Args); err != nil { |
||||||
|
log.Printf("%s", err) |
||||||
|
os.Exit(1) |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue