Skip to content

Commit ff24a02

Browse files
committed
main: Restructuring and cleanup
- Include (build/run).(bat/sh) scripts - Add support for feature toggles - Sync configuration on load to dispose of unused fields - Update configuration template with non-nil values - Add support for authenticating Wolfram|Alpha - Add conversational query support, using Wolfram|Alpha only for now - Split up command framework - Move actual commands into subpackages of features (currently dumpctx and hellodolly, removing helloworld) - Return command if name matches, not just alias list - Stop attempting to support raw message commands for now - Remove Discord metadata from command context - Add service client interface to command context for service callbacks (not yet a custom interface type with methods) - Support embed-style command responses - Add ability for command to hold off on responding by being not ready (not yet reflected by Discord) - Split up Discord framework - Heavily revise Discord command handler to support nested subcommands - Support Discord embeds with fields such as text, color, and image - Remove display name and command prefix from Discord configuration - Stop returning a Discord session when starting Discord, as the service is now stored internally within the package - Add preliminary support for responding to message components - Add go mod support - Other specifics I didn't notice when reading the git diff
1 parent ce56e62 commit ff24a02

26 files changed

+1014
-347
lines changed

bot.go

+34-7
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,21 @@ import (
66
"os/signal"
77
"syscall"
88

9-
"github.com/Clinet/clinet/discord"
9+
"github.com/Clinet/clinet/cmds"
1010
"github.com/Clinet/clinet/config"
11+
"github.com/Clinet/clinet/convos"
12+
"github.com/Clinet/clinet/discord"
13+
"github.com/Clinet/clinet/features"
14+
"github.com/Clinet/clinet/features/dumpctx"
15+
"github.com/Clinet/clinet/features/hellodolly"
16+
"github.com/JoshuaDoes/go-wolfram"
1117
)
1218

1319
//Global error value because functions are mean
1420
var err error
1521

1622
var (
17-
cfg *config.Config
18-
Discord *discord.DiscordSession
23+
cfg *config.Config
1924
)
2025

