Compare commits

...

1 Commits
main ... staff

Author SHA1 Message Date
Etzelia f10f83e3b9
Add ServerAPI, clean up help, Twitter
Signed-off-by: Etzelia <etzelia@hotmail.com>
2021-02-21 23:36:06 -06:00
18 changed files with 473 additions and 96 deletions

4
.gitignore vendored
View File

@ -1,8 +1,6 @@
# GoLand # GoLand
.idea/ .idea/
# Generated
config/config_default.go
# sedbot # sedbot
sedbot* sedbot*
!config/sedbot.example.toml

View File

@ -1,13 +1,15 @@
package config package config
import ( import (
_ "embed"
"io/ioutil" "io/ioutil"
"os" "os"
"github.com/pelletier/go-toml" "github.com/pelletier/go-toml"
) )
var defaultConfig = []byte("") //go:embed sedbot.example.toml
var defaultConfig []byte
type Config struct { type Config struct {
Token string `toml:"token"` Token string `toml:"token"`
@ -23,6 +25,16 @@ type Config struct {
DBPath string `toml:"db_path"` DBPath string `toml:"db_path"`
MCPath string `toml:"mc_path"` MCPath string `toml:"mc_path"`
ImgurClientID string `toml:"imgur_client_id"` ImgurClientID string `toml:"imgur_client_id"`
ServerAPI struct {
Endpoint string `toml:"endpoint"`
Token string `toml:"token"`
} `toml:"serverapi"`
Twitter struct {
ConsumerKey string `toml:"consumer_key"`
ConsumerSecret string `toml:"consumer_secret"`
AccessToken string `toml:"access_token"`
AccessSecret string `toml:"access_secret"`
} `toml:"twitter"`
StaffRoles []string `toml:"staff_roles"` StaffRoles []string `toml:"staff_roles"`
Echoes []Echo `toml:"echoes"` Echoes []Echo `toml:"echoes"`

View File

@ -31,6 +31,24 @@ meme_rate = "0"
# Imgur Client ID # Imgur Client ID
imgur_client_id = "" imgur_client_id = ""
# ServerAPI options
[serverapi]
# API endpoint
endpoint = ""
# Auth token
token = ""
# Twitter options
[twitter]
# Consumer Key
consumer_key = ""
# Consumer Secret
consumer_secret = ""
# Access Token
access_token = ""
# Access Secret
access_secret = ""
# Server options # Server options
[server] [server]
# connection address # connection address

View File

@ -1,16 +1,16 @@
package database package database
import ( import (
"strconv"
"go.etcd.io/bbolt" "go.etcd.io/bbolt"
) )
var ( var (
firedBucket = []byte("fired") firedBucket = []byte("fired")
unbanBucket = []byte("unban")
buckets = [][]byte{ buckets = [][]byte{
firedBucket, firedBucket,
unbanBucket,
} }
) )
@ -35,26 +35,3 @@ func Load(dbPath string) (*Database, error) {
db: db, db: db,
}, nil }, nil
} }
func (db *Database) CheckPing(roleID string) int {
roleIDByte := []byte(roleID)
var idx int
_ = db.db.View(func(tx *bbolt.Tx) error {
num := tx.Bucket(firedBucket).Get(roleIDByte)
if num != nil {
if i, err := strconv.Atoi(string(num)); err == nil {
idx = i
}
}
return nil
})
return idx
}
func (db *Database) IncrementPing(roleID string) error {
roleIDByte := []byte(roleID)
return db.db.Update(func(tx *bbolt.Tx) error {
idx := db.CheckPing(roleID)
return tx.Bucket(firedBucket).Put(roleIDByte, []byte(strconv.Itoa(idx+1)))
})
}

30
database/ping.go 100644
View File

@ -0,0 +1,30 @@
package database
import (
"strconv"
"go.etcd.io/bbolt"
)
func (db *Database) CheckPing(roleID string) int {
roleIDByte := []byte(roleID)
var idx int
_ = db.db.View(func(tx *bbolt.Tx) error {
num := tx.Bucket(firedBucket).Get(roleIDByte)
if num != nil {
if i, err := strconv.Atoi(string(num)); err == nil {
idx = i
}
}
return nil
})
return idx
}
func (db *Database) IncrementPing(roleID string) error {
roleIDByte := []byte(roleID)
return db.db.Update(func(tx *bbolt.Tx) error {
idx := db.CheckPing(roleID)
return tx.Bucket(firedBucket).Put(roleIDByte, []byte(strconv.Itoa(idx+1)))
})
}

