Added subday module with a subday handlers
This commit is contained in:
parent
bb26c57985
commit
8ba3b08ed1
7 changed files with 273 additions and 22 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1 +1,2 @@
|
||||||
tokens/*token
|
tokens/*token
|
||||||
|
backups/*
|
13
main.go
13
main.go
|
@ -7,6 +7,7 @@ import (
|
||||||
"galched-bot/modules/discord"
|
"galched-bot/modules/discord"
|
||||||
"galched-bot/modules/grace"
|
"galched-bot/modules/grace"
|
||||||
"galched-bot/modules/settings"
|
"galched-bot/modules/settings"
|
||||||
|
"galched-bot/modules/subday"
|
||||||
|
|
||||||
"go.uber.org/fx"
|
"go.uber.org/fx"
|
||||||
)
|
)
|
||||||
|
@ -25,14 +26,16 @@ type (
|
||||||
|
|
||||||
func (s *silentPrinter) Printf(str string, i ...interface{}) {}
|
func (s *silentPrinter) Printf(str string, i ...interface{}) {}
|
||||||
|
|
||||||
func start(p appParam) {
|
func start(p appParam) error {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
log.Print("main: starting galched-bot v", p.Settings.Version)
|
log.Print("main: starting galched-bot v", p.Settings.Version)
|
||||||
|
|
||||||
err = p.Discord.Start()
|
err = p.Discord.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("discord: cannot start instance", err)
|
log.Print("discord: cannot start instance", err)
|
||||||
|
return err
|
||||||
|
|
||||||
}
|
}
|
||||||
log.Printf("main: discord instance running")
|
log.Printf("main: discord instance running")
|
||||||
log.Printf("main: — — —")
|
log.Printf("main: — — —")
|
||||||
|
@ -42,17 +45,19 @@ func start(p appParam) {
|
||||||
|
|
||||||
err = p.Discord.Stop()
|
err = p.Discord.Stop()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("discord: cannot stop instance", err)
|
log.Print("discord: cannot stop instance", err)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Print("main: galched bot successfully stopped")
|
log.Print("main: galched bot successfully stopped")
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var err error
|
var err error
|
||||||
app := fx.New(
|
app := fx.New(
|
||||||
fx.Logger(new(silentPrinter)),
|
fx.Logger(new(silentPrinter)),
|
||||||
fx.Provide(settings.New, grace.New, discord.New),
|
fx.Provide(settings.New, grace.New, discord.New, subday.New),
|
||||||
fx.Invoke(start))
|
fx.Invoke(start))
|
||||||
|
|
||||||
err = app.Start(context.Background())
|
err = app.Start(context.Background())
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"galched-bot/modules/settings"
|
"galched-bot/modules/settings"
|
||||||
|
"galched-bot/modules/subday"
|
||||||
|
|
||||||
"github.com/bwmarrin/discordgo"
|
"github.com/bwmarrin/discordgo"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
@ -18,7 +19,7 @@ type (
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func New(s *settings.Settings) (*Discord, error) {
|
func New(s *settings.Settings, subday *subday.Subday) (*Discord, error) {
|
||||||
key := fmt.Sprintf("Bot %s", s.DiscordToken)
|
key := fmt.Sprintf("Bot %s", s.DiscordToken)
|
||||||
instance, err := discordgo.New(key)
|
instance, err := discordgo.New(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -26,6 +27,9 @@ func New(s *settings.Settings) (*Discord, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
processor := NewProcessor(s.Version)
|
processor := NewProcessor(s.Version)
|
||||||
|
for _, subdayHandler := range SubdayHandlers(subday, s.PermittedRoles) {
|
||||||
|
processor.AddHandler(subdayHandler)
|
||||||
|
}
|
||||||
|
|
||||||
log.Printf("discord: added %d message handlers", len(processor.handlers))
|
log.Printf("discord: added %d message handlers", len(processor.handlers))
|
||||||
if len(processor.handlers) > 0 {
|
if len(processor.handlers) > 0 {
|
||||||
|
@ -45,6 +49,13 @@ func LogMessage(m *discordgo.MessageCreate) {
|
||||||
log.Printf("discord: msg [%s]: %s", m.Author.Username, m.Content)
|
log.Printf("discord: msg [%s]: %s", m.Author.Username, m.Content)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SendMessage(s *discordgo.Session, m *discordgo.MessageCreate, text string) {
|
||||||
|
_, err := s.ChannelMessageSend(m.ChannelID, text)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("discord: cannot send message [%s]: %v", text, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (d *Discord) Start() error {
|
func (d *Discord) Start() error {
|
||||||
d.session.AddHandler(d.processor.Process)
|
d.session.AddHandler(d.processor.Process)
|
||||||
return d.session.Open()
|
return d.session.Open()
|
||||||
|
|
150
modules/discord/subdayhandlers.go
Normal file
150
modules/discord/subdayhandlers.go
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
package discord
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"galched-bot/modules/subday"
|
||||||
|
|
||||||
|
"github.com/bwmarrin/discordgo"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SubdayListHandler struct {
|
||||||
|
subday *subday.Subday
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *SubdayListHandler) Signature() string {
|
||||||
|
return "!sublist"
|
||||||
|
}
|
||||||
|
func (h *SubdayListHandler) Description() string {
|
||||||
|
return "список игр для сабдея"
|
||||||
|
}
|
||||||
|
func (h *SubdayListHandler) IsValid(msg string) bool {
|
||||||
|
return msg == "!sublist"
|
||||||
|
}
|
||||||
|
func (h *SubdayListHandler) Handle(s *discordgo.Session, m *discordgo.MessageCreate) {
|
||||||
|
h.subday.RLock()
|
||||||
|
defer h.subday.RUnlock()
|
||||||
|
LogMessage(m)
|
||||||
|
|
||||||
|
c, err := s.State.Channel(m.ChannelID)
|
||||||
|
if err != nil {
|
||||||
|
log.Print("discord: cannot obtain state", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
g, err := s.State.Guild(c.GuildID)
|
||||||
|
if err != nil {
|
||||||
|
log.Print("discord: cannot obtain guild", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
message := "Игры предыдущих сабдеев:\n**20.10.18**: _DmC_ -> _Fable 1_ -> _Overcooked 2_\n" +
|
||||||
|
"**17.11.18**: _The Witcher_ -> _Xenus: Белое Золото_ -> _NFS: Underground 2_\n" +
|
||||||
|
"**22.12.18**: _True Crime: Streets of LA_ -> _Serious Sam 3_ -> _Kholat_\n" +
|
||||||
|
"**26.01.19**: _Disney’s Aladdin_ -> _~~Gothic~~_ -> _Scrapland_ -> _Donut County_\n\n" +
|
||||||
|
"Список игр для следующего сабдея:\n"
|
||||||
|
for k, v := range h.subday.Database() {
|
||||||
|
nickname := " "
|
||||||
|
for _, member := range g.Members {
|
||||||
|
if k == member.User.ID {
|
||||||
|
if member.Nick != "" {
|
||||||
|
nickname = member.Nick
|
||||||
|
} else {
|
||||||
|
nickname = member.User.Username
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, game := range v {
|
||||||
|
message += fmt.Sprintf(" **- %s** от _%s_\n", game, nickname)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_, err = s.ChannelMessageSend(m.ChannelID, strings.Trim(message, "\n"))
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("discord: cannot send message [%s]: %v", message, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type SubdayAddHandler struct {
|
||||||
|
subday *subday.Subday
|
||||||
|
roles []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *SubdayAddHandler) Signature() string {
|
||||||
|
return "!subday <game-name>"
|
||||||
|
}
|
||||||
|
func (h *SubdayAddHandler) Description() string {
|
||||||
|
return "добавление игры в список сабдея"
|
||||||
|
}
|
||||||
|
func (h *SubdayAddHandler) IsValid(msg string) bool {
|
||||||
|
return strings.HasPrefix(msg, "!subday")
|
||||||
|
}
|
||||||
|
func (h *SubdayAddHandler) Handle(s *discordgo.Session, m *discordgo.MessageCreate) {
|
||||||
|
h.subday.Lock()
|
||||||
|
defer h.subday.Unlock()
|
||||||
|
LogMessage(m)
|
||||||
|
|
||||||
|
c, err := s.State.Channel(m.ChannelID)
|
||||||
|
if err != nil {
|
||||||
|
log.Print("discord: cannot obtain state", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
g, err := s.State.Guild(c.GuildID)
|
||||||
|
if err != nil {
|
||||||
|
log.Print("discord: cannot obtain guild", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
member, err := s.State.Member(g.ID, m.Author.ID)
|
||||||
|
if err != nil {
|
||||||
|
log.Print("discord: cannot obtain user role", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if g.Name != "AV" && g.Name != "Galched" {
|
||||||
|
log.Printf("discord: message from unsupported guild %s, ignore", g.Name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
permissionGranted := false
|
||||||
|
loop:
|
||||||
|
for i := range member.Roles {
|
||||||
|
for j := range h.roles {
|
||||||
|
if member.Roles[i] == h.roles[j] {
|
||||||
|
permissionGranted = true
|
||||||
|
break loop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if permissionGranted {
|
||||||
|
game := strings.Trim(strings.Replace(m.Content, "!subday", "", 1), " ")
|
||||||
|
if game != "" {
|
||||||
|
gameList, ok := h.subday.Database()[m.Author.ID]
|
||||||
|
if ok && len(gameList) > 10 {
|
||||||
|
SendMessage(s, m, "Нельзя заказать больше 10 игр")
|
||||||
|
return
|
||||||
|
} else if ok {
|
||||||
|
for i := range gameList {
|
||||||
|
if game == gameList[i] {
|
||||||
|
SendMessage(s, m, "Эта игра уже заказана вами")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
h.subday.Database()[m.Author.ID] = append(h.subday.Database()[m.Author.ID], game)
|
||||||
|
log.Printf("subday: game [%s] is added to subday database", game)
|
||||||
|
SendMessage(s, m, fmt.Sprintf("Игра \"%s\" добавлена в список", game))
|
||||||
|
h.subday.DumpToFile()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Print("subday: game is not added, insufficient rights")
|
||||||
|
SendMessage(s, m, "Заказ игр для сабдея доступен только для подписчиков канала (и Нифлая)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SubdayHandlers(s *subday.Subday, r []string) []MessageHandler {
|
||||||
|
var result []MessageHandler
|
||||||
|
|
||||||
|
addHandler := &SubdayAddHandler{s, r}
|
||||||
|
listHandler := &SubdayListHandler{s}
|
||||||
|
return append(result, addHandler, listHandler)
|
||||||
|
}
|
|
@ -6,20 +6,20 @@ import (
|
||||||
|
|
||||||
type testHandler struct{}
|
type testHandler struct{}
|
||||||
|
|
||||||
var _ = (testHandler)(nil) // ignore unused warning
|
var _ = testHandler{} // ignore unused warning
|
||||||
|
|
||||||
func (t *testHandler) Signature() string {
|
func (h *testHandler) Signature() string {
|
||||||
return "!test"
|
return "!test"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *testHandler) Description() string {
|
func (h *testHandler) Description() string {
|
||||||
return "тестовый хэндлер"
|
return "тестовый хэндлер"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *testHandler) IsValid(msg string) bool {
|
func (h *testHandler) IsValid(msg string) bool {
|
||||||
return msg == "!test"
|
return msg == "!test"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *testHandler) Handle(s *discordgo.Session, m *discordgo.MessageCreate) {
|
func (h *testHandler) Handle(s *discordgo.Session, m *discordgo.MessageCreate) {
|
||||||
LogMessage(m)
|
LogMessage(m)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,32 +3,43 @@ package settings
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"time"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
version = "3.0.0"
|
version = "3.0.0"
|
||||||
discordTokenPath = "./tokens/.discordtoken"
|
discordTokenPath = "./tokens/.discordtoken"
|
||||||
|
subdayDataPath = "./backups/subday"
|
||||||
|
subdayDataDuration = 10 // in seconds
|
||||||
|
|
||||||
|
// Permitted roles in discord for subday
|
||||||
|
subRole1 = "433672344737677322"
|
||||||
|
subRole2 = "433680494635515904"
|
||||||
|
galchedRole = "301467455497175041"
|
||||||
|
smorcRole = "301470784491356172"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
Settings struct {
|
Settings struct {
|
||||||
Version string
|
Version string
|
||||||
DiscordToken string
|
DiscordToken string
|
||||||
|
SubdayDataPath string
|
||||||
|
SubdayJobDuration time.Duration
|
||||||
|
PermittedRoles []string
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func New() (*Settings, error) {
|
func New() (*Settings, error) {
|
||||||
log.Print(os.Getwd())
|
|
||||||
discordToken, err := ioutil.ReadFile(discordTokenPath)
|
discordToken, err := ioutil.ReadFile(discordTokenPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "cannot read discord token file")
|
log.Print("settings: cannot read discord token file", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Settings{
|
return &Settings{
|
||||||
Version: version,
|
Version: version,
|
||||||
DiscordToken: string(discordToken),
|
DiscordToken: string(discordToken),
|
||||||
|
SubdayDataPath: subdayDataPath,
|
||||||
|
SubdayJobDuration: subdayDataDuration * time.Second,
|
||||||
|
PermittedRoles: []string{subRole1, subRole2, galchedRole, smorcRole},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
73
modules/subday/subday.go
Normal file
73
modules/subday/subday.go
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
package subday
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"galched-bot/modules/settings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Subday struct {
|
||||||
|
sync.RWMutex
|
||||||
|
path string
|
||||||
|
database map[string][]string
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(s *settings.Settings) (*Subday, error) {
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
data = make(map[string][]string)
|
||||||
|
)
|
||||||
|
|
||||||
|
subdayData, err := ioutil.ReadFile(s.SubdayDataPath)
|
||||||
|
if err != nil {
|
||||||
|
log.Print("subday: cannot read subday data file", err)
|
||||||
|
log.Print("subday: creating new subday database")
|
||||||
|
} else {
|
||||||
|
err = json.Unmarshal(subdayData, &data)
|
||||||
|
if err != nil {
|
||||||
|
data = make(map[string][]string)
|
||||||
|
log.Print("subday: cannot unmarshal subday data file", err)
|
||||||
|
log.Print("subday: creating new subday database")
|
||||||
|
} else {
|
||||||
|
log.Print("subday: using previously saved subday database")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
subday := &Subday{
|
||||||
|
RWMutex: sync.RWMutex{},
|
||||||
|
path: s.SubdayDataPath,
|
||||||
|
database: data,
|
||||||
|
}
|
||||||
|
return subday, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Subday) Database() map[string][]string {
|
||||||
|
return s.database
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Subday) DumpToFile() {
|
||||||
|
data, err := json.Marshal(s.database)
|
||||||
|
if err != nil {
|
||||||
|
log.Print("subday: cannot marshal database file", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
file, err := os.Create(s.path)
|
||||||
|
if err != nil {
|
||||||
|
log.Print("subday: cannot open database file", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, err = fmt.Fprintf(file, string(data))
|
||||||
|
if err != nil {
|
||||||
|
log.Print("subday: cannot write to database file")
|
||||||
|
}
|
||||||
|
err = file.Close()
|
||||||
|
if err != nil {
|
||||||
|
log.Print("subday: cannot close database file")
|
||||||
|
}
|
||||||
|
log.Print("subday: database dumped to file")
|
||||||
|
}
|
Loading…
Reference in a new issue