2126
func doBot() {
@@ -29,22 +34,44 @@ func doBot() {
2934
log.Error("Error loading configuration: ", err)
3035
}
3136

37+
log.Info("Syncing configuration...")
38+
cfg.SaveTo(configFile, config.ConfigTypeJSON)
39+
3240
if writeConfigTemplate {
3341
log.Info("Updating configuration template...")
34-
var templateCfg *config.Config = &config.Config{}
42+
var templateCfg *config.Config = &config.Config{
43+
Features: []*features.Feature{&features.Feature{Name: "example", Toggle: true}},
44+
Discord: &discord.CfgDiscord{},
45+
WolframAlpha: &wolfram.Client{},
46+
}
3547
templateCfg.SaveTo("config.template.json", config.ConfigTypeJSON)
3648
}
3749

50+
log.Debug("Setting feature toggles...")
51+
features.SetFeatures(cfg.Features)
52+
53+
log.Debug("Registering features...")
54+
if features.IsEnabled("dumpctx") {
55+
cmds.Commands = append(cmds.Commands, dumpctx.CmdRoot)
56+
}
57+
if features.IsEnabled("hellodolly") {
58+
cmds.Commands = append(cmds.Commands, hellodolly.CmdRoot)
59+
}
60+
61+
log.Debug("Enabling services...")
62+
convos.AuthWolframAlpha(cfg.WolframAlpha)
63+
log.Trace("- Wolfram|Alpha")
64+
3865
//Load modules
3966
log.Info("Loading modules...")
4067
loadModules()
4168

4269
//Start Discord
4370
log.Info("Starting Discord...")
44-
Discord = discord.StartDiscord(cfg.Discord)
45-
defer Discord.Close()
71+
discord.StartDiscord(cfg.Discord)
72+
defer discord.Discord.Close()
4673

47-
log.Debug("Waiting for SIGINT syscall signal")
74+
log.Debug("Waiting for SIGINT syscall signal...")
4875
sc := make(chan os.Signal, 1)
4976
signal.Notify(sc, syscall.SIGINT)
5077
<-sc

build.bat

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
@echo off
2+
:: Please use govvv when possible! (go install github.com/JoshuaDoes/govvv@latest)
3+
4+
govvv build -ldflags="-s -w" -o clinet.exe
5+
:: go build -ldflags="-s -w" -o clinet.exe

build.sh

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/bin/sh
2+
# Please use govvv when possible! (go install github.com/JoshuaDoes/govvv@latest)
3+
4+
govvv build -ldflags="-s -w" -o clinet.app
5+
## go build -ldflags="-s -w" -o clinet.app
6+
chmod +x clinet.app

cmds/arguments.go

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package cmds
2+
3+
type CmdArg struct {
4+
Name string //Display name for argument
5+
Description string //Description for command usage
6+
Value interface{} //Value for argument, set to default value (or zero value if required argument) when creating command
7+
Required bool //True when argument must be changed
8+
}
9+
func NewCmdArg(name, desc string, value interface{}) *CmdArg {
10+
return &CmdArg{
11+
Name: name,
12+
Description: desc,
13+
Value: value,
14+
}
15+
}
16+
func (arg *CmdArg) GetString() string {
17+
return arg.Value.(string)
18+
}
19+
func (arg *CmdArg) SetRequired() {
20+
arg.Required = true
21+
}

cmds/builder.go

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package cmds
2+
3+
//CmdBuilder builds a list of Cmd paired to a CmdCtx
4+
type CmdBuilder struct {
5+
Commands []*CmdBuilderCommand
6+
}
7+
func CmdBatch(cmds ...*CmdBuilderCommand) *CmdBuilder {
8+
return &CmdBuilder{
9+
Commands: cmds,
10+
}
11+
}
12+
type CmdBuilderCommand struct {
13+
Command *Cmd //Command to execute
14+
Context *CmdCtx //Context for command
15+
}
16+
func CmdBuildCommand(cmd *Cmd, ctx *CmdCtx) *CmdBuilderCommand {
17+
return &CmdBuilderCommand{Command: cmd, Context: ctx}
18+
}
19+
func (cmdBuild *CmdBuilder) Run() ([]*CmdResp) {
20+
if cmdBuild == nil || len(cmdBuild.Commands) == 0 {
21+
return nil
22+
}
23+
resps := make([]*CmdResp, 0)
24+
for _, command := range cmdBuild.Commands {
25+
resps = append(resps, command.Command.Exec(command.Context))
26+
}
27+
return resps
28+
}

cmds/cmd-help.go

-16
This file was deleted.

cmds/cmds.go

+45-49
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package cmds
22

33
import (
44
"errors"
5-
"strings"
5+
"regexp"
66
)
77

88
var (
@@ -12,18 +12,15 @@ var (
1212
)
1313

1414
//Commands holds the complete command list
15-
var Commands []*Cmd = []*Cmd{
16-
&Cmd{
17-
Handler: makeCmdRespHandler("Hello, world!"),
18-
Matches: []string{"helloworld", "hw"},
19-
Description: "Simply responds with a hello, world!",
20-
},
21-
}
15+
var Commands []*Cmd = make([]*Cmd, 0)
2216

2317
//GetCmd returns a cmd that matches the given alias
24-
func GetCmd(alias string) *Cmd {
18+
func GetCmd(match string) *Cmd {
2519
for _, cmd := range Commands {
26-
for _, match := range cmd.Matches {
20+
if match == cmd.Name {
21+
return cmd
22+
}
23+
for _, alias := range cmd.Aliases {
2724
if match == alias {
2825
return cmd
2926
}
@@ -32,50 +29,49 @@ func GetCmd(alias string) *Cmd {
3229
return nil
3330
}
3431

35-
//CmdBuilder builds a list of Cmd paired to a CmdCtx
36-
type CmdBuilder struct {
37-
Commands []*CmdBuilderCommand
32+
type Cmd struct {
33+
Exec func(*CmdCtx) *CmdResp //Go function to handle command
34+
Name string //Display name for command
35+
Description string //Description for command lists and command usage
36+
Aliases []string //Aliases to refer to command
37+
Regexes []regexp.Regexp //Regular expressions to match command call with natural language ($1 is Args[0], $2 is Args[1], etc)
38+
Args []CmdArg //Arguments for command
39+
Subcommands []*Cmd //Subcommands for command (nestable, i.e. "/minecraft server mc.hypixel.net" where server is subcommand to minecraft command)
3840
}
39-
func CmdBatch(cmds ...*CmdBuilderCommand) *CmdBuilder {
40-
return &CmdBuilder{
41-
Commands: cmds,
41+
func NewCmd(name, desc string, handler func(*CmdCtx) *CmdResp) *Cmd {
42+
return &Cmd{
43+
Name: name,
44+
Description: desc,
45+
Aliases: []string{name},
46+
Exec: handler,
4247
}
4348
}
44-
type CmdBuilderCommand struct {
45-
Command *Cmd //Command to execute
46-
Context *CmdCtx //Context for command
49+
func (cmd *Cmd) SetHandler(handler func(*CmdCtx) *CmdResp) {
50+
cmd.Exec = handler
4751
}
48-
func CmdBuildCommand(cmd *Cmd, ctx *CmdCtx) *CmdBuilderCommand {
49-
return &CmdBuilderCommand{Command: cmd, Context: ctx}
52+
func (cmd *Cmd) SetName(name string) {
53+
cmd.Name = name
5054
}
51-
func (cmdBuild *CmdBuilder) Run() ([]*CmdResp) {
52-
if cmdBuild == nil || len(cmdBuild.Commands) == 0 {
53-
return nil
54-
}
55-
resps := make([]*CmdResp, 0)
56-
for _, command := range cmdBuild.Commands {
57-
resps = append(resps, command.Command.Exec(command.Context))
58-
}
59-
return resps
55+
func (cmd *Cmd) SetDescription(desc string) {
56+
cmd.Description = desc
6057
}
61-
62-
func CmdMessage(ctx *CmdCtx, content string) (*CmdBuilderCommand, error) {
63-
//Build cmd
64-
var cmd *Cmd = nil
65-
66-
raw := strings.Split(content, " ")
67-
cmd = GetCmd(raw[0])
68-
if cmd == nil {
69-
return nil, ErrCmdNotFound
70-
}
71-
72-
//Process ctx
73-
ctx.CmdAlias = raw[0]
74-
ctx.CmdParams = make([]string, 0)
75-
if len(raw) > 1 {
76-
ctx.CmdParams = raw[1:]
58+
func (cmd *Cmd) AddAliases(alias ...string) {
59+
cmd.Aliases = append(cmd.Aliases, alias...)
60+
}
61+
func (cmd *Cmd) AddRegexes(regex ...regexp.Regexp) {
62+
cmd.Regexes = append(cmd.Regexes, regex...)
63+
}
64+
func (cmd *Cmd) AddArgs(arg ...CmdArg) {
65+
cmd.Args = append(cmd.Args, arg...)
66+
}
67+
func (cmd *Cmd) AddSubCmds(subCmd ...*Cmd) {
68+
cmd.Subcommands = append(cmd.Subcommands, subCmd...)
69+
}
70+
func (cmd *Cmd) IsAlias(alias string) bool {
71+
for i := 0; i < len(cmd.Aliases); i++ {
72+
if cmd.Aliases[i] == alias {
73+
return true
74+
}
7775
}
78-
79-
//Return cmd builder command
80-
return CmdBuildCommand(cmd, ctx), nil
76+
return false
8177
}

cmds/context.go

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package cmds
2+
3+
import (
4+
"github.com/JoshuaDoes/json"
5+
)
6+
7+
type CmdCtx struct {
8+
Content string //Raw message that triggered command
9+
ContentDisplay string //Displayable form of raw message
10+
Alias string //Alias that triggered command
11+
Args []*CmdArg //Arguments for command handler
12+
Edited bool //True when called in response to edited call
13+
Service interface{} //Service client for service callbacks
14+
}
15+
func NewCmdCtx() *CmdCtx {
16+
return &CmdCtx{}
17+
}
18+
func (ctx *CmdCtx) String() string {
19+
jsonData, err := json.Marshal(ctx, true)
20+
if err != nil {
21+
return err.Error()
22+
}
23+
return string(jsonData)
24+
}
25+
func (ctx *CmdCtx) SetAlias(alias string) *CmdCtx {
26+
ctx.Alias = alias
27+
return ctx
28+
}
29+
func (ctx *CmdCtx) SetContent(content, contentDisplay string) *CmdCtx {
30+
ctx.Content = content //<@!xxxxxxxxxx> Hello, world!
31+
ctx.ContentDisplay = contentDisplay //@Clinet Hello, world!
32+
return ctx
33+
}
34+
func (ctx *CmdCtx) SetQuery(alias string) *CmdCtx {
35+
ctx.Alias = alias //helloworld
36+
return ctx
37+
}
38+
func (ctx *CmdCtx) SetEdited() *CmdCtx {
39+
ctx.Edited = true
40+
return ctx
41+
}
42+
func (ctx *CmdCtx) SetService(service interface{}) *CmdCtx {
43+
ctx.Service = service
44+
return ctx
45+
}
46+
func (ctx *CmdCtx) AddArgs(arg ...*CmdArg) *CmdCtx {
47+
ctx.Args = append(ctx.Args, arg...)
48+
return ctx
49+
}

0 commit comments

Comments
 (0)