49
database/unban.go 100644
View File

@ -0,0 +1,49 @@
package database
import (
"strconv"
"time"
"go.etcd.io/bbolt"
)
type UnbanRecord struct {
Username string
Expiration time.Time
}
func (u UnbanRecord) ExpirationString() string {
return u.Expiration.Format("01/02/2006 at 03:04:05 pm MST")
}
func (db *Database) ListUnbans() []UnbanRecord {
unbans := make([]UnbanRecord, 0)
_ = db.db.View(func(tx *bbolt.Tx) error {
return tx.Bucket(unbanBucket).ForEach(func(username, unix []byte) error {
unixNum, err := strconv.ParseInt(string(unix), 10, 64)
if err != nil {
return err
}
unbans = append(unbans, UnbanRecord{
Username: string(username),
Expiration: time.Unix(unixNum, 0),
})
return nil
})
})
return unbans
}
func (db *Database) AddUnban(record UnbanRecord) error {
usernameByte := []byte(record.Username)
return db.db.Update(func(tx *bbolt.Tx) error {
return tx.Bucket(unbanBucket).Put(usernameByte, []byte(strconv.FormatInt(record.Expiration.Unix(), 10)))
})
}
func (db *Database) RemoveUnban(username string) error {
usernameByte := []byte(username)
return db.db.Update(func(tx *bbolt.Tx) error {
return tx.Bucket(unbanBucket).Delete(usernameByte)
})
}

53
discord/ban.go 100644
View File

@ -0,0 +1,53 @@
package discord
import (
"fmt"
"net/http"
"strings"
"time"
"go.etztech.xyz/go-serverapi"
)
func init() {
commands["ban"] = command{
staffOnly: true,
validate: func(cmd commandInit) bool {
return isStaff(cmd.message.Member.Roles, cmd.config.StaffRoles)
},
run: func(cmd commandInit) (string, error) {
args := strings.Fields(cmd.message.Content)
if len(args) < 2 {
return "This command requires an in-game username.", nil
}
target := args[1]
reason := "You have been banned. Appeal at https://birbmc.com/appeal"
if len(args) >= 3 {
reason = fmt.Sprintf("%s. Appeal at https://birbmc.com/appeal", strings.Join(args[2:], " "))
}
ban := serverapi.Ban{
Kick: serverapi.Kick{
Unban: serverapi.Unban{
Target: target,
},
Reason: reason,
},
Source: "Discord",
Created: time.Now().Unix(),
}
status, err := cmd.sapiClient.Ban(ban)
if err != nil {
return "", err
}
if status != http.StatusOK {
return fmt.Sprintf("ServerAPI returned status %d when trying to ban %s", status, target), nil
}
return fmt.Sprintf("%s was banned by %s", target, cmd.message.Author.Username), nil
},
help: "Ban a player",
}
}

View File

@ -0,0 +1,41 @@
package discord
import (
"fmt"
"net/http"
"strings"
"go.etztech.xyz/go-serverapi"
)
func init() {
commands["broadcast"] = command{
staffOnly: true,
validate: func(cmd commandInit) bool {
return isStaff(cmd.message.Member.Roles, cmd.config.StaffRoles)
},
run: func(cmd commandInit) (string, error) {
args := strings.Fields(cmd.message.Content)
if len(args) < 2 {
return "This command requires a message to broadcast", nil
}
message := strings.Join(args[1:], " ")
broadcast := serverapi.Broadcast{
From: cmd.message.Author.Username,
Message: message,
}
status, err := cmd.sapiClient.Broadcast(broadcast)
if err != nil {
return "", err
}
if status != http.StatusOK {
return fmt.Sprintf("ServerAPI returned status %d when trying to broadcast.", status), nil
}
return "Broadcast sent!", nil
},
help: "Send an in-game broadcast",
}
}

View File

@ -10,6 +10,9 @@ import (
"go.etztech.xyz/sedbot/imgur" "go.etztech.xyz/sedbot/imgur"
"github.com/bwmarrin/discordgo" "github.com/bwmarrin/discordgo"
"github.com/dghubble/go-twitter/twitter"
"github.com/dghubble/oauth1"
"go.etztech.xyz/go-serverapi"
"go.jolheiser.com/beaver" "go.jolheiser.com/beaver"
) )
@ -22,13 +25,17 @@ var (
) )
type commandInit struct { type commandInit struct {
session *discordgo.Session session *discordgo.Session
message *discordgo.Message message *discordgo.Message
config *config.Config config *config.Config
database *database.Database database *database.Database
sapiClient *serverapi.Client
twitterClient *twitter.Client
} }
type command struct { type command struct {
staffOnly bool
// TODO Does this really need to exist separately?
validate func(cmd commandInit) bool validate func(cmd commandInit) bool
run func(cmd commandInit) (string, error) run func(cmd commandInit) (string, error)
help string help string
@ -46,6 +53,22 @@ func Bot(cfg *config.Config, db *database.Database) (*discordgo.Session, error)
return nil, err return nil, err
} }
// Init ServerAPI
sapi := serverapi.NewClient(cfg.ServerAPI.Endpoint, serverapi.WithToken(cfg.ServerAPI.Token))
// Init Twitter
twitterConfig := oauth1.NewConfig(cfg.Twitter.ConsumerKey, cfg.Twitter.ConsumerSecret)
twitterToken := oauth1.NewToken(cfg.Twitter.AccessToken, cfg.Twitter.AccessSecret)
twitterHttpClient := twitterConfig.Client(oauth1.NoContext, twitterToken)
twitterClient := twitter.NewClient(twitterHttpClient)
// Init Unban Schedule
sched := &unbanSchedule{
db: db,
sapi: sapi,
}
go sched.Run()
for _, messageRole := range cfg.MessageRoles { for _, messageRole := range cfg.MessageRoles {
if messageRoleMap[messageRole.MessageID] == nil { if messageRoleMap[messageRole.MessageID] == nil {
messageRoleMap[messageRole.MessageID] = make(map[string]string) messageRoleMap[messageRole.MessageID] = make(map[string]string)
@ -57,7 +80,7 @@ func Bot(cfg *config.Config, db *database.Database) (*discordgo.Session, error)
Echo(cfg) Echo(cfg)
bot.AddHandler(readyHandler()) bot.AddHandler(readyHandler())
bot.AddHandler(leaveHandler(cfg)) bot.AddHandler(leaveHandler(cfg))
bot.AddHandler(commandHandler(cfg, db)) bot.AddHandler(commandHandler(cfg, db, sapi, twitterClient))
bot.AddHandler(messageHandler(cfg, db)) bot.AddHandler(messageHandler(cfg, db))
bot.AddHandler(reactionAddHandler()) bot.AddHandler(reactionAddHandler())
bot.AddHandler(reactionRemoveHandler()) bot.AddHandler(reactionRemoveHandler())
@ -125,7 +148,7 @@ func readyHandler() func(s *discordgo.Session, m *discordgo.Ready) {
} }
} }
func commandHandler(cfg *config.Config, db *database.Database) func(s *discordgo.Session, m *discordgo.MessageCreate) { func commandHandler(cfg *config.Config, db *database.Database, sapi *serverapi.Client, twitterClient *twitter.Client) func(s *discordgo.Session, m *discordgo.MessageCreate) {
return func(s *discordgo.Session, m *discordgo.MessageCreate) { return func(s *discordgo.Session, m *discordgo.MessageCreate) {
// Ignore bots // Ignore bots
if m.Author.Bot { if m.Author.Bot {
@ -150,11 +173,17 @@ func commandHandler(cfg *config.Config, db *database.Database) func(s *discordgo
return return
} }
if cmd.staffOnly && !isStaff(m.Member.Roles, cfg.StaffRoles) {
return
}
cmdInit := commandInit{ cmdInit := commandInit{
session: s, session: s,
message: m.Message, message: m.Message,
config: cfg, config: cfg,
database: db, database: db,
sapiClient: sapi,
twitterClient: twitterClient,
} }
if !cmd.validate(cmdInit) { if !cmd.validate(cmdInit) {
sendMessage(s, m.ChannelID, "You cannot run this command.", false) sendMessage(s, m.ChannelID, "You cannot run this command.", false)

View File

@ -1,8 +1,9 @@
package discord package discord
import ( import (
"fmt"
"strings" "strings"
"github.com/bwmarrin/discordgo"
) )
func init() { func init() {
@ -13,29 +14,64 @@ func init() {
run: func(cmd commandInit) (string, error) { run: func(cmd commandInit) (string, error) {
args := strings.Fields(cmd.message.Content)[1:] args := strings.Fields(cmd.message.Content)[1:]
var resp string var resp *discordgo.MessageEmbed
if len(args) == 1 { if len(args) == 1 {
resp = singleHelp(args[0]) resp = singleHelp(cmd, args[0])
} else { } else {
resp = allHelp() resp = allHelp(cmd)
} }
return resp, nil
channel, err := cmd.session.UserChannelCreate(cmd.message.Author.ID)
if err != nil {
return "", err
}
sendEmbed(cmd.session, channel.ID, resp)
return "", nil
}, },
help: "HELP! HEEEEEEEEEELP!", help: "HELP! HEEEEEEEEEELP!",
} }
} }
func singleHelp(cmd string) string { func singleHelp(cmd commandInit, arg string) *discordgo.MessageEmbed {
if c, ok := commands[cmd]; ok { embed := &discordgo.MessageEmbed{
return fmt.Sprintf("%s: %s", cmd, c.help) Title: "Unkown Command",
} }
return "Unknown command" c, ok := commands[arg]
if !ok {
return embed
}
if c.staffOnly && !isStaff(cmd.message.Member.Roles, cmd.config.StaffRoles) {
return embed
}
embed.Title = arg
embed.Description = c.help
return embed
} }
func allHelp() string { func allHelp(cmd commandInit) *discordgo.MessageEmbed {
helps := make([]string, 0) staff := isStaff(cmd.message.Member.Roles, cmd.config.StaffRoles)
for n, c := range commands { embed := &discordgo.MessageEmbed{
helps = append(helps, fmt.Sprintf("%s: %s", n, c.help)) Title: "SedBot Help",
Fields: make([]*discordgo.MessageEmbedField, 0),
} }
return strings.Join(helps, "\n") if staff {
embed.Description = "Commands with an asterisk (*) are staff-only"
}
for n, c := range commands {
cmdName := n
if c.staffOnly {
cmdName += "*"
}
if !c.staffOnly || staff {
embed.Fields = append(embed.Fields, &discordgo.MessageEmbedField{
Name: cmdName,
Value: c.help,
Inline: true,
})
}
}
return embed
} }

34
discord/tweet.go 100644
View File

@ -0,0 +1,34 @@
package discord
import (
"fmt"
"strings"
)
func init() {
commands["tweet"] = command{
staffOnly: true,
validate: func(cmd commandInit) bool {
return isStaff(cmd.message.Member.Roles, cmd.config.StaffRoles)
},
run: func(cmd commandInit) (string, error) {
args := strings.Fields(cmd.message.Content)
if len(args) < 2 {
return "This command requires a message to tweet", nil
}
message := strings.Join(args[1:], " ")
tweet, resp, err := cmd.twitterClient.Statuses.Update(message, nil)
if err != nil {
return "", err
}
if resp.StatusCode%100 != 2 {
}
return fmt.Sprintf("https://twitter.com/%d/status/%d", tweet.User.ID, tweet.ID), nil
},
help: "Send a tweet from the BirbMC Twitter",
}
}

40
discord/unban.go 100644
View File

@ -0,0 +1,40 @@
package discord
import (
"fmt"
"strconv"
"strings"
"time"
"go.etztech.xyz/sedbot/database"
)
func init() {
commands["unban"] = command{
staffOnly: true,
validate: func(cmd commandInit) bool {
return isStaff(cmd.message.Member.Roles, cmd.config.StaffRoles)
},
run: func(cmd commandInit) (string, error) {
args := strings.Fields(cmd.message.Content)
if len(args) < 3 {
return "This command requires an in-game username and number of days (use 0 days to unban on next schedule).", nil
}
days, err := strconv.Atoi(args[2])
if err != nil {
return "number of days must be an integer", nil
}
target := args[1]
expiration := time.Now().Add(time.Hour * 24 * time.Duration(days))
record := database.UnbanRecord{
Username: target,
Expiration: expiration,
}
return fmt.Sprintf("%s will be unbanned on %s", target, record.ExpirationString()),
cmd.database.AddUnban(record)
},
help: "Unban a player",
}
}

35
discord/unbans.go 100644
View File

@ -0,0 +1,35 @@
package discord
import (
"github.com/bwmarrin/discordgo"
)
func init() {
commands["unbans"] = command{
staffOnly: true,
validate: func(cmd commandInit) bool {
return isStaff(cmd.message.Member.Roles, cmd.config.StaffRoles)
},
run: func(cmd commandInit) (string, error) {
unbans := cmd.database.ListUnbans()
if len(unbans) == 0 {
return "There are no pending unbans", nil
}
embed := &discordgo.MessageEmbed{
Fields: make([]*discordgo.MessageEmbedField, len(unbans)),
}
for i, record := range cmd.database.ListUnbans() {
embed.Fields[i] = &discordgo.MessageEmbedField{
Name: record.Username,
Value: record.ExpirationString(),
Inline: true,
}
}
sendEmbed(cmd.session, cmd.message.ChannelID, embed)
return "", nil
},
help: "Unban a player",
}
}

View File

@ -2,7 +2,13 @@ package discord
import ( import (
r "math/rand" r "math/rand"
"net/http"
"time" "time"
"go.etztech.xyz/sedbot/database"
"go.etztech.xyz/go-serverapi"
"go.jolheiser.com/beaver"
) )
type rateLimit struct { type rateLimit struct {
@ -38,3 +44,40 @@ func random(list []string) string {
idx := rand.Intn(size) idx := rand.Intn(size)
return list[idx] return list[idx]
} }
type unbanSchedule struct {
db *database.Database
sapi *serverapi.Client
}
func (u *unbanSchedule) Run() {
u.check()
ticker := time.NewTicker(time.Minute * 5)
for {
<-ticker.C
u.check()
}
}
func (u *unbanSchedule) check() {
beaver.Debug("Running unban schedule")
now := time.Now()
for _, record := range u.db.ListUnbans() {
if now.After(record.Expiration) {
beaver.Infof("Unbanning %s", record.Username)
unban := serverapi.Unban{
Target: record.Username,
}
status, err := u.sapi.Unban(unban)
if err != nil {
beaver.Error(err)
}
if status != http.StatusOK {
beaver.Errorf("ServerAPI returned status %d when trying to ban %s", status, record.Username)
}
if err := u.db.RemoveUnban(record.Username); err != nil {
beaver.Errorf("could not remove unban for %s in database", record.Username)
}
}
}
}

5
go.mod
View File

@ -1,14 +1,17 @@
module go.etztech.xyz/sedbot module go.etztech.xyz/sedbot
go 1.14 go 1.16
require ( require (
github.com/bwmarrin/discordgo v0.22.0 github.com/bwmarrin/discordgo v0.22.0
github.com/dghubble/go-twitter v0.0.0-20201011215211-4b180d0cc78d
github.com/dghubble/oauth1 v0.7.0
github.com/gorilla/websocket v1.4.2 // indirect github.com/gorilla/websocket v1.4.2 // indirect
github.com/pelletier/go-toml v1.8.1 github.com/pelletier/go-toml v1.8.1
go.etcd.io/bbolt v1.3.4 go.etcd.io/bbolt v1.3.4
go.etztech.xyz/falseknees v0.0.1 go.etztech.xyz/falseknees v0.0.1
go.etztech.xyz/go-mcm v1.3.1 go.etztech.xyz/go-mcm v1.3.1
go.etztech.xyz/go-serverapi v0.0.3
go.etztech.xyz/inspiro v0.0.0-20200606185551-edfdf9da2359 go.etztech.xyz/inspiro v0.0.0-20200606185551-edfdf9da2359
go.jolheiser.com/beaver v1.0.2 go.jolheiser.com/beaver v1.0.2
go.jolheiser.com/gojang v0.0.3 go.jolheiser.com/gojang v0.0.3

24
go.sum
View File

@ -1,28 +1,46 @@
github.com/bwmarrin/discordgo v0.22.0 h1:uBxY1HmlVCsW1IuaPjpCGT6A2DBwRn0nvOguQIxDdFM= github.com/bwmarrin/discordgo v0.22.0 h1:uBxY1HmlVCsW1IuaPjpCGT6A2DBwRn0nvOguQIxDdFM=
github.com/bwmarrin/discordgo v0.22.0/go.mod h1:c1WtWUGN6nREDmzIpyTp/iD3VYt4Fpx+bVyfBG7JE+M= github.com/bwmarrin/discordgo v0.22.0/go.mod h1:c1WtWUGN6nREDmzIpyTp/iD3VYt4Fpx+bVyfBG7JE+M=
github.com/cenkalti/backoff v2.1.1+incompatible h1:tKJnvO2kl0zmb/jA5UKAt4VoEVw1qxKWjE/Bpp46npY=
github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 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/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= github.com/dghubble/go-twitter v0.0.0-20201011215211-4b180d0cc78d h1:sBKr0A8iQ1qAOozedZ8Aox+Jpv+TeP1Qv7dcQyW8V+M=
github.com/dghubble/go-twitter v0.0.0-20201011215211-4b180d0cc78d/go.mod h1:xfg4uS5LEzOj8PgZV7SQYRHbG7jPUnelEiaAVJxmhJE=
github.com/dghubble/oauth1 v0.7.0 h1:AlpZdbRiJM4XGHIlQ8BuJ/wlpGwFEJNnB4Mc+78tA/w=
github.com/dghubble/oauth1 v0.7.0/go.mod h1:8pFdfPkv/jr8mkChVbNVuJ0suiHe278BtWI4Tk1ujxk=
github.com/dghubble/sling v1.3.0 h1:pZHjCJq4zJvc6qVQ5wN1jo5oNZlNE0+8T/h0XeXBUKU=
github.com/dghubble/sling v1.3.0/go.mod h1:XXShWaBWKzNLhu2OxikSNFrlsvowtz4kyRuXUG7oQKY=
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/pelletier/go-toml v1.8.1 h1:1Nf83orprkJyknT6h7zbuEGUEjcyVlCxSUGTENmNCRM= github.com/pelletier/go-toml v1.8.1 h1:1Nf83orprkJyknT6h7zbuEGUEjcyVlCxSUGTENmNCRM=
github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
go.etcd.io/bbolt v1.3.4 h1:hi1bXHMVrlQh6WwxAy+qZCV/SYIlqo+Ushwdpa4tAKg= go.etcd.io/bbolt v1.3.4 h1:hi1bXHMVrlQh6WwxAy+qZCV/SYIlqo+Ushwdpa4tAKg=
go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
go.etztech.xyz/falseknees v0.0.1 h1:XjlBqMyBUH5b7e/9oedEwZ9pnz3sqMhXQv6vnQocxeM= go.etztech.xyz/falseknees v0.0.1 h1:XjlBqMyBUH5b7e/9oedEwZ9pnz3sqMhXQv6vnQocxeM=
go.etztech.xyz/falseknees v0.0.1/go.mod h1:Acn1AwrvAArQEqhMBDlak5BvCZ3jgV8vdL8Pe5ZldRE= go.etztech.xyz/falseknees v0.0.1/go.mod h1:Acn1AwrvAArQEqhMBDlak5BvCZ3jgV8vdL8Pe5ZldRE=
go.etztech.xyz/go-mcm v1.3.1 h1:RLdOQrMgw0eP7bsfRRbXLW8c5/RaJ5Mg7i/ESFaUwvY= go.etztech.xyz/go-mcm v1.3.1 h1:RLdOQrMgw0eP7bsfRRbXLW8c5/RaJ5Mg7i/ESFaUwvY=
go.etztech.xyz/go-mcm v1.3.1/go.mod h1:Hz2YULB3sN/aQA8cPSm2d6LM3E3qTMspzfRCIAD/1dc= go.etztech.xyz/go-mcm v1.3.1/go.mod h1:Hz2YULB3sN/aQA8cPSm2d6LM3E3qTMspzfRCIAD/1dc=
go.etztech.xyz/go-serverapi v0.0.3 h1:h2Zww0x5E61cH4jXB97x3oUnbryEuLkuq+RTgIi5/U4=
go.etztech.xyz/go-serverapi v0.0.3/go.mod h1:tq4J5zxVnAwzOiv79iLUzpfNAd7IoNirOfb0gt3/IEY=
go.etztech.xyz/inspiro v0.0.0-20200606185551-edfdf9da2359 h1:j/ZeoAj185wHfCSYD52Kt/69i3Bzk1MXN4Qh1yP6+P4= go.etztech.xyz/inspiro v0.0.0-20200606185551-edfdf9da2359 h1:j/ZeoAj185wHfCSYD52Kt/69i3Bzk1MXN4Qh1yP6+P4=
go.etztech.xyz/inspiro v0.0.0-20200606185551-edfdf9da2359/go.mod h1:+fC1WzJm/oS4UEgqr1jPouWerxBys52lTTDA94/5bf8= go.etztech.xyz/inspiro v0.0.0-20200606185551-edfdf9da2359/go.mod h1:+fC1WzJm/oS4UEgqr1jPouWerxBys52lTTDA94/5bf8=
go.jolheiser.com/beaver v1.0.2 h1:KA2D6iO8MQhZi1nZYi/Chak/f1Cxfrs6b1XO623+Khk= go.jolheiser.com/beaver v1.0.2 h1:KA2D6iO8MQhZi1nZYi/Chak/f1Cxfrs6b1XO623+Khk=
go.jolheiser.com/beaver v1.0.2/go.mod h1:7X4F5+XOGSC3LejTShoBdqtRCnPWcnRgmYGmG3EKW8g= go.jolheiser.com/beaver v1.0.2/go.mod h1:7X4F5+XOGSC3LejTShoBdqtRCnPWcnRgmYGmG3EKW8g=
go.jolheiser.com/gojang v0.0.3 h1:EWDLMo6X3f67DK2p/mSB680H43t8SDrDYNZnXvY7PLg= go.jolheiser.com/gojang v0.0.3 h1:EWDLMo6X3f67DK2p/mSB680H43t8SDrDYNZnXvY7PLg=
go.jolheiser.com/gojang v0.0.3/go.mod h1:hUBULFDoampNM97E1IaYUhkLBJ30sb7iGsoFOdDU76I= go.jolheiser.com/gojang v0.0.3/go.mod h1:hUBULFDoampNM97E1IaYUhkLBJ30sb7iGsoFOdDU76I=
go.jolheiser.com/gql v0.0.1 h1:y3LGHcJUZI9otTCcMn8TVdF3aEzNX0FW6m0YUamlLto=
go.jolheiser.com/gql v0.0.1/go.mod h1:74eYqVRIxsOFxtVl0RYGKNyYQgJYQaxOCgar7LP71Hw=
go.jolheiser.com/xkcd v0.0.1 h1:pRNY2BXxUS+NMtKlm/ENumOr7g3k4VWY/QoDri9YSNU= go.jolheiser.com/xkcd v0.0.1 h1:pRNY2BXxUS+NMtKlm/ENumOr7g3k4VWY/QoDri9YSNU=
go.jolheiser.com/xkcd v0.0.1/go.mod h1:AzWPrZToCLfpazsZBkeu/nPuIvurMqfCOptiydz7Dvk= go.jolheiser.com/xkcd v0.0.1/go.mod h1:AzWPrZToCLfpazsZBkeu/nPuIvurMqfCOptiydz7Dvk=
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16 h1:y6ce7gCWtnH+m3dCjzQ1PCuwl28DDIc3VNnvY29DlIA=
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E= golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E=
@ -30,9 +48,7 @@ golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5 h1:LfCXLvNmTYH9kEmVgqbnsWfruoXZIrh4YBgqVHtDvw0=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201024232916-9f70ab9862d5 h1:iCaAy5bMeEvwANu3YnJfWwI0kWAGkEa2RXPdweI/ysk= golang.org/x/sys v0.0.0-20201024232916-9f70ab9862d5 h1:iCaAy5bMeEvwANu3YnJfWwI0kWAGkEa2RXPdweI/ysk=
golang.org/x/sys v0.0.0-20201024232916-9f70ab9862d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201024232916-9f70ab9862d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=

View File

@ -1,5 +1,3 @@
//go:generate go run sedbot.example.go
package main package main
import ( import (

View File

@ -1,35 +0,0 @@
// +build ignore
package main
import (
"fmt"
"io/ioutil"
"os"
)
const (
exampleFile = "sedbot.example.toml"
writeFile = "config/config_default.go"
tmpl = `package config
func init() {
defaultConfig = []byte(` + "`" + `%s` + "`" + `)
}
`
)
func main() {
bytes, err := ioutil.ReadFile(exampleFile)
if err != nil {
fmt.Printf("Could not read from %s. Are you in the root directory of the project?", exampleFile)
os.Exit(1)
}
data := fmt.Sprintf(tmpl, string(bytes))
if err := ioutil.WriteFile(writeFile, []byte(data), os.ModePerm); err != nil {
fmt.Printf("Could not write to %s.", writeFile)
os.Exit(1)
}
}